Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / edns0.c
1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
2
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.
7  
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.
12      
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/>.
15 */
16
17 #include "dnsmasq.h"
18
19 unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign, int *is_last)
20 {
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) */
25   
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;
30
31   if (is_sign)
32     {
33       *is_sign = 0;
34
35       if (OPCODE(header) == QUERY)
36         {
37           for (i = ntohs(header->qdcount); i != 0; i--)
38             {
39               if (!(ansp = skip_name(ansp, header, plen, 4)))
40                 return NULL;
41               
42               GETSHORT(type, ansp); 
43               GETSHORT(class, ansp);
44               
45               if (class == C_IN && type == T_TKEY)
46                 *is_sign = 1;
47             }
48         }
49     }
50   else
51     {
52       if (!(ansp = skip_questions(header, plen)))
53         return NULL;
54     }
55     
56   if (arcount == 0)
57     return NULL;
58   
59   if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
60     return NULL; 
61   
62   for (i = 0; i < arcount; i++)
63     {
64       unsigned char *save, *start = ansp;
65       if (!(ansp = skip_name(ansp, header, plen, 10)))
66         return NULL; 
67
68       GETSHORT(type, ansp);
69       save = ansp;
70       GETSHORT(class, ansp);
71       ansp += 4; /* TTL */
72       GETSHORT(rdlen, ansp);
73       if (!ADD_RDLEN(header, ansp, plen, rdlen))
74         return NULL;
75       if (type == T_OPT)
76         {
77           if (len)
78             *len = ansp - start;
79
80           if (p)
81             *p = save;
82           
83           if (is_last)
84             *is_last = (i == arcount-1);
85
86           ret = start;
87         }
88       else if (is_sign && 
89                i == arcount - 1 && 
90                class == C_ANY && 
91                type == T_TSIG)
92         *is_sign = 1;
93     }
94   
95   return ret;
96 }
97  
98
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)
102
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;
106
107   p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
108   
109   if (is_sign)
110     return plen;
111
112   if (p)
113     {
114       /* Existing header */
115       int i;
116       unsigned short code, len;
117
118       p = udp_len;
119       GETSHORT(udp_sz, p);
120       GETSHORT(rcode, p);
121       GETSHORT(flags, p);
122
123       if (set_do)
124         {
125           p -= 2;
126           flags |= 0x8000;
127           PUTSHORT(flags, p);
128         }
129
130       lenp = p;
131       GETSHORT(rdlen, p);
132       if (!CHECK_LEN(header, p, plen, rdlen))
133         return plen; /* bad packet */
134       datap = p;
135
136        /* no option to add */
137       if (optno == 0)
138         return plen;
139           
140       /* check if option already there */
141       for (i = 0; i + 4 < rdlen;)
142         {
143           GETSHORT(code, p);
144           GETSHORT(len, p);
145           
146           /* malformed option, delete the whole OPT RR and start again. */
147           if (i + 4 + len > rdlen)
148             {
149               rdlen = 0;
150               is_last = 0;
151               break;
152             }
153           
154           if (code == optno)
155             {
156               if (replace == 0)
157                 return plen;
158
159               /* delete option if we're to replace it. */
160               p -= 4;
161               rdlen -= len + 4;
162               memmove(p, p+len+4, rdlen - i);
163               PUTSHORT(rdlen, lenp);
164               lenp -= 2;
165             }
166           else
167             {
168               p += len;
169               i += len + 4;
170             }
171         }
172
173       /* If we're going to extend the RR, it has to be the last RR in the packet */
174       if (!is_last)
175         {
176           /* First, take a copy of the options. */
177           if (rdlen != 0 && (buff = whine_malloc(rdlen)))
178             memcpy(buff, datap, rdlen);       
179           
180           /* now, delete OPT RR */
181           plen = rrfilter(header, plen, RRFILTER_EDNS0);
182           
183           /* Now, force addition of a new one */
184           p = NULL;       
185         }
186     }
187   
188   if (!p)
189     {
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), 
194                              header, plen)))
195       {
196         free(buff);
197         return plen;
198       }
199       if (p + 11 > limit)
200       {
201         free(buff);
202         return plen; /* Too big */
203       }
204       *p++ = 0; /* empty name */
205       PUTSHORT(T_OPT, p);
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 */
209       lenp = p;
210       PUTSHORT(rdlen, p);    /* RDLEN */
211       datap = p;
212       /* Copy back any options */
213       if (buff)
214         {
215           if (p + rdlen > limit)
216           {
217             free(buff);
218             return plen; /* Too big */
219           }
220           memcpy(p, buff, rdlen);
221           free(buff);
222           p += rdlen;
223         }
224       
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);
228     }
229   
230   if (((ssize_t)optlen) > (limit - (p + 4)))
231     return plen; /* Too big */
232   
233   /* Add new option */
234   if (optno != 0 && replace != 2)
235     {
236       if (p + 4 > limit)
237        return plen; /* Too big */
238       PUTSHORT(optno, p);
239       PUTSHORT(optlen, p);
240       if (p + optlen > limit)
241        return plen; /* Too big */
242       memcpy(p, opt, optlen);
243       p += optlen;  
244       PUTSHORT(p - datap, lenp);
245     }
246   return p - (unsigned char *)header;
247 }
248
249 size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
250 {
251   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
252 }
253
254 static unsigned char char64(unsigned char c)
255 {
256   return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
257 }
258
259 static void encoder(unsigned char *in, char *out)
260 {
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]);
265 }
266
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)
272 {
273   int replace = 0, maclen = 0;
274   unsigned char mac[DHCP_CHADDR_MAX];
275   char encode[18]; /* handle 6 byte MACs ONLY */
276
277   if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
278     {
279       if (option_bool(OPT_STRIP_MAC))
280          replace = 1;
281        *cacheablep = 0;
282     
283        if (option_bool(OPT_MAC_HEX))
284          print_mac(encode, mac, maclen);
285        else
286          {
287            encoder(mac, encode);
288            encoder(mac+3, encode+4);
289            encode[8] = 0;
290          }
291     }
292   else if (option_bool(OPT_STRIP_MAC))
293     replace = 2;
294
295   if (replace != 0 || maclen == 6)
296     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
297
298   return plen;
299 }
300
301
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)
307 {
308   int maclen = 0, replace = 0;
309   unsigned char mac[DHCP_CHADDR_MAX];
310     
311   if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0)
312     {
313       *cacheablep = 0;
314       if (option_bool(OPT_STRIP_MAC))
315         replace = 1;
316     }
317   else if (option_bool(OPT_STRIP_MAC))
318     replace = 2;
319   
320   if (replace != 0 || maclen != 0)
321     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
322
323   return plen; 
324 }
325
326 struct subnet_opt {
327   u16 family;
328   u8 source_netmask, scope_netmask; 
329   u8 addr[IN6ADDRSZ];
330 };
331
332 static void *get_addrp(union mysockaddr *addr, const short family) 
333 {
334   if (family == AF_INET6)
335     return &addr->in6.sin6_addr;
336
337   return &addr->in.sin_addr;
338 }
339
340 static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
341 {
342   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
343   
344   int len;
345   void *addrp = NULL;
346   int sa_family = source->sa.sa_family;
347   int cacheable = 0;
348   
349   opt->source_netmask = 0;
350   opt->scope_netmask = 0;
351     
352   if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
353     {
354       opt->source_netmask = daemon->add_subnet6->mask;
355       if (daemon->add_subnet6->addr_used) 
356         {
357           sa_family = daemon->add_subnet6->addr.sa.sa_family;
358           addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
359           cacheable = 1;
360         } 
361       else 
362         addrp = &source->in6.sin6_addr;
363     }
364
365   if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
366     {
367       opt->source_netmask = daemon->add_subnet4->mask;
368       if (daemon->add_subnet4->addr_used)
369         {
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 */
373         } 
374         else 
375           addrp = &source->in.sin_addr;
376     }
377   
378   opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
379   
380   if (addrp && opt->source_netmask != 0)
381     {
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));
386     }
387   else
388     {
389       cacheable = 1; /* No address ever supplied. */
390       len = 0;
391     }
392
393   if (cacheablep)
394     *cacheablep = cacheable;
395   
396   return len + 4;
397 }
398  
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)
404 {
405   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
406   
407   int replace = 0, len = 0;
408   struct subnet_opt opt;
409   
410   if (option_bool(OPT_CLIENT_SUBNET))
411     {
412       if (option_bool(OPT_STRIP_ECS))
413         replace = 1;
414       len = calc_subnet_opt(&opt, source, cacheable);
415     }
416   else if (option_bool(OPT_STRIP_ECS))
417     replace = 2;
418   else
419     return plen;
420
421   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
422 }
423
424 int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
425 {
426   /* Section 9.2, Check that subnet option in reply matches. */
427   
428   int len, calc_len;
429   struct subnet_opt opt;
430   unsigned char *p;
431   int code, i, rdlen;
432   
433   calc_len = calc_subnet_opt(&opt, peer, NULL);
434    
435   if (!(p = skip_name(pseudoheader, header, plen, 10)))
436     return 1;
437   
438   p += 8; /* skip UDP length and RCODE */
439   
440   GETSHORT(rdlen, p);
441   if (!CHECK_LEN(header, p, plen, rdlen))
442     return 1; /* bad packet */
443   
444   /* check if option there */
445    for (i = 0; i + 4 < rdlen; i += len + 4)
446      {
447        GETSHORT(code, p);
448        GETSHORT(len, p);
449        if (code == EDNS0_OPTION_CLIENT_SUBNET)
450          {
451            /* make sure this doesn't mismatch. */
452            opt.scope_netmask = p[3];
453            if (len != calc_len || memcmp(p, &opt, len) != 0)
454              return 0;
455          }
456        p += len;
457      }
458    
459    return 1;
460 }
461
462 /* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
463  * detailed information on packet formating.
464  */
465 #define UMBRELLA_VERSION    1
466 #define UMBRELLA_TYPESZ     2
467
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)
476
477 struct umbrella_opt {
478   u8 magic[4];
479   u8 version;
480   u8 flags;
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.
485    */
486   u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
487 };
488
489 static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
490 {
491   *cacheable = 0;
492
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;
497
498   if (daemon->umbrella_org)
499     {
500       PUTSHORT(UMBRELLA_ORG, u);
501       PUTLONG(daemon->umbrella_org, u);
502     }
503   
504   PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
505   memcpy(u, get_addrp(source, family), size);
506   u += size;
507   
508   if (option_bool(OPT_UMBRELLA_DEVID))
509     {
510       PUTSHORT(UMBRELLA_DEVICE, u);
511       memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
512       u += UMBRELLA_DEVICESZ;
513     }
514
515   if (daemon->umbrella_asset)
516     {
517       PUTSHORT(UMBRELLA_ASSET, u);
518       PUTLONG(daemon->umbrella_asset, u);
519     }
520   
521   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
522 }
523
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
526    may depend on. */
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)    
529 {
530   *cacheable = 1;
531   
532   plen  = add_mac(header, plen, limit, source, now, cacheable);
533   plen = add_dns_client(header, plen, limit, source, now, cacheable);
534   
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);
538
539   if (option_bool(OPT_UMBRELLA))
540     plen = add_umbrella_opt(header, plen, limit, source, cacheable);
541   
542   plen = add_source_addr(header, plen, limit, source, cacheable);
543           
544   return plen;
545 }