static int dns_parse_a(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, void **result, unsigned dsize) { struct dns_rr_a *ret; struct dns_parse p; struct dns_rr rr; int r; /* first, validate and count number of addresses */ dns_initparse(&p, qdn, pkt, cur, end); while((r = dns_nextrr(&p, &rr)) > 0) if (rr.dnsrr_dsz != dsize) return DNS_E_PROTOCOL; if (r < 0) return DNS_E_PROTOCOL; else if (!p.dnsp_nrr) return DNS_E_NODATA; ret = malloc(sizeof(*ret) + dsize * p.dnsp_nrr + dns_stdrr_size(&p)); if (!ret) return DNS_E_NOMEM; ret->dnsa_nrr = p.dnsp_nrr; ret->dnsa_addr = (unsigned char*)(ret+1); /* copy the RRs */ for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) memcpy(ret->dnsa_addr + dsize * r, rr.dnsrr_dptr, dsize); dns_stdrr_finish((struct dns_rr_null *)ret, (char *)(ret->dnsa_addr + dsize * p.dnsp_nrr), &p); *result = ret; return 0; }
static void dnscb(struct dns_ctx *ctx, void *result, void *data) { int r = dns_status(ctx); struct query *q = data; struct dns_parse p; struct dns_rr rr; unsigned nrr; unsigned char dn[DNS_MAXDN]; const unsigned char *pkt, *cur, *end; if (!result) { return; } 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 = p.dnsp_qtyp = 0; nrr = 0; while((r = dns_nextrr(&p, &rr)) > 0) { if (!dns_dnequal(dn, rr.dnsrr_dn)) continue; if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && (q->qtyp == DNS_T_ANY || q->qtyp == 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) { r = DNS_E_PROTOCOL; break; } else { dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn)); } } } if (!r && !nrr) r = DNS_E_NODATA; if (r < 0) { free(result); return; } dns_rewind(&p, NULL); p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp; p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls; while(dns_nextrr(&p, &rr)) { const unsigned char *dptr = rr.dnsrr_dptr; if (rr.dnsrr_dsz == 4) { char *ip = xmalloc(sizeof(char) * 16); sprintf(ip, "%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]); q->callback(ip, q->data, q->g_ape); break; } } free(result); query_free(q); }
int dns_parse_srv(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, void **result) { struct dns_rr_srv *ret; struct dns_parse p; struct dns_rr rr; int r, l; char *sp; dnsc_t srv[DNS_MAXDN]; assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_SRV); /* first, validate the answer and count size of the result */ l = 0; dns_initparse(&p, qdn, pkt, cur, end); while((r = dns_nextrr(&p, &rr)) > 0) { cur = rr.dnsrr_dptr + 6; r = dns_getdn(pkt, &cur, end, srv, sizeof(srv)); if (r <= 0 || cur != rr.dnsrr_dend) return DNS_E_PROTOCOL; l += dns_dntop_size(srv); } if (r < 0) return DNS_E_PROTOCOL; if (!p.dnsp_nrr) return DNS_E_NODATA; /* next, allocate and set up result */ l += dns_stdrr_size(&p); ret = malloc(sizeof(*ret) + sizeof(struct dns_srv) * p.dnsp_nrr + l); if (!ret) return DNS_E_NOMEM; ret->dnssrv_nrr = p.dnsp_nrr; ret->dnssrv_srv = (struct dns_srv *)(ret+1); /* and 3rd, fill in result, finally */ sp = (char*)(ret->dnssrv_srv + p.dnsp_nrr); for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { ret->dnssrv_srv[r].name = sp; cur = rr.dnsrr_dptr; ret->dnssrv_srv[r].priority = dns_get16(cur); ret->dnssrv_srv[r].weight = dns_get16(cur+2); ret->dnssrv_srv[r].port = dns_get16(cur+4); cur += 6; dns_getdn(pkt, &cur, end, srv, sizeof(srv)); sp += dns_dntop(srv, sp, DNS_MAXNAME); } dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); *result = ret; return 0; }
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; }
static void dns_cb(struct dns_ctx *ctx, void *result, void *data) { int r = dns_status(ctx); int len, i; struct dns_check_info *ci = data; struct dns_parse p; struct dns_rr rr; unsigned nrr; unsigned char dn[DNS_MAXDN]; const unsigned char *pkt, *cur, *end; char *result_str[MAX_RR] = { NULL }; char *result_combined = NULL; /* If out ci isn't active, we must have timed out already */ if(!__isactive_ci(ci)) { if(result) free(result); return; } ci->timed_out = 0; /* If we don't have a result, explode */ if (!result) { ci->error = strdup(dns_strerror(r)); goto cleanup; } /* Process the packet */ 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; while((r = dns_nextrr(&p, &rr)) > 0) { if (!dns_dnequal(dn, rr.dnsrr_dn)) continue; if ((ci->query_ctype == DNS_C_ANY || ci->query_ctype == rr.dnsrr_cls) && (ci->query_rtype == DNS_T_ANY || ci->query_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) { ci->error = strdup("protocol error"); break; } else { int32_t on = 1; /* This actually updates what we're looking for */ dns_dntodn(p.dnsp_dnbuf, ci->dn, sizeof(dn)); noit_stats_set_metric(ci->check, &ci->current, "cname", METRIC_INT32, &on); /* Now follow the leader */ noitL(nldeb, "%s. CNAME %s.\n", dns_dntosp(dn), dns_dntosp(p.dnsp_dnbuf)); dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn)); noitL(nldeb, " ---> '%s'\n", dns_dntosp(dn)); } } } if (!r && !nrr) { ci->error = strdup("no data"); } dns_rewind(&p, NULL); p.dnsp_qtyp = ci->query_rtype == DNS_T_ANY ? 0 : ci->query_rtype; p.dnsp_qcls = ci->query_ctype == DNS_C_ANY ? 0 : ci->query_ctype; while(dns_nextrr(&p, &rr) && ci->nrr < MAX_RR) decode_rr(ci, &p, &rr, &result_str[ci->nrr]); if(ci->sort) qsort(result_str, ci->nrr, sizeof(*result_str), cstring_cmp); /* calculate the length and allocate on the stack */ len = 0; for(i=0; i<ci->nrr; i++) len += strlen(result_str[i]) + 2; result_combined = alloca(len); result_combined[0] = '\0'; /* string it together */ len = 0; for(i=0; i<ci->nrr; i++) { int slen; if(i) { memcpy(result_combined + len, ", ", 2); len += 2; } slen = strlen(result_str[i]); memcpy(result_combined + len, result_str[i], slen); len += slen; result_combined[len] = '\0'; free(result_str[i]); /* free as we go */ } noit_stats_set_metric(ci->check, &ci->current, "answer", METRIC_STRING, result_combined); cleanup: if(result) free(result); if(ci->timeout_event) { eventer_t e = eventer_remove(ci->timeout_event); ci->timeout_event = NULL; if(e) eventer_free(e); } ci->check->flags &= ~NP_RUNNING; dns_check_log_results(ci); __deactivate_ci(ci); }
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; }
static void dns_cb(struct dns_ctx *ctx, void *result, void *data) { int r = dns_status(ctx); dns_lookup_ctx_t *dlc = data; struct dns_parse p; struct dns_rr rr; unsigned nrr = 0; unsigned char dn[DNS_MAXDN]; const unsigned char *pkt, *cur, *end; lua_State *L; if(!dlc->active) goto cleanup; if(!result) goto cleanup; L = dlc->ci->coro_state; 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; while(dns_nextrr(&p, &rr) > 0) { const char *fieldname = NULL; char buff[DNS_MAXDN], *txt_str, *c; int totalsize; const unsigned char *pkt = p.dnsp_pkt; const unsigned char *end = p.dnsp_end; const unsigned char *dptr = rr.dnsrr_dptr; const unsigned char *dend = rr.dnsrr_dend; unsigned char *dn = rr.dnsrr_dn; const unsigned char *tmp; if (!dns_dnequal(dn, rr.dnsrr_dn)) continue; if ((dlc->query_ctype == DNS_C_ANY || dlc->query_ctype == rr.dnsrr_cls) && (dlc->query_rtype == DNS_T_ANY || dlc->query_rtype == rr.dnsrr_typ)) { lua_newtable(L); lua_pushinteger(L, rr.dnsrr_ttl); lua_setfield(L, -2, "ttl"); switch(rr.dnsrr_typ) { case DNS_T_A: if(rr.dnsrr_dsz == 4) { snprintf(buff, sizeof(buff), "%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]); lua_pushstring(L, buff); lua_setfield(L, -2, "a"); } break; case DNS_T_AAAA: if(rr.dnsrr_dsz == 16) { inet_ntop(AF_INET6, dptr, buff, 16); lua_pushstring(L, buff); lua_setfield(L, -2, "aaaa"); } break; case DNS_T_TXT: totalsize = 0; for(tmp = dptr; tmp < dend; totalsize += *tmp, tmp += *tmp + 1) if(tmp + *tmp + 1 > dend) break; /* worst case: every character escaped + '\0' */ txt_str = alloca(totalsize * 3 + 1); if(!txt_str) break; c = txt_str; for(tmp = dptr; tmp < dend; tmp += *tmp + 1) c = encode_txt(c, tmp+1, *tmp); lua_pushstring(L, txt_str); lua_setfield(L, -2, "txt"); break; case DNS_T_MX: lua_pushinteger(L, dns_get16(dptr)); lua_setfield(L, -2, "preference"); tmp = dptr + 2; if(dns_getdn(pkt, &tmp, end, dn, DNS_MAXDN) <= 0 || tmp != dend) break; dns_dntop(dn, buff + strlen(buff), sizeof(buff) - strlen(buff)); lua_pushstring(L, buff); lua_setfield(L, -2, "mx"); break; case DNS_T_CNAME: if(!fieldname) fieldname = "cname"; case DNS_T_PTR: if(!fieldname) fieldname = "ptr"; case DNS_T_NS: if(!fieldname) fieldname = "ns"; case DNS_T_MB: if(!fieldname) fieldname = "mb"; case DNS_T_MD: if(!fieldname) fieldname = "md"; case DNS_T_MF: if(!fieldname) fieldname = "mf"; case DNS_T_MG: if(!fieldname) fieldname = "mg"; case DNS_T_MR: if(!fieldname) fieldname = "mr"; if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) break; dns_dntop(dn, buff, sizeof(buff)); lua_pushstring(L, buff); lua_setfield(L, -2, fieldname); break; default: break; } ++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; } } } cleanup: if(result) free(result); if(dlc->active) noit_lua_resume(dlc->ci, nrr); lookup_ctx_release(dlc); }