blob: 1f91ca033cec1a9bd75964d2e4058ec60c71bd23 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* dnsmasq is Copyright (c) 2000-2021 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
21void 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
39ssize_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() */
84int 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->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
112struct 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
132struct 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 */
202int 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. */
229char *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
243void 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
268int 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
298int 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
312static 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
347static 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. */
417struct 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
431void 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
536char *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 return found->name;
570
571 return NULL;
572}
573
574void bindtodevice(char *device, int fd)
575{
576 size_t len = strlen(device)+1;
577 if (len > IFNAMSIZ)
578 len = IFNAMSIZ;
579 /* only allowed by root. */
580 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
581 errno != EPERM)
582 die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
583}
584#endif
585
586static const struct opttab_t {
587 char *name;
588 u16 val, size;
589} opttab[] = {
590 { "netmask", 1, OT_ADDR_LIST },
591 { "time-offset", 2, 4 },
592 { "router", 3, OT_ADDR_LIST },
593 { "dns-server", 6, OT_ADDR_LIST },
594 { "log-server", 7, OT_ADDR_LIST },
595 { "lpr-server", 9, OT_ADDR_LIST },
596 { "hostname", 12, OT_INTERNAL | OT_NAME },
597 { "boot-file-size", 13, 2 | OT_DEC },
598 { "domain-name", 15, OT_NAME },
599 { "swap-server", 16, OT_ADDR_LIST },
600 { "root-path", 17, OT_NAME },
601 { "extension-path", 18, OT_NAME },
602 { "ip-forward-enable", 19, 1 },
603 { "non-local-source-routing", 20, 1 },
604 { "policy-filter", 21, OT_ADDR_LIST },
605 { "max-datagram-reassembly", 22, 2 | OT_DEC },
606 { "default-ttl", 23, 1 | OT_DEC },
607 { "mtu", 26, 2 | OT_DEC },
608 { "all-subnets-local", 27, 1 },
609 { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
610 { "router-discovery", 31, 1 },
611 { "router-solicitation", 32, OT_ADDR_LIST },
612 { "static-route", 33, OT_ADDR_LIST },
613 { "trailer-encapsulation", 34, 1 },
614 { "arp-timeout", 35, 4 | OT_DEC },
615 { "ethernet-encap", 36, 1 },
616 { "tcp-ttl", 37, 1 },
617 { "tcp-keepalive", 38, 4 | OT_DEC },
618 { "nis-domain", 40, OT_NAME },
619 { "nis-server", 41, OT_ADDR_LIST },
620 { "ntp-server", 42, OT_ADDR_LIST },
621 { "vendor-encap", 43, OT_INTERNAL },
622 { "netbios-ns", 44, OT_ADDR_LIST },
623 { "netbios-dd", 45, OT_ADDR_LIST },
624 { "netbios-nodetype", 46, 1 },
625 { "netbios-scope", 47, 0 },
626 { "x-windows-fs", 48, OT_ADDR_LIST },
627 { "x-windows-dm", 49, OT_ADDR_LIST },
628 { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
629 { "lease-time", 51, OT_INTERNAL | OT_TIME },
630 { "option-overload", 52, OT_INTERNAL },
631 { "message-type", 53, OT_INTERNAL | OT_DEC },
632 { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
633 { "parameter-request", 55, OT_INTERNAL },
634 { "message", 56, OT_INTERNAL },
635 { "max-message-size", 57, OT_INTERNAL },
636 { "T1", 58, OT_TIME},
637 { "T2", 59, OT_TIME},
638 { "vendor-class", 60, 0 },
639 { "client-id", 61, OT_INTERNAL },
640 { "nis+-domain", 64, OT_NAME },
641 { "nis+-server", 65, OT_ADDR_LIST },
642 { "tftp-server", 66, OT_NAME },
643 { "bootfile-name", 67, OT_NAME },
644 { "mobile-ip-home", 68, OT_ADDR_LIST },
645 { "smtp-server", 69, OT_ADDR_LIST },
646 { "pop3-server", 70, OT_ADDR_LIST },
647 { "nntp-server", 71, OT_ADDR_LIST },
648 { "irc-server", 74, OT_ADDR_LIST },
649 { "user-class", 77, 0 },
650 { "rapid-commit", 80, 0 },
651 { "FQDN", 81, OT_INTERNAL },
652 { "agent-id", 82, OT_INTERNAL },
653 { "client-arch", 93, 2 | OT_DEC },
654 { "client-interface-id", 94, 0 },
655 { "client-machine-id", 97, 0 },
656 { "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
657 { "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
658 { "subnet-select", 118, OT_INTERNAL },
659 { "domain-search", 119, OT_RFC1035_NAME },
660 { "sip-server", 120, 0 },
661 { "classless-static-route", 121, 0 },
662 { "vendor-id-encap", 125, 0 },
663 { "tftp-server-address", 150, OT_ADDR_LIST },
664 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
665 { NULL, 0, 0 }
666};
667
668#ifdef HAVE_DHCP6
669static const struct opttab_t opttab6[] = {
670 { "client-id", 1, OT_INTERNAL },
671 { "server-id", 2, OT_INTERNAL },
672 { "ia-na", 3, OT_INTERNAL },
673 { "ia-ta", 4, OT_INTERNAL },
674 { "iaaddr", 5, OT_INTERNAL },
675 { "oro", 6, OT_INTERNAL },
676 { "preference", 7, OT_INTERNAL | OT_DEC },
677 { "unicast", 12, OT_INTERNAL },
678 { "status", 13, OT_INTERNAL },
679 { "rapid-commit", 14, OT_INTERNAL },
680 { "user-class", 15, OT_INTERNAL | OT_CSTRING },
681 { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
682 { "vendor-opts", 17, OT_INTERNAL },
683 { "sip-server-domain", 21, OT_RFC1035_NAME },
684 { "sip-server", 22, OT_ADDR_LIST },
685 { "dns-server", 23, OT_ADDR_LIST },
686 { "domain-search", 24, OT_RFC1035_NAME },
687 { "nis-server", 27, OT_ADDR_LIST },
688 { "nis+-server", 28, OT_ADDR_LIST },
689 { "nis-domain", 29, OT_RFC1035_NAME },
690 { "nis+-domain", 30, OT_RFC1035_NAME },
691 { "sntp-server", 31, OT_ADDR_LIST },
692 { "information-refresh-time", 32, OT_TIME },
693 { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
694 { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
695 { "bootfile-url", 59, OT_NAME },
696 { "bootfile-param", 60, OT_CSTRING },
697 { NULL, 0, 0 }
698};
699#endif
700
701
702
703void display_opts(void)
704{
705 int i;
706
707 printf(_("Known DHCP options:\n"));
708
709 for (i = 0; opttab[i].name; i++)
710 if (!(opttab[i].size & OT_INTERNAL))
711 printf("%3d %s\n", opttab[i].val, opttab[i].name);
712}
713
714#ifdef HAVE_DHCP6
715void display_opts6(void)
716{
717 int i;
718 printf(_("Known DHCPv6 options:\n"));
719
720 for (i = 0; opttab6[i].name; i++)
721 if (!(opttab6[i].size & OT_INTERNAL))
722 printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
723}
724#endif
725
726int lookup_dhcp_opt(int prot, char *name)
727{
728 const struct opttab_t *t;
729 int i;
730
731 (void)prot;
732
733#ifdef HAVE_DHCP6
734 if (prot == AF_INET6)
735 t = opttab6;
736 else
737#endif
738 t = opttab;
739
740 for (i = 0; t[i].name; i++)
741 if (strcasecmp(t[i].name, name) == 0)
742 return t[i].val;
743
744 return -1;
745}
746
747int lookup_dhcp_len(int prot, int val)
748{
749 const struct opttab_t *t;
750 int i;
751
752 (void)prot;
753
754#ifdef HAVE_DHCP6
755 if (prot == AF_INET6)
756 t = opttab6;
757 else
758#endif
759 t = opttab;
760
761 for (i = 0; t[i].name; i++)
762 if (val == t[i].val)
763 return t[i].size & ~OT_DEC;
764
765 return 0;
766}
767
768char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
769{
770 int o, i, j, nodecode = 0;
771 const struct opttab_t *ot = opttab;
772
773#ifdef HAVE_DHCP6
774 if (prot == AF_INET6)
775 ot = opttab6;
776#endif
777
778 for (o = 0; ot[o].name; o++)
779 if (ot[o].val == opt)
780 {
781 if (buf)
782 {
783 memset(buf, 0, buf_len);
784
785 if (ot[o].size & OT_ADDR_LIST)
786 {
787 union all_addr addr;
788 int addr_len = INADDRSZ;
789
790#ifdef HAVE_DHCP6
791 if (prot == AF_INET6)
792 addr_len = IN6ADDRSZ;
793#endif
794 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
795 {
796 if (i != 0)
797 strncat(buf, ", ", buf_len - strlen(buf));
798 /* align */
799 memcpy(&addr, &val[i], addr_len);
800 inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
801 strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
802 }
803 }
804 else if (ot[o].size & OT_NAME)
805 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
806 {
807 char c = val[i];
808 if (isprint((int)c))
809 buf[j++] = c;
810 }
811#ifdef HAVE_DHCP6
812 /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
813 else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
814 {
815 i = 0, j = 0;
816 while (i < opt_len && val[i] != 0)
817 {
818 int k, l = i + val[i] + 1;
819 for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
820 {
821 char c = val[k];
822 if (isprint((int)c))
823 buf[j++] = c;
824 }
825 i = l;
826 if (val[i] != 0 && j < buf_len)
827 buf[j++] = '.';
828 }
829 }
830 else if ((ot[o].size & OT_CSTRING))
831 {
832 int k, len;
833 unsigned char *p;
834
835 i = 0, j = 0;
836 while (1)
837 {
838 p = &val[i];
839 GETSHORT(len, p);
840 for (k = 0; k < len && j < buf_len; k++)
841 {
842 char c = *p++;
843 if (isprint((int)c))
844 buf[j++] = c;
845 }
846 i += len +2;
847 if (i >= opt_len)
848 break;
849
850 if (j < buf_len)
851 buf[j++] = ',';
852 }
853 }
854#endif
855 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
856 {
857 unsigned int dec = 0;
858
859 for (i = 0; i < opt_len; i++)
860 dec = (dec << 8) | val[i];
861
862 if (ot[o].size & OT_TIME)
863 prettyprint_time(buf, dec);
864 else
865 sprintf(buf, "%u", dec);
866 }
867 else
868 nodecode = 1;
869 }
870 break;
871 }
872
873 if (opt_len != 0 && buf && (!ot[o].name || nodecode))
874 {
875 int trunc = 0;
876 if (opt_len > 14)
877 {
878 trunc = 1;
879 opt_len = 14;
880 }
881 print_mac(buf, val, opt_len);
882 if (trunc)
883 strncat(buf, "...", buf_len - strlen(buf));
884
885
886 }
887
888 return ot[o].name ? ot[o].name : "";
889
890}
891
892void log_context(int family, struct dhcp_context *context)
893{
894 /* Cannot use dhcp_buff* for RA contexts */
895
896 void *start = &context->start;
897 void *end = &context->end;
898 char *template = "", *p = daemon->namebuff;
899
900 *p = 0;
901
902#ifdef HAVE_DHCP6
903 if (family == AF_INET6)
904 {
905 struct in6_addr subnet = context->start6;
906 if (!(context->flags & CONTEXT_TEMPLATE))
907 setaddr6part(&subnet, 0);
908 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
909 start = &context->start6;
910 end = &context->end6;
911 }
912#endif
913
914 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
915 strcpy(daemon->namebuff, _(", prefix deprecated"));
916 else
917 {
918 p += sprintf(p, _(", lease time "));
919 prettyprint_time(p, context->lease_time);
920 p += strlen(p);
921 }
922
923#ifdef HAVE_DHCP6
924 if (context->flags & CONTEXT_CONSTRUCTED)
925 {
926 char ifrn_name[IFNAMSIZ];
927
928 template = p;
929 p += sprintf(p, ", ");
930
931 if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
932 sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
933 }
934 else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
935 {
936 template = p;
937 p += sprintf(p, ", ");
938
939 sprintf(p, "template for %s", context->template_interface);
940 }
941#endif
942
943 if (!(context->flags & CONTEXT_OLD) &&
944 ((context->flags & CONTEXT_DHCP) || family == AF_INET))
945 {
946#ifdef HAVE_DHCP6
947 if (context->flags & CONTEXT_RA_STATELESS)
948 {
949 if (context->flags & CONTEXT_TEMPLATE)
950 strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
951 else
952 strcpy(daemon->dhcp_buff, daemon->addrbuff);
953 }
954 else
955#endif
956 inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
957 inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
958 my_syslog(MS_DHCP | LOG_INFO,
959 (context->flags & CONTEXT_RA_STATELESS) ?
960 _("%s stateless on %s%.0s%.0s%s") :
961 (context->flags & CONTEXT_STATIC) ?
962 _("%s, static leases only on %.0s%s%s%.0s") :
963 (context->flags & CONTEXT_PROXY) ?
964 _("%s, proxy on subnet %.0s%s%.0s%.0s") :
965 _("%s, IP range %s -- %s%s%.0s"),
966 (family != AF_INET) ? "DHCPv6" : "DHCP",
967 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
968 }
969
970#ifdef HAVE_DHCP6
971 if (context->flags & CONTEXT_TEMPLATE)
972 {
973 strcpy(daemon->addrbuff, context->template_interface);
974 template = "";
975 }
976
977 if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
978 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
979
980 if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
981 my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
982#endif
983
984}
985
986void log_relay(int family, struct dhcp_relay *relay)
987{
988 inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
989 inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
990
991 if (relay->interface)
992 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
993 else
994 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
995}
996
997#endif