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/>.
21 void dhcp_common_init(void)
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);
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,
32 expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
35 expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
39 ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
46 while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
51 if (!(msg->msg_flags & MSG_TRUNC))
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)
58 if (!expand_buf(msg->msg_iov, sz + 100))
63 expand_buf(msg->msg_iov, sz);
68 while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
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. */
76 if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
79 return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
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)
86 struct dhcp_netid *tmp1;
88 for (; check; check = check->next)
90 const int check_len = strlen(check->net);
91 const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
93 /* '#' for not is for backwards compat. */
94 if (check->net[0] != '!' && check->net[0] != '#')
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))
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))
112 struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
114 struct tag_if *exprs;
115 struct dhcp_netid_list *list;
117 /* this now uses match_netid_wild() above so that tag_if can
118 * be used to set a 'group of interfaces' tag.
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)
124 list->list->next = tags;
132 struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
134 struct dhcp_netid *tagif = run_tag_if(tags);
135 struct dhcp_opt *opt;
136 struct dhcp_opt *tmp;
138 /* flag options which are valid with the current tag set (sans context tags) */
139 for (opt = opts; opt; opt = opt->next)
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;
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 */
151 struct dhcp_netid *last_tag;
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);
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;
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))
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))
173 opt->flags |= DHOPT_TAGOK;
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)
181 for (tmp = opts; tmp; tmp = tmp->next)
182 if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
185 opt->flags |= DHOPT_TAGOK;
186 else if (!tmp->netid)
187 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
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;
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)
204 struct dhcp_netid *tmp1;
206 if (!check && !tagnotneeded)
209 for (; check; check = check->next)
211 /* '#' for not is for backwards compat. */
212 if (check->net[0] != '!' && check->net[0] != '#')
214 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
215 if (strcmp(check->net, tmp1->net) == 0)
221 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
222 if (strcmp((check->net)+1, tmp1->net) == 0)
228 /* return domain or NULL if none. */
229 char *strip_hostname(char *hostname)
231 char *dot = strchr(hostname, '.');
236 *dot = 0; /* truncate */
237 if (strlen(dot+1) != 0)
243 void log_tags(struct dhcp_netid *netid, u32 xid)
245 if (netid && option_bool(OPT_LOG_OPTS))
247 char *s = daemon->namebuff;
248 for (*s = 0; netid; netid = netid->next)
251 struct dhcp_netid *n;
253 for (n = netid->next; n; n = n->next)
254 if (strcmp(netid->net, n->net) == 0)
259 strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
261 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
264 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
268 int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
278 if (o->flags & DHOPT_HEX)
280 if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
284 for (i = 0; i <= (len - o->len); )
286 if (memcmp(o->val, p + i, o->len) == 0)
289 if (o->flags & DHOPT_STRING)
298 int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
300 struct hwaddr_config *conf_addr;
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)
312 static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
314 if (!context) /* called via find_config() from lease_update_from_configs() */
317 if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
321 if (context->flags & CONTEXT_V6)
323 struct addrlist *addr_list;
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)
329 if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
332 if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
339 for (; context; context = context->current)
340 if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
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)
355 struct dhcp_config *config, *candidate;
356 struct hwaddr_config *conf_addr;
359 for (config = configs; config; config = config->next)
360 if (config->flags & CONFIG_CLID)
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))
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))
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))
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))
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)
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)
423 struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
426 ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
431 void dhcp_update_configs(struct dhcp_config *configs)
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. */
440 struct dhcp_config *config, *conf_tmp;
444 for (config = configs; config; config = config->next)
446 if (config->flags & CONFIG_ADDR_HOSTS)
447 config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
449 if (config->flags & CONFIG_ADDR6_HOSTS)
450 config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
458 if (daemon->port != 0)
459 for (config = configs; config; config = config->next)
461 int conflags = CONFIG_ADDR;
462 int cacheflags = F_IPV4;
465 if (prot == AF_INET6)
467 conflags = CONFIG_ADDR6;
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))
476 if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
478 /* use primary (first) address */
479 while (crec && !(crec->flags & F_REVERSE))
480 crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
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);
488 if (prot == AF_INET &&
489 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config))
491 config->addr = crec->addr.addr4;
492 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
497 if (prot == AF_INET6 &&
498 (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config))
500 /* host must have exactly one address if comming from /etc/hosts. */
501 if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
503 config->addr6->next = NULL;
504 config->addr6->flags = 0;
507 if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
509 memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ);
510 config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
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);
535 #ifdef HAVE_LINUX_NETWORK
536 char *whichdevice(void)
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.
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.
549 struct irec *iface, *found;
550 struct iname *if_tmp;
552 if (!daemon->if_names)
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, '*')))
559 for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
564 else if (strcmp(found->name, iface->name) != 0)
565 return NULL; /* more than one. */
570 char *ret = safe_malloc(strlen(found->name)+1);
571 strcpy(ret, found->name);
578 static int bindtodevice(char *device, int fd)
580 size_t len = strlen(device)+1;
583 /* only allowed by root. */
584 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
591 int bind_dhcp_devices(char *bound_device)
600 ret |= bindtodevice(bound_device, daemon->dhcpfd);
602 if (daemon->enable_pxe && daemon->pxefd != -1)
603 ret |= bindtodevice(bound_device, daemon->pxefd);
606 #if defined(HAVE_DHCP6)
607 if (daemon->doing_dhcp6 && !daemon->relay6)
608 ret |= bindtodevice(bound_device, daemon->dhcp6fd);
616 static const struct opttab_t {
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 */
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 },
736 void display_opts(void)
740 printf(_("Known DHCP options:\n"));
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);
748 void display_opts6(void)
751 printf(_("Known DHCPv6 options:\n"));
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);
759 int lookup_dhcp_opt(int prot, char *name)
761 const struct opttab_t *t;
767 if (prot == AF_INET6)
773 for (i = 0; t[i].name; i++)
774 if (strcasecmp(t[i].name, name) == 0)
780 int lookup_dhcp_len(int prot, int val)
782 const struct opttab_t *t;
788 if (prot == AF_INET6)
794 for (i = 0; t[i].name; i++)
796 return t[i].size & ~OT_DEC;
801 char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
803 int o, i, j, nodecode = 0;
804 const struct opttab_t *ot = opttab;
807 if (prot == AF_INET6)
811 for (o = 0; ot[o].name; o++)
812 if (ot[o].val == opt)
816 memset(buf, 0, buf_len);
818 if (ot[o].size & OT_ADDR_LIST)
821 int addr_len = INADDRSZ;
824 if (prot == AF_INET6)
825 addr_len = IN6ADDRSZ;
827 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
830 strncat(buf, ", ", buf_len - strlen(buf));
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));
837 else if (ot[o].size & OT_NAME)
838 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
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)
849 while (i < opt_len && val[i] != 0)
851 int k, l = i + val[i] + 1;
852 for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
859 if (val[i] != 0 && j < buf_len)
863 else if ((ot[o].size & OT_CSTRING))
873 for (k = 0; k < len && j < buf_len; k++)
888 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
890 unsigned int dec = 0;
892 for (i = 0; i < opt_len; i++)
893 dec = (dec << 8) | val[i];
895 if (ot[o].size & OT_TIME)
896 prettyprint_time(buf, dec);
898 sprintf(buf, "%u", dec);
906 if (opt_len != 0 && buf && (!ot[o].name || nodecode))
914 print_mac(buf, val, opt_len);
916 strncat(buf, "...", buf_len - strlen(buf));
921 return ot[o].name ? ot[o].name : "";
925 void log_context(int family, struct dhcp_context *context)
927 /* Cannot use dhcp_buff* for RA contexts */
929 void *start = &context->start;
930 void *end = &context->end;
931 char *template = "", *p = daemon->namebuff;
936 if (family == AF_INET6)
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;
947 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
948 strcpy(daemon->namebuff, _(", prefix deprecated"));
951 p += sprintf(p, _(", lease time "));
952 prettyprint_time(p, context->lease_time);
957 if (context->flags & CONTEXT_CONSTRUCTED)
959 char ifrn_name[IFNAMSIZ];
962 p += sprintf(p, ", ");
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);
967 else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
970 p += sprintf(p, ", ");
972 sprintf(p, "template for %s", context->template_interface);
976 if (!(context->flags & CONTEXT_OLD) &&
977 ((context->flags & CONTEXT_DHCP) || family == AF_INET))
980 if (context->flags & CONTEXT_RA_STATELESS)
982 if (context->flags & CONTEXT_TEMPLATE)
983 strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
985 strcpy(daemon->dhcp_buff, daemon->addrbuff);
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);
1004 if (context->flags & CONTEXT_TEMPLATE)
1006 strcpy(daemon->addrbuff, context->template_interface);
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);
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);
1019 void log_relay(int family, struct dhcp_relay *relay)
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);
1025 if (family == AF_INET && relay->port != DHCP_SERVER_PORT)
1026 sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
1029 struct in6_addr multicast;
1031 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
1033 if (family == AF_INET6)
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);
1042 if (relay->interface)
1045 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
1047 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
1050 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);