Beispiel #1
0
static uchar *
ixfr_gobble_authority_rr(TASK *t, uchar *query, size_t querylen, uchar *current, IARR *rr){
  uchar * src = current;
  int rdlength = 0;
  task_error_t errcode = TASK_FAILED;

  if (!(IARR_NAME(rr) = name_unencode2(query, querylen, &src, &errcode))) {
    formerr(t, DNS_RCODE_FORMERR, errcode, NULL);
    return NULL;
  }
  DNS_GET16(rr->type, src);
  DNS_GET16(rr->class, src);
  DNS_GET32(rr->ttl, src);

  DNS_GET16(rdlength, src);
  if (!(IARR_MNAME(rr) = name_unencode2(query, querylen, &src, &errcode))) {
    formerr(t, DNS_RCODE_FORMERR, errcode, NULL);
    return NULL;
  }

  if (!(IARR_RNAME(rr) = name_unencode2(query, querylen, &src, &errcode))) {
    formerr(t, DNS_RCODE_FORMERR, errcode, NULL);
    return NULL;
  }

  DNS_GET32(rr->serial, src);
  DNS_GET32(rr->refresh, src);
  DNS_GET32(rr->retry, src);
  DNS_GET32(rr->expire, src);
  DNS_GET32(rr->minimum, src);

  return src;
}
Beispiel #2
0
//process a segment of data
int
passer_related_data(struct sockinfo *si, mbuf_type *mbuf,
                    struct author *author)
{
    uchar *buf = si->buf, *tail = NULL;
    int stype = 0/*, ret*//*, seg*/;
    struct rbtree *rbt;
    int datalen = 0;
    ushort n;
    struct hlpp hlp;
    dnsheader *hdr = (dnsheader *) buf;
    
    tail = buf + sizeof(dnsheader) + si->lowerdomain->label_len[0];       //domain len
    /* type = ntohs(*(ushort *) tail); */
    /* class = ntohs(*(ushort *) (tail + 2)); */
    tail = tail + 4;
    datalen = si->buflen;
    rbt = author->s->ttlexp;
    n = ntohs(hdr->ancount);
    hlp.stype = &stype;
    hlp.ds = author->s->datasets;
    hlp.rbt = rbt;
    hlp.buf = buf;
    hlp.datalen = datalen;
    hlp.tmpbuf = mbuf->tempbuffer;
    hlp.domainbuf = mbuf->tdbuffer;
    hlp.dmbuf = mbuf->dmbuffer;
    if (n > 0) {
        hlp.section = AN_SECTION;
        tail = process_rdata(&hlp, tail, n);
        if (tail == NULL)
            return -1;
    }
    n = ntohs(hdr->nscount);
    if (n > 0) {
        hlp.section = NS_SECTION;
        tail = process_rdata(&hlp, tail, n);
        if (tail == NULL)
            return -1;
    }
    n = ntohs(hdr->arcount);
    if (n > 0) {
        // ignore OPT(EDNS0 option)
        if ((tail + OPT_LEN + OPT_RDATA) <= (buf + datalen))
        {
            uint8_t opt_owner = *(uint8_t *)tail;
            uint16_t opt_type = *(uint16_t *)(tail + 1);
            if (opt_owner == 0 && DNS_GET16(opt_type) == OPT)
            {
                return stype;
            }
        }
        
        hlp.section = AR_SECTION;
        tail = process_rdata(&hlp, tail, n);
        if (tail == NULL)
            return -1;
    }
    return stype;
}
Beispiel #3
0
uchar *
fill_header_in_msg(struct setheader * sh)
{
    uchar *itor = sh->itor;
    dnsheader *hdr = (dnsheader *) (sh->itor);
    qdns *qd;
    hdr->flags = 0;
    hdr->flags = SET_QR_R(hdr->flags);
    hdr->flags = SET_RA(hdr->flags);
    hdr->flags = DNS_GET16(hdr->flags);
    hdr->ancount = DNS_GET16(sh->an);
    hdr->nscount = DNS_GET16(sh->ns);
    hdr->arcount = 0; //DNS_GET16(0);
    itor += sizeof(dnsheader);
    itor = itor + sh->dlen;
    qd = (qdns *) itor;
    qd->type = DNS_GET16(sh->type);
    qd->dclass = DNS_GET16(CLASS_IN);
    itor += sizeof(qdns);
    return itor;
}
Beispiel #4
0
taskexec_t
ixfr(TASK * t, datasection_t section, dns_qtype_t qtype, char *fqdn, int truncateonly) {
  MYDNS_SOA	*soa = NULL;
  uchar		*query = (uchar*)t->query;
  int		querylen = t->len;
  uchar		*src = query + DNS_HEADERSIZE;
  IQ		*q = NULL;
  task_error_t	errcode = 0;

#if DEBUG_ENABLED && DEBUG_IXFR
  DebugX("ixfr", 1, "%s: ixfr(%s, %s, \"%s\", %d)", desctask(t),
	 resolve_datasection_str[section], mydns_qtype_str(qtype), fqdn, truncateonly);
#endif

  if (!dns_ixfr_enabled) {
    dnserror(t, DNS_RCODE_REFUSED, ERR_IXFR_NOT_ENABLED);
    return (TASK_FAILED);
  }

  /*
   * Authority section contains the SOA record for the client's version of the zone
   * only trust the serial number.
   */

  if (mydns_soa_load(sql, &soa, fqdn) < 0) {
    dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);
    return (TASK_FAILED);
  }

  if (!soa) {
    dnserror(t, DNS_RCODE_REFUSED, ERR_ZONE_NOT_FOUND);
    return (TASK_FAILED);
  }

