void noit_check_resolver_maintain() { time_t now; noit_skiplist *tlist; noit_skiplist_node *sn; now = time(NULL); sn = noit_skiplist_getlist(nc_dns_cache.index); tlist = sn->data; sn = noit_skiplist_getlist(tlist); while(sn) { dns_cache_node *n = sn->data; noit_skiplist_next(tlist, &sn); /* move forward */ /* remove if needed */ if(n->last_updated + n->ttl > now) break; if(n->last_needed + DEFAULT_PURGE_AGE < now && !(n->lookup_inflight_v4 || n->lookup_inflight_v6)) noit_skiplist_remove(&nc_dns_cache, n->target, dns_cache_node_free); else { int abs; if(!dns_ptodn(n->target, strlen(n->target), n->dn, sizeof(n->dn), &abs)) { blank_update(n); } else { if(!n->lookup_inflight_v4) { n->lookup_inflight_v4 = noit_true; if(!dns_submit_dn(dns_ctx, n->dn, DNS_C_IN, DNS_T_A, abs | DNS_NOSRCH, NULL, dns_cache_resolve_v4, n)) blank_update_v4(n); else dns_timeouts(dns_ctx, -1, now); } if(!n->lookup_inflight_v6) { n->lookup_inflight_v6 = noit_true; if(!dns_submit_dn(dns_ctx, n->dn, DNS_C_IN, DNS_T_AAAA, abs | DNS_NOSRCH, NULL, dns_cache_resolve_v6, n)) blank_update_v6(n); else dns_timeouts(dns_ctx, -1, now); } } noitL(noit_debug, "Firing lookup for '%s'\n", n->target); continue; } } }
static void dns_cache_resolve(struct dns_ctx *ctx, void *result, void *data, enum dns_type rtype) { int i, ttl, acnt, r = dns_status(ctx); dns_cache_node *n = data; unsigned char idn[DNS_MAXDN], dn[DNS_MAXDN]; struct dns_parse p; struct dns_rr rr; unsigned nrr; char **answers; const unsigned char *pkt, *cur, *end; if(!result) goto blank; dns_dntodn(n->dn, idn, sizeof(idn)); pkt = result; end = pkt + r; cur = dns_payload(pkt); dns_getdn(pkt, &cur, end, dn, sizeof(dn)); dns_initparse(&p, NULL, pkt, cur, end); p.dnsp_qcls = 0; p.dnsp_qtyp = 0; nrr = 0; ttl = 0; while((r = dns_nextrr(&p, &rr)) > 0) { if (!dns_dnequal(idn, rr.dnsrr_dn)) continue; if (DNS_C_IN == rr.dnsrr_cls && rtype == rr.dnsrr_typ) ++nrr; else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) { if (dns_getdn(pkt, &rr.dnsrr_dptr, end, p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || rr.dnsrr_dptr != rr.dnsrr_dend) { break; } else { if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl)) ttl = rr.dnsrr_ttl; dns_dntodn(p.dnsp_dnbuf, idn, sizeof(idn)); } } } if(!r && !nrr) goto blank; dns_rewind(&p, NULL); p.dnsp_qcls = DNS_C_IN; p.dnsp_qtyp = rtype; answers = calloc(nrr, sizeof(*answers)); acnt = 0; while(dns_nextrr(&p, &rr) && nrr < MAX_RR) { char buff[INET6_ADDRSTRLEN]; if (!dns_dnequal(idn, rr.dnsrr_dn)) continue; if (p.dnsp_rrl && !rr.dnsrr_dn[0] && rr.dnsrr_typ == DNS_T_OPT) continue; if (rtype == rr.dnsrr_typ) { if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl)) ttl = rr.dnsrr_ttl; switch(rr.dnsrr_typ) { case DNS_T_A: if(rr.dnsrr_dsz != 4) continue; inet_ntop(AF_INET, rr.dnsrr_dptr, buff, sizeof(buff)); answers[acnt++] = strdup(buff); break; case DNS_T_AAAA: if(rr.dnsrr_dsz != 16) continue; inet_ntop(AF_INET6, rr.dnsrr_dptr, buff, sizeof(buff)); answers[acnt++] = strdup(buff); break; default: break; } } } n->ttl = ttl; if(rtype == DNS_T_A) { for(i=0;i<n->ip4_cnt;i++) if(n->ip4[i]) free(n->ip4[i]); if(n->ip4) free(n->ip4); n->ip4_cnt = acnt; n->ip4 = answers; n->lookup_inflight_v4 = noit_false; } else if(rtype == DNS_T_AAAA) { for(i=0;i<n->ip6_cnt;i++) if(n->ip6[i]) free(n->ip6[i]); if(n->ip6) free(n->ip6); n->ip6_cnt = acnt; n->ip6 = answers; n->lookup_inflight_v6 = noit_false; } noit_skiplist_remove(&nc_dns_cache, n->target, NULL); n->last_updated = time(NULL); noit_skiplist_insert(&nc_dns_cache, n); noitL(noit_debug, "Resolved %s/%s -> %d records\n", n->target, (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???")), acnt); if(result) free(result); return; blank: if(rtype == DNS_T_A) blank_update_v4(n); if(rtype == DNS_T_AAAA) blank_update_v6(n); noitL(noit_debug, "Resolved %s/%s -> blank\n", n->target, (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???"))); if(result) free(result); return; }
void noit_check_resolver_maintain() { time_t now; mtev_skiplist *tlist; mtev_skiplist_node *sn; now = time(NULL); sn = mtev_skiplist_getlist(nc_dns_cache.index); assert(sn); tlist = sn->data; assert(tlist); sn = mtev_skiplist_getlist(tlist); while(sn) { dns_cache_node *n = sn->data; mtev_skiplist_next(tlist, &sn); /* move forward */ /* remove if needed */ if(n->last_updated + n->ttl > now) break; if(n->last_needed + DEFAULT_PURGE_AGE < now && !(n->lookup_inflight_v4 || n->lookup_inflight_v6)) mtev_skiplist_remove(&nc_dns_cache, n->target, dns_cache_node_free); else { int abs; if(!dns_ptodn(n->target, strlen(n->target), n->dn, sizeof(n->dn), &abs)) { blank_update(n); } else { if(!n->lookup_inflight_v4) { n->lookup_inflight_v4 = mtev_true; if(!dns_submit_dn(dns_ctx, n->dn, DNS_C_IN, DNS_T_A, abs | dns_search_flag, NULL, dns_cache_resolve_v4, n)) blank_update_v4(n); else dns_timeouts(dns_ctx, -1, now); } if(!n->lookup_inflight_v6) { n->lookup_inflight_v6 = mtev_true; if(!dns_submit_dn(dns_ctx, n->dn, DNS_C_IN, DNS_T_AAAA, abs | dns_search_flag, NULL, dns_cache_resolve_v6, n)) blank_update_v6(n); else dns_timeouts(dns_ctx, -1, now); } } mtevL(noit_debug, "Firing lookup for '%s'\n", n->target); continue; } } /* If we have a cache implementation */ if(noit_resolver_cache_store_hook_exists()) { /* And that implementation is interested in getting a dump... */ if(noit_resolver_cache_store_hook_invoke(NULL, NULL, 0) == MTEV_HOOK_CONTINUE) { mtev_skiplist_node *sn; /* dump it all */ DCLOCK(); for(sn = mtev_skiplist_getlist(&nc_dns_cache); sn; mtev_skiplist_next(&nc_dns_cache, &sn)) { int sbuffsize; char sbuff[1024]; dns_cache_node *n = (dns_cache_node *)sn->data; sbuffsize = dns_cache_node_serialize(sbuff, sizeof(sbuff), n); if(sbuffsize > 0) noit_resolver_cache_store_hook_invoke(n->target, sbuff, sbuffsize); } DCUNLOCK(); } } }
static void blank_update(dns_cache_node *n) { blank_update_v4(n); blank_update_v6(n); }
static void dns_cache_resolve(struct dns_ctx *ctx, void *result, void *data, enum dns_type rtype) { int ttl, acnt, r = dns_status(ctx), idnlen; dns_cache_node *n = data; unsigned char idn[DNS_MAXDN], dn[DNS_MAXDN]; struct dns_parse p; struct dns_rr rr; unsigned nrr; struct in_addr *answers4; struct in6_addr *answers6; const unsigned char *pkt, *cur, *end; if(!result) goto blank; dns_dntodn(n->dn, idn, sizeof(idn)); idnlen = dns_dnlen(idn); pkt = result; end = pkt + r; cur = dns_payload(pkt); dns_getdn(pkt, &cur, end, dn, sizeof(dn)); dns_initparse(&p, NULL, pkt, cur, end); p.dnsp_qcls = 0; p.dnsp_qtyp = 0; nrr = 0; ttl = 0; while((r = dns_nextrr(&p, &rr)) > 0) { int dnlen = dns_dnlen(rr.dnsrr_dn); /* if we aren't searching and the don't match... * or if we are searching and the prefixes don't match... */ if ((dns_search_flag && !dns_dnequal(idn, rr.dnsrr_dn)) || (dns_search_flag == 0 && (idnlen > dnlen || memcmp(idn, rr.dnsrr_dn, idnlen-1)))) continue; if (DNS_C_IN == rr.dnsrr_cls && rtype == rr.dnsrr_typ) ++nrr; else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) { if (dns_getdn(pkt, &rr.dnsrr_dptr, end, p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || rr.dnsrr_dptr != rr.dnsrr_dend) { break; } else { if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl)) ttl = rr.dnsrr_ttl; dns_dntodn(p.dnsp_dnbuf, idn, sizeof(idn)); idnlen = dns_dnlen(idn); } } } if(!r && !nrr) goto blank; dns_rewind(&p, NULL); p.dnsp_qcls = DNS_C_IN; p.dnsp_qtyp = rtype; if(rtype == DNS_T_A) answers4 = calloc(nrr, sizeof(*answers4)); else if(rtype == DNS_T_AAAA) answers6 = calloc(nrr, sizeof(*answers6)); acnt = 0; while(dns_nextrr(&p, &rr) && nrr < MAX_RR) { int dnlen = dns_dnlen(rr.dnsrr_dn); if ((dns_search_flag && !dns_dnequal(idn, rr.dnsrr_dn)) || (dns_search_flag == 0 && (idnlen > dnlen || memcmp(idn, rr.dnsrr_dn, idnlen-1)))) continue; if (p.dnsp_rrl && !rr.dnsrr_dn[0] && rr.dnsrr_typ == DNS_T_OPT) continue; if (rtype == rr.dnsrr_typ) { if(rr.dnsrr_ttl > 0 && (ttl == 0 || rr.dnsrr_ttl < ttl)) ttl = rr.dnsrr_ttl; switch(rr.dnsrr_typ) { case DNS_T_A: if(rr.dnsrr_dsz != 4) continue; memcpy(&answers4[acnt++], rr.dnsrr_dptr, rr.dnsrr_dsz); break; case DNS_T_AAAA: if(rr.dnsrr_dsz != 16) continue; memcpy(&answers6[acnt++], rr.dnsrr_dptr, rr.dnsrr_dsz); break; default: break; } } } n->ttl = ttl; if(rtype == DNS_T_A) { if(n->ip4) free(n->ip4); n->ip4_cnt = acnt; n->ip4 = answers4; n->lookup_inflight_v4 = mtev_false; } else if(rtype == DNS_T_AAAA) { if(n->ip6) free(n->ip6); n->ip6_cnt = acnt; n->ip6 = answers6; n->lookup_inflight_v6 = mtev_false; } else { if(result) free(result); return; } DCLOCK(); mtev_skiplist_remove(&nc_dns_cache, n->target, NULL); n->last_updated = time(NULL); mtev_skiplist_insert(&nc_dns_cache, n); DCUNLOCK(); mtevL(noit_debug, "Resolved %s/%s -> %d records\n", n->target, (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???")), acnt); if(result) free(result); return; blank: DCLOCK(); if(rtype == DNS_T_A) blank_update_v4(n); if(rtype == DNS_T_AAAA) blank_update_v6(n); DCUNLOCK(); mtevL(noit_debug, "Resolved %s/%s -> blank\n", n->target, (rtype == DNS_T_AAAA ? "IPv6" : (rtype == DNS_T_A ? "IPv4" : "???"))); if(result) free(result); return; }