?? namecachemain.c
字號:
} return 0; } else if(rbt_status == RBT_STATUS_OK) {#ifdef DEBUG KadC_log("create_pending_entry() found an existing pending_query entry for that question, so did nothing\n");#endif /* already there, do nothing */ return 1; } else { assert(0); /* if other cases, big trouble */ return -1; }}/* If name is equal (apart from capitalization and trailing dots) to one of array's elements (which are supposed to have have no trailing dots), return 1 + index in the array */static int is_in(char *array[], int arraysize, char *name) { int i, l; if(name == NULL) return 0; for(l = strlen(name); l > 0 ; --l) { if(name[l-1] != '.') break; } /* l is now the length of name trimmed of any trailing dots */ if(l == 0) return 0; /* zero-length names are not supposed to be good */ for(i=0; i<arraysize; i++) { char *s = strdup(array[i]); char *p; assert(s != NULL); if((p = strchr(s, '=')) != NULL) { *p = 0; /* truncate string's copy at first '=' (if any) */ } if(strlen(s) == l && strncasecmp(name, s, l) == 0) { free(s); return 1+i; } free(s); } return 0;}/* returns true (1) if name ends with a sequence of labels equal (apart from capitalization and trailing dots) to one of array's elements (which are guaranteed to have no trailing dots) */static int end_is_in(char *array[], int arraysize, char *name) { int i, l; if(name == NULL) return 0; for(l = strlen(name); l > 0 ; --l) { if(name[l-1] != '.') break; } /* l is now the length of name trimmed of any trailing dots */ if(l == 0) return 0; /* zero-length names are not supposed to be good */ for(i=0; i<arraysize; i++) { int la = strlen(array[i]); if(la > l) continue; /* array element must be not longer than name */ if(strncasecmp(name+l-la, array[i], la) == 0 && (l == la || name[l-la-1] == '.')) { return 1; break; } } return 0;}static void replyA(DNSIO *pdnsio, dns_msg *pdm, DNSpacket *pdnp, unsigned long int ip) { DNSpacket *pdnpreply; char *ipbuf = calloc(1, sizeof(unsigned long int)); assert(ipbuf != NULL); pdm->rcode = RCODE_NO_ERROR; pdm->ra = 1; /* recursion available */ pdm->qr = 1; /* it's a reply */ pdm->aa = 1; /* we are authority */ pdm->nanswer_rr = 1; assert(pdm->answer_rr == NULL); /* pdm came from a query... */ pdm->answer_rr = calloc(1, sizeof(dns_rr *)); /* allocate space for one parsed answer field */ assert(pdm->answer_rr != NULL); pdm->answer_rr[0] = calloc(1, sizeof(dns_rr)); assert(pdm->answer_rr[0] != NULL); pdm->answer_rr[0]->rdata = ipbuf; ipbuf[0] = (ip>>24) & 0xff; ipbuf[1] = (ip>>16) & 0xff; ipbuf[2] = (ip>> 8) & 0xff; ipbuf[3] = (ip ) & 0xff; pdm->answer_rr[0]->rdatalen = sizeof(unsigned long int); strcpy(pdm->answer_rr[0]->name, pdm->questions[0]->name); pdm->answer_rr[0]->type = A; pdm->answer_rr[0]->class = pdm->questions[0]->class; pdm->answer_rr[0]->ttl = 600; /* Why 10 minutes? And why not? */ pdnpreply = DNSmsg2packet(pdm, pdnp->remoteip, pdnp->remoteport, pdnp->fd); DNSreply(pdnsio, pdnpreply); DNSpacket_destroy(pdnpreply);}static void replyPTR(DNSIO *pdnsio, dns_msg *pdm, DNSpacket *pdnp, char *name) { DNSpacket *pdnpreply; packedname pn; pdm->rcode = RCODE_NO_ERROR; pdm->ra = 1; /* recursion available */ pdm->qr = 1; /* it's a reply */ pdm->aa = 1; /* we are authority */ pdm->nanswer_rr = 1; assert(pdm->answer_rr == NULL); /* pdm came from a query... */ pdm->answer_rr = calloc(1, sizeof(dns_rr *)); /* allocate space for one parsed answer field */ assert(pdm->answer_rr != NULL); pdm->answer_rr[0] = calloc(1, sizeof(dns_rr)); assert(pdm->answer_rr[0] != NULL); pn = dns_domain_pack(name); assert(pn.buf != NULL); pdm->answer_rr[0]->rdata = pn.buf; pdm->answer_rr[0]->rdatalen = pn.buflen; strcpy(pdm->answer_rr[0]->name, pdm->questions[0]->name); pdm->answer_rr[0]->type = PTR; pdm->answer_rr[0]->class = pdm->questions[0]->class; pdm->answer_rr[0]->ttl = 600; /* Why 10 minutes? And why not? */ pdnpreply = DNSmsg2packet(pdm, pdnp->remoteip, pdnp->remoteport, pdnp->fd); DNSreply(pdnsio, pdnpreply); DNSpacket_destroy(pdnpreply);}static void replyERR(DNSIO *pdnsio, dns_msg *pdm, DNSpacket *pdnp, dns_rcode_t rcode) { /* sigh, we can't answer. */ DNSpacket *pdnpreply; pdm->rcode = rcode; pdm->ra = 1; /* recursion available */ pdm->qr = 1; /* it's a reply */ pdnpreply = DNSmsg2packet(pdm, pdnp->remoteip, pdnp->remoteport, pdnp->fd); DNSreply(pdnsio, pdnpreply); DNSpacket_destroy(pdnpreply);}static void *p2pquery(void *p) { raw_qa *pqa = p; processing_thread_params *pptp = pqa->pptp; DNSIO *pdnsio = pptp->pdnsio; DNSpacket *pdnp = pqa->q; dns_msg *pdm = DNSpacket2msg(pdnp); dns_question *question = pdm->questions[0]; DNSpacket *pdnpreply;#ifdef DEBUG KadC_log("p2pquery thread routine processing query for %s\n", question->name);#endif /* it has already been checked that nquestions == 1 and question is sane and has class == I */ if(question->type == A) { /* now start the time-consuming P2P search */ void *resdictrbt; char index[512]; char filter[1024]; void *iter; sprintf(index, "KadC::namecache::%s", question->name); sprintf(filter, "KadCapp=namecache&rrtype=A"); /* launch a search with 10 threads, max 5 hits and 7 s duration */ resdictrbt = KadC_find(pptp->pkcc, index, filter, 20, 5, 7); pdm->rcode = RCODE_NAME_ERROR; /* default: record NOT found */ if(rbt_size(resdictrbt) == 0) {#ifdef DEBUG KadC_log("p2pquery found no records, and will reply RCODE_NAME_ERROR\n");#endif } else { unsigned long int ip; KadCdictionary *pkd; char *ipbuf = calloc(1, sizeof(unsigned long int));#ifdef DEBUG KadC_log("p2pquery found %d records, and will reply RCODE_NO_ERROR\n", rbt_size(resdictrbt));#endif assert(ipbuf != NULL); /* list each k-object */ for(iter = rbt_begin(resdictrbt); iter != NULL; iter = rbt_next(resdictrbt, iter)) { KadCtag_iter kt_iter; pkd = rbt_value(iter); KadC_log("Found: \n"); KadCdictionary_dump(pkd); KadC_log("\n"); if(KadCtag_find(pkd, "kadcapp", &kt_iter) == KADCTAG_STRING && strcasecmp(kt_iter.tagvalue, "namecache") == 0 && KadCtag_find(pkd, "rrtype", &kt_iter) == KADCTAG_STRING && strcasecmp(kt_iter.tagvalue, "a") == 0 && KadCtag_find(pkd, "ip", &kt_iter) == KADCTAG_STRING) { ip = inet_addr(kt_iter.tagvalue); ip = ntohl(ip); KadC_log("Retrieved ip = %s\n", htoa(ip)); break; } } /* build answer_rr */ assert(pdm->answer_rr == NULL); /* double checking won't hurt */ pdm->answer_rr = calloc(1, sizeof(dns_rr *)); /* allocate space for one parsed answer field */ assert(pdm->answer_rr != NULL); pdm->answer_rr[0] = calloc(1, sizeof(dns_rr)); assert(pdm->answer_rr[0] != NULL); pdm->answer_rr[0]->rdata = ipbuf; ipbuf[0] = (ip>>24) & 0xff; ipbuf[1] = (ip>>16) & 0xff; ipbuf[2] = (ip>> 8) & 0xff; ipbuf[3] = (ip ) & 0xff; pdm->answer_rr[0]->rdatalen = sizeof(unsigned long int); strcpy(pdm->answer_rr[0]->name, pdm->questions[0]->name); pdm->answer_rr[0]->type = A; pdm->answer_rr[0]->class = pdm->questions[0]->class; pdm->answer_rr[0]->ttl = 600; /* Why 10 minutes? And why not? */ pdm->nanswer_rr = 1; pdm->rcode = RCODE_NO_ERROR; /* record found */ } for(iter = rbt_begin(resdictrbt); iter != NULL; iter = rbt_begin(resdictrbt)) { KadCdictionary *pkd = rbt_value(iter); rbt_erase(resdictrbt, iter); KadCdictionary_destroy(pkd); } rbt_destroy(resdictrbt); } else { pdm->rcode = RCODE_NOT_IMPLEMENTED; /* TEMPORARY!! */ } pdm->aa = 1; /* we are authoritative on this */ pdm->ra = 1; /* recursion available */ pdm->qr = 1; /* it's a reply */ pdnpreply = DNSmsg2packet(pdm, pdnp->remoteip, pdnp->remoteport, pdnp->fd); dns_msg_destroy(pdm); /* parsed dns_msg no longer necessary */ /* post the reply to the same queue used by the DNS network listener */ if(pdnsio->fifo->enq(pdnsio->fifo, pdnpreply) != 0) { /* if FIFO full, drop the packet? */ free(pdnpreply->buf); free(pdnpreply); } pqa->done = 1; return NULL;}static void *processing_thread(void *p){ processing_thread_params *pptp = p; for(;;) { int sf; DNSpacket *pdnp; pthread_mutex_lock(&pptp->pdnsio->mutex); /* \\\\\\ LOCK \\\\\\ */ sf = pptp->pdnsio->shutdown_flag; pthread_mutex_unlock(&pptp->pdnsio->mutex); /* ///// UNLOCK ///// */ if(sf) break; /* wait for requests on pptp->d.fifo */ pdnp = pptp->pdnsio->fifo->deqtw(pptp->pdnsio->fifo, 1000); if(pdnp != NULL) { dns_msg *pdm; /* process request, possibly starting a separate thread if the tld is in tlpd[], use KadC search rather than upstream DNS servers */#ifdef VERBOSE_DEBUG /* DEBUG ONLY */ { int i; KadC_log("processing_thread - received from %s:%d %d bytes:", htoa(pdnp->remoteip), pdnp->remoteport, pdnp->bufsize); for(i=0; i < pdnp->bufsize /* && i < 48 */; i++) { if((i % 16) == 0) KadC_log("\n"); KadC_log("%02x ", pdnp->buf[i]); } } KadC_log("\n--------------------------------\n");#endif /* parse the DNSpacket into a dns_msg to perform tests more easily */ pdm = DNSpacket2msg(pdnp); if(pdm != NULL) { /* adjust the qsize field in pdnp (used by rbt comparison functions) */ pdnp->qsize = pdm->questions[0]->raw_length; /* is this a query or a response? */ if(pdm->qr == 0) { /* it's a query */ if(pdm->nquestions != 1 || /* sorry, unable to handle more than one question */ pdm->nanswer_rr != 0) { /* hey, queries are supposed not to contain answers... */ DNSpacket *pdnpreply;#ifdef DEBUG KadC_log("This query had %d questions\n", pdm->nquestions);#endif pdm->rcode = RCODE_NOT_IMPLEMENTED; pdm->ra = 1; /* recursion available */ pdm->qr = 1; /* it's a reply */ pdnpreply = DNSmsg2packet(pdm, pdnp->remoteip, pdnp->remoteport, pdnp->fd); DNSreply(pptp->pdnsio, pdnpreply); DNSpacket_destroy(pdnpreply); } else { /* single question, good. */ void *iter = NULL; rbt_StatusEnum rbt_status; unsigned long int ip; dns_type_t qtype; char *qname; dns_class_t qclass; int dnindex; assert(pdm->questions != NULL); assert(pdm->questions[0] != NULL); /* if there is one question it must be the first... */ qtype = pdm->questions[0]->type; qname = pdm->questions[0]->name; qclass = pdm->questions[0]->class; rbt_status = RBT_STATUS_KEY_NOT_FOUND; /* default */ /* check if a q/a for it is in cache */ pthread_mutex_lock(&pptp->mutex); /* \\\\\\ LOCK \\\\\\ */ if(pdnp->remoteip != 0) /* if not locally generated for predictive caching refresh */ rbt_status = rbt_find(pptp->cache_q_rbt, pdnp, &iter); if(rbt_status == RBT_STATUS_OK) { DNSpacket dnpreply; raw_qa *cached_qa = rbt_value(iter); assert(cached_qa != NULL); cached_qa->last_accessed = time(NULL); /* update "last read" time */ /* create on the stack a clone of reply fetched from cache */ dnpreply = *(cached_qa->a); dnpreply.buf = malloc(dnpreply.bufsize); assert(dnpreply.buf != NULL); memcpy(dnpreply.buf, cached_qa->a->buf, dnpreply.bufsize); /* modify the ID to match the query's */ dnpreply.buf[0] = ((pdm->id)>>8) & 0xff; dnpreply.buf[1] = ((pdm->id) ) & 0xff; /* also match destination IP and port to the requestor's */ dnpreply.remoteip = pdnp->remoteip; dnpreply.remoteport = pdnp->remoteport; dnpreply.fd = pdnp->fd; /* send the reply to the requestor */ DNSreply(pptp->pdnsio, &dnpreply); /* free the buffer (the DNSpacket is auto... */ free(dnpreply.buf); } else if(qclass == I && (qtype == PTR || qtype == 255) && is_a_local_address(ip = reverse_inet_addr(qname))) { /* perhaps it's a query for things on which we are authoritative: PTR for local IP address, A and PTR for localhost (duh) or KadC-related domains (subdomains of arguments of "-t") IMMEDIATE REPLY, no pending_qa is created */ if(ip == 0x7f000001) { /* 127.0.0.1 */ replyPTR(pptp->pdnsio, pdm, pdnp, "localhost"); /* which dumb resolver could ever ask that over the network? */ } else { /* must be an IP on a local interface */ replyPTR(pptp->pdnsio, pdm, pdnp, "cachehost.cachedomain"); /* assumed to be an alias of our machine... */ } } else if(qclass == I && (dnindex=is_in(pptp->my_pseudo, pptp->nmy_pseudo, qname)) > 0) { char *arg = strchr(pptp->my_pseudo[dnindex-1], '='); if(arg == NULL) ip = KadC_getextIP(pptp->pkcc); else ip = ntohl(inet_addr(arg+1)); if(ip != 0) { /* if we know from KadC our external IP address */ /* handle here queries for domain names equal to our pseudomains IMMEDIATE REPLY, no pending_qa is created */#ifdef DEBUG KadC_log("A query for the pseudodomain %s resolves to %s\n", qname, htoa(ip));#endif replyA(pptp->pdnsio, pdm, pdnp, ip); /* assumed to be an alias of our machine... */ } else { replyERR(pptp->pdnsio, pdm, pdnp, RCODE_NAME_ERROR); /* we are authoritative, but the IP is unknown */ } } else if(qclass == I && end_is_in(pptp->tlpd, pptp->ntlpd, qname)) { /* handle here A queries for domain names that are subdomains of one of our tpld's */ /* post a search for the keyword "namecache::some.domain" */#ifdef DEBUG KadC_log("A query for %s, a subdomain of one of the KadC TLPD's\n", qname);#endif if(create_pending_entry(pptp, pdnp, &p2pquery) == 0) { /* if there wasn't already one (also with same id), and it's been created... */ pdnp = NULL; /* so it won't be freed below (now the packet is referenced by the pending_q rbt...) */ } else { /* do nothing, maybe it's an unnecessary retry for timeout that is already being taken care of */ } } else if(pptp->pdnsio->nupstream > 0) { /* nope: if no pending queries, query all upstream servers and create a "pending" entry */ if(create_pending_entry(pptp, pdnp, NULL) == 0) { /* if there wasn't already one (also with same id), and it's been created... */ int i; for(i=0; i < pptp->pdnsio->nupstream; i++) { DNSquery(pptp->pdnsio, pdnp, pptp->pdnsio->upstream[i]); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -