1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last)
21 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
22 also return length of pseudoheader in *len and pointer to the UDP size in *p
23 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
24 forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
26 int i, arcount = ntohs(header->arcount);
27 unsigned char *ansp = (unsigned char *)(header+1);
28 unsigned short rdlen, type, class;
29 unsigned char *ret = NULL;
35 if (OPCODE(header) == QUERY)
37 for (i = ntohs(header->qdcount); i != 0; i--)
39 if (!(ansp = skip_name(ansp, header, plen, 4)))
43 GETSHORT(class, ansp);
45 if (class == C_IN && type == T_TKEY)
52 if (!(ansp = skip_questions(header, plen)))
59 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
62 for (i = 0; i < arcount; i++)
64 unsigned char *save, *start = ansp;
65 if (!(ansp = skip_name(ansp, header, plen, 10)))
70 GETSHORT(class, ansp);
72 GETSHORT(rdlen, ansp);
73 if (!ADD_RDLEN(header, ansp, plen, rdlen))
84 *is_last = (i == arcount-1);
99 /* replace == 2 ->delete existing option only. */
100 size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
101 unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
103 unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
104 int rdlen = 0, is_sign, is_last;
105 unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
107 p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
114 /* Existing header */
116 unsigned short code, len;
132 if (!CHECK_LEN(header, p, plen, rdlen))
133 return plen; /* bad packet */
136 /* no option to add */
140 /* check if option already there */
141 for (i = 0; i + 4 < rdlen;)
146 /* malformed option, delete the whole OPT RR and start again. */
147 if (i + 4 + len > rdlen)
159 /* delete option if we're to replace it. */
162 memmove(p, p+len+4, rdlen - i);
163 PUTSHORT(rdlen, lenp);
173 /* If we're going to extend the RR, it has to be the last RR in the packet */
176 /* First, take a copy of the options. */
177 if (rdlen != 0 && (buff = whine_malloc(rdlen)))
178 memcpy(buff, datap, rdlen);
180 /* now, delete OPT RR */
181 plen = rrfilter(header, plen, RRFILTER_EDNS0);
183 /* Now, force addition of a new one */
190 /* We are (re)adding the pseudoheader */
191 if (!(p = skip_questions(header, plen)) ||
192 !(p = skip_section(p,
193 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
202 return plen; /* Too big */
204 *p++ = 0; /* empty name */
206 PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
207 PUTSHORT(rcode, p); /* extended RCODE and version */
208 PUTSHORT(flags, p); /* DO flag */
210 PUTSHORT(rdlen, p); /* RDLEN */
212 /* Copy back any options */
215 if (p + rdlen > limit)
218 return plen; /* Too big */
220 memcpy(p, buff, rdlen);
225 /* Only bump arcount if RR is going to fit */
226 if (((ssize_t)optlen) <= (limit - (p + 4)))
227 header->arcount = htons(ntohs(header->arcount) + 1);
230 if (((ssize_t)optlen) > (limit - (p + 4)))
231 return plen; /* Too big */
234 if (optno != 0 && replace != 2)
237 return plen; /* Too big */
240 if (p + optlen > limit)
241 return plen; /* Too big */
242 memcpy(p, opt, optlen);
244 PUTSHORT(p - datap, lenp);
246 return p - (unsigned char *)header;
249 size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
251 return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
254 static unsigned char char64(unsigned char c)
256 return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
259 static void encoder(unsigned char *in, char *out)
261 out[0] = char64(in[0]>>2);
262 out[1] = char64((in[0]<<4) | (in[1]>>4));
263 out[2] = char64((in[1]<<2) | (in[2]>>6));
264 out[3] = char64(in[2]);
267 /* OPT_ADD_MAC = MAC is added (if available)
268 OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
269 OPT_STRIP_MAC = MAC is removed */
270 static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
271 union mysockaddr *l3, time_t now, int *cacheablep)
273 int replace = 0, maclen = 0;
274 unsigned char mac[DHCP_CHADDR_MAX];
275 char encode[18]; /* handle 6 byte MACs ONLY */
277 if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
279 if (option_bool(OPT_STRIP_MAC))
283 if (option_bool(OPT_MAC_HEX))
284 print_mac(encode, mac, maclen);
287 encoder(mac, encode);
288 encoder(mac+3, encode+4);
292 else if (option_bool(OPT_STRIP_MAC))
295 if (replace != 0 || maclen == 6)
296 plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
302 /* OPT_ADD_MAC = MAC is added (if available)
303 OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
304 OPT_STRIP_MAC = MAC is removed */
305 static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
306 union mysockaddr *l3, time_t now, int *cacheablep)
308 int maclen = 0, replace = 0;
309 unsigned char mac[DHCP_CHADDR_MAX];
311 if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0)
314 if (option_bool(OPT_STRIP_MAC))
317 else if (option_bool(OPT_STRIP_MAC))
320 if (replace != 0 || maclen != 0)
321 plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
328 u8 source_netmask, scope_netmask;
332 static void *get_addrp(union mysockaddr *addr, const short family)
334 if (family == AF_INET6)
335 return &addr->in6.sin6_addr;
337 return &addr->in.sin_addr;
340 static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
342 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
346 int sa_family = source->sa.sa_family;
349 opt->source_netmask = 0;
350 opt->scope_netmask = 0;
352 if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
354 opt->source_netmask = daemon->add_subnet6->mask;
355 if (daemon->add_subnet6->addr_used)
357 sa_family = daemon->add_subnet6->addr.sa.sa_family;
358 addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
362 addrp = &source->in6.sin6_addr;
365 if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
367 opt->source_netmask = daemon->add_subnet4->mask;
368 if (daemon->add_subnet4->addr_used)
370 sa_family = daemon->add_subnet4->addr.sa.sa_family;
371 addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
372 cacheable = 1; /* Address is constant */
375 addrp = &source->in.sin_addr;
378 opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
380 if (addrp && opt->source_netmask != 0)
382 len = ((opt->source_netmask - 1) >> 3) + 1;
383 memcpy(opt->addr, addrp, len);
384 if (opt->source_netmask & 7)
385 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
389 cacheable = 1; /* No address ever supplied. */
394 *cacheablep = cacheable;
399 /* OPT_CLIENT_SUBNET = client subnet is added
400 OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced
401 OPT_STRIP_ECS = client subnet is removed */
402 static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit,
403 union mysockaddr *source, int *cacheable)
405 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
407 int replace = 0, len = 0;
408 struct subnet_opt opt;
410 if (option_bool(OPT_CLIENT_SUBNET))
412 if (option_bool(OPT_STRIP_ECS))
414 len = calc_subnet_opt(&opt, source, cacheable);
416 else if (option_bool(OPT_STRIP_ECS))
421 return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
424 int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
426 /* Section 9.2, Check that subnet option in reply matches. */
429 struct subnet_opt opt;
433 calc_len = calc_subnet_opt(&opt, peer, NULL);
435 if (!(p = skip_name(pseudoheader, header, plen, 10)))
438 p += 8; /* skip UDP length and RCODE */
441 if (!CHECK_LEN(header, p, plen, rdlen))
442 return 1; /* bad packet */
444 /* check if option there */
445 for (i = 0; i + 4 < rdlen; i += len + 4)
449 if (code == EDNS0_OPTION_CLIENT_SUBNET)
451 /* make sure this doesn't mismatch. */
452 opt.scope_netmask = p[3];
453 if (len != calc_len || memcmp(p, &opt, len) != 0)
462 /* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
463 * detailed information on packet formating.
465 #define UMBRELLA_VERSION 1
466 #define UMBRELLA_TYPESZ 2
468 #define UMBRELLA_ASSET 0x0004
469 #define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset)
470 #define UMBRELLA_ORG 0x0008
471 #define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org)
472 #define UMBRELLA_IPV4 0x0010
473 #define UMBRELLA_IPV6 0x0020
474 #define UMBRELLA_DEVICE 0x0040
475 #define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
477 struct umbrella_opt {
481 /* We have 4 possible fields since we'll never send both IPv4 and
482 * IPv6, so using the larger of the two to calculate max buffer size.
483 * Each field also has a type header. So the following accounts for
484 * the type headers and each field size to get a max buffer size.
486 u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
489 static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
493 struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
494 u8 *u = &opt.fields[0];
495 int family = source->sa.sa_family;
496 int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
498 if (daemon->umbrella_org)
500 PUTSHORT(UMBRELLA_ORG, u);
501 PUTLONG(daemon->umbrella_org, u);
504 PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
505 memcpy(u, get_addrp(source, family), size);
508 if (option_bool(OPT_UMBRELLA_DEVID))
510 PUTSHORT(UMBRELLA_DEVICE, u);
511 memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
512 u += UMBRELLA_DEVICESZ;
515 if (daemon->umbrella_asset)
517 PUTSHORT(UMBRELLA_ASSET, u);
518 PUTLONG(daemon->umbrella_asset, u);
521 return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
524 /* Set *check_subnet if we add a client subnet option, which needs to checked
525 in the reply. Set *cacheable to zero if we add an option which the answer
527 size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
528 union mysockaddr *source, time_t now, int *cacheable)
532 plen = add_mac(header, plen, limit, source, now, cacheable);
533 plen = add_dns_client(header, plen, limit, source, now, cacheable);
535 if (daemon->dns_client_id)
536 plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
537 (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
539 if (option_bool(OPT_UMBRELLA))
540 plen = add_umbrella_opt(header, plen, limit, source, cacheable);
542 plen = add_source_addr(header, plen, limit, source, cacheable);