00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qplatformdefs.h"
00025 #include "qbytearray.h"
00026 #ifdef Q_OS_WIN32
00027 # include "qt_windows.h"
00028 #else
00029 # include <sys/types.h>
00030 # include <netinet/in.h>
00031 # include <arpa/nameser.h>
00032 # include <resolv.h>
00033 extern "C" int res_init();
00034 #endif
00035
00036
00037 #if defined(open)
00038 # undef open
00039 #endif
00040
00041
00042 #if defined(truncate)
00043 # undef truncate
00044 #endif
00045
00046
00047 #if defined(connect)
00048 # undef connect
00049 #endif
00050
00051
00052 #if defined(socket)
00053 # undef socket
00054 #endif
00055
00056 #include "q3dns.h"
00057
00058 #ifndef QT_NO_DNS
00059
00060 #include "qdatetime.h"
00061 #include "q3dict.h"
00062 #include "q3ptrlist.h"
00063 #include "qstring.h"
00064 #include "qtimer.h"
00065 #include "qapplication.h"
00066 #include "q3ptrvector.h"
00067 #include "q3strlist.h"
00068 #include "q3ptrdict.h"
00069 #include "qfile.h"
00070 #include "qtextstream.h"
00071 #include "q3socketdevice.h"
00072 #include "q3cleanuphandler.h"
00073 #include <limits.h>
00074
00075
00076
00077 static Q_UINT16 id;
00078
00079
00080 static QDateTime * originOfTime = 0;
00081
00082 static Q3CleanupHandler<QDateTime> q3dns_cleanup_time;
00083
00084 static Q_UINT32 now()
00085 {
00086 if ( originOfTime )
00087 return originOfTime->secsTo( QDateTime::currentDateTime() );
00088
00089 originOfTime = new QDateTime( QDateTime::currentDateTime() );
00090 ::id = originOfTime->time().msec() * 60 + originOfTime->time().second();
00091 q3dns_cleanup_time.add( &originOfTime );
00092 return 0;
00093 }
00094
00095
00096 static Q3PtrList<QHostAddress> * ns = 0;
00097 static Q3StrList * domains = 0;
00098 static bool ipv6support = false;
00099
00100 class Q3DnsPrivate {
00101 public:
00102 Q3DnsPrivate() : queryTimer( 0 ), noNames(false)
00103 {
00104 #if defined(Q_DNS_SYNCHRONOUS)
00105 #if defined(Q_OS_UNIX)
00106 noEventLoop = qApp==0 || qApp->loopLevel()==0;
00107 #else
00108 noEventLoop = false;
00109 #endif
00110 #endif
00111 }
00112 ~Q3DnsPrivate()
00113 {
00114 delete queryTimer;
00115 }
00116 private:
00117 QTimer * queryTimer;
00118 bool noNames;
00119 #if defined(Q_DNS_SYNCHRONOUS)
00120 bool noEventLoop;
00121 #endif
00122
00123 friend class Q3Dns;
00124 friend class Q3DnsAnswer;
00125 };
00126
00127
00128 class Q3DnsRR;
00129 class Q3DnsDomain;
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 class Q3DnsRR {
00140 public:
00141 Q3DnsRR( const QString & label );
00142 ~Q3DnsRR();
00143
00144 public:
00145 Q3DnsDomain * domain;
00146 Q3Dns::RecordType t;
00147 bool nxdomain;
00148 bool current;
00149 Q_UINT32 expireTime;
00150 Q_UINT32 deleteTime;
00151
00152
00153 QHostAddress address;
00154
00155 QString target;
00156
00157 Q_UINT16 priority;
00158
00159 Q_UINT16 weight;
00160 Q_UINT16 port;
00161
00162 QString text;
00163 private:
00164
00165 };
00166
00167
00168 class Q3DnsDomain {
00169 public:
00170 Q3DnsDomain( const QString & label );
00171 ~Q3DnsDomain();
00172
00173 static void add( const QString & label, Q3DnsRR * );
00174 static Q3PtrList<Q3DnsRR> * cached( const Q3Dns * );
00175
00176 void take( Q3DnsRR * );
00177
00178 void sweep( Q_UINT32 thisSweep );
00179
00180 bool isEmpty() const { return rrs == 0 || rrs->isEmpty(); }
00181
00182 QString name() const { return l; }
00183
00184 public:
00185 QString l;
00186 Q3PtrList<Q3DnsRR> * rrs;
00187 };
00188
00189
00190 class Q3DnsQuery: public QTimer {
00191 public:
00192 Q3DnsQuery():
00193 id( 0 ), t( Q3Dns::None ), step(0), started(0),
00194 dns( new Q3PtrDict<void>(17) ) {}
00195 ~Q3DnsQuery() { delete dns; }
00196 Q_UINT16 id;
00197 Q3Dns::RecordType t;
00198 QString l;
00199
00200 uint step;
00201 Q_UINT32 started;
00202
00203 Q3PtrDict<void> * dns;
00204 };
00205
00206
00207
00208 class Q3DnsAnswer {
00209 public:
00210 Q3DnsAnswer( Q3DnsQuery * );
00211 Q3DnsAnswer( const QByteArray &, Q3DnsQuery * );
00212 ~Q3DnsAnswer();
00213
00214 void parse();
00215 void notify();
00216
00217 bool ok;
00218
00219 private:
00220 Q3DnsQuery * query;
00221
00222 Q_UINT8 * answer;
00223 int size;
00224 int pp;
00225
00226 Q3PtrList<Q3DnsRR> * rrs;
00227
00228
00229 int next;
00230 int ttl;
00231 QString label;
00232 Q3DnsRR * rr;
00233
00234 QString readString(bool multipleLabels = true);
00235 void parseA();
00236 void parseAaaa();
00237 void parseMx();
00238 void parseSrv();
00239 void parseCname();
00240 void parsePtr();
00241 void parseTxt();
00242 void parseNs();
00243 };
00244
00245
00246 Q3DnsRR::Q3DnsRR( const QString & label )
00247 : domain( 0 ), t( Q3Dns::None ),
00248 nxdomain( false ), current( false ),
00249 expireTime( 0 ), deleteTime( 0 ),
00250 priority( 0 ), weight( 0 ), port( 0 )
00251 {
00252 Q3DnsDomain::add( label, this );
00253 }
00254
00255
00256
00257 Q3DnsRR::~Q3DnsRR()
00258 {
00259
00260 }
00261
00262
00263
00264 Q3DnsAnswer::Q3DnsAnswer( Q3DnsQuery * query_ )
00265 {
00266 ok = true;
00267
00268 answer = 0;
00269 size = 0;
00270 query = query_;
00271 pp = 0;
00272 rrs = new Q3PtrList<Q3DnsRR>;
00273 rrs->setAutoDelete( false );
00274 next = size;
00275 ttl = 0;
00276 label.clear();
00277 rr = 0;
00278
00279 Q3DnsRR * newrr = new Q3DnsRR( query->l );
00280 newrr->t = query->t;
00281 newrr->deleteTime = query->started + 10;
00282 newrr->expireTime = query->started + 10;
00283 newrr->nxdomain = true;
00284 newrr->current = true;
00285 rrs->append( newrr );
00286 }
00287
00288
00289 Q3DnsAnswer::Q3DnsAnswer( const QByteArray& answer_,
00290 Q3DnsQuery * query_ )
00291 {
00292 ok = true;
00293
00294 answer = (Q_UINT8 *)(answer_.data());
00295 size = (int)answer_.size();
00296 query = query_;
00297 pp = 0;
00298 rrs = new Q3PtrList<Q3DnsRR>;
00299 rrs->setAutoDelete( false );
00300 next = size;
00301 ttl = 0;
00302 label.clear();
00303 rr = 0;
00304 }
00305
00306
00307 Q3DnsAnswer::~Q3DnsAnswer()
00308 {
00309 if ( !ok && rrs ) {
00310 Q3PtrListIterator<Q3DnsRR> it( *rrs );
00311 Q3DnsRR * tmprr;
00312 while( (tmprr=it.current()) != 0 ) {
00313 ++it;
00314 tmprr->t = Q3Dns::None;
00315 }
00316 }
00317 delete rrs;
00318 }
00319
00320
00321 QString Q3DnsAnswer::readString(bool multipleLabels)
00322 {
00323 int p = pp;
00324 QString r;
00325 Q_UINT8 b;
00326 for( ;; ) {
00327 b = 128;
00328
00329 if ( p >= 0 && p < size )
00330 b = answer[p];
00331
00332 switch( b >> 6 ) {
00333 case 0:
00334
00335 p++;
00336
00337
00338 if ( b == 0 ) {
00339 if ( p > pp )
00340 pp = p;
00341 return r.isNull() ? QString( "." ) : r;
00342 }
00343
00344
00345 if ( !r.isNull() )
00346 r += '.';
00347 while( b-- > 0 )
00348 r += QChar( answer[p++] );
00349
00350
00351
00352 if (!multipleLabels)
00353 return r;
00354
00355 break;
00356 default:
00357
00358
00359 goto not_ok;
00360 case 3:
00361
00362
00363 int q = ( (answer[p] & 0x3f) << 8 ) + answer[p+1];
00364
00365 if ( q >= pp || q >= p )
00366 goto not_ok;
00367 if ( p >= pp )
00368 pp = p + 2;
00369 p = q;
00370 }
00371 }
00372 not_ok:
00373 ok = false;
00374 return QString();
00375 }
00376
00377
00378
00379 void Q3DnsAnswer::parseA()
00380 {
00381 if ( next != pp + 4 ) {
00382 #if defined(Q3DNS_DEBUG)
00383 qDebug( "Q3Dns: saw %d bytes long IN A for %s",
00384 next - pp, label.ascii() );
00385 #endif
00386 return;
00387 }
00388
00389 rr = new Q3DnsRR( label );
00390 rr->t = Q3Dns::A;
00391 rr->address = QHostAddress( ( answer[pp+0] << 24 ) +
00392 ( answer[pp+1] << 16 ) +
00393 ( answer[pp+2] << 8 ) +
00394 ( answer[pp+3] ) );
00395 #if defined(Q3DNS_DEBUG)
00396 qDebug( "Q3Dns: saw %s IN A %s (ttl %d)", label.ascii(),
00397 rr->address.toString().ascii(), ttl );
00398 #endif
00399 }
00400
00401
00402 void Q3DnsAnswer::parseAaaa()
00403 {
00404 if ( next != pp + 16 ) {
00405 #if defined(Q3DNS_DEBUG)
00406 qDebug( "Q3Dns: saw %d bytes long IN Aaaa for %s",
00407 next - pp, label.ascii() );
00408 #endif
00409 return;
00410 }
00411
00412 rr = new Q3DnsRR( label );
00413 rr->t = Q3Dns::Aaaa;
00414 rr->address = QHostAddress( answer+pp );
00415 #if defined(Q3DNS_DEBUG)
00416 qDebug( "Q3Dns: saw %s IN Aaaa %s (ttl %d)", label.ascii(),
00417 rr->address.toString().ascii(), ttl );
00418 #endif
00419 }
00420
00421
00422
00423 void Q3DnsAnswer::parseMx()
00424 {
00425 if ( next < pp + 2 ) {
00426 #if defined(Q3DNS_DEBUG)
00427 qDebug( "Q3Dns: saw %d bytes long IN MX for %s",
00428 next - pp, label.ascii() );
00429 #endif
00430 return;
00431 }
00432
00433 rr = new Q3DnsRR( label );
00434 rr->priority = (answer[pp] << 8) + answer[pp+1];
00435 pp += 2;
00436 rr->target = readString().lower();
00437 if ( !ok ) {
00438 #if defined(Q3DNS_DEBUG)
00439 qDebug( "Q3Dns: saw bad string in MX for %s", label.ascii() );
00440 #endif
00441 return;
00442 }
00443 rr->t = Q3Dns::Mx;
00444 #if defined(Q3DNS_DEBUG)
00445 qDebug( "Q3Dns: saw %s IN MX %d %s (ttl %d)", label.ascii(),
00446 rr->priority, rr->target.ascii(), ttl );
00447 #endif
00448 }
00449
00450
00451 void Q3DnsAnswer::parseSrv()
00452 {
00453 if ( next < pp + 6 ) {
00454 #if defined(Q3DNS_DEBUG)
00455 qDebug( "Q3Dns: saw %d bytes long IN SRV for %s",
00456 next - pp, label.ascii() );
00457 #endif
00458 return;
00459 }
00460
00461 rr = new Q3DnsRR( label );
00462 rr->priority = (answer[pp] << 8) + answer[pp+1];
00463 rr->weight = (answer[pp+2] << 8) + answer[pp+3];
00464 rr->port = (answer[pp+4] << 8) + answer[pp+5];
00465 pp += 6;
00466 rr->target = readString().lower();
00467 if ( !ok ) {
00468 #if defined(Q3DNS_DEBUG)
00469 qDebug( "Q3Dns: saw bad string in SRV for %s", label.ascii() );
00470 #endif
00471 return;
00472 }
00473 rr->t = Q3Dns::Srv;
00474 #if defined(Q3DNS_DEBUG)
00475 qDebug( "Q3Dns: saw %s IN SRV %d %d %d %s (ttl %d)", label.ascii(),
00476 rr->priority, rr->weight, rr->port, rr->target.ascii(), ttl );
00477 #endif
00478 }
00479
00480
00481 void Q3DnsAnswer::parseCname()
00482 {
00483 QString target = readString().lower();
00484 if ( !ok ) {
00485 #if defined(Q3DNS_DEBUG)
00486 qDebug( "Q3Dns: saw bad cname for for %s", label.ascii() );
00487 #endif
00488 return;
00489 }
00490
00491 rr = new Q3DnsRR( label );
00492 rr->t = Q3Dns::Cname;
00493 rr->target = target;
00494 #if defined(Q3DNS_DEBUG)
00495 qDebug( "Q3Dns: saw %s IN CNAME %s (ttl %d)", label.ascii(),
00496 rr->target.ascii(), ttl );
00497 #endif
00498 }
00499
00500
00501 void Q3DnsAnswer::parseNs()
00502 {
00503 QString target = readString().lower();
00504 if ( !ok ) {
00505 #if defined(Q3DNS_DEBUG)
00506 qDebug( "Q3Dns: saw bad cname for for %s", label.ascii() );
00507 #endif
00508 return;
00509 }
00510
00511
00512
00513 #if defined(Q3DNS_DEBUG)
00514 qDebug( "Q3Dns: saw %s IN NS %s (ttl %d)", label.ascii(),
00515 target.ascii(), ttl );
00516 #endif
00517 }
00518
00519
00520 void Q3DnsAnswer::parsePtr()
00521 {
00522 QString target = readString().lower();
00523 if ( !ok ) {
00524 #if defined(Q3DNS_DEBUG)
00525 qDebug( "Q3Dns: saw bad PTR for for %s", label.ascii() );
00526 #endif
00527 return;
00528 }
00529
00530 rr = new Q3DnsRR( label );
00531 rr->t = Q3Dns::Ptr;
00532 rr->target = target;
00533 #if defined(Q3DNS_DEBUG)
00534 qDebug( "Q3Dns: saw %s IN PTR %s (ttl %d)", label.ascii(),
00535 rr->target.ascii(), ttl );
00536 #endif
00537 }
00538
00539
00540 void Q3DnsAnswer::parseTxt()
00541 {
00542 QString text = readString(false);
00543 if ( !ok ) {
00544 #if defined(Q3DNS_DEBUG)
00545 qDebug( "Q3Dns: saw bad TXT for for %s", label.ascii() );
00546 #endif
00547 return;
00548 }
00549
00550 rr = new Q3DnsRR( label );
00551 rr->t = Q3Dns::Txt;
00552 rr->text = text;
00553 #if defined(Q3DNS_DEBUG)
00554 qDebug( "Q3Dns: saw %s IN TXT \"%s\" (ttl %d)", label.ascii(),
00555 rr->text.ascii(), ttl );
00556 #endif
00557 }
00558
00559
00560 void Q3DnsAnswer::parse()
00561 {
00562
00563 if ( (answer[2] & 0x78) != 0 ) {
00564 #if defined(Q3DNS_DEBUG)
00565 qDebug( "DNS Manager: answer to wrong query type (%d)", answer[1] );
00566 #endif
00567 ok = false;
00568 return;
00569 }
00570
00571
00572 bool aa = (answer[2] & 4) != 0;
00573
00574
00575 if ( (answer[2] & 2) != 0 ) {
00576 #if defined(Q3DNS_DEBUG)
00577 qDebug( "DNS Manager: truncated answer; pressing on" );
00578 #endif
00579 }
00580
00581
00582 bool rd = (answer[2] & 1) != 0;
00583
00584
00585
00586
00587 if ( (answer[3] & 0x0f) == 3 ) {
00588 #if defined(Q3DNS_DEBUG)
00589 qDebug( "DNS Manager: saw NXDomain for %s", query->l.ascii() );
00590 #endif
00591
00592 rr = new Q3DnsRR( query->l );
00593 rr->t = query->t;
00594 rr->deleteTime = query->started + 60;
00595 rr->expireTime = query->started + 60;
00596 rr->nxdomain = true;
00597 rr->current = true;
00598 rrs->append( rr );
00599 return;
00600 }
00601
00602 if ( (answer[3] & 0x0f) != 0 ) {
00603 #if defined(Q3DNS_DEBUG)
00604 qDebug( "DNS Manager: error code %d", answer[3] & 0x0f );
00605 #endif
00606 ok = false;
00607 return;
00608 }
00609
00610 int qdcount = ( answer[4] << 8 ) + answer[5];
00611 int ancount = ( answer[6] << 8 ) + answer[7];
00612 int nscount = ( answer[8] << 8 ) + answer[9];
00613 int adcount = (answer[10] << 8 ) +answer[11];
00614
00615 pp = 12;
00616
00617
00618 while( qdcount > 0 && pp < size ) {
00619
00620 (void)readString();
00621 if ( !ok )
00622 return;
00623 pp += 4;
00624 qdcount--;
00625 }
00626
00627
00628 int rrno = 0;
00629
00630
00631 int answers = 0;
00632 while( ( rrno < ancount ||
00633 ( ok && answers >0 && rrno < ancount + nscount + adcount ) ) &&
00634 pp < size ) {
00635 label = readString().lower();
00636 if ( !ok )
00637 return;
00638 int rdlength = 0;
00639 if ( pp + 10 <= size )
00640 rdlength = ( answer[pp+8] << 8 ) + answer[pp+9];
00641 if ( pp + 10 + rdlength > size ) {
00642 #if defined(Q3DNS_DEBUG)
00643 qDebug( "DNS Manager: ran out of stuff to parse (%d+%d>%d (%d)",
00644 pp, rdlength, size, rrno < ancount );
00645 #endif
00646
00647
00648
00649
00650 ok = ( rrno < ancount );
00651 return;
00652 }
00653 uint type, clas;
00654 type = ( answer[pp+0] << 8 ) + answer[pp+1];
00655 clas = ( answer[pp+2] << 8 ) + answer[pp+3];
00656 ttl = ( answer[pp+4] << 24 ) + ( answer[pp+5] << 16 ) +
00657 ( answer[pp+6] << 8 ) + answer[pp+7];
00658 pp = pp + 10;
00659 if ( clas != 1 ) {
00660 #if defined(Q3DNS_DEBUG)
00661 qDebug( "DNS Manager: class %d (not internet) for %s",
00662 clas, label.isNull() ? "." : label.ascii() );
00663 #endif
00664 } else {
00665 next = pp + rdlength;
00666 rr = 0;
00667 switch( type ) {
00668 case 1:
00669 parseA();
00670 break;
00671 case 28:
00672 parseAaaa();
00673 break;
00674 case 15:
00675 parseMx();
00676 break;
00677 case 33:
00678 parseSrv();
00679 break;
00680 case 5:
00681 parseCname();
00682 break;
00683 case 12:
00684 parsePtr();
00685 break;
00686 case 16:
00687 parseTxt();
00688 break;
00689 case 2:
00690 parseNs();
00691 break;
00692 default:
00693
00694 #if defined(Q3DNS_DEBUG)
00695 qDebug( "DNS Manager: type %d for %s", type,
00696 label.isNull() ? "." : label.ascii() );
00697 #endif
00698 break;
00699 }
00700 if ( rr ) {
00701 rr->deleteTime = 0;
00702 if ( ttl > 0 )
00703 rr->expireTime = query->started + ttl;
00704 else
00705 rr->expireTime = query->started + 20;
00706 if ( rrno < ancount ) {
00707 answers++;
00708 rr->deleteTime = rr->expireTime;
00709 }
00710 rr->current = true;
00711 rrs->append( rr );
00712 }
00713 }
00714 if ( !ok )
00715 return;
00716 pp = next;
00717 next = size;
00718 rrno++;
00719 }
00720 if ( answers == 0 ) {
00721 #if defined(Q3DNS_DEBUG)
00722 qDebug( "DNS Manager: answer contained no answers" );
00723 #endif
00724 ok = ( aa && rd );
00725 }
00726
00727
00728
00729 rrs->first();
00730 Q3Dict<void> used( 17 );
00731 used.setAutoDelete( false );
00732 while( (rr=rrs->current()) != 0 ) {
00733 rrs->next();
00734 if ( rr->target.length() && rr->deleteTime > 0 && rr->current )
00735 used.insert( rr->target, (void*)42 );
00736 if ( ( rr->t == Q3Dns::A || rr->t == Q3Dns::Aaaa ) &&
00737 used.find( rr->domain->name() ) != 0 )
00738 rr->deleteTime = rr->expireTime;
00739 }
00740
00741
00742 rrs->first();
00743 while( (rr=rrs->current()) != 0 ) {
00744 rrs->next();
00745 if ( rr && rr->domain && rr->domain->rrs ) {
00746 Q3PtrList<Q3DnsRR> * drrs = rr->domain->rrs;
00747 drrs->first();
00748 Q3DnsRR * older;
00749 while( (older=drrs->current()) != 0 ) {
00750 if ( older != rr &&
00751 older->t == rr->t &&
00752 older->nxdomain == rr->nxdomain &&
00753 older->address == rr->address &&
00754 older->target == rr->target &&
00755 older->priority == rr->priority &&
00756 older->weight == rr->weight &&
00757 older->port == rr->port &&
00758 older->text == rr->text ) {
00759
00760
00761 #if defined(Q3DNS_DEBUG)
00762 qDebug( "killing off old %d for %s, expire was %d",
00763 older->t, older->domain->name().latin1(),
00764 rr->expireTime );
00765 #endif
00766 older->t = Q3Dns::None;
00767 rr->expireTime = QMAX( older->expireTime, rr->expireTime );
00768 rr->deleteTime = QMAX( older->deleteTime, rr->deleteTime );
00769 older->deleteTime = 0;
00770 #if defined(Q3DNS_DEBUG)
00771 qDebug( " adjusted expire is %d", rr->expireTime );
00772 #endif
00773 }
00774 drrs->next();
00775 }
00776 }
00777 }
00778
00779 #if defined(Q3DNS_DEBUG)
00780
00781 #endif
00782 }
00783
00784
00785 class Q3DnsUgleHack: public Q3Dns {
00786 public:
00787 void ugle( bool emitAnyway=false );
00788 };
00789
00790
00791 void Q3DnsAnswer::notify()
00792 {
00793 if ( !rrs || !ok || !query || !query->dns )
00794 return;
00795
00796 Q3PtrDict<void> notified;
00797 notified.setAutoDelete( false );
00798
00799 Q3PtrDictIterator<void> it( *query->dns );
00800 Q3Dns * dns;
00801 it.toFirst();
00802 while( (dns=(Q3Dns*)(it.current())) != 0 ) {
00803 ++it;
00804 if ( notified.find( (void*)dns ) == 0 ) {
00805 notified.insert( (void*)dns, (void*)42 );
00806 if ( rrs->count() == 0 ) {
00807 #if defined(Q3DNS_DEBUG)
00808 qDebug( "DNS Manager: found no answers!" );
00809 #endif
00810 dns->d->noNames = true;
00811 ((Q3DnsUgleHack*)dns)->ugle( true );
00812 } else {
00813 QStringList n = dns->qualifiedNames();
00814 if ( n.contains(query->l) )
00815 ((Q3DnsUgleHack*)dns)->ugle();
00816 #if defined(Q3DNS_DEBUG)
00817 else
00818 qDebug( "DNS Manager: DNS thing %s not notified for %s",
00819 dns->label().ascii(), query->l.ascii() );
00820 #endif
00821 }
00822 }
00823 }
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834 class Q3DnsManager: public Q3DnsSocket {
00835 private:
00836 public:
00837 Q3DnsManager();
00838 ~Q3DnsManager();
00839 public:
00840 static Q3DnsManager * manager();
00841
00842 Q3DnsDomain * domain( const QString & );
00843
00844 void transmitQuery( Q3DnsQuery * );
00845 void transmitQuery( int );
00846
00847
00848 void cleanCache();
00849 void retransmit();
00850 void answer();
00851
00852 public:
00853 Q3PtrVector<Q3DnsQuery> queries;
00854 Q3Dict<Q3DnsDomain> cache;
00855 Q3SocketDevice * ipv4Socket;
00856 #if !defined (QT_NO_IPV6)
00857 Q3SocketDevice * ipv6Socket;
00858 #endif
00859 };
00860
00861
00862
00863 static Q3DnsManager * globalManager = 0;
00864
00865 static void cleanupDns()
00866 {
00867 delete globalManager;
00868 globalManager = 0;
00869 }
00870
00871 Q3DnsManager * Q3DnsManager::manager()
00872 {
00873 if ( !globalManager ) {
00874 qAddPostRoutine(cleanupDns);
00875 new Q3DnsManager();
00876 }
00877 return globalManager;
00878 }
00879
00880
00881 void Q3DnsUgleHack::ugle( bool emitAnyway)
00882 {
00883 if ( emitAnyway || !isWorking() ) {
00884 #if defined(Q3DNS_DEBUG)
00885 qDebug( "DNS Manager: status change for %s (type %d)",
00886 label().ascii(), recordType() );
00887 #endif
00888 emit resultsReady();
00889 }
00890 }
00891
00892
00893 Q3DnsManager::Q3DnsManager()
00894 : Q3DnsSocket( qApp, "Internal DNS manager" ),
00895 queries( Q3PtrVector<Q3DnsQuery>( 0 ) ),
00896 cache( Q3Dict<Q3DnsDomain>( 83, false ) ),
00897 ipv4Socket( new Q3SocketDevice( Q3SocketDevice::Datagram, Q3SocketDevice::IPv4, 0 ) )
00898 #if !defined (QT_NO_IPV6)
00899 , ipv6Socket( new Q3SocketDevice( Q3SocketDevice::Datagram, Q3SocketDevice::IPv6, 0 ) )
00900 #endif
00901 {
00902 cache.setAutoDelete( true );
00903 globalManager = this;
00904
00905 QTimer * sweepTimer = new QTimer( this );
00906 sweepTimer->start( 1000 * 60 * 3 );
00907 connect( sweepTimer, SIGNAL(timeout()),
00908 this, SLOT(cleanCache()) );
00909
00910 QSocketNotifier * rn4 = new QSocketNotifier( ipv4Socket->socket(),
00911 QSocketNotifier::Read,
00912 this, "dns IPv4 socket watcher" );
00913 ipv4Socket->setAddressReusable( false );
00914 ipv4Socket->setBlocking( false );
00915 connect( rn4, SIGNAL(activated(int)), SLOT(answer()) );
00916
00917 #if !defined (QT_NO_IPV6)
00918
00919
00920 if ( ipv6Socket->socket() != -1 ) {
00921 QSocketNotifier * rn6 = new QSocketNotifier( ipv6Socket->socket(),
00922 QSocketNotifier::Read,
00923 this, "dns IPv6 socket watcher" );
00924
00925 ipv6support = true;
00926 ipv6Socket->setAddressReusable( false );
00927 ipv6Socket->setBlocking( false );
00928 connect( rn6, SIGNAL(activated(int)), SLOT(answer()) );
00929 }
00930 #endif
00931
00932 if ( !ns )
00933 Q3Dns::doResInit();
00934
00935
00936
00937
00938 Q3PtrList<QHostAddress> * ns = new Q3PtrList<QHostAddress>;
00939
00940 ::ns->first();
00941 QHostAddress * h;
00942 while( (h=::ns->current()) != 0 ) {
00943 ns->first();
00944 while( ns->current() != 0 && !(*ns->current() == *h) )
00945 ns->next();
00946 if ( !ns->current() ) {
00947 ns->append( new QHostAddress(*h) );
00948 #if defined(Q3DNS_DEBUG)
00949 qDebug( "using name server %s", h->toString().latin1() );
00950 } else {
00951 qDebug( "skipping address %s", h->toString().latin1() );
00952 #endif
00953 }
00954 ::ns->next();
00955 }
00956
00957 delete ::ns;
00958 ::ns = ns;
00959 ::ns->setAutoDelete( true );
00960
00961 Q3StrList * domains = new Q3StrList( true );
00962
00963 ::domains->first();
00964 const char * s;
00965 while( (s=::domains->current()) != 0 ) {
00966 domains->first();
00967 while( domains->current() != 0 && qstrcmp( domains->current(), s ) )
00968 domains->next();
00969 if ( !domains->current() ) {
00970 domains->append( s );
00971 #if defined(Q3DNS_DEBUG)
00972 qDebug( "searching domain %s", s );
00973 } else {
00974 qDebug( "skipping domain %s", s );
00975 #endif
00976 }
00977 ::domains->next();
00978 }
00979
00980 delete ::domains;
00981 ::domains = domains;
00982 ::domains->setAutoDelete( true );
00983 }
00984
00985
00986 Q3DnsManager::~Q3DnsManager()
00987 {
00988 if ( globalManager )
00989 globalManager = 0;
00990 queries.setAutoDelete( true );
00991 cache.setAutoDelete( true );
00992 delete ipv4Socket;
00993 #if !defined (QT_NO_IPV6)
00994 delete ipv6Socket;
00995 #endif
00996 }
00997
00998 static Q_UINT32 lastSweep = 0;
00999
01000 void Q3DnsManager::cleanCache()
01001 {
01002 bool again = false;
01003 Q3DictIterator<Q3DnsDomain> it( cache );
01004 Q3DnsDomain * d;
01005 Q_UINT32 thisSweep = now();
01006 #if defined(Q3DNS_DEBUG)
01007 qDebug( "Q3DnsManager::cleanCache(: Called, time is %u, last was %u",
01008 thisSweep, lastSweep );
01009 #endif
01010
01011 while( (d=it.current()) != 0 ) {
01012 ++it;
01013 d->sweep( thisSweep );
01014 if ( !again )
01015 again = !d->isEmpty();
01016 }
01017 if ( !again )
01018 delete this;
01019 lastSweep = thisSweep;
01020 }
01021
01022
01023 void Q3DnsManager::retransmit()
01024 {
01025 const QObject * o = sender();
01026 if ( o == 0 || globalManager == 0 || this != globalManager )
01027 return;
01028 uint q = 0;
01029 while( q < queries.size() && queries[q] != o )
01030 q++;
01031 if ( q < queries.size() )
01032 transmitQuery( q );
01033 }
01034
01035
01036 void Q3DnsManager::answer()
01037 {
01038 QByteArray a( 16383 );
01039
01040 int r;
01041 #if defined (QT_NO_IPV6)
01042 r = ipv4Socket->readBlock(a.data(), a.size());
01043 #else
01044 if (((QSocketNotifier *)sender())->socket() == ipv4Socket->socket())
01045 r = ipv4Socket->readBlock(a.data(), a.size());
01046 else
01047 r = ipv6Socket->readBlock(a.data(), a.size());
01048 #endif
01049 #if defined(Q3DNS_DEBUG)
01050 #if !defined (QT_NO_IPV6)
01051 qDebug("DNS Manager: answer arrived: %d bytes from %s:%d", r,
01052 useIpv4Socket ? ipv4Socket->peerAddress().toString().ascii()
01053 : ipv6Socket->peerAddress().toString().ascii(),
01054 useIpv4Socket ? ipv4Socket->peerPort() : ipv6Socket->peerPort() );
01055 #else
01056 qDebug("DNS Manager: answer arrived: %d bytes from %s:%d", r,
01057 ipv4Socket->peerAddress().toString().ascii(), ipv4Socket->peerPort());;
01058 #endif
01059 #endif
01060 if ( r < 12 )
01061 return;
01062
01063
01064 a.resize( r );
01065
01066 Q_UINT16 aid = (((Q_UINT8)a[0]) << 8) + ((Q_UINT8)a[1]);
01067 uint i = 0;
01068 while( i < queries.size() &&
01069 !( queries[i] && queries[i]->id == aid ) )
01070 i++;
01071 if ( i == queries.size() ) {
01072 #if defined(Q3DNS_DEBUG)
01073 qDebug( "DNS Manager: bad id (0x%04x) %d", aid, i );
01074 #endif
01075 return;
01076 }
01077
01078
01079
01080 if ( ( (Q_UINT8)(a[2]) & 0x80 ) == 0 ) {
01081 #if defined(Q3DNS_DEBUG)
01082 qDebug( "DNS Manager: received a query" );
01083 #endif
01084 return;
01085 }
01086
01087 Q3DnsQuery * q = queries[i];
01088 Q3DnsAnswer answer( a, q );
01089 answer.parse();
01090 if ( answer.ok ) {
01091 queries.take( i );
01092 answer.notify();
01093 delete q;
01094 }
01095 }
01096
01097
01098 void Q3DnsManager::transmitQuery( Q3DnsQuery * query_ )
01099 {
01100 if ( !query_ )
01101 return;
01102
01103 uint i = 0;
01104 while( i < queries.size() && queries[i] != 0 )
01105 i++;
01106 if ( i == queries.size() )
01107 queries.resize( i+1 );
01108 queries.insert( i, query_ );
01109 transmitQuery( i );
01110 }
01111
01112
01113 void Q3DnsManager::transmitQuery( int i )
01114 {
01115 if ( i < 0 || i >= (int)queries.size() )
01116 return;
01117 Q3DnsQuery * q = queries[i];
01118
01119 if ( q && q->step > 8 ) {
01120
01121
01122 Q3DnsAnswer answer( q );
01123 answer.notify();
01124
01125 queries.take( i );
01126 #if defined(Q3DNS_DEBUG)
01127 qDebug( "DNS Manager: giving up on query 0x%04x", q->id );
01128 #endif
01129 delete q;
01130 QTimer::singleShot( 0, Q3DnsManager::manager(), SLOT(cleanCache()) );
01131
01132 return;
01133 }
01134
01135 if ( q && !q->dns || q->dns->isEmpty() )
01136
01137
01138
01139
01140 return;
01141
01142 QByteArray p( 12 + q->l.length() + 2 + 4 );
01143 if ( p.size() > 500 )
01144 return;
01145
01146
01147
01148 p[0] = (q->id & 0xff00) >> 8;
01149 p[1] = q->id & 0x00ff;
01150 p[2] = 1;
01151 p[3] = 0;
01152
01153 p[4] = 0;
01154 p[5] = 1;
01155
01156 p[6] = p[7] = p[8] = p[9] = p[10] = p[11] = 0;
01157
01158
01159
01160
01161 int pp = 12;
01162 uint lp = 0;
01163 while( lp < (uint) q->l.length() ) {
01164 int le = q->l.find( '.', lp );
01165 if ( le < 0 )
01166 le = q->l.length();
01167 QString component = q->l.mid( lp, le-lp );
01168 p[pp++] = component.length();
01169 int cp;
01170 for( cp=0; cp < (int)component.length(); cp++ )
01171 p[pp++] = component[cp].latin1();
01172 lp = le + 1;
01173 }
01174
01175 p[pp++] = 0;
01176
01177 p[pp++] = 0;
01178 switch( q->t ) {
01179 case Q3Dns::A:
01180 p[pp++] = 1;
01181 break;
01182 case Q3Dns::Aaaa:
01183 p[pp++] = 28;
01184 break;
01185 case Q3Dns::Mx:
01186 p[pp++] = 15;
01187 break;
01188 case Q3Dns::Srv:
01189 p[pp++] = 33;
01190 break;
01191 case Q3Dns::Cname:
01192 p[pp++] = 5;
01193 break;
01194 case Q3Dns::Ptr:
01195 p[pp++] = 12;
01196 break;
01197 case Q3Dns::Txt:
01198 p[pp++] = 16;
01199 break;
01200 default:
01201 p[pp++] = (char)255;
01202 break;
01203 }
01204
01205 p[pp++] = 0;
01206 p[pp++] = 1;
01207
01208
01209
01210
01211
01212 if ( !ns || ns->isEmpty() )
01213 Q3Dns::doResInit();
01214
01215 if ( !ns || ns->isEmpty() ) {
01216
01217
01218 Q3DnsAnswer answer( q );
01219 answer.notify();
01220
01221 queries.take( i );
01222 #if defined(Q3DNS_DEBUG)
01223 qDebug( "DNS Manager: no DNS server found on query 0x%04x", q->id );
01224 #endif
01225 delete q;
01226 QTimer::singleShot( 1000*10, Q3DnsManager::manager(), SLOT(cleanCache()) );
01227
01228 return;
01229 }
01230
01231 QHostAddress receiver = *ns->at( q->step % ns->count() );
01232 if (receiver.isIPv4Address())
01233 ipv4Socket->writeBlock( p.data(), pp, receiver, 53 );
01234 #if !defined (QT_NO_IPV6)
01235 else
01236 ipv6Socket->writeBlock( p.data(), pp, receiver, 53 );
01237 #endif
01238 #if defined(Q3DNS_DEBUG)
01239 qDebug( "issuing query 0x%04x (%d) about %s type %d to %s",
01240 q->id, q->step, q->l.ascii(), q->t,
01241 ns->at( q->step % ns->count() )->toString().ascii() );
01242 #endif
01243 if ( ns->count() > 1 && q->step == 0 && queries.count() == 1 ) {
01244
01245
01246
01247 p[2] = 0;
01248 QHostAddress * server;
01249 while( (server=ns->next()) != 0 ) {
01250 if (server->isIPv4Address())
01251 ipv4Socket->writeBlock( p.data(), pp, *server, 53 );
01252 #if !defined (QT_NO_IPV6)
01253 else
01254 ipv6Socket->writeBlock( p.data(), pp, *server, 53 );
01255 #endif
01256 #if defined(Q3DNS_DEBUG)
01257 qDebug( "copying query to %s", server->toString().ascii() );
01258 #endif
01259 }
01260 }
01261 q->step++;
01262
01263
01264
01265
01266 q->start( q->step < ns->count() ? 800 : 1500, true );
01267 }
01268
01269
01270 Q3DnsDomain * Q3DnsManager::domain( const QString & label )
01271 {
01272 Q3DnsDomain * d = cache.find( label );
01273 if ( !d ) {
01274 d = new Q3DnsDomain( label );
01275 cache.insert( label, d );
01276 }
01277 return d;
01278 }
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291 Q3DnsDomain::Q3DnsDomain( const QString & label )
01292 {
01293 l = label;
01294 rrs = 0;
01295 }
01296
01297
01298 Q3DnsDomain::~Q3DnsDomain()
01299 {
01300 delete rrs;
01301 rrs = 0;
01302 }
01303
01304
01305 void Q3DnsDomain::add( const QString & label, Q3DnsRR * rr )
01306 {
01307 Q3DnsDomain * d = Q3DnsManager::manager()->domain( label );
01308 if ( !d->rrs ) {
01309 d->rrs = new Q3PtrList<Q3DnsRR>;
01310 d->rrs->setAutoDelete( true );
01311 }
01312 d->rrs->append( rr );
01313 rr->domain = d;
01314 }
01315
01316
01317 Q3PtrList<Q3DnsRR> * Q3DnsDomain::cached( const Q3Dns * r )
01318 {
01319 Q3PtrList<Q3DnsRR> * l = new Q3PtrList<Q3DnsRR>;
01320
01321
01322 if ( r->recordType() == Q3Dns::A ) {
01323 if ( r->label().lower() == "localhost" ) {
01324
01325
01326
01327 Q3DnsRR *rrTmp = new Q3DnsRR( r->label() );
01328 rrTmp->t = Q3Dns::A;
01329 rrTmp->address = QHostAddress( 0x7f000001 );
01330 rrTmp->current = true;
01331 l->append( rrTmp );
01332 return l;
01333 }
01334 QHostAddress tmp;
01335 if ( tmp.setAddress( r->label() ) ) {
01336 Q3DnsRR *rrTmp = new Q3DnsRR( r->label() );
01337 if ( tmp.isIPv4Address() ) {
01338 rrTmp->t = Q3Dns::A;
01339 rrTmp->address = tmp;
01340 rrTmp->current = true;
01341 l->append( rrTmp );
01342 } else {
01343 rrTmp->nxdomain = true;
01344 }
01345 return l;
01346 }
01347 }
01348 if ( r->recordType() == Q3Dns::Aaaa ) {
01349 QHostAddress tmp;
01350 if ( tmp.setAddress(r->label()) ) {
01351 Q3DnsRR *rrTmp = new Q3DnsRR( r->label() );
01352 if ( tmp.isIPv6Address() ) {
01353 rrTmp->t = Q3Dns::Aaaa;
01354 rrTmp->address = tmp;
01355 rrTmp->current = true;
01356 l->append( rrTmp );
01357 } else {
01358 rrTmp->nxdomain = true;
01359 }
01360 return l;
01361 }
01362 }
01363
01364
01365 Q3DnsManager * m = Q3DnsManager::manager();
01366 QStringList n = r->qualifiedNames();
01367 bool nxdomain;
01368 int cnamecount = 0;
01369 int it = 0;
01370 while( it < n.count() ) {
01371 QString s = n.at(it++);
01372 nxdomain = false;
01373 #if defined(Q3DNS_DEBUG)
01374 qDebug( "looking at cache for %s (%s %d)",
01375 s.ascii(), r->label().ascii(), r->recordType() );
01376 #endif
01377 Q3DnsDomain * d = m->domain( s );
01378 #if defined(Q3DNS_DEBUG)
01379 qDebug( " - found %d RRs", d && d->rrs ? d->rrs->count() : 0 );
01380 #endif
01381 if ( d->rrs )
01382 d->rrs->first();
01383 Q3DnsRR * rr;
01384 bool answer = false;
01385 while( d->rrs && (rr=d->rrs->current()) != 0 ) {
01386 if ( rr->t == Q3Dns::Cname && r->recordType() != Q3Dns::Cname &&
01387 !rr->nxdomain && cnamecount < 16 ) {
01388
01389
01390 #if defined(Q3DNS_DEBUG)
01391 qDebug( "found cname from %s to %s",
01392 r->label().ascii(), rr->target.ascii() );
01393 #endif
01394 s = rr->target;
01395 d = m->domain( s );
01396 if ( d->rrs )
01397 d->rrs->first();
01398 it = n.count();
01399
01400
01401
01402
01403 cnamecount++;
01404 } else {
01405 if ( rr->t == r->recordType() ) {
01406 if ( rr->nxdomain )
01407 nxdomain = true;
01408 else
01409 answer = true;
01410 l->append( rr );
01411 if ( rr->deleteTime <= lastSweep ) {
01412
01413
01414
01415
01416 Q3DnsQuery * query = new Q3DnsQuery;
01417 query->started = now();
01418 query->id = ++::id;
01419 query->t = rr->t;
01420 query->l = rr->domain->name();
01421
01422
01423
01424
01425 query->step = ns->count();
01426 QObject::connect( query, SIGNAL(timeout()),
01427 Q3DnsManager::manager(),
01428 SLOT(retransmit()) );
01429 Q3DnsManager::manager()->transmitQuery( query );
01430 }
01431 }
01432 d->rrs->next();
01433 }
01434 }
01435
01436 if ( answer && l->count() ) {
01437 #if defined(Q3DNS_DEBUG)
01438 qDebug( "found %d records for %s",
01439 l->count(), r->label().ascii() );
01440 l->first();
01441 while( l->current() ) {
01442 qDebug( " type %d target %s address %s",
01443 l->current()->t,
01444 l->current()->target.latin1(),
01445 l->current()->address.toString().latin1() );
01446 l->next();
01447 }
01448 #endif
01449 l->first();
01450 return l;
01451 }
01452
01453 #if defined(Q3DNS_DEBUG)
01454 if ( nxdomain )
01455 qDebug( "found NXDomain %s", s.ascii() );
01456 #endif
01457
01458 if ( !nxdomain ) {
01459
01460
01461 uint q = 0;
01462 while ( q < m->queries.size() &&
01463 ( m->queries[q] == 0 ||
01464 m->queries[q]->t != r->recordType() ||
01465 m->queries[q]->l != s ) )
01466 q++;
01467
01468
01469
01470 if ( q == m->queries.size() && ( s.find( '.' ) >= 0 ||
01471 int(l->count()) >= n.count()-1 ) ) {
01472 Q3DnsQuery * query = new Q3DnsQuery;
01473 query->started = now();
01474 query->id = ++::id;
01475 query->t = r->recordType();
01476 query->l = s;
01477 query->dns->replace( (void*)r, (void*)r );
01478 QObject::connect( query, SIGNAL(timeout()),
01479 Q3DnsManager::manager(), SLOT(retransmit()) );
01480 Q3DnsManager::manager()->transmitQuery( query );
01481 } else if ( q < m->queries.size() ) {
01482
01483
01484 m->queries[q]->dns->replace( (void*)r, (void*)r );
01485 }
01486 }
01487 }
01488 l->first();
01489 return l;
01490 }
01491
01492
01493 void Q3DnsDomain::sweep( Q_UINT32 thisSweep )
01494 {
01495 if ( !rrs )
01496 return;
01497
01498 Q3DnsRR * rr;
01499 rrs->first();
01500 while( (rr=rrs->current()) != 0 ) {
01501 if ( !rr->deleteTime )
01502 rr->deleteTime = thisSweep;
01503
01504 #if defined(Q3DNS_DEBUG)
01505 qDebug( "Q3Dns::sweep: %s type %d expires %u %u - %s / %s",
01506 rr->domain->name().latin1(), rr->t,
01507 rr->expireTime, rr->deleteTime,
01508 rr->target.latin1(), rr->address.toString().latin1());
01509 #endif
01510 if ( rr->current == false ||
01511 rr->t == Q3Dns::None ||
01512 rr->deleteTime <= thisSweep ||
01513 rr->expireTime <= thisSweep )
01514 rrs->remove();
01515 else
01516 rrs->next();
01517 }
01518
01519 if ( rrs->isEmpty() ) {
01520 delete rrs;
01521 rrs = 0;
01522 }
01523 }
01524
01525
01526
01527
01528
01529
01530
01531
01532 Q3DnsSocket::Q3DnsSocket( QObject * parent, const char * name )
01533 : QObject( parent, name )
01534 {
01535
01536 }
01537
01538
01539 Q3DnsSocket::~Q3DnsSocket()
01540 {
01541
01542 }
01543
01544
01545 void Q3DnsSocket::cleanCache()
01546 {
01547
01548 }
01549
01550
01551 void Q3DnsSocket::retransmit()
01552 {
01553
01554 }
01555
01556
01557 void Q3DnsSocket::answer()
01558 {
01559
01560 }
01561
01562
01606 Q3Dns::Q3Dns()
01607 {
01608 d = new Q3DnsPrivate;
01609 t = None;
01610 }
01611
01612
01613
01614
01626 Q3Dns::Q3Dns( const QString & label, RecordType rr )
01627 {
01628 d = new Q3DnsPrivate;
01629 t = rr;
01630 setLabel( label );
01631 setStartQueryTimer();
01632 }
01633
01634
01635
01650 Q3Dns::Q3Dns( const QHostAddress & address, RecordType rr )
01651 {
01652 d = new Q3DnsPrivate;
01653 t = rr;
01654 setLabel( address );
01655 setStartQueryTimer();
01656 }
01657
01658
01659
01660
01665 Q3Dns::~Q3Dns()
01666 {
01667 if ( globalManager ) {
01668 uint q = 0;
01669 Q3DnsManager * m = globalManager;
01670 while( q < m->queries.size() ) {
01671 Q3DnsQuery * query=m->queries[q];
01672 if ( query && query->dns )
01673 (void)query->dns->take( (void*) this );
01674 q++;
01675 }
01676
01677 }
01678
01679 delete d;
01680 d = 0;
01681 }
01682
01683
01684
01685
01698 void Q3Dns::setLabel( const QString & label )
01699 {
01700 l = label;
01701 d->noNames = false;
01702
01703
01704 n.clear();
01705 if ( l.length() > 1 && l[(int)l.length()-1] == '.' ) {
01706 n.append( l.left( l.length()-1 ).lower() );
01707 } else {
01708 int i = l.length();
01709 int dots = 0;
01710 const int maxDots = 2;
01711 while( i && dots < maxDots ) {
01712 if ( l[--i] == '.' )
01713 dots++;
01714 }
01715 if ( dots < maxDots ) {
01716 (void)Q3DnsManager::manager();
01717 Q3StrListIterator it( *domains );
01718 const char * dom;
01719 while( (dom=it.current()) != 0 ) {
01720 ++it;
01721 n.append( l.lower() + "." + dom );
01722 }
01723 }
01724 n.append( l.lower() );
01725 }
01726
01727 #if defined(Q_DNS_SYNCHRONOUS)
01728 if ( d->noEventLoop ) {
01729 doSynchronousLookup();
01730 } else {
01731 setStartQueryTimer();
01732 }
01733 #else
01734 setStartQueryTimer();
01735 #endif
01736 #if defined(Q3DNS_DEBUG)
01737 qDebug( "Q3Dns::setLabel: %d address(es) for %s", n.count(), l.ascii() );
01738 int i = 0;
01739 for( i = 0; i < (int)n.count(); i++ )
01740 qDebug( "Q3Dns::setLabel: %d: %s", i, n[i].ascii() );
01741 #endif
01742 }
01743
01744
01754 void Q3Dns::setLabel( const QHostAddress & address )
01755 {
01756 setLabel( toInAddrArpaDomain( address ) );
01757 }
01758
01759
01829 void Q3Dns::setRecordType( RecordType rr )
01830 {
01831 t = rr;
01832 d->noNames = false;
01833 setStartQueryTimer();
01834 }
01835
01841 void Q3Dns::startQuery()
01842 {
01843
01844 if ( !isWorking() )
01845 emit resultsReady();
01846 }
01847
01853 void Q3Dns::setStartQueryTimer()
01854 {
01855 #if defined(Q_DNS_SYNCHRONOUS)
01856 if ( !d->queryTimer && !d->noEventLoop )
01857 #else
01858 if ( !d->queryTimer )
01859 #endif
01860 {
01861
01862 d->queryTimer = new QTimer( this );
01863 connect( d->queryTimer, SIGNAL(timeout()),
01864 this, SLOT(startQuery()) );
01865 d->queryTimer->start( 0, true );
01866 }
01867 }
01868
01869
01870
01871
01872
01873
01874
01875 QString Q3Dns::toInAddrArpaDomain( const QHostAddress &address )
01876 {
01877 QString s;
01878 if ( address.isNull() ) {
01879
01880
01881 } else if ( address.isIp4Addr() ) {
01882 Q_UINT32 i = address.ip4Addr();
01883 s.sprintf( "%d.%d.%d.%d.IN-ADDR.ARPA",
01884 i & 0xff, (i >> 8) & 0xff, (i>>16) & 0xff, (i>>24) & 0xff );
01885 } else {
01886
01887
01888 Q_IPV6ADDR i = address.toIPv6Address();
01889 s = "ip6.arpa";
01890 uint b = 0;
01891 while( b < 16 ) {
01892 s = QString::number( i.c[b]%16, 16 ) + "." +
01893 QString::number( i.c[b]/16, 16 ) + "." + s;
01894 b++;
01895 }
01896 }
01897 return s;
01898 }
01899
01900
01924 bool Q3Dns::isWorking() const
01925 {
01926 #if defined(Q3DNS_DEBUG)
01927 qDebug( "Q3Dns::isWorking (%s, %d)", l.ascii(), t );
01928 #endif
01929 if ( t == None )
01930 return false;
01931
01932 #if defined(Q_DNS_SYNCHRONOUS)
01933 if ( d->noEventLoop )
01934 return true;
01935 #endif
01936
01937 Q3PtrList<Q3DnsRR> * ll = Q3DnsDomain::cached( this );
01938 Q_LONG queries = n.count();
01939 while( ll->current() != 0 ) {
01940 if ( ll->current()->nxdomain ) {
01941 queries--;
01942 } else {
01943 delete ll;
01944 return false;
01945 }
01946 ll->next();
01947 }
01948 delete ll;
01949
01950 if ( queries <= 0 )
01951 return false;
01952 if ( d->noNames )
01953 return false;
01954 return true;
01955 }
01956
01957
01979 Q3ValueList<QHostAddress> Q3Dns::addresses() const
01980 {
01981 #if defined(Q3DNS_DEBUG)
01982 qDebug( "Q3Dns::addresses (%s)", l.ascii() );
01983 #endif
01984 Q3ValueList<QHostAddress> result;
01985 if ( t != A && t != Aaaa )
01986 return result;
01987
01988 Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this );
01989
01990 Q3DnsRR * rr;
01991 while( (rr=cached->current()) != 0 ) {
01992 if ( rr->current && !rr->nxdomain )
01993 result.append( rr->address );
01994 cached->next();
01995 }
01996 delete cached;
01997 return result;
01998 }
01999
02000
02028 Q3ValueList<Q3Dns::MailServer> Q3Dns::mailServers() const
02029 {
02030 #if defined(Q3DNS_DEBUG)
02031 qDebug( "Q3Dns::mailServers (%s)", l.ascii() );
02032 #endif
02033 Q3ValueList<Q3Dns::MailServer> result;
02034 if ( t != Mx )
02035 return result;
02036
02037 Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this );
02038
02039 Q3DnsRR * rr;
02040 while( (rr=cached->current()) != 0 ) {
02041 if ( rr->current && !rr->nxdomain ) {
02042 MailServer ms( rr->target, rr->priority );
02043 result.append( ms );
02044 }
02045 cached->next();
02046 }
02047 delete cached;
02048 return result;
02049 }
02050
02051
02080 Q3ValueList<Q3Dns::Server> Q3Dns::servers() const
02081 {
02082 #if defined(Q3DNS_DEBUG)
02083 qDebug( "Q3Dns::servers (%s)", l.ascii() );
02084 #endif
02085 Q3ValueList<Q3Dns::Server> result;
02086 if ( t != Srv )
02087 return result;
02088
02089 Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this );
02090
02091 Q3DnsRR * rr;
02092 while( (rr=cached->current()) != 0 ) {
02093 if ( rr->current && !rr->nxdomain ) {
02094 Server s( rr->target, rr->priority, rr->weight, rr->port );
02095 result.append( s );
02096 }
02097 cached->next();
02098 }
02099 delete cached;
02100 return result;
02101 }
02102
02103
02119 QStringList Q3Dns::hostNames() const
02120 {
02121 #if defined(Q3DNS_DEBUG)
02122 qDebug( "Q3Dns::hostNames (%s)", l.ascii() );
02123 #endif
02124 QStringList result;
02125 if ( t != Ptr )
02126 return result;
02127
02128 Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this );
02129
02130 Q3DnsRR * rr;
02131 while( (rr=cached->current()) != 0 ) {
02132 if ( rr->current && !rr->nxdomain ) {
02133 QString str( rr->target );
02134 result.append( str );
02135 }
02136 cached->next();
02137 }
02138 delete cached;
02139 return result;
02140 }
02141
02142
02157 QStringList Q3Dns::texts() const
02158 {
02159 #if defined(Q3DNS_DEBUG)
02160 qDebug( "Q3Dns::texts (%s)", l.ascii() );
02161 #endif
02162 QStringList result;
02163 if ( t != Txt )
02164 return result;
02165
02166 Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( this );
02167
02168 Q3DnsRR * rr;
02169 while( (rr=cached->current()) != 0 ) {
02170 if ( rr->current && !rr->nxdomain ) {
02171 QString str( rr->text );
02172 result.append( str );
02173 }
02174 cached->next();
02175 }
02176 delete cached;
02177 return result;
02178 }
02179
02180
02196 QString Q3Dns::canonicalName() const
02197 {
02198
02199
02200 Q3Dns *that = (Q3Dns*) this;
02201 RecordType oldType = t;
02202 that->t = Cname;
02203 Q3PtrList<Q3DnsRR> * cached = Q3DnsDomain::cached( that );
02204 that->t = oldType;
02205
02206 Q3DnsRR * rr;
02207 while( (rr=cached->current()) != 0 ) {
02208 if ( rr->current && !rr->nxdomain && rr->domain ) {
02209 delete cached;
02210 return rr->target;
02211 }
02212 cached->next();
02213 }
02214 delete cached;
02215 return QString();
02216 }
02217
02218 #if defined(Q_DNS_SYNCHRONOUS)
02219
02221 void Q3Dns::connectNotify( const char *signal )
02222 {
02223 if ( d->noEventLoop && qstrcmp(signal,SIGNAL(resultsReady()) )==0 ) {
02224 doSynchronousLookup();
02225 }
02226 }
02227 #endif
02228
02229 #if defined(Q_OS_WIN32) || defined(Q_OS_CYGWIN)
02230
02231 #if defined(Q_DNS_SYNCHRONOUS)
02232 void Q3Dns::doSynchronousLookup()
02233 {
02234
02235 }
02236 #endif
02237
02238
02239 #ifndef IP_TYPES_INCLUDED
02240 #define MAX_HOSTNAME_LEN 128
02241 #define MAX_DOMAIN_NAME_LEN 128
02242 #define MAX_SCOPE_ID_LEN 256
02243 typedef struct {
02244 char String[4 * 4];
02245 } IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
02246 typedef struct _IP_ADDR_STRING {
02247 struct _IP_ADDR_STRING* Next;
02248 IP_ADDRESS_STRING IpAddress;
02249 IP_MASK_STRING IpMask;
02250 DWORD Context;
02251 } IP_ADDR_STRING, *PIP_ADDR_STRING;
02252 typedef struct {
02253 char HostName[MAX_HOSTNAME_LEN + 4] ;
02254 char DomainName[MAX_DOMAIN_NAME_LEN + 4];
02255 PIP_ADDR_STRING CurrentDnsServer;
02256 IP_ADDR_STRING DnsServerList;
02257 UINT NodeType;
02258 char ScopeId[MAX_SCOPE_ID_LEN + 4];
02259 UINT EnableRouting;
02260 UINT EnableProxy;
02261 UINT EnableDns;
02262 } FIXED_INFO, *PFIXED_INFO;
02263 #endif
02264 typedef DWORD (WINAPI *GNP)( PFIXED_INFO, PULONG );
02265
02266
02267 static QString getWindowsRegString( HKEY key, const QString &subKey )
02268 {
02269 QString s;
02270 QT_WA( {
02271 char buf[1024];
02272 DWORD bsz = sizeof(buf);
02273 int r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz );
02274 if ( r == ERROR_SUCCESS ) {
02275 s = QString::fromUcs2( (unsigned short *)buf );
02276 } else if ( r == ERROR_MORE_DATA ) {
02277 char *ptr = new char[bsz+1];
02278 r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz );
02279 if ( r == ERROR_SUCCESS )
02280 s = ptr;
02281 delete [] ptr;
02282 }
02283 } , {
02284 char buf[512];
02285 DWORD bsz = sizeof(buf);
02286 int r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz );
02287 if ( r == ERROR_SUCCESS ) {
02288 s = buf;
02289 } else if ( r == ERROR_MORE_DATA ) {
02290 char *ptr = new char[bsz+1];
02291 r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz );
02292 if ( r == ERROR_SUCCESS )
02293 s = ptr;
02294 delete [] ptr;
02295 }
02296 } );
02297 return s;
02298 }
02299
02300 static bool getDnsParamsFromRegistry( const QString &path,
02301 QString *domainName, QString *nameServer, QString *searchList )
02302 {
02303 HKEY k;
02304 int r;
02305 QT_WA( {
02306 r = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
02307 (TCHAR*)path.ucs2(),
02308 0, KEY_READ, &k );
02309 } , {
02310 r = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
02311 path.latin1(),
02312 0, KEY_READ, &k );
02313 } );
02314
02315 if ( r == ERROR_SUCCESS ) {
02316 *domainName = getWindowsRegString( k, "DhcpDomain" );
02317 if ( domainName->isEmpty() )
02318 *domainName = getWindowsRegString( k, "Domain" );
02319
02320 *nameServer = getWindowsRegString( k, "DhcpNameServer" );
02321 if ( nameServer->isEmpty() )
02322 *nameServer = getWindowsRegString( k, "NameServer" );
02323
02324 *searchList = getWindowsRegString( k, "SearchList" );
02325 }
02326 RegCloseKey( k );
02327 return r == ERROR_SUCCESS;
02328 }
02329
02330 void Q3Dns::doResInit()
02331 {
02332 char separator = 0;
02333
02334 if ( ns )
02335 delete ns;
02336 ns = new Q3PtrList<QHostAddress>;
02337 ns->setAutoDelete( true );
02338 domains = new Q3StrList( true );
02339 domains->setAutoDelete( true );
02340
02341 QString domainName, nameServer, searchList;
02342
02343 bool gotNetworkParams = false;
02344
02345
02346 #ifdef Q_OS_TEMP
02347 HINSTANCE hinstLib = LoadLibraryW( L"iphlpapi" );
02348 #else
02349 HINSTANCE hinstLib = LoadLibraryA( "iphlpapi" );
02350 #endif
02351 if ( hinstLib != 0 ) {
02352 #ifdef Q_OS_TEMP
02353 GNP getNetworkParams = (GNP) GetProcAddressW( hinstLib, L"GetNetworkParams" );
02354 #else
02355 GNP getNetworkParams = (GNP) GetProcAddress( hinstLib, "GetNetworkParams" );
02356 #endif
02357 if ( getNetworkParams != 0 ) {
02358 ULONG l = 0;
02359 DWORD res;
02360 res = getNetworkParams( 0, &l );
02361 if ( res == ERROR_BUFFER_OVERFLOW ) {
02362 FIXED_INFO *finfo = (FIXED_INFO*)new char[l];
02363 res = getNetworkParams( finfo, &l );
02364 if ( res == ERROR_SUCCESS ) {
02365 domainName = finfo->DomainName;
02366 nameServer = "";
02367 IP_ADDR_STRING *dnsServer = &finfo->DnsServerList;
02368 while ( dnsServer != 0 ) {
02369 nameServer += dnsServer->IpAddress.String;
02370 dnsServer = dnsServer->Next;
02371 if ( dnsServer != 0 )
02372 nameServer += " ";
02373 }
02374 searchList = "";
02375 separator = ' ';
02376 gotNetworkParams = true;
02377 }
02378 delete[] finfo;
02379 }
02380 }
02381 FreeLibrary( hinstLib );
02382 }
02383 if ( !gotNetworkParams ) {
02384 if ( getDnsParamsFromRegistry(
02385 QString( "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" ),
02386 &domainName, &nameServer, &searchList )) {
02387
02388 separator = ' ';
02389 } else if ( getDnsParamsFromRegistry(
02390 QString( "System\\CurrentControlSet\\Services\\VxD\\MSTCP" ),
02391 &domainName, &nameServer, &searchList )) {
02392
02393 separator = ',';
02394 } else {
02395
02396 domainName = "";
02397 nameServer = "127.0.0.1";
02398 searchList = "";
02399 separator = ' ';
02400 }
02401 }
02402
02403 nameServer = nameServer.simplifyWhiteSpace();
02404 int first, last;
02405 if ( !nameServer.isEmpty() ) {
02406 first = 0;
02407 do {
02408 last = nameServer.find( separator, first );
02409 if ( last < 0 )
02410 last = nameServer.length();
02411 Q3Dns tmp( nameServer.mid( first, last-first ), Q3Dns::A );
02412 Q3ValueList<QHostAddress> address = tmp.addresses();
02413 Q_LONG i = address.count();
02414 while( i )
02415 ns->append( new QHostAddress(address[--i]) );
02416 first = last+1;
02417 } while( first < (int)nameServer.length() );
02418 }
02419
02420 searchList = searchList + " " + domainName;
02421 searchList = searchList.simplifyWhiteSpace().lower();
02422 first = 0;
02423 do {
02424 last = searchList.find( separator, first );
02425 if ( last < 0 )
02426 last = searchList.length();
02427 domains->append( qstrdup( searchList.mid( first, last-first ).latin1() ) );
02428 first = last+1;
02429 } while( first < (int)searchList.length() );
02430 }
02431
02432 #elif defined(Q_OS_UNIX)
02433
02434 #if defined(Q_DNS_SYNCHRONOUS)
02435 void Q3Dns::doSynchronousLookup()
02436 {
02437 if ( t!=None && !l.isEmpty() ) {
02438 Q3ValueListIterator<QString> it = n.begin();
02439 Q3ValueListIterator<QString> end = n.end();
02440 int type;
02441 switch( t ) {
02442 case Q3Dns::A:
02443 type = 1;
02444 break;
02445 case Q3Dns::Aaaa:
02446 type = 28;
02447 break;
02448 case Q3Dns::Mx:
02449 type = 15;
02450 break;
02451 case Q3Dns::Srv:
02452 type = 33;
02453 break;
02454 case Q3Dns::Cname:
02455 type = 5;
02456 break;
02457 case Q3Dns::Ptr:
02458 type = 12;
02459 break;
02460 case Q3Dns::Txt:
02461 type = 16;
02462 break;
02463 default:
02464 type = (char)255;
02465 break;
02466 }
02467 while( it != end ) {
02468 QString s = *it;
02469 it++;
02470 QByteArray ba( 512 );
02471 int len = res_search( s.latin1(), 1, type, (uchar*)ba.data(), ba.size() );
02472 if ( len > 0 ) {
02473 ba.resize( len );
02474
02475 Q3DnsQuery * query = new Q3DnsQuery;
02476 query->started = now();
02477 query->id = ++::id;
02478 query->t = t;
02479 query->l = s;
02480 Q3DnsAnswer a( ba, query );
02481 a.parse();
02482 } else if ( len == -1 ) {
02483
02484 }
02485 }
02486 emit resultsReady();
02487 }
02488 }
02489 #endif
02490
02491 #if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
02492 #define Q_MODERN_RES_API
02493 #endif
02494
02495 void Q3Dns::doResInit()
02496 {
02497 if ( ns )
02498 return;
02499 ns = new Q3PtrList<QHostAddress>;
02500 ns->setAutoDelete( true );
02501 domains = new Q3StrList( true );
02502 domains->setAutoDelete( true );
02503
02504
02505 QFile resolvConf("/etc/resolv.conf");
02506 if (resolvConf.open(QIODevice::ReadOnly)) {
02507 QTextStream stream( &resolvConf );
02508 QString line;
02509
02510 while ( !stream.atEnd() ) {
02511 line = stream.readLine();
02512 QStringList list = QStringList::split( " ", line );
02513 if( line.startsWith( "#" ) || list.size() < 2 )
02514 continue;
02515 const QString type = list[0].lower();
02516
02517 if ( type == "nameserver" ) {
02518 QHostAddress *address = new QHostAddress();
02519 if ( address->setAddress( QString(list[1]) ) ) {
02520
02521
02522 if ( address->isIPv4Address() || ipv6support )
02523 ns->append( address );
02524 else
02525 delete address;
02526 } else {
02527 delete address;
02528 }
02529 } else if ( type == "search" ) {
02530 QStringList srch = QStringList::split( " ", list[1] );
02531 for ( QStringList::Iterator i = srch.begin(); i != srch.end(); ++i )
02532 domains->append( (*i).lower().local8Bit() );
02533
02534 } else if ( type == "domain" ) {
02535 domains->append( list[1].lower().local8Bit() );
02536 }
02537 }
02538 }
02539
02540 if (ns->isEmpty()) {
02541 #if defined(Q_MODERN_RES_API)
02542 struct __res_state res;
02543 res_ninit( &res );
02544 int i;
02545
02546 for( i=0; i < MAXNS && i < res.nscount; i++ )
02547 ns->append( new QHostAddress( ntohl( res.nsaddr_list[i].sin_addr.s_addr ) ) );
02548 # if defined(MAXDFLSRCH)
02549 for( i=0; i < MAXDFLSRCH; i++ ) {
02550 if ( res.dnsrch[i] && *(res.dnsrch[i]) )
02551 domains->append( QString::fromLatin1( res.dnsrch[i] ).lower().local8Bit() );
02552 else
02553 break;
02554 }
02555 # endif
02556 if ( *res.defdname )
02557 domains->append( QString::fromLatin1( res.defdname ).lower().local8Bit() );
02558 #else
02559 res_init();
02560 int i;
02561
02562 for( i=0; i < MAXNS && i < _res.nscount; i++ )
02563 ns->append( new QHostAddress( ntohl( _res.nsaddr_list[i].sin_addr.s_addr ) ) );
02564 # if defined(MAXDFLSRCH)
02565 for( i=0; i < MAXDFLSRCH; i++ ) {
02566 if ( _res.dnsrch[i] && *(_res.dnsrch[i]) )
02567 domains->append( QString::fromLatin1( _res.dnsrch[i] ).lower().local8Bit() );
02568 else
02569 break;
02570 }
02571 # endif
02572 if ( *_res.defdname )
02573 domains->append( QString::fromLatin1( _res.defdname ).lower().local8Bit() );
02574 #endif
02575
02576
02577
02578 ns->first();
02579 while( ns->current() ) {
02580 if ( ns->current()->isNull() )
02581 delete ns->take();
02582 else
02583 ns->next();
02584 }
02585 }
02586
02587 QFile hosts( QString::fromLatin1( "/etc/hosts" ) );
02588 if ( hosts.open( QIODevice::ReadOnly ) ) {
02589
02590
02591 QTextStream i( &hosts );
02592 QString line;
02593 while( !i.atEnd() ) {
02594 line = i.readLine().simplifyWhiteSpace().lower();
02595 uint n = 0;
02596 while( (int) n < line.length() && line[(int)n] != '#' )
02597 n++;
02598 line.truncate( n );
02599 n = 0;
02600 while( (int) n < line.length() && !line[(int)n].isSpace() )
02601 n++;
02602 QString ip = line.left( n );
02603 QHostAddress a;
02604 a.setAddress( ip );
02605 if ( ( a.isIPv4Address() || a.isIPv6Address() ) && !a.isNull() ) {
02606 bool first = true;
02607 line = line.mid( n+1 );
02608 n = 0;
02609 while( (int) n < line.length() && !line[(int)n].isSpace() )
02610 n++;
02611 QString hostname = line.left( n );
02612
02613 if ( n ) {
02614 Q3DnsRR * rr = new Q3DnsRR( hostname );
02615 if ( a.isIPv4Address() )
02616 rr->t = Q3Dns::A;
02617 else
02618 rr->t = Q3Dns::Aaaa;
02619 rr->address = a;
02620 rr->deleteTime = UINT_MAX;
02621 rr->expireTime = UINT_MAX;
02622 rr->current = true;
02623 if ( first ) {
02624 first = false;
02625 Q3DnsRR * ptr = new Q3DnsRR( Q3Dns::toInAddrArpaDomain( a ) );
02626 ptr->t = Q3Dns::Ptr;
02627 ptr->target = hostname;
02628 ptr->deleteTime = UINT_MAX;
02629 ptr->expireTime = UINT_MAX;
02630 ptr->current = true;
02631 }
02632 }
02633 }
02634 }
02635 }
02636 }
02637
02638 #endif
02639
02640 #endif // QT_NO_DNS