diff --git a/edns.c b/edns.c index 035ce4f4..e9e322d8 100644 --- a/edns.c +++ b/edns.c @@ -71,6 +71,7 @@ edns_init_record(edns_record_type *edns) edns->dnssec_ok = 0; edns->nsid = 0; edns->zoneversion = 0; + edns->cookie_seen = 0; edns->cookie_status = COOKIE_NOT_PRESENT; edns->cookie_len = 0; edns->ede = -1; /* -1 means no Extended DNS Error */ @@ -88,7 +89,7 @@ edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, switch(optcode) { case NSID_CODE: /* is NSID enabled? */ - if(nsd->nsid_len > 0) { + if(nsd->nsid_len > 0 && !edns->nsid) { edns->nsid = 1; /* we have to check optlen, and move the buffer along */ buffer_skip(packet, optlen); @@ -101,7 +102,8 @@ edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet, break; case COOKIE_CODE: /* Cookies enabled? */ - if(nsd->do_answer_cookie) { + if(nsd->do_answer_cookie && !edns->cookie_seen) { + edns->cookie_seen = 1; if (optlen == 8) edns->cookie_status = COOKIE_INVALID; else if (optlen < 16 || optlen > 40) diff --git a/edns.h b/edns.h index 3e1f5e79..1b182e1b 100644 --- a/edns.h +++ b/edns.h @@ -64,6 +64,7 @@ struct edns_record int dnssec_ok; int nsid; int zoneversion; + int cookie_seen; cookie_status_type cookie_status; size_t cookie_len; uint8_t cookie[40]; diff --git a/options.c b/options.c index ccfa13eb..486b61cf 100644 --- a/options.c +++ b/options.c @@ -2221,9 +2221,9 @@ acl_addr_match_range_v4(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t /* check treats x as one huge number */ /* if outside bounds, we are done */ - if(*minval > *x) + if(ntohl(*minval) > ntohl(*x)) return 0; - if(*maxval < *x) + if(ntohl(*maxval) < ntohl(*x)) return 0; return 1; @@ -2244,10 +2244,10 @@ acl_addr_match_range_v6(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t { /* if outside bounds, we are done */ if(checkmin) - if(minval[i] > x[i]) + if(ntohl(minval[i]) > ntohl(x[i])) return 0; if(checkmax) - if(maxval[i] < x[i]) + if(ntohl(maxval[i]) < ntohl(x[i])) return 0; /* if x is equal to a bound, that bound needs further checks */ if(checkmin && minval[i]!=x[i]) diff --git a/query.c b/query.c index 9954c5f0..fd90a3a8 100644 --- a/query.c +++ b/query.c @@ -249,7 +249,8 @@ query_reset(query_type *q, size_t maxlen, int is_tcp) region_free_all(q->region); q->remote_addrlen = (socklen_t)sizeof(q->remote_addr); q->client_addrlen = (socklen_t)sizeof(q->client_addr); - q->is_proxied = 0; + if(!is_tcp) + q->is_proxied = 0; q->maxlen = maxlen; q->reserved_space = 0; buffer_clear(q->packet); @@ -1776,6 +1777,16 @@ query_process(query_type *q, nsd_type *nsd, uint32_t *now_p) cookie_verify(q, nsd, now_p); query_prepare_response(q); + if(q->reserved_space + QHEADERSZ + (size_t)q->qname->name_size + + 2 /* qtype */ + 2 /* qclass */ > q->maxlen) { + /* Clear out some space, and return error, it does not fit. */ + q->edns.status = EDNS_NOT_PRESENT; + q->tsig.status = TSIG_NOT_PRESENT; + if(q->tcp) + return query_error(q, NSD_RC_SERVFAIL); + TC_SET(q->packet); + return query_error(q, NSD_RC_OK); + } if (q->qclass != CLASS_IN && q->qclass != CLASS_ANY) { if (q->qclass == CLASS_CH) { diff --git a/server.c b/server.c index ccf6e2dc..ea9a858a 100644 --- a/server.c +++ b/server.c @@ -4813,7 +4813,8 @@ handle_tcp_writing(int fd, short event, void* arg) } #ifdef HAVE_WRITEV - sent -= sizeof(n_tcplen); + /* The number of bytes transmitted for the message content. */ + sent = data->bytes_transmitted - sizeof(n_tcplen); /* handle potential 'packet done' code */ goto packet_could_be_done; #endif diff --git a/xfrd-tcp.c b/xfrd-tcp.c index acea5e2d..5f3abb51 100644 --- a/xfrd-tcp.c +++ b/xfrd-tcp.c @@ -1252,8 +1252,8 @@ int conn_write(struct xfrd_tcp* tcp) } tcp->total_bytes += sent; - if(sent > (ssize_t)sizeof(tcp->msglen)) - buffer_skip(tcp->packet, sent-sizeof(tcp->msglen)); + if(tcp->total_bytes > (ssize_t)sizeof(tcp->msglen)) + buffer_skip(tcp->packet, tcp->total_bytes-sizeof(tcp->msglen)); if(tcp->total_bytes < sizeof(tcp->msglen)) { /* incomplete write, resume later */ return 0;