version 1.1, 2016/11/02 09:57:01
|
version 1.1.1.3, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 14
|
Line 14
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
along with this program. If not, see <http://www.gnu.org/licenses/>. |
*/ |
*/ |
|
|
/* Code to safely remove RRs from an DNS answer */ | /* Code to safely remove RRs from a DNS answer */ |
|
|
#include "dnsmasq.h" |
#include "dnsmasq.h" |
|
|
Line 156 static int check_rrs(unsigned char *p, struct dns_head
|
Line 156 static int check_rrs(unsigned char *p, struct dns_head
|
} |
} |
|
|
|
|
/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */ | /* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section. */ |
size_t rrfilter(struct dns_header *header, size_t plen, int mode) |
size_t rrfilter(struct dns_header *header, size_t plen, int mode) |
{ |
{ |
static unsigned char **rrs; | static unsigned char **rrs = NULL; |
static int rr_sz = 0; |
static int rr_sz = 0; |
|
|
unsigned char *p = (unsigned char *)(header+1); |
unsigned char *p = (unsigned char *)(header+1); |
Line 173 size_t rrfilter(struct dns_header *header, size_t plen
|
Line 173 size_t rrfilter(struct dns_header *header, size_t plen
|
GETSHORT(qclass, p); |
GETSHORT(qclass, p); |
|
|
/* First pass, find pointers to start and end of all the records we wish to elide: |
/* First pass, find pointers to start and end of all the records we wish to elide: |
records added for DNSSEC, unless explicity queried for */ | records added for DNSSEC, unless explicitly queried for */ |
for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; |
for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0; |
i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); |
i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); |
i++) |
i++) |
Line 192 size_t rrfilter(struct dns_header *header, size_t plen
|
Line 192 size_t rrfilter(struct dns_header *header, size_t plen
|
if (!ADD_RDLEN(header, p, plen, rdlen)) |
if (!ADD_RDLEN(header, p, plen, rdlen)) |
return plen; |
return plen; |
|
|
/* Don't remove the answer. */ | if (mode == RRFILTER_EDNS0) /* EDNS */ |
if (i < ntohs(header->ancount) && type == qtype && class == qclass) | |
continue; | |
| |
if (mode == 0) /* EDNS */ | |
{ |
{ |
/* EDNS mode, remove T_OPT from additional section only */ |
/* EDNS mode, remove T_OPT from additional section only */ |
if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT) |
if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT) |
continue; |
continue; |
} |
} |
else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG) | else if (mode == RRFILTER_DNSSEC) |
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */ | { |
continue; | if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG) |
| /* DNSSEC mode, remove SIGs and NSECs from all three sections. */ |
| continue; |
| |
| /* Don't remove the answer. */ |
| if (i < ntohs(header->ancount) && type == qtype && class == qclass) |
| continue; |
| } |
| else |
| { |
| /* Only looking at answer section now. */ |
| if (i >= ntohs(header->ancount)) |
| break; |
| |
| if (class != C_IN) |
| continue; |
| |
| if (mode == RRFILTER_A && type != T_A) |
| continue; |
| |
| if (mode == RRFILTER_AAAA && type != T_AAAA) |
| continue; |
| } |
|
|
|
|
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1)) |
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1)) |
return plen; |
return plen; |
|
|
Line 239 size_t rrfilter(struct dns_header *header, size_t plen
|
Line 256 size_t rrfilter(struct dns_header *header, size_t plen
|
if (!check_rrs(p, header, plen, 0, rrs, rr_found)) |
if (!check_rrs(p, header, plen, 0, rrs, rr_found)) |
return plen; |
return plen; |
|
|
/* Third pass, elide records */ | /* Third pass, actually fix up pointers in the records */ |
| p = (unsigned char *)(header+1); |
| |
| check_name(&p, header, plen, 1, rrs, rr_found); |
| p += 4; /* qclass, qtype */ |
| |
| check_rrs(p, header, plen, 1, rrs, rr_found); |
| |
| /* Fourth pass, elide records */ |
for (p = rrs[0], i = 1; i < rr_found; i += 2) |
for (p = rrs[0], i = 1; i < rr_found; i += 2) |
{ |
{ |
unsigned char *start = rrs[i]; |
unsigned char *start = rrs[i]; |
Line 254 size_t rrfilter(struct dns_header *header, size_t plen
|
Line 279 size_t rrfilter(struct dns_header *header, size_t plen
|
header->nscount = htons(ntohs(header->nscount) - chop_ns); |
header->nscount = htons(ntohs(header->nscount) - chop_ns); |
header->arcount = htons(ntohs(header->arcount) - chop_ar); |
header->arcount = htons(ntohs(header->arcount) - chop_ar); |
|
|
/* Fourth pass, fix up pointers in the remaining records */ |
|
p = (unsigned char *)(header+1); |
|
|
|
check_name(&p, header, plen, 1, rrs, rr_found); |
|
p += 4; /* qclass, qtype */ |
|
|
|
check_rrs(p, header, plen, 1, rrs, rr_found); |
|
|
|
return plen; |
return plen; |
} |
} |
|
|
Line 270 u16 *rrfilter_desc(int type)
|
Line 287 u16 *rrfilter_desc(int type)
|
{ |
{ |
/* List of RRtypes which include domains in the data. |
/* List of RRtypes which include domains in the data. |
0 -> domain |
0 -> domain |
integer -> no of plain bytes | integer -> no. of plain bytes |
-1 -> end |
-1 -> end |
|
|
zero is not a valid RRtype, so the final entry is returned for |
zero is not a valid RRtype, so the final entry is returned for |
Line 322 int expand_workspace(unsigned char ***wkspc, int *szp,
|
Line 339 int expand_workspace(unsigned char ***wkspc, int *szp,
|
return 0; |
return 0; |
|
|
new += 5; |
new += 5; |
| |
if (!(p = whine_malloc(new * sizeof(unsigned char *)))) | if (!(p = whine_realloc(*wkspc, new * sizeof(unsigned char *)))) |
return 0; | return 0; |
| |
if (old != 0 && *wkspc) | memset(p+old, 0, new-old); |
{ | |
memcpy(p, *wkspc, old * sizeof(unsigned char *)); | |
free(*wkspc); | |
} | |
|
|
*wkspc = p; |
*wkspc = p; |
*szp = new; |
*szp = new; |