#if DEBUG_ENABLED && DEBUG_IXFR
  DebugX("ixfr", 1, _("%s: DNS IXFR: SOA id %u"), desctask(t), soa->id);
  DebugX("ixfr", 1, _("%s: DNS IXFR: QDCOUNT=%d (Query)"), desctask(t), t->qdcount);
  DebugX("ixfr", 1, _("%s: DNS IXFR: ANCOUNT=%d (Answer)"), desctask(t), t->ancount);
  DebugX("ixfr", 1, _("%s: DNS IXFR: AUCOUNT=%d (Authority)"), desctask(t), t->nscount);
  DebugX("ixfr", 1, _("%s: DNS IXFR: ADCOUNT=%d (Additional data)"), desctask(t), t->arcount);
#endif
  if (!t->nscount)
    return formerr(t, DNS_RCODE_FORMERR, ERR_NO_AUTHORITY,
		   _("ixfr query contains no authority data"));

  if (t->nscount != 1)
    return formerr(t, DNS_RCODE_FORMERR, ERR_MULTI_AUTHORITY,
		   _("ixfr query contains multiple authority records"));

  if (!t->qdcount)
    return formerr(t, DNS_RCODE_FORMERR, ERR_NO_QUESTION,
		   _("ixfr query does not contain question"));

  if (t->qdcount != 1)
    return formerr(t, DNS_RCODE_FORMERR, ERR_MULTI_QUESTIONS,
		   _("ixfr query contains multiple questions"));

  if (t->ancount || t->arcount)
    return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST,
		   _("ixfr query has answer or additional data"));

  q = allocate_iq();

  if (!(IQ_NAME(q) = name_unencode2(query, querylen, &src, &errcode))) {
    free_iq(q);
    return formerr(t, DNS_RCODE_FORMERR, errcode, NULL);
  }

  DNS_GET16(q->type, src);
  DNS_GET16(q->class, src);

  if (!(src = ixfr_gobble_authority_rr(t, query, querylen, src, &q->IR))) {
    free_iq(q);
    return (TASK_FAILED);
  }

  /* Get the serial number from the RR record in the authority section */
