📄 q3dns.cpp
字号:
#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN NS %s (ttl %d)", label.ascii(), target.ascii(), ttl );#endif}void Q3DnsAnswer::parsePtr(){ QString target = readString().lower(); if ( !ok ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw bad PTR for for %s", label.ascii() );#endif return; } rr = new Q3DnsRR( label ); rr->t = Q3Dns::Ptr; rr->target = target;#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN PTR %s (ttl %d)", label.ascii(), rr->target.ascii(), ttl );#endif}void Q3DnsAnswer::parseTxt(){ QString text = readString(false); if ( !ok ) {#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw bad TXT for for %s", label.ascii() );#endif return; } rr = new Q3DnsRR( label ); rr->t = Q3Dns::Txt; rr->text = text;#if defined(Q3DNS_DEBUG) qDebug( "Q3Dns: saw %s IN TXT \"%s\" (ttl %d)", label.ascii(), rr->text.ascii(), ttl );#endif}void Q3DnsAnswer::parse(){ // okay, do the work... if ( (answer[2] & 0x78) != 0 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: answer to wrong query type (%d)", answer[1] );#endif ok = false; return; } // AA bool aa = (answer[2] & 4) != 0; // TC if ( (answer[2] & 2) != 0 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: truncated answer; pressing on" );#endif } // RD bool rd = (answer[2] & 1) != 0; // we don't test RA // we don't test the MBZ fields if ( (answer[3] & 0x0f) == 3 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: saw NXDomain for %s", query->l.ascii() );#endif // NXDomain. cache that for one minute. rr = new Q3DnsRR( query->l ); rr->t = query->t; rr->deleteTime = query->started + 60; rr->expireTime = query->started + 60; rr->nxdomain = true; rr->current = true; rrs->append( rr ); return; } if ( (answer[3] & 0x0f) != 0 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: error code %d", answer[3] & 0x0f );#endif ok = false; return; } int qdcount = ( answer[4] << 8 ) + answer[5]; int ancount = ( answer[6] << 8 ) + answer[7]; int nscount = ( answer[8] << 8 ) + answer[9]; int adcount = (answer[10] << 8 ) +answer[11]; pp = 12; // read query while( qdcount > 0 && pp < size ) { // should I compare the string against query->l? (void)readString(); if ( !ok ) return; pp += 4; qdcount--; } // answers and stuff int rrno = 0; // if we parse the answer completely, but there are no answers, // ignore the entire thing. int answers = 0; while( ( rrno < ancount || ( ok && answers >0 && rrno < ancount + nscount + adcount ) ) && pp < size ) { label = readString().lower(); if ( !ok ) return; int rdlength = 0; if ( pp + 10 <= size ) rdlength = ( answer[pp+8] << 8 ) + answer[pp+9]; if ( pp + 10 + rdlength > size ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: ran out of stuff to parse (%d+%d>%d (%d)", pp, rdlength, size, rrno < ancount );#endif // if we're still in the AN section, we should go back and // at least down the TTLs. probably best to invalidate // the results. // the rrs list is good for this ok = ( rrno < ancount ); return; } uint type, clas; type = ( answer[pp+0] << 8 ) + answer[pp+1]; clas = ( answer[pp+2] << 8 ) + answer[pp+3]; ttl = ( answer[pp+4] << 24 ) + ( answer[pp+5] << 16 ) + ( answer[pp+6] << 8 ) + answer[pp+7]; pp = pp + 10; if ( clas != 1 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: class %d (not internet) for %s", clas, label.isNull() ? "." : label.ascii() );#endif } else { next = pp + rdlength; rr = 0; switch( type ) { case 1: parseA(); break; case 28: parseAaaa(); break; case 15: parseMx(); break; case 33: parseSrv(); break; case 5: parseCname(); break; case 12: parsePtr(); break; case 16: parseTxt(); break; case 2: parseNs(); break; default: // something we don't know#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: type %d for %s", type, label.isNull() ? "." : label.ascii() );#endif break; } if ( rr ) { rr->deleteTime = 0; if ( ttl > 0 ) rr->expireTime = query->started + ttl; else rr->expireTime = query->started + 20; if ( rrno < ancount ) { answers++; rr->deleteTime = rr->expireTime; } rr->current = true; rrs->append( rr ); } } if ( !ok ) return; pp = next; next = size; rrno++; } if ( answers == 0 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: answer contained no answers" );#endif ok = ( aa && rd ); } // now go through the list and mark all the As that are referenced // by something we care about. we want to cache such As. rrs->first(); Q3Dict<void> used( 17 ); used.setAutoDelete( false ); while( (rr=rrs->current()) != 0 ) { rrs->next(); if ( rr->target.length() && rr->deleteTime > 0 && rr->current ) used.insert( rr->target, (void*)42 ); if ( ( rr->t == Q3Dns::A || rr->t == Q3Dns::Aaaa ) && used.find( rr->domain->name() ) != 0 ) rr->deleteTime = rr->expireTime; } // next, for each RR, delete any older RRs that are equal to it rrs->first(); while( (rr=rrs->current()) != 0 ) { rrs->next(); if ( rr && rr->domain && rr->domain->rrs ) { Q3PtrList<Q3DnsRR> * drrs = rr->domain->rrs; drrs->first(); Q3DnsRR * older; while( (older=drrs->current()) != 0 ) { if ( older != rr && older->t == rr->t && older->nxdomain == rr->nxdomain && older->address == rr->address && older->target == rr->target && older->priority == rr->priority && older->weight == rr->weight && older->port == rr->port && older->text == rr->text ) { // well, it's equal, but it's not the same. so we kill it, // but use its expiry time.#if defined(Q3DNS_DEBUG) qDebug( "killing off old %d for %s, expire was %d", older->t, older->domain->name().latin1(), rr->expireTime );#endif older->t = Q3Dns::None; rr->expireTime = QMAX( older->expireTime, rr->expireTime ); rr->deleteTime = QMAX( older->deleteTime, rr->deleteTime ); older->deleteTime = 0;#if defined(Q3DNS_DEBUG) qDebug( " adjusted expire is %d", rr->expireTime );#endif } drrs->next(); } } }#if defined(Q3DNS_DEBUG) //qDebug( "DNS Manager: ()" );#endif}class Q3DnsUgleHack: public Q3Dns {public: void ugle( bool emitAnyway=false );};void Q3DnsAnswer::notify(){ if ( !rrs || !ok || !query || !query->dns ) return; Q3PtrDict<void> notified; notified.setAutoDelete( false ); Q3PtrDictIterator<void> it( *query->dns ); Q3Dns * dns; it.toFirst(); while( (dns=(Q3Dns*)(it.current())) != 0 ) { ++it; if ( notified.find( (void*)dns ) == 0 ) { notified.insert( (void*)dns, (void*)42 ); if ( rrs->count() == 0 ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: found no answers!" );#endif dns->d->noNames = true; ((Q3DnsUgleHack*)dns)->ugle( true ); } else { QStringList n = dns->qualifiedNames(); if ( query && n.contains(query->l) ) ((Q3DnsUgleHack*)dns)->ugle();#if defined(Q3DNS_DEBUG) else qDebug( "DNS Manager: DNS thing %s not notified for %s", dns->label().ascii(), query->l.ascii() );#endif } } }}////// Q3DnsManager////class Q3DnsManager: public Q3DnsSocket {private:public: // just to silence the moronic g++. Q3DnsManager(); ~Q3DnsManager();public: static Q3DnsManager * manager(); Q3DnsDomain * domain( const QString & ); void transmitQuery( Q3DnsQuery * ); void transmitQuery( int ); // reimplementation of the slots void cleanCache(); void retransmit(); void answer();public: Q3PtrVector<Q3DnsQuery> queries; Q3Dict<Q3DnsDomain> cache; Q3SocketDevice * ipv4Socket;#if !defined (QT_NO_IPV6) Q3SocketDevice * ipv6Socket;#endif};static Q3DnsManager * globalManager = 0;static void cleanupDns(){ delete globalManager; globalManager = 0;}Q3DnsManager * Q3DnsManager::manager(){ if ( !globalManager ) { qAddPostRoutine(cleanupDns); new Q3DnsManager(); } return globalManager;}void Q3DnsUgleHack::ugle( bool emitAnyway){ if ( emitAnyway || !isWorking() ) {#if defined(Q3DNS_DEBUG) qDebug( "DNS Manager: status change for %s (type %d)", label().ascii(), recordType() );#endif emit resultsReady(); }}Q3DnsManager::Q3DnsManager() : Q3DnsSocket( qApp, "Internal DNS manager" ), queries( Q3PtrVector<Q3DnsQuery>( 0 ) ), cache( Q3Dict<Q3DnsDomain>( 83, false ) ), ipv4Socket( new Q3SocketDevice( Q3SocketDevice::Datagram, Q3SocketDevice::IPv4, 0 ) )#if !defined (QT_NO_IPV6) , ipv6Socket( new Q3SocketDevice( Q3SocketDevice::Datagram, Q3SocketDevice::IPv6, 0 ) )#endif{ cache.setAutoDelete( true ); globalManager = this; QTimer * sweepTimer = new QTimer( this ); sweepTimer->start( 1000 * 60 * 3 ); connect( sweepTimer, SIGNAL(timeout()), this, SLOT(cleanCache()) ); QSocketNotifier * rn4 = new QSocketNotifier( ipv4Socket->socket(), QSocketNotifier::Read, this, "dns IPv4 socket watcher" ); ipv4Socket->setAddressReusable( false ); ipv4Socket->setBlocking( false ); connect( rn4, SIGNAL(activated(int)), SLOT(answer()) );#if !defined (QT_NO_IPV6) // Don't connect the IPv6 socket notifier if the host does not // support IPv6. if ( ipv6Socket->socket() != -1 ) { QSocketNotifier * rn6 = new QSocketNotifier( ipv6Socket->socket(), QSocketNotifier::Read, this, "dns IPv6 socket watcher" ); ipv6support = true; ipv6Socket->setAddressReusable( false ); ipv6Socket->setBlocking( false ); connect( rn6, SIGNAL(activated(int)), SLOT(answer()) ); }#endif if ( !ns ) Q3Dns::doResInit(); // O(n*n) stuff here. but for 3 and 6, O(n*n) with a low k should // be perfect. the point is to eliminate any duplicates that // might be hidden in the lists. Q3PtrList<QHostAddress> * ns = new Q3PtrList<QHostAddress>; ::ns->first(); QHostAddress * h; while( (h=::ns->current()) != 0 ) { ns->first(); while( ns->current() != 0 && !(*ns->current() == *h) ) ns->next(); if ( !ns->current() ) { ns->append( new QHostAddress(*h) );#if defined(Q3DNS_DEBUG) qDebug( "using name server %s", h->toString().latin1() ); } else { qDebug( "skipping address %s", h->toString().latin1() );#endif } ::ns->next(); } delete ::ns; ::ns = ns; ::ns->setAutoDelete( true ); Q3StrList * domains = new Q3StrList( true ); ::domains->first(); const char * s; while( (s=::domains->current()) != 0 ) { domains->first(); while( domains->current() != 0 && qstrcmp( domains->current(), s ) ) domains->next(); if ( !domains->current() ) { domains->append( s );#if defined(Q3DNS_DEBUG) qDebug( "searching domain %s", s ); } else { qDebug( "skipping domain %s", s );#endif } ::domains->next(); } delete ::domains; ::domains = domains; ::domains->setAutoDelete( true );}Q3DnsManager::~Q3DnsManager(){ if ( globalManager ) globalManager = 0; queries.setAutoDelete( true ); cache.setAutoDelete( true ); delete ipv4Socket;#if !defined (QT_NO_IPV6) delete ipv6Socket;#endif}static Q_UINT32 lastSweep = 0;void Q3DnsManager::cleanCache(){ bool again = false; Q3DictIterator<Q3DnsDomain> it( cache ); Q3DnsDomain * d; Q_UINT32 thisSweep = now();#if defined(Q3DNS_DEBUG) qDebug( "Q3DnsManager::cleanCache(: Called, time is %u, last was %u", thisSweep, lastSweep );#endif while( (d=it.current()) != 0 ) { ++it; d->sweep( thisSweep ); // after this, d may be empty if ( !again ) again = !d->isEmpty(); } if ( !again ) delete this; lastSweep = thisSweep;}void Q3DnsManager::retransmit(){ const QObject * o = sender(); if ( o == 0 || globalManager == 0 || this != globalManager ) return; uint q = 0; while( q < queries.size() && queries[q] != o ) q++; if ( q < queries.size() ) transmitQuery( q );}void Q3DnsManager::answer(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -