00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifdef WIN32
00015 #include "../config.h.win"
00016 #else
00017 #include "config.h"
00018 #endif
00019
00020 #include "dns.h"
00021
00022 #include <sys/types.h>
00023
00024 #ifndef WIN32
00025 #include <netinet/in.h>
00026 #include <resolv.h>
00027 #include <sys/socket.h>
00028 #include <sys/un.h>
00029 #include <netdb.h>
00030 #include <sys/socket.h>
00031 #include <arpa/inet.h>
00032 #else
00033 #include <winsock.h>
00034 #endif
00035
00036 #define SRV_COST (RRFIXEDSZ+0)
00037 #define SRV_WEIGHT (RRFIXEDSZ+2)
00038 #define SRV_PORT (RRFIXEDSZ+4)
00039 #define SRV_SERVER (RRFIXEDSZ+6)
00040 #define SRV_FIXEDSZ (RRFIXEDSZ+6)
00041
00042 #ifndef T_SRV
00043 #define T_SRV 33
00044 #endif
00045
00046 #ifndef C_IN
00047 #define C_IN 1
00048 #endif
00049
00050 #ifndef INVALID_SOCKET
00051 #define INVALID_SOCKET -1
00052 #endif
00053
00054 #define XMPP_PORT 5222
00055
00056 namespace gloox
00057 {
00058
00059 #if defined( SKYOS ) || defined( WIN32 ) || ( defined( __NetBSD__ ) && ( __NetBSD_Version__ < 300000000 ) )
00060 int DNS::connect( const std::string& domain )
00061 {
00062 return DNS::connect( domain, XMPP_PORT );
00063 }
00064 #else
00065 DNS::HostMap DNS::resolve( const std::string& domain )
00066 {
00067 std::string service = "xmpp-client";
00068 std::string proto = "tcp";
00069
00070 return resolve( service, proto, domain );
00071 }
00072
00073 DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto,
00074 const std::string& domain )
00075 {
00076 buffer srvbuf;
00077 bool error = false;
00078
00079 const std::string dname = "_" + service + "._" + proto;
00080
00081 if( !domain.empty() )
00082 srvbuf.len = res_querydomain( dname.c_str(), (char*)domain.c_str(),
00083 C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
00084 else
00085 srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
00086
00087 if( srvbuf.len < 0 )
00088 return defaultHostMap( service, proto, domain );
00089
00090 HEADER* hdr = (HEADER*)srvbuf.buf;
00091 unsigned char* here = srvbuf.buf + NS_HFIXEDSZ;
00092
00093 if( ( hdr->tc ) || ( srvbuf.len < NS_HFIXEDSZ ) )
00094 error = true;
00095
00096 if( hdr->rcode >= 1 && hdr->rcode <= 5 )
00097 error = true;
00098
00099 if( ntohs( hdr->ancount ) == 0 )
00100 error = true;
00101
00102 if( ntohs( hdr->ancount ) > NS_PACKETSZ )
00103 error = true;
00104
00105 int cnt;
00106 for( cnt = ntohs( hdr->qdcount ); cnt>0; cnt-- )
00107 {
00108 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
00109 here += strlen + NS_QFIXEDSZ;
00110 }
00111
00112 unsigned char *srv[NS_PACKETSZ];
00113 int srvnum = 0;
00114 for( cnt = ntohs( hdr->ancount ); cnt>0; cnt-- )
00115 {
00116 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
00117 here += strlen;
00118 srv[srvnum++] = here;
00119 here += SRV_FIXEDSZ;
00120 here += dn_skipname( here, srvbuf.buf + srvbuf.len );
00121 }
00122
00123 if( error )
00124 {
00125 return defaultHostMap( service, proto, domain );
00126 }
00127
00128
00129
00130 HostMap servers;
00131 for( cnt=0; cnt<srvnum; ++cnt )
00132 {
00133 name srvname;
00134
00135 if( ns_name_ntop( srv[cnt] + SRV_SERVER, (char*)srvname, NS_MAXDNAME ) < 0 )
00136 printf( "handle this error!\n" );
00137
00138 servers[(char*)srvname] = ns_get16( srv[cnt] + SRV_PORT );
00139 }
00140
00141 return servers;
00142 }
00143
00144 DNS::HostMap DNS::defaultHostMap( const std::string& service, const std::string& proto,
00145 const std::string& domain )
00146 {
00147 HostMap server;
00148 struct servent *servent;
00149
00150 if( ( servent = getservbyname( service.c_str(), proto.c_str() ) ) == 0 )
00151 {
00152 server[domain] = 0;
00153 return server;
00154 }
00155
00156 if( !domain.empty() )
00157 server[domain] = ntohs( servent->s_port );
00158
00159 return server;
00160 }
00161
00162 int DNS::connect( const std::string& domain )
00163 {
00164 HostMap hosts = resolve( domain );
00165 if( hosts.size() == 0 )
00166 return -DNS_NO_HOSTS_FOUND;
00167
00168 struct protoent* prot;
00169 if( ( prot = getprotobyname( "tcp" ) ) == 0)
00170 return -DNS_COULD_NOT_RESOLVE;
00171
00172 int fd;
00173 if( ( fd = socket( PF_INET, SOCK_STREAM, prot->p_proto ) ) == -1 )
00174 return -DNS_COULD_NOT_RESOLVE;
00175
00176 struct hostent *h;
00177 struct sockaddr_in target;
00178 target.sin_family = AF_INET;
00179 int ret = 0;
00180 HostMap::const_iterator it = hosts.begin();
00181 for( ; it != hosts.end(); ++it )
00182 {
00183 int port;
00184 if( (*it).second == 0 )
00185 port = XMPP_PORT;
00186 else
00187 port = (*it).second;
00188
00189 target.sin_port = htons( port );
00190 if( ( h = gethostbyname( (*it).first.c_str() ) ) == 0 )
00191 {
00192 ret = -DNS_COULD_NOT_RESOLVE;
00193 continue;
00194 }
00195
00196 #ifdef DEBUG
00197 char *tmp = inet_ntoa( *((struct in_addr *)h->h_addr) );
00198 printf( "resolved %s to: %s:%d\n", (*it).first.c_str(), tmp, port );
00199 #endif
00200
00201 if( inet_aton( inet_ntoa(*((struct in_addr *)h->h_addr)), &(target.sin_addr) ) == 0 )
00202 continue;
00203
00204 memset( &(target.sin_zero), '\0', 8 );
00205 if( ::connect( fd, (struct sockaddr *)&target, sizeof( struct sockaddr ) ) == 0 )
00206 return fd;
00207
00208 close( fd );
00209 }
00210 if( ret )
00211 return ret;
00212
00213 return -DNS_COULD_NOT_CONNECT;
00214 }
00215 #endif
00216
00217 int DNS::connect( const std::string& domain, int port )
00218 {
00219 #ifdef WIN32
00220 WSADATA wsaData;
00221 if( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 )
00222 return -DNS_COULD_NOT_RESOLVE;
00223 #endif
00224
00225 struct protoent* prot;
00226 if( ( prot = getprotobyname( "tcp" ) ) == 0)
00227 {
00228 cleanup();
00229 return -DNS_COULD_NOT_RESOLVE;
00230 }
00231
00232 int fd;
00233 if( ( fd = socket( PF_INET, SOCK_STREAM, prot->p_proto ) ) == -1)
00234 {
00235 cleanup();
00236 return -DNS_COULD_NOT_CONNECT;
00237 }
00238
00239 struct hostent *h;
00240 if( ( h = gethostbyname( domain.c_str() ) ) == 0 )
00241 {
00242 cleanup();
00243 return -DNS_COULD_NOT_RESOLVE;
00244 }
00245
00246 #ifdef DEBUG
00247 printf( "resolved %s to: %s\n", domain.c_str(), inet_ntoa( *((struct in_addr *)h->h_addr) ) );
00248 #endif
00249
00250 struct sockaddr_in target;
00251 target.sin_family = AF_INET;
00252 target.sin_port = htons( port );
00253
00254
00255 #if !defined( SKYOS ) && !defined( WIN32 )
00256 if( inet_aton( inet_ntoa(*((struct in_addr *)h->h_addr)), &(target.sin_addr) ) == 0 )
00257 return -DNS_COULD_NOT_RESOLVE;
00258 #else
00259 target.sin_addr.s_addr = inet_addr( inet_ntoa(*((struct in_addr *)h->h_addr)) );
00260 #endif
00261
00262 memset( &(target.sin_zero), '\0', 8 );
00263 if( ::connect( fd, (struct sockaddr *)&target, sizeof( struct sockaddr ) ) == 0 )
00264 return fd;
00265
00266 #ifndef WIN32
00267 close( fd );
00268 #else
00269 closesocket( fd );
00270 cleanup();
00271 #endif
00272 return -DNS_COULD_NOT_CONNECT;
00273 }
00274
00275 void DNS::cleanup()
00276 {
00277 #ifdef WIN32
00278 WSACleanup();
00279 #endif
00280 }
00281 }