00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifdef _WIN32
00015 # include "../config.h.win"
00016 #elif defined( _WIN32_WCE )
00017 # include "../config.h.win"
00018 #else
00019 # include "config.h"
00020 #endif
00021
00022 #include "gloox.h"
00023 #include "dns.h"
00024
00025 #ifndef _WIN32_WCE
00026 # include <sys/types.h>
00027 # include <sstream>
00028 #endif
00029
00030 #include <stdio.h>
00031
00032 #if !defined( _WIN32 ) && !defined( _WIN32_WCE )
00033 # include <netinet/in.h>
00034 # include <arpa/nameser.h>
00035 # include <resolv.h>
00036 # include <netdb.h>
00037 # include <arpa/inet.h>
00038 # include <sys/socket.h>
00039 # include <sys/un.h>
00040 # include <unistd.h>
00041 #endif
00042
00043 #ifdef _WIN32
00044 # include <winsock.h>
00045 #elif defined( _WIN32_WCE )
00046 # include <winsock2.h>
00047 #endif
00048
00049 #ifdef HAVE_WINDNS_H
00050 # include <windns.h>
00051 #endif
00052
00053 #define SRV_COST (RRFIXEDSZ+0)
00054 #define SRV_WEIGHT (RRFIXEDSZ+2)
00055 #define SRV_PORT (RRFIXEDSZ+4)
00056 #define SRV_SERVER (RRFIXEDSZ+6)
00057 #define SRV_FIXEDSZ (RRFIXEDSZ+6)
00058
00059 #ifndef T_SRV
00060 # define T_SRV 33
00061 #endif
00062
00063
00064 #ifndef DNS_TYPE_SRV
00065 # define DNS_TYPE_SRV 33
00066 #endif
00067
00068 #ifndef C_IN
00069 # define C_IN 1
00070 #endif
00071
00072 #ifndef INVALID_SOCKET
00073 # define INVALID_SOCKET -1
00074 #endif
00075
00076 #define XMPP_PORT 5222
00077
00078 namespace gloox
00079 {
00080
00081 #if defined( HAVE_RES_QUERYDOMAIN ) && defined( HAVE_DN_SKIPNAME ) && defined( HAVE_RES_QUERY )
00082 DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto,
00083 const std::string& domain, const LogSink& logInstance )
00084 {
00085 buffer srvbuf;
00086 bool error = false;
00087
00088 const std::string dname = "_" + service + "._" + proto;
00089
00090 if( !domain.empty() )
00091 srvbuf.len = res_querydomain( dname.c_str(), const_cast<char*>( domain.c_str() ),
00092 C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
00093 else
00094 srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
00095
00096 if( srvbuf.len < 0 )
00097 return defaultHostMap( domain, logInstance );
00098
00099 HEADER* hdr = (HEADER*)srvbuf.buf;
00100 unsigned char* here = srvbuf.buf + NS_HFIXEDSZ;
00101
00102 if( ( hdr->tc ) || ( srvbuf.len < NS_HFIXEDSZ ) )
00103 error = true;
00104
00105 if( hdr->rcode >= 1 && hdr->rcode <= 5 )
00106 error = true;
00107
00108 if( ntohs( hdr->ancount ) == 0 )
00109 error = true;
00110
00111 if( ntohs( hdr->ancount ) > NS_PACKETSZ )
00112 error = true;
00113
00114 int cnt;
00115 for( cnt = ntohs( hdr->qdcount ); cnt>0; --cnt )
00116 {
00117 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
00118 here += strlen + NS_QFIXEDSZ;
00119 }
00120
00121 unsigned char *srv[NS_PACKETSZ];
00122 int srvnum = 0;
00123 for( cnt = ntohs( hdr->ancount ); cnt>0; --cnt )
00124 {
00125 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
00126 here += strlen;
00127 srv[srvnum++] = here;
00128 here += SRV_FIXEDSZ;
00129 here += dn_skipname( here, srvbuf.buf + srvbuf.len );
00130 }
00131
00132 if( error )
00133 {
00134 return defaultHostMap( domain, logInstance );
00135 }
00136
00137
00138
00139 HostMap servers;
00140 for( cnt=0; cnt<srvnum; ++cnt )
00141 {
00142 name srvname;
00143
00144 if( ns_name_ntop( srv[cnt] + SRV_SERVER, (char*)srvname, NS_MAXDNAME ) < 0 )
00145 printf( "handle this error!\n" );
00146
00147 servers[(char*)srvname] = ns_get16( srv[cnt] + SRV_PORT );
00148 }
00149
00150 return servers;
00151 }
00152
00153 #elif defined( _WIN32 ) && defined( HAVE_WINDNS_H )
00154 DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto,
00155 const std::string& domain, const LogSink& logInstance )
00156 {
00157 const std::string dname = "_" + service + "._" + proto + "." + domain;
00158 bool error = false;
00159
00160 DNS::HostMap servers;
00161 DNS_RECORD *pRecord;
00162 if( DnsQuery( dname.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &pRecord, NULL ) == ERROR_SUCCESS )
00163 {
00164 DNS_RECORD *pRec = pRecord;
00165 do
00166 {
00167 if( pRec->wType == DNS_TYPE_SRV )
00168 {
00169 servers[pRec->Data.SRV.pNameTarget] = pRec->Data.SRV.wPort;
00170 }
00171 pRec = pRec->pNext;
00172 }
00173 while( pRec != NULL );
00174 DnsRecordListFree( pRecord, DnsFreeRecordList );
00175 }
00176 else
00177 error = true;
00178
00179 if( error || !servers.size() )
00180 {
00181 servers = defaultHostMap( domain, logInstance );
00182 }
00183
00184 return servers;
00185 }
00186
00187 #else
00188 DNS::HostMap DNS::resolve( const std::string& , const std::string& ,
00189 const std::string& domain, const LogSink& logInstance )
00190 {
00191 logInstance.log( LogLevelWarning, LogAreaClassDns,
00192 "notice: gloox does not support SRV records on this platform. Using A records instead." );
00193 return defaultHostMap( domain, logInstance );
00194 }
00195 #endif
00196
00197 DNS::HostMap DNS::defaultHostMap( const std::string& domain, const LogSink& logInstance )
00198 {
00199 HostMap server;
00200
00201 logInstance.log( LogLevelWarning, LogAreaClassDns, "notice: no SRV record found for " + domain
00202 + ", using default port." );
00203
00204 if( !domain.empty() )
00205 server[domain] = XMPP_PORT;
00206
00207 return server;
00208 }
00209
00210 int DNS::connect( const std::string& domain, const LogSink& logInstance )
00211 {
00212 HostMap hosts = resolve( domain, logInstance );
00213 if( hosts.size() == 0 )
00214 return -ConnDnsError;
00215
00216 HostMap::const_iterator it = hosts.begin();
00217 for( ; it != hosts.end(); ++it )
00218 {
00219 int fd = DNS::connect( (*it).first, (*it).second, logInstance );
00220 if( fd >= 0 )
00221 return fd;
00222 }
00223
00224 return -ConnConnectionRefused;
00225 }
00226
00227 int DNS::getSocket()
00228 {
00229 #ifdef _WIN32
00230 WSADATA wsaData;
00231 if( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 )
00232 return -ConnDnsError;
00233 #endif
00234
00235 struct protoent* prot;
00236 if( ( prot = getprotobyname( "tcp" ) ) == 0 )
00237 {
00238 cleanup();
00239 return -ConnDnsError;
00240 }
00241
00242 int fd;
00243 if( ( fd = socket( PF_INET, SOCK_STREAM, prot->p_proto ) ) == -1 )
00244 {
00245 cleanup();
00246 return -ConnConnectionRefused;
00247 }
00248
00249 #ifdef HAVE_SETSOCKOPT
00250 int val = 1;
00251 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof( val ) );
00252 #endif
00253
00254 return fd;
00255 }
00256
00257 int DNS::connect( const std::string& domain, unsigned short port, const LogSink& logInstance )
00258 {
00259 int fd = getSocket();
00260 if( fd < 0 )
00261 return fd;
00262
00263 struct hostent *h;
00264 if( ( h = gethostbyname( domain.c_str() ) ) == 0 )
00265 {
00266 cleanup();
00267 return -ConnDnsError;
00268 }
00269
00270 struct sockaddr_in target;
00271 target.sin_family = AF_INET;
00272 target.sin_port = htons( port );
00273
00274 if( h->h_length != sizeof( struct in_addr ) )
00275 {
00276 cleanup();
00277 return -ConnDnsError;
00278 }
00279 else
00280 {
00281 memcpy( &target.sin_addr, h->h_addr, sizeof( struct in_addr ) );
00282 }
00283
00284 #ifndef _WIN32_WCE
00285 std::ostringstream oss;
00286 #endif
00287
00288 memset( target.sin_zero, '\0', 8 );
00289 if( ::connect( fd, (struct sockaddr *)&target, sizeof( struct sockaddr ) ) == 0 )
00290 {
00291 #ifndef _WIN32_WCE
00292 oss << "connecting to " << domain.c_str()
00293 << " (" << inet_ntoa( target.sin_addr ) << ":" << port << ")";
00294 logInstance.log( LogLevelDebug, LogAreaClassDns, oss.str() );
00295 #endif
00296 return fd;
00297 }
00298
00299 #ifndef _WIN32_WCE
00300 oss << "connection to " << domain.c_str()
00301 << " (" << inet_ntoa( target.sin_addr ) << ":" << port << ") failed";
00302 logInstance.log( LogLevelDebug, LogAreaClassDns, oss.str() );
00303 #endif
00304
00305 closeSocket( fd );
00306 return -ConnConnectionRefused;
00307 }
00308
00309 void DNS::closeSocket( int fd )
00310 {
00311 #ifndef _WIN32
00312 close( fd );
00313 #else
00314 closesocket( fd );
00315 #endif
00316 }
00317
00318 void DNS::cleanup()
00319 {
00320 #ifdef _WIN32
00321 WSACleanup();
00322 #endif
00323 }
00324
00325 }