From: Simon Kelley Date: Sun, 20 Dec 2015 17:12:16 +0000 (+0000) Subject: Major tidy up of EDNS0 handling and computation/use of udp packet size. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fa14bec83b2db010fd076910fddab56957b9375d;p=people%2Fms%2Fdnsmasq.git Major tidy up of EDNS0 handling and computation/use of udp packet size. --- diff --git a/src/auth.c b/src/auth.c index 2b0b7d6..85bd5e7 100644 --- a/src/auth.c +++ b/src/auth.c @@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut) } -size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) +size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, + int local_query, int do_bit, int have_pseudoheader) { char *name = daemon->namebuff; unsigned char *p, *ansp; @@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n header->ancount = htons(anscount); header->nscount = htons(authcount); header->arcount = htons(0); + + /* Advertise our packet size limit in our reply */ + if (have_pseudoheader) + return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit); + return ansp - (unsigned char *)header; } diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 39a930c..abb34c5 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff, int no_cache, int secure, int *doctored); size_t answer_request(struct dns_header *header, char *limit, size_t qlen, struct in_addr local_addr, struct in_addr local_netmask, - time_t now, int *ad_reqd, int *do_bit); + time_t now, int ad_reqd, int do_bit, int have_pseudoheader); int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, struct bogus_addr *addr, time_t now); int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr); @@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now); unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff); size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen); +size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, + unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do); size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source); #ifdef HAVE_DNSSEC @@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost); /* auth.c */ #ifdef HAVE_AUTH size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, - time_t now, union mysockaddr *peer_addr, int local_query); + time_t now, union mysockaddr *peer_addr, int local_query, + int do_bit, int have_pseudoheader); int in_zone(struct auth_zone *zone, char *name, char **cut); #endif diff --git a/src/dnssec.c b/src/dnssec.c index 82394ee..299ca64 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -67,7 +67,6 @@ static char *algo_digest_name(int algo) case 12: return "gosthash94"; case 13: return "sha256"; case 14: return "sha384"; - default: return NULL; } } diff --git a/src/forward.c b/src/forward.c index 3e801c8..041353c 100644 --- a/src/forward.c +++ b/src/forward.c @@ -244,7 +244,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, void *hash = &crc; #endif unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL); - unsigned char *pheader; (void)do_bit; @@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, there's no point retrying the query, retry the key query instead...... */ if (forward->blocking_query) { - int fd; + int fd, is_sign; + unsigned char *pheader; forward->flags &= ~FREC_TEST_PKTSZ; @@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); plen = forward->stash_len; - if (find_pseudoheader(header, plen, NULL, &pheader, NULL)) - PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader); + if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign) + PUTSHORT(SAFE_PKTSZ, pheader); if (forward->sentto->addr.sa.sa_family == AF_INET) log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); @@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, forward->log_id = daemon->log_id; if (option_bool(OPT_ADD_MAC)) - plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); - + { + size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); + if (new != plen) + { + plen = new; + forward->flags |= FREC_ADDED_PHEADER; + } + } + if (option_bool(OPT_CLIENT_SUBNET)) { size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); if (new != plen) { plen = new; - forward->flags |= FREC_HAS_SUBNET; + forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER; } } #ifdef HAVE_DNSSEC if (option_bool(OPT_DNSSEC_VALID)) { - size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz); + size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz); + if (new != plen) + forward->flags |= FREC_ADDED_PHEADER; + + plen = new; + /* For debugging, set Checking Disabled, otherwise, have the upstream check too, this allows it to select auth servers when one is returning bad data. */ if (option_bool(OPT_DNSSEC_DEBUG)) header->hb4 |= HB4_CD; - if (new_plen != plen) - forward->flags |= FREC_ADDED_PHEADER; - - plen = new_plen; } #endif @@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, } #endif } - - if (find_pseudoheader(header, plen, NULL, &pheader, NULL)) - PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader); +#ifdef HAVE_DNSSEC + if (option_bool(OPT_DNSSEC_VALID) && !do_bit) + { + /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP + packet size to 512. But that won't provide space for the RRSIGS in many cases. + The RRSIGS will be stripped out before the answer goes back, so the packet should + shrink again. So, if we added a do-bit, bump the udp packet size to the value + known to be OK for this server. Maybe check returned size after stripping and set + the truncated bit? */ + unsigned char *pheader; + int is_sign; + if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign)) + PUTSHORT(start->edns_pktsz, pheader); + } +#endif + if (retry_send(sendto(fd, (char *)header, plen, 0, &start->addr.sa, sa_len(&start->addr)))) @@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server } #endif - /* If upstream is advertising a larger UDP packet size - than we allow, trim it so that we don't get overlarge - requests for the client. We can't do this for signed packets. */ - if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign))) { - unsigned short udpsz; - unsigned char *psave = sizep; - - GETSHORT(udpsz, sizep); - - if (!is_sign && udpsz > daemon->edns_pktsz) - PUTSHORT(daemon->edns_pktsz, psave); - if (check_subnet && !check_source(header, plen, pheader, query_source)) { my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch")); return 0; } - if (added_pheader) + if (!is_sign) { - pheader = 0; - header->arcount = htons(0); + if (added_pheader) + { + /* client didn't send EDNS0, we added one, strip it off before returning answer. */ + n = rrfilter(header, n, 0); + pheader = NULL; + } + else + { + /* If upstream is advertising a larger UDP packet size + than we allow, trim it so that we don't get overlarge + requests for the client. We can't do this for signed packets. */ + unsigned short udpsz; + unsigned char *psave = sizep; + + GETSHORT(udpsz, sizep); + if (udpsz > daemon->edns_pktsz) + PUTSHORT(daemon->edns_pktsz, psave); + } } } @@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server } if (option_bool(OPT_DNSSEC_VALID)) - header->hb4 &= ~HB4_AD; - - if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) - header->hb4 |= HB4_AD; - - /* If the requestor didn't set the DO bit, don't return DNSSEC info. */ - if (!do_bit) - n = rrfilter(header, n, 1); + { + header->hb4 &= ~HB4_AD; + + if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure) + header->hb4 |= HB4_AD; + + /* If the requestor didn't set the DO bit, don't return DNSSEC info. */ + if (!do_bit) + n = rrfilter(header, n, 1); + } #endif /* do this after extract_addresses. Ensure NODATA reply and remove @@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now) if ((nn = resize_packet(header, (size_t)n, pheader, plen))) { header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC); - header->hb4 &= ~(HB4_RA | HB4_RCODE); - forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0); + header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD); + if (forward->flags |= FREC_CHECKING_DISABLED) + header->hb4 |= HB4_CD; + if (forward->flags |= FREC_AD_QUESTION) + header->hb4 |= HB4_AD; + if (forward->flags & FREC_DO_QUESTION) + add_do_bit(header, nn, (char *)pheader + plen); + forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION); return; } } @@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now) { struct dns_header *header = (struct dns_header *)daemon->packet; union mysockaddr source_addr; - unsigned short type; + unsigned char *pheader; + unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */ struct all_addr dst_addr; struct in_addr netmask, dst_addr_4; size_t m; ssize_t n; - int if_index = 0, auth_dns = 0; + int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0; #ifdef HAVE_AUTH int local_auth = 0; #endif @@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now) #endif } + if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL)) + { + unsigned short flags; + + have_pseudoheader = 1; + GETSHORT(udp_size, pheader); + pheader += 2; /* ext_rcode */ + GETSHORT(flags, pheader); + + if (flags & 0x8000) + do_bit = 1;/* do bit */ + + /* If the client provides an EDNS0 UDP size, use that to limit our reply. + (bounded by the maximum configured). If no EDNS0, then it + defaults to 512 */ + if (udp_size > daemon->edns_pktsz) + udp_size = daemon->edns_pktsz; + } + #ifdef HAVE_AUTH if (auth_dns) { - m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth); + m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, + local_auth, do_bit, have_pseudoheader); if (m >= 1) { send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), @@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now) else #endif { - int ad_reqd, do_bit; - m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, - dst_addr_4, netmask, now, &ad_reqd, &do_bit); + int ad_reqd = do_bit; + /* RFC 6840 5.7 */ + if (header->hb4 & HB4_AD) + ad_reqd = 1; + + m = answer_request(header, ((char *) header) + udp_size, (size_t)n, + dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); if (m >= 1) { @@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now, #ifdef HAVE_AUTH int local_auth = 0; #endif - int checking_disabled, ad_question, do_bit, added_pheader = 0; + int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0; int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; size_t m; unsigned short qtype; @@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now, union mysockaddr peer_addr; socklen_t peer_len = sizeof(union mysockaddr); int query_count = 0; + unsigned char *pheader; if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) return packet; @@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now, else dst_addr_4.s_addr = 0; + do_bit = 0; + + if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL)) + { + unsigned short flags; + + have_pseudoheader = 1; + pheader += 4; /* udp_size, ext_rcode */ + GETSHORT(flags, pheader); + + if (flags & 0x8000) + do_bit = 1;/* do bit */ + } + #ifdef HAVE_AUTH if (auth_dns) - m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth); + m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, + local_auth, do_bit, have_pseudoheader); else #endif { - /* m > 0 if answered from cache */ - m = answer_request(header, ((char *) header) + 65536, (size_t)size, - dst_addr_4, netmask, now, &ad_question, &do_bit); + int ad_reqd = do_bit; + /* RFC 6840 5.7 */ + if (header->hb4 & HB4_AD) + ad_reqd = 1; + + /* m > 0 if answered from cache */ + m = answer_request(header, ((char *) header) + 65536, (size_t)size, + dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader); /* Do this by steam now we're not in the select() loop */ check_log_writer(1); @@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now, } #ifdef HAVE_DNSSEC + added_pheader = 0; if (option_bool(OPT_DNSSEC_VALID)) { size_t new_size = add_do_bit(header, size, ((char *) header) + 65536); @@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now, m = process_reply(header, now, last_server, (unsigned int)m, option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer, - ad_question, do_bit, added_pheader, check_subnet, &peer_addr); + ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); break; } diff --git a/src/netlink.c b/src/netlink.c index 753784d..3376d68 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)()) rta = RTA_NEXT(rta, len1); } - if (inaddr && mac && callback_ok) + if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) && + inaddr && mac && callback_ok) if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm))) callback_ok = 0; } diff --git a/src/rfc1035.c b/src/rfc1035.c index 188d05f..18858a8 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -489,8 +489,8 @@ struct macparm { union mysockaddr *l3; }; -static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, - int optno, unsigned char *opt, size_t optlen, int set_do) +size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, + unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do) { unsigned char *lenp, *datap, *p; int rdlen, is_sign; @@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned return plen; *p++ = 0; /* empty name */ PUTSHORT(T_OPT, p); - PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */ + PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */ PUTSHORT(0, p); /* extended RCODE and version */ PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ lenp = p; @@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p if (!match) return 1; /* continue */ - parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); + parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); return 0; /* done */ } @@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock { struct macparm parm; -/* Must have an existing pseudoheader as the only ar-record, - or have no ar-records. Must also not be signed */ - - if (ntohs(header->arcount) > 1) - return plen; - parm.header = header; parm.limit = (unsigned char *)limit; parm.plen = plen; @@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio struct subnet_opt opt; len = calc_subnet_opt(&opt, source); - return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); } #ifdef HAVE_DNSSEC size_t add_do_bit(struct dns_header *header, size_t plen, char *limit) { - return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1); + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1); } #endif @@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) /* return zero if we can't answer from cache, or packet size if we can */ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, struct in_addr local_addr, struct in_addr local_netmask, - time_t now, int *ad_reqd, int *do_bit) + time_t now, int ad_reqd, int do_bit, int have_pseudoheader) { char *name = daemon->namebuff; - unsigned char *p, *ansp, *pheader; + unsigned char *p, *ansp; unsigned int qtype, qclass; struct all_addr addr; int nameoffset; unsigned short flag; int q, ans, anscount = 0, addncount = 0; - int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0; + int dryrun = 0; struct crec *crecp; int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; struct mx_srv_record *rec; @@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (header->hb4 & HB4_CD) sec_data = 0; - /* RFC 6840 5.7 */ - *ad_reqd = header->hb4 & HB4_AD; - *do_bit = 0; - /* If there is an additional data section then it will be overwritten by partial replies, so we have to do a dry run to see if we can answer the query. */ - if (ntohs(header->arcount) != 0) - { - dryrun = 1; - - /* If there's an additional section, there might be an EDNS(0) pseudoheader */ - if (find_pseudoheader(header, qlen, NULL, &pheader, NULL)) - { - unsigned short flags; - - have_pseudoheader = 1; - - pheader += 4; /* udp size, ext_rcode */ - GETSHORT(flags, pheader); - - if ((sec_reqd = flags & 0x8000)) - { - *do_bit = 1;/* do bit */ - *ad_reqd = 1; - } - } - } + dryrun = 1; for (rec = daemon->mxnames; rec; rec = rec->next) rec->offset = 0; @@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, GETSHORT(qtype, p); GETSHORT(qclass, p); - /* Don't filter RRSIGS from answers to ANY queries, even if do-bit - not set. */ - if (qtype == T_ANY) - *do_bit = 1; - ans = 0; /* have we answered this question */ if (qtype == T_TXT || qtype == T_ANY) @@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, the zone is unsigned, which implies that we're doing validation. */ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || - !sec_reqd || + !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) { do @@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, } /* If the client asked for DNSSEC don't use cached data. */ - if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) + if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK)) do { /* don't answer wildcard queries with data not from /etc/hosts @@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (crecp->flags & F_NEG) { - /* We don't cache NSEC records, so if a DNSSEC-validated negative answer - is cached and the client wants DNSSEC, forward rather than answering from the cache */ - if (!sec_reqd || !(crecp->flags & F_DNSSECOK)) - { - ans = 1; - auth = 0; - if (crecp->flags & F_NXDOMAIN) - nxdomain = 1; - if (!dryrun) - log_query(crecp->flags, name, NULL, NULL); - } + ans = 1; + auth = 0; + if (crecp->flags & F_NXDOMAIN) + nxdomain = 1; + if (!dryrun) + log_query(crecp->flags, name, NULL, NULL); } else { @@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, len = ansp - (unsigned char *)header; + /* Advertise our packet size limit in our reply */ if (have_pseudoheader) - len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd); + len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit); - if (*ad_reqd && sec_data) + if (ad_reqd && sec_data) header->hb4 |= HB4_AD; else header->hb4 &= ~HB4_AD; diff --git a/src/rrfilter.c b/src/rrfilter.c index ae12261..b26b39f 100644 --- a/src/rrfilter.c +++ b/src/rrfilter.c @@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode) for (p = rrs[0], i = 1; i < rr_found; i += 2) { unsigned char *start = rrs[i]; - unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen; + unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen; memmove(p, start, end-start); p += end-start;