Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / dhcp-common.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 #ifdef HAVE_DHCP
20
21 void dhcp_common_init(void)
22 {
23   /* These each hold a DHCP option max size 255
24      and get a terminating zero added */
25   daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
26   daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ); 
27   daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
28   
29   /* dhcp_packet is used by v4 and v6, outpacket only by v6 
30      sizeof(struct dhcp_packet) is as good an initial size as any,
31      even for v6 */
32   expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
33 #ifdef HAVE_DHCP6
34   if (daemon->dhcp6)
35     expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
36 #endif
37 }
38
39 ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
40 {  
41   ssize_t sz, new_sz;
42  
43   while (1)
44     {
45       msg->msg_flags = 0;
46       while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
47       
48       if (sz == -1)
49         return -1;
50       
51       if (!(msg->msg_flags & MSG_TRUNC))
52         break;
53
54       /* Very new Linux kernels return the actual size needed, 
55          older ones always return truncated size */
56       if ((size_t)sz == msg->msg_iov->iov_len)
57         {
58           if (!expand_buf(msg->msg_iov, sz + 100))
59             return -1;
60         }
61       else
62         {
63           expand_buf(msg->msg_iov, sz);
64           break;
65         }
66     }
67   
68   while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
69
70   /* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway. 
71      If that happens we get EAGAIN here because the socket is non-blocking.
72      Use the result of the original testing recvmsg as long as the buffer
73      was big enough. There's a small race here that may lose the odd packet,
74      but it's UDP anyway. */
75   
76   if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
77     new_sz = sz;
78   
79   return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
80 }
81
82 /* like match_netid() except that the check can have a trailing * for wildcard */
83 /* started as a direct copy of match_netid() */
84 int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
85 {
86   struct dhcp_netid *tmp1;
87   
88   for (; check; check = check->next)
89     {
90       const int check_len = strlen(check->net);
91       const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
92       
93       /* '#' for not is for backwards compat. */
94       if (check->net[0] != '!' && check->net[0] != '#')
95         {
96           for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
97             if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
98                 (strcmp(check->net, tmp1->net) == 0))
99               break;
100           if (!tmp1)
101             return 0;
102         }
103       else
104         for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
105           if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
106               (strcmp((check->net)+1, tmp1->net) == 0))
107             return 0;
108     }
109   return 1;
110 }
111
112 struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
113 {
114   struct tag_if *exprs;
115   struct dhcp_netid_list *list;
116
117   /* this now uses match_netid_wild() above so that tag_if can
118    * be used to set a 'group of interfaces' tag.
119    */
120   for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
121     if (match_netid_wild(exprs->tag, tags))
122       for (list = exprs->set; list; list = list->next)
123         {
124           list->list->next = tags;
125           tags = list->list;
126         }
127
128   return tags;
129 }
130
131
132 struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
133 {
134   struct dhcp_netid *tagif = run_tag_if(tags);
135   struct dhcp_opt *opt;
136   struct dhcp_opt *tmp;  
137
138   /* flag options which are valid with the current tag set (sans context tags) */
139   for (opt = opts; opt; opt = opt->next)
140     {
141       opt->flags &= ~DHOPT_TAGOK;
142       if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
143           match_netid(opt->netid, tagif, 0))
144         opt->flags |= DHOPT_TAGOK;
145     }
146
147   /* now flag options which are valid, including the context tags,
148      otherwise valid options are inhibited if we found a higher priority one above */
149   if (context_tags)
150     {
151       struct dhcp_netid *last_tag;
152
153       for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
154       last_tag->next = tags;
155       tagif = run_tag_if(context_tags);
156       
157       /* reset stuff with tag:!<tag> which now matches. */
158       for (opt = opts; opt; opt = opt->next)
159         if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
160             (opt->flags & DHOPT_TAGOK) &&
161             !match_netid(opt->netid, tagif, 0))
162           opt->flags &= ~DHOPT_TAGOK;
163
164       for (opt = opts; opt; opt = opt->next)
165         if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
166             match_netid(opt->netid, tagif, 0))
167           {
168             struct dhcp_opt *tmp;  
169             for (tmp = opts; tmp; tmp = tmp->next) 
170               if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
171                 break;
172             if (!tmp)
173               opt->flags |= DHOPT_TAGOK;
174           }      
175     }
176   
177   /* now flag untagged options which are not overridden by tagged ones */
178   for (opt = opts; opt; opt = opt->next)
179     if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
180       {
181         for (tmp = opts; tmp; tmp = tmp->next) 
182           if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
183             break;
184         if (!tmp)
185           opt->flags |= DHOPT_TAGOK;
186         else if (!tmp->netid)
187           my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt); 
188       }
189
190   /* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
191   for (opt = opts; opt; opt = opt->next)
192     if (opt->flags & DHOPT_TAGOK)
193       for (tmp = opt->next; tmp; tmp = tmp->next) 
194         if (tmp->opt == opt->opt)
195           tmp->flags &= ~DHOPT_TAGOK;
196   
197   return tagif;
198 }
199         
200 /* Is every member of check matched by a member of pool? 
201    If tagnotneeded, untagged is OK */
202 int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
203 {
204   struct dhcp_netid *tmp1;
205   
206   if (!check && !tagnotneeded)
207     return 0;
208
209   for (; check; check = check->next)
210     {
211       /* '#' for not is for backwards compat. */
212       if (check->net[0] != '!' && check->net[0] != '#')
213         {
214           for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
215             if (strcmp(check->net, tmp1->net) == 0)
216               break;
217           if (!tmp1)
218             return 0;
219         }
220       else
221         for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
222           if (strcmp((check->net)+1, tmp1->net) == 0)
223             return 0;
224     }
225   return 1;
226 }
227
228 /* return domain or NULL if none. */
229 char *strip_hostname(char *hostname)
230 {
231   char *dot = strchr(hostname, '.');
232  
233   if (!dot)
234     return NULL;
235   
236   *dot = 0; /* truncate */
237   if (strlen(dot+1) != 0)
238     return dot+1;
239   
240   return NULL;
241 }
242
243 void log_tags(struct dhcp_netid *netid, u32 xid)
244 {
245   if (netid && option_bool(OPT_LOG_OPTS))
246     {
247       char *s = daemon->namebuff;
248       for (*s = 0; netid; netid = netid->next)
249         {
250           /* kill dupes. */
251           struct dhcp_netid *n;
252           
253           for (n = netid->next; n; n = n->next)
254             if (strcmp(netid->net, n->net) == 0)
255               break;
256           
257           if (!n)
258             {
259               strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
260               if (netid->next)
261                 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
262             }
263         }
264       my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
265     } 
266 }   
267   
268 int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
269 {
270   int i;
271   
272   if (o->len > len)
273     return 0;
274   
275   if (o->len == 0)
276     return 1;
277      
278   if (o->flags & DHOPT_HEX)
279     { 
280       if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
281         return 1;
282     }
283   else 
284     for (i = 0; i <= (len - o->len); ) 
285       {
286         if (memcmp(o->val, p + i, o->len) == 0)
287           return 1;
288             
289         if (o->flags & DHOPT_STRING)
290           i++;
291         else
292           i += o->len;
293       }
294   
295   return 0;
296 }
297
298 int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
299 {
300   struct hwaddr_config *conf_addr;
301   
302   for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
303     if (conf_addr->wildcard_mask == 0 &&
304         conf_addr->hwaddr_len == len &&
305         (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
306         memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
307       return 1;
308   
309   return 0;
310 }
311
312 static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
313 {
314   if (!context) /* called via find_config() from lease_update_from_configs() */
315     return 1; 
316
317   if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
318     return 1;
319   
320 #ifdef HAVE_DHCP6
321   if (context->flags & CONTEXT_V6)
322     {
323        struct addrlist *addr_list;
324
325        if (config->flags & CONFIG_ADDR6)
326          for (; context; context = context->current)
327            for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
328              {
329                if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
330                  return 1;
331                
332                if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
333                  return 1;
334              }
335     }
336   else
337 #endif
338     {
339       for (; context; context = context->current)
340         if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
341           return 1;
342     }
343
344   return 0;
345 }
346
347 static struct dhcp_config *find_config_match(struct dhcp_config *configs,
348                                              struct dhcp_context *context,
349                                              unsigned char *clid, int clid_len,
350                                              unsigned char *hwaddr, int hw_len, 
351                                              int hw_type, char *hostname,
352                                              struct dhcp_netid *tags, int tag_not_needed)
353 {
354   int count, new;
355   struct dhcp_config *config, *candidate; 
356   struct hwaddr_config *conf_addr;
357
358   if (clid)
359     for (config = configs; config; config = config->next)
360       if (config->flags & CONFIG_CLID)
361         {
362           if (config->clid_len == clid_len && 
363               memcmp(config->clid, clid, clid_len) == 0 &&
364               is_config_in_context(context, config) &&
365               match_netid(config->filter, tags, tag_not_needed))
366             
367             return config;
368           
369           /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
370              cope with that here. This is IPv4 only. context==NULL implies IPv4, 
371              see lease_update_from_configs() */
372           if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1  &&
373               memcmp(config->clid, clid+1, clid_len-1) == 0 &&
374               is_config_in_context(context, config) &&
375               match_netid(config->filter, tags, tag_not_needed))
376             return config;
377         }
378   
379
380   if (hwaddr)
381     for (config = configs; config; config = config->next)
382       if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
383           is_config_in_context(context, config) &&
384           match_netid(config->filter, tags, tag_not_needed))
385         return config;
386   
387   if (hostname && context)
388     for (config = configs; config; config = config->next)
389       if ((config->flags & CONFIG_NAME) && 
390           hostname_isequal(config->hostname, hostname) &&
391           is_config_in_context(context, config) &&
392           match_netid(config->filter, tags, tag_not_needed))
393         return config;
394
395   
396   if (!hwaddr)
397     return NULL;
398
399   /* use match with fewest wildcard octets */
400   for (candidate = NULL, count = 0, config = configs; config; config = config->next)
401     if (is_config_in_context(context, config) &&
402         match_netid(config->filter, tags, tag_not_needed))
403       for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
404         if (conf_addr->wildcard_mask != 0 &&
405             conf_addr->hwaddr_len == hw_len &&  
406             (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
407             (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
408           {
409               count = new;
410               candidate = config;
411           }
412   
413   return candidate;
414 }
415
416 /* Find tagged configs first. */
417 struct dhcp_config *find_config(struct dhcp_config *configs,
418                                 struct dhcp_context *context,
419                                 unsigned char *clid, int clid_len,
420                                 unsigned char *hwaddr, int hw_len, 
421                                 int hw_type, char *hostname, struct dhcp_netid *tags)
422 {
423   struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
424
425   if (!ret)
426     ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
427
428   return ret;
429 }
430
431 void dhcp_update_configs(struct dhcp_config *configs)
432 {
433   /* Some people like to keep all static IP addresses in /etc/hosts.
434      This goes through /etc/hosts and sets static addresses for any DHCP config
435      records which don't have an address and whose name matches. 
436      We take care to maintain the invariant that any IP address can appear
437      in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, 
438      restore the status-quo ante first. */
439   
440   struct dhcp_config *config, *conf_tmp;
441   struct crec *crec;
442   int prot = AF_INET;
443
444   for (config = configs; config; config = config->next)
445   {
446     if (config->flags & CONFIG_ADDR_HOSTS)
447       config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
448 #ifdef HAVE_DHCP6
449     if (config->flags & CONFIG_ADDR6_HOSTS)
450       config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
451 #endif
452   }
453
454 #ifdef HAVE_DHCP6 
455  again:  
456 #endif
457
458   if (daemon->port != 0)
459     for (config = configs; config; config = config->next)
460       {
461         int conflags = CONFIG_ADDR;
462         int cacheflags = F_IPV4;
463
464 #ifdef HAVE_DHCP6
465         if (prot == AF_INET6)
466           {
467             conflags = CONFIG_ADDR6;
468             cacheflags = F_IPV6;
469           }
470 #endif
471         if (!(config->flags & conflags) &&
472             (config->flags & CONFIG_NAME) && 
473             (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
474             (crec->flags & F_HOSTS))
475           {
476             if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
477               {
478                 /* use primary (first) address */
479                 while (crec && !(crec->flags & F_REVERSE))
480                   crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
481                 if (!crec)
482                   continue; /* should be never */
483                 inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
484                 my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 
485                           config->hostname, daemon->addrbuff);
486               }
487             
488             if (prot == AF_INET && 
489                 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config))
490               {
491                 config->addr = crec->addr.addr4;
492                 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
493                 continue;
494               }
495
496 #ifdef HAVE_DHCP6
497             if (prot == AF_INET6 && 
498                 (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config))
499               {
500                 /* host must have exactly one address if comming from /etc/hosts. */
501                 if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
502                   {
503                     config->addr6->next = NULL;
504                     config->addr6->flags = 0;
505                   }
506
507                 if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
508                   {
509                     memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ);
510                     config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
511                   }
512             
513                 continue;
514               }
515 #endif
516
517             inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
518             my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 
519                       daemon->addrbuff, config->hostname);
520             
521             
522           }
523       }
524
525 #ifdef HAVE_DHCP6
526   if (prot == AF_INET)
527     {
528       prot = AF_INET6;
529       goto again;
530     }
531 #endif
532
533 }
534
535 #ifdef HAVE_LINUX_NETWORK 
536 char *whichdevice(void)
537 {
538   /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
539      to that device. This is for the use case of  (eg) OpenStack, which runs a new
540      dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE, 
541      individual processes don't always see the packets they should.
542      SO_BINDTODEVICE is only available Linux. 
543
544      Note that if wildcards are used in --interface, or --interface is not used at all,
545      or a configured interface doesn't yet exist, then more interfaces may arrive later, 
546      so we can't safely assert there is only one interface and proceed.
547 */
548   
549   struct irec *iface, *found;
550   struct iname *if_tmp;
551   
552   if (!daemon->if_names)
553     return NULL;
554   
555   for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
556     if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
557       return NULL;
558
559   for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
560     if (iface->dhcp_ok)
561       {
562         if (!found)
563           found = iface;
564         else if (strcmp(found->name, iface->name) != 0) 
565           return NULL; /* more than one. */
566       }
567
568   if (found)
569     {
570       char *ret = safe_malloc(strlen(found->name)+1);
571       strcpy(ret, found->name);
572       return ret;
573     }
574   
575   return NULL;
576 }
577  
578 static int bindtodevice(char *device, int fd)
579 {
580   size_t len = strlen(device)+1;
581   if (len > IFNAMSIZ)
582     len = IFNAMSIZ;
583   /* only allowed by root. */
584   if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
585       errno != EPERM)
586     return 2;
587   
588   return 1;
589 }
590
591 int bind_dhcp_devices(char *bound_device)
592 {
593   int ret = 0;
594
595   if (bound_device)
596     {
597       if (daemon->dhcp)
598         {
599           if (!daemon->relay4)
600             ret |= bindtodevice(bound_device, daemon->dhcpfd);
601           
602           if (daemon->enable_pxe && daemon->pxefd != -1)
603             ret |= bindtodevice(bound_device, daemon->pxefd);
604         }
605       
606 #if defined(HAVE_DHCP6)
607       if (daemon->doing_dhcp6 && !daemon->relay6)
608         ret |= bindtodevice(bound_device, daemon->dhcp6fd);
609 #endif
610     }
611   
612   return ret;
613 }
614 #endif
615
616 static const struct opttab_t {
617   char *name;
618   u16 val, size;
619 } opttab[] = {
620   { "netmask", 1, OT_ADDR_LIST },
621   { "time-offset", 2, 4 },
622   { "router", 3, OT_ADDR_LIST  },
623   { "dns-server", 6, OT_ADDR_LIST },
624   { "log-server", 7, OT_ADDR_LIST },
625   { "lpr-server", 9, OT_ADDR_LIST },
626   { "hostname", 12, OT_INTERNAL | OT_NAME },
627   { "boot-file-size", 13, 2 | OT_DEC },
628   { "domain-name", 15, OT_NAME },
629   { "swap-server", 16, OT_ADDR_LIST },
630   { "root-path", 17, OT_NAME },
631   { "extension-path", 18, OT_NAME },
632   { "ip-forward-enable", 19, 1 },
633   { "non-local-source-routing", 20, 1 },
634   { "policy-filter", 21, OT_ADDR_LIST },
635   { "max-datagram-reassembly", 22, 2 | OT_DEC },
636   { "default-ttl", 23, 1 | OT_DEC },
637   { "mtu", 26, 2 | OT_DEC },
638   { "all-subnets-local", 27, 1 },
639   { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
640   { "router-discovery", 31, 1 },
641   { "router-solicitation", 32, OT_ADDR_LIST },
642   { "static-route", 33, OT_ADDR_LIST },
643   { "trailer-encapsulation", 34, 1 },
644   { "arp-timeout", 35, 4 | OT_DEC },
645   { "ethernet-encap", 36, 1 },
646   { "tcp-ttl", 37, 1 },
647   { "tcp-keepalive", 38, 4 | OT_DEC },
648   { "nis-domain", 40, OT_NAME },
649   { "nis-server", 41, OT_ADDR_LIST },
650   { "ntp-server", 42, OT_ADDR_LIST },
651   { "vendor-encap", 43, OT_INTERNAL },
652   { "netbios-ns", 44, OT_ADDR_LIST },
653   { "netbios-dd", 45, OT_ADDR_LIST },
654   { "netbios-nodetype", 46, 1 },
655   { "netbios-scope", 47, 0 },
656   { "x-windows-fs", 48, OT_ADDR_LIST },
657   { "x-windows-dm", 49, OT_ADDR_LIST },
658   { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
659   { "lease-time", 51, OT_INTERNAL | OT_TIME },
660   { "option-overload", 52, OT_INTERNAL },
661   { "message-type", 53, OT_INTERNAL | OT_DEC },
662   { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
663   { "parameter-request", 55, OT_INTERNAL },
664   { "message", 56, OT_INTERNAL },
665   { "max-message-size", 57, OT_INTERNAL },
666   { "T1", 58, OT_TIME},
667   { "T2", 59, OT_TIME},
668   { "vendor-class", 60, 0 },
669   { "client-id", 61, OT_INTERNAL },
670   { "nis+-domain", 64, OT_NAME },
671   { "nis+-server", 65, OT_ADDR_LIST },
672   { "tftp-server", 66, OT_NAME },
673   { "bootfile-name", 67, OT_NAME },
674   { "mobile-ip-home", 68, OT_ADDR_LIST }, 
675   { "smtp-server", 69, OT_ADDR_LIST }, 
676   { "pop3-server", 70, OT_ADDR_LIST }, 
677   { "nntp-server", 71, OT_ADDR_LIST }, 
678   { "irc-server", 74, OT_ADDR_LIST }, 
679   { "user-class", 77, 0 },
680   { "rapid-commit", 80, 0 },
681   { "FQDN", 81, OT_INTERNAL },
682   { "agent-id", 82, OT_INTERNAL },
683   { "client-arch", 93, 2 | OT_DEC },
684   { "client-interface-id", 94, 0 },
685   { "client-machine-id", 97, 0 },
686   { "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
687   { "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
688   { "ipv6-only", 108, 4 | OT_DEC },  /* RFC 8925 */ 
689   { "subnet-select", 118, OT_INTERNAL },
690   { "domain-search", 119, OT_RFC1035_NAME },
691   { "sip-server", 120, 0 },
692   { "classless-static-route", 121, 0 },
693   { "vendor-id-encap", 125, 0 },
694   { "tftp-server-address", 150, OT_ADDR_LIST },
695   { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
696   { NULL, 0, 0 }
697 };
698
699 #ifdef HAVE_DHCP6
700 static const struct opttab_t opttab6[] = {
701   { "client-id", 1, OT_INTERNAL },
702   { "server-id", 2, OT_INTERNAL },
703   { "ia-na", 3, OT_INTERNAL },
704   { "ia-ta", 4, OT_INTERNAL },
705   { "iaaddr", 5, OT_INTERNAL },
706   { "oro", 6, OT_INTERNAL },
707   { "preference", 7, OT_INTERNAL | OT_DEC },
708   { "unicast", 12, OT_INTERNAL },
709   { "status", 13, OT_INTERNAL },
710   { "rapid-commit", 14, OT_INTERNAL },
711   { "user-class", 15, OT_INTERNAL | OT_CSTRING },
712   { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
713   { "vendor-opts", 17, OT_INTERNAL },
714   { "sip-server-domain", 21,  OT_RFC1035_NAME },
715   { "sip-server", 22, OT_ADDR_LIST },
716   { "dns-server", 23, OT_ADDR_LIST },
717   { "domain-search", 24, OT_RFC1035_NAME },
718   { "nis-server", 27, OT_ADDR_LIST },
719   { "nis+-server", 28, OT_ADDR_LIST },
720   { "nis-domain", 29,  OT_RFC1035_NAME },
721   { "nis+-domain", 30, OT_RFC1035_NAME },
722   { "sntp-server", 31,  OT_ADDR_LIST },
723   { "information-refresh-time", 32, OT_TIME },
724   { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
725   { "posix-timezone", 41, OT_NAME }, /* RFC 4833, Sec. 3 */
726   { "tzdb-timezone", 42, OT_NAME }, /* RFC 4833, Sec. 3 */
727   { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
728   { "bootfile-url", 59, OT_NAME },
729   { "bootfile-param", 60, OT_CSTRING },
730   { NULL, 0, 0 }
731 };
732 #endif
733
734
735
736 void display_opts(void)
737 {
738   int i;
739   
740   printf(_("Known DHCP options:\n"));
741   
742   for (i = 0; opttab[i].name; i++)
743     if (!(opttab[i].size & OT_INTERNAL))
744       printf("%3d %s\n", opttab[i].val, opttab[i].name);
745 }
746
747 #ifdef HAVE_DHCP6
748 void display_opts6(void)
749 {
750   int i;
751   printf(_("Known DHCPv6 options:\n"));
752   
753   for (i = 0; opttab6[i].name; i++)
754     if (!(opttab6[i].size & OT_INTERNAL))
755       printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
756 }
757 #endif
758
759 int lookup_dhcp_opt(int prot, char *name)
760 {
761   const struct opttab_t *t;
762   int i;
763
764   (void)prot;
765
766 #ifdef HAVE_DHCP6
767   if (prot == AF_INET6)
768     t = opttab6;
769   else
770 #endif
771     t = opttab;
772
773   for (i = 0; t[i].name; i++)
774     if (strcasecmp(t[i].name, name) == 0)
775       return t[i].val;
776   
777   return -1;
778 }
779
780 int lookup_dhcp_len(int prot, int val)
781 {
782   const struct opttab_t *t;
783   int i;
784
785   (void)prot;
786
787 #ifdef HAVE_DHCP6
788   if (prot == AF_INET6)
789     t = opttab6;
790   else
791 #endif
792     t = opttab;
793
794   for (i = 0; t[i].name; i++)
795     if (val == t[i].val)
796       return t[i].size & ~OT_DEC;
797
798    return 0;
799 }
800
801 char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
802 {
803   int o, i, j, nodecode = 0;
804   const struct opttab_t *ot = opttab;
805
806 #ifdef HAVE_DHCP6
807   if (prot == AF_INET6)
808     ot = opttab6;
809 #endif
810
811   for (o = 0; ot[o].name; o++)
812     if (ot[o].val == opt)
813       {
814         if (buf)
815           {
816             memset(buf, 0, buf_len);
817             
818             if (ot[o].size & OT_ADDR_LIST) 
819               {
820                 union all_addr addr;
821                 int addr_len = INADDRSZ;
822
823 #ifdef HAVE_DHCP6
824                 if (prot == AF_INET6)
825                   addr_len = IN6ADDRSZ;
826 #endif
827                 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len) 
828                   {
829                     if (i != 0)
830                       strncat(buf, ", ", buf_len - strlen(buf));
831                     /* align */
832                     memcpy(&addr, &val[i], addr_len); 
833                     inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
834                     strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
835                   }
836               }
837             else if (ot[o].size & OT_NAME)
838                 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
839                   {
840                     char c = val[i];
841                     if (isprint((int)c))
842                       buf[j++] = c;
843                   }
844 #ifdef HAVE_DHCP6
845             /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
846             else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
847               {
848                 i = 0, j = 0;
849                 while (i < opt_len && val[i] != 0)
850                   {
851                     int k, l = i + val[i] + 1;
852                     for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
853                      {
854                        char c = val[k];
855                        if (isprint((int)c))
856                          buf[j++] = c;
857                      }
858                     i = l;
859                     if (val[i] != 0 && j < buf_len)
860                       buf[j++] = '.';
861                   }
862               }
863             else if ((ot[o].size & OT_CSTRING))
864               {
865                 int k, len;
866                 unsigned char *p;
867
868                 i = 0, j = 0;
869                 while (1)
870                   {
871                     p = &val[i];
872                     GETSHORT(len, p);
873                     for (k = 0; k < len && j < buf_len; k++)
874                       {
875                        char c = *p++;
876                        if (isprint((int)c))
877                          buf[j++] = c;
878                      }
879                     i += len +2;
880                     if (i >= opt_len)
881                       break;
882
883                     if (j < buf_len)
884                       buf[j++] = ',';
885                   }
886               }       
887 #endif
888             else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
889               {
890                 unsigned int dec = 0;
891                 
892                 for (i = 0; i < opt_len; i++)
893                   dec = (dec << 8) | val[i]; 
894
895                 if (ot[o].size & OT_TIME)
896                   prettyprint_time(buf, dec);
897                 else
898                   sprintf(buf, "%u", dec);
899               }
900             else
901               nodecode = 1;
902           }
903         break;
904       }
905
906   if (opt_len != 0 && buf && (!ot[o].name || nodecode))
907     {
908       int trunc  = 0;
909       if (opt_len > 14)
910         {
911           trunc = 1;
912           opt_len = 14;
913         }
914       print_mac(buf, val, opt_len);
915       if (trunc)
916         strncat(buf, "...", buf_len - strlen(buf));
917     
918
919     }
920
921   return ot[o].name ? ot[o].name : "";
922
923 }
924
925 void log_context(int family, struct dhcp_context *context)
926 {
927   /* Cannot use dhcp_buff* for RA contexts */
928
929   void *start = &context->start;
930   void *end = &context->end;
931   char *template = "", *p = daemon->namebuff;
932   
933   *p = 0;
934     
935 #ifdef HAVE_DHCP6
936   if (family == AF_INET6)
937     {
938       struct in6_addr subnet = context->start6;
939       if (!(context->flags & CONTEXT_TEMPLATE))
940         setaddr6part(&subnet, 0);
941       inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN); 
942       start = &context->start6;
943       end = &context->end6;
944     }
945 #endif
946
947   if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
948     strcpy(daemon->namebuff, _(", prefix deprecated"));
949   else
950     {
951       p += sprintf(p, _(", lease time "));
952       prettyprint_time(p, context->lease_time);
953       p += strlen(p);
954     }   
955
956 #ifdef HAVE_DHCP6
957   if (context->flags & CONTEXT_CONSTRUCTED)
958     {
959       char ifrn_name[IFNAMSIZ];
960       
961       template = p;
962       p += sprintf(p, ", ");
963       
964       if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
965         sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
966     }
967   else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
968     {
969       template = p;
970       p += sprintf(p, ", ");
971       
972       sprintf(p, "template for %s", context->template_interface);  
973     }
974 #endif
975      
976   if (!(context->flags & CONTEXT_OLD) &&
977       ((context->flags & CONTEXT_DHCP) || family == AF_INET)) 
978     {
979 #ifdef HAVE_DHCP6
980       if (context->flags & CONTEXT_RA_STATELESS)
981         {
982           if (context->flags & CONTEXT_TEMPLATE)
983             strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
984           else
985             strcpy(daemon->dhcp_buff, daemon->addrbuff);
986         }
987       else 
988 #endif
989         inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
990       inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
991       my_syslog(MS_DHCP | LOG_INFO, 
992                 (context->flags & CONTEXT_RA_STATELESS) ? 
993                 _("%s stateless on %s%.0s%.0s%s") :
994                 (context->flags & CONTEXT_STATIC) ? 
995                 _("%s, static leases only on %.0s%s%s%.0s") :
996                 (context->flags & CONTEXT_PROXY) ?
997                 _("%s, proxy on subnet %.0s%s%.0s%.0s") :
998                 _("%s, IP range %s -- %s%s%.0s"),
999                 (family != AF_INET) ? "DHCPv6" : "DHCP",
1000                 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
1001     }
1002   
1003 #ifdef HAVE_DHCP6
1004   if (context->flags & CONTEXT_TEMPLATE)
1005     {
1006       strcpy(daemon->addrbuff, context->template_interface);
1007       template = "";
1008     }
1009
1010   if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
1011     my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
1012   
1013   if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6)) 
1014     my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
1015 #endif
1016
1017 }
1018
1019 void log_relay(int family, struct dhcp_relay *relay)
1020 {
1021   int broadcast = relay->server.addr4.s_addr == 0;
1022   inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
1023   inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
1024
1025   if (family == AF_INET && relay->port != DHCP_SERVER_PORT)
1026     sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
1027
1028 #ifdef HAVE_DHCP6
1029   struct in6_addr multicast;
1030
1031   inet_pton(AF_INET6, ALL_SERVERS, &multicast);
1032
1033   if (family == AF_INET6)
1034     {
1035       broadcast = IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast);
1036       if (relay->port != DHCPV6_SERVER_PORT)
1037         sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
1038     }
1039 #endif
1040   
1041   
1042   if (relay->interface)
1043     {
1044       if (broadcast)
1045         my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
1046       else
1047         my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
1048     }
1049   else
1050     my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
1051 }
1052    
1053 #endif