#if DEBUG_ENABLED && DEBUG_IXFR
  DebugX("ixfr", 1, _("%s: DNS IXFR Question[zone %s qclass %s qtype %s]"
		      " Authority[zone %s qclass %s qtype %s ttl %u "
		      "mname %s rname %s serial %u refresh %u retry %u expire %u minimum %u]"),
	 desctask(t), q->name, mydns_class_str(q->class), mydns_qtype_str(q->type),
	 q->IR.name, mydns_class_str(q->IR.class), mydns_qtype_str(q->IR.type), q->IR.ttl,
	 q->IR.mname, q->IR.rname, q->IR.serial, q->IR.refresh, q->IR.retry, q->IR.expire, q->IR.minimum);
#endif

  /*
   * As per RFC 1995 we have 3 options for a response if a delta exists.
   *
   * We can send a full zone transfer if it will fit in a UDP packet and is smaller
   * than sending deltas
   *
   * We can send a delta transfer if it will fit into a single UDP packet and we can calculate
   * one for the difference between the client and the current serial
   *
   * We can send a packet with a single SOA record for the latest SOA. This will force the client
   * to initiate an AXFR.
   *
   * We can calculate the size of the response by either building both messages
   * or by an estimation technique. In either case we need to look at the data.
   *
   * I have chosen to check for altered records within the database first.
   *
   * First check is to make sure that the serial held by the client is not the current one
   *
   * Next check to see if out incremental data for the transition from client serial
   * to current serial has not expired.
   *
   * Then retrieve the updated records between the client serial and the latest serial.
   * and retrieve the entire zone ... a record count is the first check.
   *
   * If the number of delta records is larger than the number of zone records then send the zone
   *
   * Calculate the size of the variable parts of the record and compare.
   * We assume that name encoding will have an equal effect on the data.
   * So having chosen to send either the zone or the deltas construct the packet.
   *
   * Check that the packet has not overflowed the UDP limit and send. If it has
   * that abandon the packet and send one containing just the latest SOA.
   *
   */

  if (soa->serial == q->IR.serial) {
    /* Tell the client to do no zone transfer */
    rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
    t->sort_level++;
  } else {
    /* Do we have incremental information in the database */
    if (!truncateonly && mydns_rr_use_active && mydns_rr_use_stamp && mydns_rr_use_serial) {
      /* We can do incrementals */
      /* Need to send an IXFR if available */
      /*
       * Work out when the client SOA came into being
       */
      MYDNS_RR	*ThisRR = NULL, *rr = NULL;
      char	*deltafilter = NULL;
      int	deletecount, activecount, zonesize;
      size_t	deltasize, fullsize;
       
      /* For very large zones we do not want to load all of the records just to give up */
      sql_build_query(&deltafilter, "serial > %u", q->IR.serial);

      /*
       * Compare counts of changes from full zone data
       * ... assumes records are about the same size
       * approximate zone size by 2 * deleted count === actual number of delta records
       */
      deletecount = mydns_rr_count_deleted_filtered(sql,
							soa->id, DNS_QTYPE_ANY, NULL,
							soa->origin, deltafilter);
      activecount = mydns_rr_count_active_filtered(sql,
						       soa->id, DNS_QTYPE_ANY, NULL,
						       soa->origin, deltafilter);
      zonesize = mydns_rr_count_active(sql,
					   soa->id, DNS_QTYPE_ANY, NULL,
					   soa->origin);
      deltasize = deletecount + activecount + 4;
      fullsize = zonesize + 2;

      if ((deletecount < 0) || (activecount < 0) || (zonesize < 0)) {
	RELEASE(deltafilter);
	dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);
	return (TASK_FAILED);
      }
      if (deletecount || activecount) {
	if (deltasize >= fullsize) {
	  /* Send a full zone transfer */
	  /* Current Serial first */
	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  if (mydns_rr_load_active(sql, &ThisRR, soa->id, DNS_QTYPE_ANY, NULL, soa->origin) == 0) {
	    for (rr = ThisRR; rr; rr = rr->next) {
	      char *name = mydns_rr_append_origin(MYDNS_RR_NAME(rr), soa->origin);
	      rrlist_add(t, ANSWER, DNS_RRTYPE_RR, (void *)rr, name);
	      if (name != MYDNS_RR_NAME(rr)) RELEASE(name);
	    }
	    t->sort_level++;
	    mydns_rr_free(ThisRR);
	    rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	    t->sort_level++;
	  }
	} else {
	  int latest_serial = soa->serial;

	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  soa->serial = q->IR.serial;
	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  soa->serial = latest_serial;
	  if (mydns_rr_load_deleted_filtered(sql, &ThisRR, soa->id, DNS_QTYPE_ANY, NULL, soa->origin,
					     deltafilter) == 0) {
	    for (rr = ThisRR; rr; rr = rr->next) {
	      char *name = mydns_rr_append_origin(MYDNS_RR_NAME(rr), soa->origin);
	      rrlist_add(t, ANSWER, DNS_RRTYPE_RR, (void *)rr, name);
	      if (name != MYDNS_RR_NAME(rr)) RELEASE(name);
	    }
	    t->sort_level++;
	    mydns_rr_free(ThisRR);
	  }
	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  if (mydns_rr_load_active_filtered(sql, &ThisRR, soa->id, DNS_QTYPE_ANY, NULL, soa->origin,
					    deltafilter) == 0) {
	    for (rr = ThisRR; rr; rr = rr->next) {
	      char *name = mydns_rr_append_origin(MYDNS_RR_NAME(rr), soa->origin);
	      rrlist_add(t, ANSWER, DNS_RRTYPE_RR, (void *)rr, name);
	      if (name != MYDNS_RR_NAME(rr)) RELEASE(name);
	    }
	    t->sort_level++;
	    mydns_rr_free(ThisRR);
	    rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	    t->sort_level++;
	  }
	  RELEASE(deltafilter);
	}
	goto FINISHEDIXFR;
      }
    }
  }

  /* Tell the client to do a full zone transfer or not at all */
  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
  t->sort_level++;

 FINISHEDIXFR:
  mydns_soa_free(soa);

  free_iq(q);

  t->hdr.aa = 1;

  return (TASK_EXECUTED);
}
Beispiel #5
0
//databuffer format
//type.mvalue.data.type.mvalue.data...
int
// write_back_to_client(uchar * td, enum rrtype otype, uint8_t level, ushort id, int dlen,
write_back_to_client(mbuf_type *mbuf, uchar * fr, int vlen)
{
    struct setheader sh = { 0 };        //data in dns header
    int main_val = 0, dnslen = 0;
    uchar *msg = mbuf->buf, type;      //if bigger, use TCP
    uchar *from = fr, *to = msg;
    struct mvalue *mv = NULL;
    int jump = 0;
    uint16_t temp = 0;
    struct hlpc hlp[100];       //p domians to compression
    hlp[0].name = mbuf->td;
    hlp[0].off = sizeof(dnsheader);
    hlp[0].level = mbuf->lowerdomain.label_count;
    hlp[0].ref = -1;
    hlp[0].mt = 0;
    hlp[0].len = mbuf->dlen;
    if (mbuf->dlen == 2) // root
        jump = sizeof(dnsheader) + 1 + sizeof(qdns);
    else
        jump = sizeof(dnsheader) + mbuf->dlen + sizeof(qdns);
    to = to + jump;
    while (vlen > 1)            //vlen include type.mvalue.data.
    {
        type = from[0];
        mv = (struct mvalue *)(from + 1);
        to = fill_rrset_in_msg(hlp, from, to, &main_val, msg);
        if (to == NULL)
            return -1;
//         *to = 0;
        vlen = vlen - 1 - mv->len - sizeof(struct mvalue);
        sh.an += mv->num;
        from = from + mv->len + 1 + sizeof(struct mvalue);      // type.mv.len.
        /**
        * if previous record is CNAME(query type can't be ANY, that we don't support now),
        * next A & AAAA & CNAME use previous domain name (cname name).
        * We duplicate here to make it possible to refer previous one.
        */
        if (type == CNAME && vlen > 1 /*&& mbuf->qtype != ANY*/ && (from[0] == A || from[0] == AAAA || from[0] == CNAME))
        {
            main_val++;
            hlp[main_val].name = hlp[main_val - 1].name;
            hlp[main_val].off = hlp[main_val - 1].off;
            hlp[main_val].level = hlp[main_val - 1].level;
            hlp[main_val].len = hlp[main_val - 1].len;
            hlp[main_val].ref = -1;
            hlp[main_val].mt = 0;
        }
    }
    sh.itor = msg;
    sh.dlen = (mbuf->dlen == 2) ? 1: (mbuf->dlen);
    sh.od = mbuf->td;
    sh.id = mbuf->id;
    sh.type = mbuf->qtype;
    fill_header_in_msg(&sh);
    dnslen = to - msg;
    mbuf->buflen = dnslen;
    mbuf->addr = &(mbuf->caddr);
    if (mbuf->socktype == UDP) {
        if (dnslen > MAX_UDP_SIZE)
            send_tc_to_client(mbuf);
        else
            udp_write_info(mbuf, 0);     //ignore send error
    } else {
        temp = DNS_GET16(dnslen);
        memcpy(msg - 2, &temp, sizeof(uint16_t));
        mbuf->buflen = dnslen + 2;
        mbuf->buf = msg - 2;
        tcp_write_info(mbuf, 0);
    }
    ////////////////////////////////////////////////////////////
    //key, val, vallen, ttl offset
    //if now + TTL_UPDATE > ttl
    //return
    /* ret = transfer_record_to_msg(msgto, td, msg + 2, dnslen, ttloff); */
    /* if (ret < 0) */
        /* return -1; */
    return 0;
}
Beispiel #6
0
int make_dns_query(char *buf, int query_len, time_t *ttl, int *Anum)
{
    struct sockaddr_in addr;
    int sockfd = -1;
    struct timeval timeout = { RETRANS_INTERVAL, 0 };
    int i, ret = -1;
    int addrlen, send_len, result_len;
    int try_num = 0;
    dns_head_type *dns_head;
#ifdef WIN32
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
#endif

    addr.sin_family = AF_INET;
    //addr.sin_addr.s_addr = inet_addr(PUBLIC_DNS_DEFAULT_SERVER);
    inet_pton(AF_INET, PUBLIC_DNS_DEFAULT_SERVER, &(addr.sin_addr.s_addr));
    addr.sin_port = htons((uint16_t)PUBLIC_DNS_DEFAULT_PORT);
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd) {
        fprintf(stderr, "socket error\n");
        goto clear;
    }

    ret = wait_writable(sockfd, timeout);
    if (ret != 0) {
        fprintf(stderr, "wait writable timeout\n");
        goto clear;
    }
    while (try_num++ <= RETRANS_TRY_NUM) {
        send_len = sendto(sockfd, buf, query_len, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr));
        if (send_len != query_len) {
            fprintf(stderr, "sendto dns query failed\n");
            ret = -1;
            goto clear;
        }
        ret = wait_readable(sockfd, timeout);
        if (ret == 0) {
            break;
        }
    }
    if (try_num > RETRANS_TRY_NUM) {
        fprintf(stderr, "dns query failed over try num\n");
        ret = -1;
        goto clear;
    }

    addrlen = sizeof(struct sockaddr);
    result_len = recvfrom(sockfd, buf, DNS_DEFAULT_DATA_SIZE, 0/*MSG_WAITALL*/,
        (struct sockaddr *)&addr, (socklen_t*)&addrlen);
    if (result_len <= 0) {
        fprintf(stderr, "receve dns response failed\n");
        ret = -1;
        goto clear;
    }

    //只支持A记录
    dns_head = (dns_head_type *)buf;
    int off = 0;
    int num = DNS_GET16(dns_head->numA);
    for (i = 0; i < num; i++) {
        char *result_set = buf + query_len + off;
        response *rp = (response *)(result_set + 2); //2 bytes' offsets
        uint16_t type = DNS_GET16(rp->type);
        *ttl = DNS_GET32(rp->ttl);
        //解析A记录
        if (TYPE_A == type) {
            memcpy(buf + (*Anum) * 4, (char *)(rp + 1), 4);
            (*Anum)++;
            off += (2 + sizeof(response) + 4);
        }
        else if (TYPE_CNAME == type) {
            //如果是CNAME记录则直接查找下一条记录
            off += (2 + sizeof(response) + DNS_GET16(rp->length));
        }
        else {
            //其他类型不支持
            goto clear;
        }
    }

    ret = 0;

