Exemplo n.º 1
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);
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
static void decode_rr(struct dns_check_info *ci, struct dns_parse *p,
                      struct dns_rr *rr, char **output) {
  char buff[DNS_MAXDN], *txt_str = buff, *c;
  u_int32_t ttl, vu;
  int32_t vs;
  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;

  /* Not interested unless it is the answer to my exact question */
  if (!dns_dnequal(ci->dn, dn)) return;

  if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) {
    /* We don't handle EDNS0 OPT records */
    goto decode_err;
  }
  noitL(nldeb, "%s. %u %s %s\n", dns_dntosp(dn), rr->dnsrr_ttl,
        dns_classname(rr->dnsrr_cls),
        dns_typename(rr->dnsrr_typ));

  ttl = rr->dnsrr_ttl;
  noit_stats_set_metric(ci->check, &ci->current, "ttl", METRIC_UINT32, &ttl);

  switch(rr->dnsrr_typ) {
   case DNS_T_A:
    if (rr->dnsrr_dsz != 4) goto decode_err;
    snprintf(buff, sizeof(buff), "%d.%d.%d.%d",
             dptr[0], dptr[1], dptr[2], dptr[3]);
    break;

   case DNS_T_AAAA:
    if (rr->dnsrr_dsz != 16) goto decode_err;
    inet_ntop(AF_INET6, dptr, buff, sizeof(buff));
    break;

   case DNS_T_TXT:
    totalsize = 0;
    for(tmp = dptr; tmp < dend; totalsize += *tmp, tmp += *tmp + 1)
      if(tmp + *tmp + 1 > dend) goto decode_err;
    /* worst case: every character escaped + '\0' */
    txt_str = alloca(totalsize * 3 + 1);
    if(!txt_str) goto decode_err;
    c = txt_str;
    for(tmp = dptr; tmp < dend; tmp += *tmp + 1)
      c = encode_txt(c, tmp+1, *tmp);
    break;

   case DNS_T_MX:
    snprintf(buff, sizeof(buff), "%d ", dns_get16(dptr));
    tmp = dptr + 2;
    if(dns_getdn(pkt, &tmp, end, dn, DNS_MAXDN) <= 0 || tmp != dend)
      goto decode_err;
    dns_dntop(dn, buff + strlen(buff), sizeof(buff) - strlen(buff));
    break;

   case DNS_T_SOA:
     if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto decode_err;
     dns_dntop(dn, buff, sizeof(buff));
     noit_stats_set_metric(ci->check, &ci->current, "name-server", METRIC_STRING, buff);
     if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto decode_err;
     dns_dntop(dn, buff, sizeof(buff));
     noit_stats_set_metric(ci->check, &ci->current, "email-addr", METRIC_STRING, buff);
     if(dptr + 5 * sizeof(u_int32_t) != dend) goto decode_err;
     vu = dns_get32(dptr); dptr += sizeof(u_int32_t);
     noit_stats_set_metric(ci->check, &ci->current, "serial", METRIC_UINT32, &vu);
     /* the serial is what we elect to store as the "answer" as text...
      * because it rarely changes and that seems the most interesting thing
      * to track change-log-style.
      */
     snprintf(buff, sizeof(buff), "%u", vu);
     vs = dns_get32(dptr); dptr += sizeof(int32_t);
     noit_stats_set_metric(ci->check, &ci->current, "refresh", METRIC_UINT32, &vs);
     vs = dns_get32(dptr); dptr += sizeof(int32_t);
     noit_stats_set_metric(ci->check, &ci->current, "retry", METRIC_UINT32, &vs);
     vs = dns_get32(dptr); dptr += sizeof(int32_t);
     noit_stats_set_metric(ci->check, &ci->current, "expiry", METRIC_UINT32, &vs);
     vs = dns_get32(dptr); dptr += sizeof(int32_t);
     noit_stats_set_metric(ci->check, &ci->current, "minimum", METRIC_UINT32, &vs);
     break;

   case DNS_T_CNAME:
   case DNS_T_PTR:
   case DNS_T_NS:
   case DNS_T_MB:
   case DNS_T_MD:
   case DNS_T_MF:
   case DNS_T_MG:
   case DNS_T_MR:
    if(dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto decode_err;
    dns_dntop(dn, buff, sizeof(buff));
    break;

   default:
    break;
  }
  if(*output) {
    int newlen = strlen(*output) + strlen(", ") + strlen(buff) + 1;
    char *newstr;
    newstr = malloc(newlen);
    snprintf(newstr, newlen, "%s, %s", *output, buff);
    free(*output);
    *output = newstr;
  }
  else
    *output = strdup(txt_str);
  ci->nrr++;
  return;

 decode_err:
  ci->error = strdup("RR decode error");
  return;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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);
}