From c7f3bd2ac8e52ae3d941d28cf807e97d09e379a9 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sun, 28 Feb 2016 21:48:34 +0000 Subject: [PATCH] Replace incoming EDNS0_OPTION_NOMDEVICEID and EDNS0_OPTION_NOMCPEID options. --- src/auth.c | 2 +- src/dnsmasq.h | 2 +- src/edns0.c | 43 +++++++++++++++++++++++++++++++++---------- src/option.c | 2 +- src/rfc1035.c | 2 +- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/auth.c b/src/auth.c index 1821c8f..198572d 100644 --- a/src/auth.c +++ b/src/auth.c @@ -824,7 +824,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n /* 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 add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0); return ansp - (unsigned char *)header; } diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 280ad9d..1896a64 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1523,7 +1523,7 @@ int expand_workspace(unsigned char ***wkspc, int *szp, int new); unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last); 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 short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace); size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit); size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, time_t now, int *check_subnet); diff --git a/src/edns0.c b/src/edns0.c index f7d1994..a8d8cb6 100644 --- a/src/edns0.c +++ b/src/edns0.c @@ -96,7 +96,7 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t } 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 short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace) { unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL; int rdlen = 0, is_sign, is_last; @@ -120,7 +120,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l if (set_do) { - p -=2; + p -= 2; flags |= 0x8000; PUTSHORT(flags, p); } @@ -136,13 +136,36 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l return plen; /* check if option already there */ - for (i = 0; i + 4 < rdlen; i += len + 4) + for (i = 0; i + 4 < rdlen;) { GETSHORT(code, p); GETSHORT(len, p); + + /* malformed option, delete the whole OPT RR and start again. */ + if (i + len > rdlen) + { + rdlen = 0; + islast = 0; + break; + } + if (code == optno) - return plen; - p += len; + { + if (!replace) + return plen; + + /* delete option if we're to replace it. */ + p -= 4; + rdlen -= len + 4; + memcpy(p, p+len+4, rdlen - i); + PUTSHORT(rdlen, lenp); + lenp -= 2; + } + else + { + p += len; + i += len + 4; + } } /* If we're going to extend the RR, it has to be the last RR in the packet */ @@ -203,7 +226,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit) { - return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1); + return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0); } static unsigned char char64(unsigned char c) @@ -235,7 +258,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch encoder(mac+3, encode+4); encode[8] = 0; } - plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0); + plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, 1); } return plen; @@ -248,7 +271,7 @@ static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *lim unsigned char mac[DHCP_CHADDR_MAX]; if ((maclen = find_mac(l3, mac, 1, now)) != 0) - plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0); + plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0); return plen; } @@ -337,7 +360,7 @@ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned c struct subnet_opt opt; len = calc_subnet_opt(&opt, source); - return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 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, 0); } int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer) @@ -391,7 +414,7 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l if (daemon->dns_client_id) plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, - (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0); + (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1); if (option_bool(OPT_CLIENT_SUBNET)) { diff --git a/src/option.c b/src/option.c index de32cad..f7dc370 100644 --- a/src/option.c +++ b/src/option.c @@ -2171,7 +2171,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma daemon->dns_client_id = opt_string_alloc(arg); break; - case LOPT_ADD_MAC: + case LOPT_ADD_MAC: /* --add-mac */ if (!arg) set_option_bool(OPT_ADD_MAC); else diff --git a/src/rfc1035.c b/src/rfc1035.c index bed5312..24d08c1 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1847,7 +1847,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, /* Advertise our packet size limit in our reply */ if (have_pseudoheader) - len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit); + len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0); if (ad_reqd && sec_data) header->hb4 |= HB4_AD;