clear:
    if (sockfd != -1) {
#ifdef WIN32
        closesocket(sockfd);
        WSACleanup();
#else
        close(sockfd);
#endif
    }

    return ret;
}
Beispiel #7
0
//databuffer format
//type.mvalue.data.type.mvalue.data...
int
// write_back_to_client(uchar * td, enum rrtype otype, uint8_t level, ushort id, int dlen,
write_back_to_client(mbuf_type *mbuf, uchar * fr, int vlen)
{
    struct setheader sh = { 0 };        //data in dns header
    int main_val = 0, dnslen = 0;
    uchar *msg = mbuf->buf, type;      //if bigger, use TCP
    uchar *from = fr, *to = msg;
    struct mvalue *mv = NULL;
    int jump = 0;
    uint16_t temp = 0;
    struct hlpc hlp[100];       //p domians to compression
    hlp[0].name = mbuf->td;
    hlp[0].off = sizeof(dnsheader);
    hlp[0].level = mbuf->lowerdomain.label_count;
    hlp[0].ref = -1;
    hlp[0].mt = 0;
    hlp[0].len = mbuf->dlen;
    jump = sizeof(dnsheader) + mbuf->dlen + sizeof(qdns);
    to = to + jump;
    while (vlen > 1)            //vlen include type.mvalue.data.
    {
        type = from[0];
        mv = (struct mvalue *)(from + 1);
        to = fill_rrset_in_msg(hlp, from, to, main_val, msg);
        if (to == NULL)
            return -1;
//         *to = 0;
        vlen = vlen - 1 - mv->len - sizeof(struct mvalue);
        sh.an += mv->num;
        if (type == CNAME)      //cname must be 1
            main_val++;             //no all rdata is the cname's
        from = from + mv->len + 1 + sizeof(struct mvalue);      // type.mv.len.
    }
    sh.itor = msg;
    sh.dlen = mbuf->dlen;
    sh.od = mbuf->td;
    sh.id = mbuf->id;
    sh.type = mbuf->qtype;
    fill_header_in_msg(&sh);
    dnslen = to - msg;
    mbuf->buflen = dnslen;
    mbuf->addr = &(mbuf->caddr);
    if (mbuf->socktype == UDP) {
        if (dnslen > MAX_UDP_SIZE)
            send_tc_to_client(mbuf);
        else
            udp_write_info(mbuf, 0);     //ignore send error
    } else {
        temp = DNS_GET16(dnslen);
        memcpy(msg - 2, &temp, sizeof(uint16_t));
        mbuf->buflen = dnslen + 2;
        mbuf->buf = msg - 2;
        tcp_write_info(mbuf, 0);
    }
    ////////////////////////////////////////////////////////////
    //key, val, vallen, ttl offset
    //if now + TTL_UPDATE > ttl
    //return
    /* ret = transfer_record_to_msg(msgto, td, msg + 2, dnslen, ttloff); */
    /* if (ret < 0) */
        /* return -1; */
    return 0;
}