dnsmasq: v2.67test16 patch Sept.25th/2013.
[tomato.git] / release / src / router / dnsmasq / src / dhcp-common.c
blob7e99fc91233e7982de6803c79af4a2a753f490f0
1 /* dnsmasq is Copyright (c) 2000-2013 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/>.
17 #include "dnsmasq.h"
19 #ifdef HAVE_DHCP
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(256);
26 daemon->dhcp_buff2 = safe_malloc(256);
27 daemon->dhcp_buff3 = safe_malloc(256);
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
39 ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
41 ssize_t sz;
43 while (1)
45 msg->msg_flags = 0;
46 while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
48 if (sz == -1)
49 return -1;
51 if (!(msg->msg_flags & MSG_TRUNC))
52 break;
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))
59 return -1;
61 else
63 expand_buf(msg->msg_iov, sz);
64 break;
68 while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
70 return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
73 struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
75 struct tag_if *exprs;
76 struct dhcp_netid_list *list;
78 for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
79 if (match_netid(exprs->tag, tags, 1))
80 for (list = exprs->set; list; list = list->next)
82 list->list->next = tags;
83 tags = list->list;
86 return tags;
90 struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
92 struct dhcp_netid *tagif = run_tag_if(tags);
93 struct dhcp_opt *opt;
94 struct dhcp_opt *tmp;
96 /* flag options which are valid with the current tag set (sans context tags) */
97 for (opt = opts; opt; opt = opt->next)
99 opt->flags &= ~DHOPT_TAGOK;
100 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
101 match_netid(opt->netid, tagif, 0))
102 opt->flags |= DHOPT_TAGOK;
105 /* now flag options which are valid, including the context tags,
106 otherwise valid options are inhibited if we found a higher priority one above */
107 if (context_tags)
109 struct dhcp_netid *last_tag;
111 for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
112 last_tag->next = tags;
113 tagif = run_tag_if(context_tags);
115 /* reset stuff with tag:!<tag> which now matches. */
116 for (opt = opts; opt; opt = opt->next)
117 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
118 (opt->flags & DHOPT_TAGOK) &&
119 !match_netid(opt->netid, tagif, 0))
120 opt->flags &= ~DHOPT_TAGOK;
122 for (opt = opts; opt; opt = opt->next)
123 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
124 match_netid(opt->netid, tagif, 0))
126 struct dhcp_opt *tmp;
127 for (tmp = opts; tmp; tmp = tmp->next)
128 if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
129 break;
130 if (!tmp)
131 opt->flags |= DHOPT_TAGOK;
135 /* now flag untagged options which are not overridden by tagged ones */
136 for (opt = opts; opt; opt = opt->next)
137 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
139 for (tmp = opts; tmp; tmp = tmp->next)
140 if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
141 break;
142 if (!tmp)
143 opt->flags |= DHOPT_TAGOK;
144 else if (!tmp->netid)
145 my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
148 /* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
149 for (opt = opts; opt; opt = opt->next)
150 if (opt->flags & DHOPT_TAGOK)
151 for (tmp = opt->next; tmp; tmp = tmp->next)
152 if (tmp->opt == opt->opt)
153 tmp->flags &= ~DHOPT_TAGOK;
155 return tagif;
158 /* Is every member of check matched by a member of pool?
159 If tagnotneeded, untagged is OK */
160 int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
162 struct dhcp_netid *tmp1;
164 if (!check && !tagnotneeded)
165 return 0;
167 for (; check; check = check->next)
169 /* '#' for not is for backwards compat. */
170 if (check->net[0] != '!' && check->net[0] != '#')
172 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
173 if (strcmp(check->net, tmp1->net) == 0)
174 break;
175 if (!tmp1)
176 return 0;
178 else
179 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
180 if (strcmp((check->net)+1, tmp1->net) == 0)
181 return 0;
183 return 1;
186 /* return domain or NULL if none. */
187 char *strip_hostname(char *hostname)
189 char *dot = strchr(hostname, '.');
191 if (!dot)
192 return NULL;
194 *dot = 0; /* truncate */
195 if (strlen(dot+1) != 0)
196 return dot+1;
198 return NULL;
201 void log_tags(struct dhcp_netid *netid, u32 xid)
203 if (netid && option_bool(OPT_LOG_OPTS))
205 char *s = daemon->namebuff;
206 for (*s = 0; netid; netid = netid->next)
208 /* kill dupes. */
209 struct dhcp_netid *n;
211 for (n = netid->next; n; n = n->next)
212 if (strcmp(netid->net, n->net) == 0)
213 break;
215 if (!n)
217 strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
218 if (netid->next)
219 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
222 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
226 int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
228 int i;
230 if (o->len > len)
231 return 0;
233 if (o->len == 0)
234 return 1;
236 if (o->flags & DHOPT_HEX)
238 if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
239 return 1;
241 else
242 for (i = 0; i <= (len - o->len); )
244 if (memcmp(o->val, p + i, o->len) == 0)
245 return 1;
247 if (o->flags & DHOPT_STRING)
248 i++;
249 else
250 i += o->len;
253 return 0;
256 int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
258 struct hwaddr_config *conf_addr;
260 for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
261 if (conf_addr->wildcard_mask == 0 &&
262 conf_addr->hwaddr_len == len &&
263 (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
264 memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
265 return 1;
267 return 0;
270 static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
272 if (!context) /* called via find_config() from lease_update_from_configs() */
273 return 1;
275 if (!(context->flags & CONTEXT_V6))
277 if (!(config->flags & CONFIG_ADDR))
278 return 1;
280 for (; context; context = context->current)
281 if (is_same_net(config->addr, context->start, context->netmask))
282 return 1;
284 #ifdef HAVE_DHCP6
285 else
287 if (!(config->flags & CONFIG_ADDR6) || (config->flags & CONFIG_WILDCARD))
288 return 1;
290 for (; context; context = context->current)
291 if (is_same_net6(&config->addr6, &context->start6, context->prefix))
292 return 1;
294 #endif
296 return 0;
299 struct dhcp_config *find_config(struct dhcp_config *configs,
300 struct dhcp_context *context,
301 unsigned char *clid, int clid_len,
302 unsigned char *hwaddr, int hw_len,
303 int hw_type, char *hostname)
305 int count, new;
306 struct dhcp_config *config, *candidate;
307 struct hwaddr_config *conf_addr;
309 if (clid)
310 for (config = configs; config; config = config->next)
311 if (config->flags & CONFIG_CLID)
313 if (config->clid_len == clid_len &&
314 memcmp(config->clid, clid, clid_len) == 0 &&
315 is_config_in_context(context, config))
316 return config;
318 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
319 cope with that here */
320 if (!(context->flags & CONTEXT_V6) && *clid == 0 && config->clid_len == clid_len-1 &&
321 memcmp(config->clid, clid+1, clid_len-1) == 0 &&
322 is_config_in_context(context, config))
323 return config;
327 if (hwaddr)
328 for (config = configs; config; config = config->next)
329 if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
330 is_config_in_context(context, config))
331 return config;
333 if (hostname && context)
334 for (config = configs; config; config = config->next)
335 if ((config->flags & CONFIG_NAME) &&
336 hostname_isequal(config->hostname, hostname) &&
337 is_config_in_context(context, config))
338 return config;
341 if (!hwaddr)
342 return NULL;
344 /* use match with fewest wildcard octets */
345 for (candidate = NULL, count = 0, config = configs; config; config = config->next)
346 if (is_config_in_context(context, config))
347 for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
348 if (conf_addr->wildcard_mask != 0 &&
349 conf_addr->hwaddr_len == hw_len &&
350 (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
351 (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
353 count = new;
354 candidate = config;
357 return candidate;
360 void dhcp_update_configs(struct dhcp_config *configs)
362 /* Some people like to keep all static IP addresses in /etc/hosts.
363 This goes through /etc/hosts and sets static addresses for any DHCP config
364 records which don't have an address and whose name matches.
365 We take care to maintain the invariant that any IP address can appear
366 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
367 restore the status-quo ante first. */
369 struct dhcp_config *config, *conf_tmp;
370 struct crec *crec;
371 int prot = AF_INET;
373 for (config = configs; config; config = config->next)
374 if (config->flags & CONFIG_ADDR_HOSTS)
375 config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
377 #ifdef HAVE_DHCP6
378 again:
379 #endif
381 if (daemon->port != 0)
382 for (config = configs; config; config = config->next)
384 int conflags = CONFIG_ADDR;
385 int cacheflags = F_IPV4;
387 #ifdef HAVE_DHCP6
388 if (prot == AF_INET6)
390 conflags = CONFIG_ADDR6;
391 cacheflags = F_IPV6;
393 #endif
394 if (!(config->flags & conflags) &&
395 (config->flags & CONFIG_NAME) &&
396 (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
397 (crec->flags & F_HOSTS))
399 if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
401 /* use primary (first) address */
402 while (crec && !(crec->flags & F_REVERSE))
403 crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
404 if (!crec)
405 continue; /* should be never */
406 inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
407 my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
408 config->hostname, daemon->addrbuff);
411 if (prot == AF_INET &&
412 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
414 config->addr = crec->addr.addr.addr.addr4;
415 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
416 continue;
419 #ifdef HAVE_DHCP6
420 if (prot == AF_INET6 &&
421 (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
423 memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
424 config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
425 continue;
427 #endif
429 inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
430 my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
431 daemon->addrbuff, config->hostname);
437 #ifdef HAVE_DHCP6
438 if (prot == AF_INET)
440 prot = AF_INET6;
441 goto again;
443 #endif
447 #ifdef HAVE_LINUX_NETWORK
448 void bindtodevice(int fd)
450 /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
451 to that device. This is for the use case of (eg) OpenStack, which runs a new
452 dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
453 individual processes don't always see the packets they should.
454 SO_BINDTODEVICE is only available Linux.
456 Note that if wildcards are used in --interface, or a configured interface doesn't
457 yet exist, then more interfaces may arrive later, so we can't safely assert there
458 is only one interface and proceed.
461 struct irec *iface, *found;
462 struct iname *if_tmp;
464 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
465 if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
466 return;
468 for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
469 if (iface->dhcp_ok)
471 if (!found)
472 found = iface;
473 else if (strcmp(found->name, iface->name) != 0)
474 return; /* more than one. */
477 if (found)
479 struct ifreq ifr;
480 strcpy(ifr.ifr_name, found->name);
481 /* only allowed by root. */
482 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
483 errno != EPERM)
484 die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
487 #endif
489 static const struct opttab_t {
490 char *name;
491 u16 val, size;
492 } opttab[] = {
493 { "netmask", 1, OT_ADDR_LIST },
494 { "time-offset", 2, 4 },
495 { "router", 3, OT_ADDR_LIST },
496 { "dns-server", 6, OT_ADDR_LIST },
497 { "log-server", 7, OT_ADDR_LIST },
498 { "lpr-server", 9, OT_ADDR_LIST },
499 { "hostname", 12, OT_INTERNAL | OT_NAME },
500 { "boot-file-size", 13, 2 | OT_DEC },
501 { "domain-name", 15, OT_NAME },
502 { "swap-server", 16, OT_ADDR_LIST },
503 { "root-path", 17, OT_NAME },
504 { "extension-path", 18, OT_NAME },
505 { "ip-forward-enable", 19, 1 },
506 { "non-local-source-routing", 20, 1 },
507 { "policy-filter", 21, OT_ADDR_LIST },
508 { "max-datagram-reassembly", 22, 2 | OT_DEC },
509 { "default-ttl", 23, 1 | OT_DEC },
510 { "mtu", 26, 2 | OT_DEC },
511 { "all-subnets-local", 27, 1 },
512 { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
513 { "router-discovery", 31, 1 },
514 { "router-solicitation", 32, OT_ADDR_LIST },
515 { "static-route", 33, OT_ADDR_LIST },
516 { "trailer-encapsulation", 34, 1 },
517 { "arp-timeout", 35, 4 | OT_DEC },
518 { "ethernet-encap", 36, 1 },
519 { "tcp-ttl", 37, 1 },
520 { "tcp-keepalive", 38, 4 | OT_DEC },
521 { "nis-domain", 40, OT_NAME },
522 { "nis-server", 41, OT_ADDR_LIST },
523 { "ntp-server", 42, OT_ADDR_LIST },
524 { "vendor-encap", 43, OT_INTERNAL },
525 { "netbios-ns", 44, OT_ADDR_LIST },
526 { "netbios-dd", 45, OT_ADDR_LIST },
527 { "netbios-nodetype", 46, 1 },
528 { "netbios-scope", 47, 0 },
529 { "x-windows-fs", 48, OT_ADDR_LIST },
530 { "x-windows-dm", 49, OT_ADDR_LIST },
531 { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
532 { "lease-time", 51, OT_INTERNAL | OT_TIME },
533 { "option-overload", 52, OT_INTERNAL },
534 { "message-type", 53, OT_INTERNAL | OT_DEC },
535 { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
536 { "parameter-request", 55, OT_INTERNAL },
537 { "message", 56, OT_INTERNAL },
538 { "max-message-size", 57, OT_INTERNAL },
539 { "T1", 58, OT_INTERNAL | OT_TIME},
540 { "T2", 59, OT_INTERNAL | OT_TIME},
541 { "vendor-class", 60, 0 },
542 { "client-id", 61, OT_INTERNAL },
543 { "nis+-domain", 64, OT_NAME },
544 { "nis+-server", 65, OT_ADDR_LIST },
545 { "tftp-server", 66, OT_NAME },
546 { "bootfile-name", 67, OT_NAME },
547 { "mobile-ip-home", 68, OT_ADDR_LIST },
548 { "smtp-server", 69, OT_ADDR_LIST },
549 { "pop3-server", 70, OT_ADDR_LIST },
550 { "nntp-server", 71, OT_ADDR_LIST },
551 { "irc-server", 74, OT_ADDR_LIST },
552 { "user-class", 77, 0 },
553 { "FQDN", 81, OT_INTERNAL },
554 { "agent-id", 82, OT_INTERNAL },
555 { "client-arch", 93, 2 | OT_DEC },
556 { "client-interface-id", 94, 0 },
557 { "client-machine-id", 97, 0 },
558 { "subnet-select", 118, OT_INTERNAL },
559 { "domain-search", 119, OT_RFC1035_NAME },
560 { "sip-server", 120, 0 },
561 { "classless-static-route", 121, 0 },
562 { "vendor-id-encap", 125, 0 },
563 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
564 { NULL, 0, 0 }
567 #ifdef HAVE_DHCP6
568 static const struct opttab_t opttab6[] = {
569 { "client-id", 1, OT_INTERNAL },
570 { "server-id", 2, OT_INTERNAL },
571 { "ia-na", 3, OT_INTERNAL },
572 { "ia-ta", 4, OT_INTERNAL },
573 { "iaaddr", 5, OT_INTERNAL },
574 { "oro", 6, OT_INTERNAL },
575 { "preference", 7, OT_INTERNAL | OT_DEC },
576 { "unicast", 12, OT_INTERNAL },
577 { "status", 13, OT_INTERNAL },
578 { "rapid-commit", 14, OT_INTERNAL },
579 { "user-class", 15, OT_INTERNAL | OT_CSTRING },
580 { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
581 { "vendor-opts", 17, OT_INTERNAL },
582 { "sip-server-domain", 21, OT_RFC1035_NAME },
583 { "sip-server", 22, OT_ADDR_LIST },
584 { "dns-server", 23, OT_ADDR_LIST },
585 { "domain-search", 24, OT_RFC1035_NAME },
586 { "nis-server", 27, OT_ADDR_LIST },
587 { "nis+-server", 28, OT_ADDR_LIST },
588 { "nis-domain", 29, OT_RFC1035_NAME },
589 { "nis+-domain", 30, OT_RFC1035_NAME },
590 { "sntp-server", 31, OT_ADDR_LIST },
591 { "information-refresh-time", 32, OT_TIME },
592 { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
593 { "ntp-server", 56, OT_ADDR_LIST },
594 { "bootfile-url", 59, OT_NAME },
595 { "bootfile-param", 60, OT_CSTRING },
596 { NULL, 0, 0 }
598 #endif
602 void display_opts(void)
604 int i;
606 printf(_("Known DHCP options:\n"));
608 for (i = 0; opttab[i].name; i++)
609 if (!(opttab[i].size & OT_INTERNAL))
610 printf("%3d %s\n", opttab[i].val, opttab[i].name);
613 #ifdef HAVE_DHCP6
614 void display_opts6(void)
616 int i;
617 printf(_("Known DHCPv6 options:\n"));
619 for (i = 0; opttab6[i].name; i++)
620 if (!(opttab6[i].size & OT_INTERNAL))
621 printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
623 #endif
625 int lookup_dhcp_opt(int prot, char *name)
627 const struct opttab_t *t;
628 int i;
630 (void)prot;
632 #ifdef HAVE_DHCP6
633 if (prot == AF_INET6)
634 t = opttab6;
635 else
636 #endif
637 t = opttab;
639 for (i = 0; t[i].name; i++)
640 if (strcasecmp(t[i].name, name) == 0)
641 return t[i].val;
643 return -1;
646 int lookup_dhcp_len(int prot, int val)
648 const struct opttab_t *t;
649 int i;
651 (void)prot;
653 #ifdef HAVE_DHCP6
654 if (prot == AF_INET6)
655 t = opttab6;
656 else
657 #endif
658 t = opttab;
660 for (i = 0; t[i].name; i++)
661 if (val == t[i].val)
662 return t[i].size & ~OT_DEC;
664 return 0;
667 char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
669 int o, i, j, nodecode = 0;
670 const struct opttab_t *ot = opttab;
672 #ifdef HAVE_DHCP6
673 if (prot == AF_INET6)
674 ot = opttab6;
675 #endif
677 for (o = 0; ot[o].name; o++)
678 if (ot[o].val == opt)
680 if (buf)
682 memset(buf, 0, buf_len);
684 if (ot[o].size & OT_ADDR_LIST)
686 struct all_addr addr;
687 int addr_len = INADDRSZ;
689 #ifdef HAVE_DHCP6
690 if (prot == AF_INET6)
691 addr_len = IN6ADDRSZ;
692 #endif
693 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
695 if (i != 0)
696 strncat(buf, ", ", buf_len - strlen(buf));
697 /* align */
698 memcpy(&addr, &val[i], addr_len);
699 inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
700 strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
703 else if (ot[o].size & OT_NAME)
704 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
706 char c = val[i];
707 if (isprint((int)c))
708 buf[j++] = c;
710 #ifdef HAVE_DHCP6
711 /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
712 else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
714 i = 0, j = 0;
715 while (i < opt_len && val[i] != 0)
717 int k, l = i + val[i] + 1;
718 for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
720 char c = val[k];
721 if (isprint((int)c))
722 buf[j++] = c;
724 i = l;
725 if (val[i] != 0 && j < buf_len)
726 buf[j++] = '.';
729 else if ((ot[o].size & OT_CSTRING))
731 int k, len;
732 unsigned char *p;
734 i = 0, j = 0;
735 while (1)
737 p = &val[i];
738 GETSHORT(len, p);
739 for (k = 0; k < len && j < buf_len; k++)
741 char c = *p++;
742 if (isprint((int)c))
743 buf[j++] = c;
745 i += len +2;
746 if (i >= opt_len)
747 break;
749 if (j < buf_len)
750 buf[j++] = ',';
753 #endif
754 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
756 unsigned int dec = 0;
758 for (i = 0; i < opt_len; i++)
759 dec = (dec << 8) | val[i];
761 if (ot[o].size & OT_TIME)
762 prettyprint_time(buf, dec);
763 else
764 sprintf(buf, "%u", dec);
766 else
767 nodecode = 1;
769 break;
772 if (opt_len != 0 && buf && (!ot[o].name || nodecode))
774 int trunc = 0;
775 if (opt_len > 14)
777 trunc = 1;
778 opt_len = 14;
780 print_mac(buf, val, opt_len);
781 if (trunc)
782 strncat(buf, "...", buf_len - strlen(buf));
787 return ot[o].name ? ot[o].name : "";
791 void log_context(int family, struct dhcp_context *context)
793 /* Cannot use dhcp_buff* for RA contexts */
795 void *start = &context->start;
796 void *end = &context->end;
797 char *template = "", *p = daemon->namebuff;
799 *p = 0;
801 #ifdef HAVE_DHCP6
802 if (family == AF_INET6)
804 struct in6_addr subnet = context->start6;
805 if (!(context->flags & CONTEXT_TEMPLATE))
806 setaddr6part(&subnet, 0);
807 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
808 start = &context->start6;
809 end = &context->end6;
811 #endif
813 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
814 strcpy(daemon->namebuff, _(", prefix deprecated"));
815 else
817 p += sprintf(p, _(", lease time "));
818 prettyprint_time(p, context->lease_time);
819 p += strlen(p);
822 #ifdef HAVE_DHCP6
823 if (context->flags & CONTEXT_CONSTRUCTED)
825 char ifrn_name[IFNAMSIZ];
827 template = p;
828 p += sprintf(p, ", ");
830 if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
831 sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
833 else if (context->flags & CONTEXT_TEMPLATE)
835 template = p;
836 p += sprintf(p, ", ");
838 sprintf(p, "template for %s", context->template_interface);
840 #endif
842 if (!(context->flags & CONTEXT_OLD) &&
843 ((context->flags & CONTEXT_DHCP) || family == AF_INET))
845 inet_ntop(family, start, daemon->dhcp_buff, 256);
846 inet_ntop(family, end, daemon->dhcp_buff3, 256);
847 my_syslog(MS_DHCP | LOG_INFO,
848 (context->flags & CONTEXT_RA_STATELESS) ?
849 _("%s stateless on %s%.0s%.0s%s") :
850 (context->flags & CONTEXT_STATIC) ?
851 _("%s, static leases only on %.0s%s%s%.0s") :
852 (context->flags & CONTEXT_PROXY) ?
853 _("%s, proxy on subnet %.0s%s%.0s%.0s") :
854 _("%s, IP range %s -- %s%s%.0s"),
855 (family != AF_INET) ? "DHCPv6" : "DHCP",
856 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
859 #ifdef HAVE_DHCP6
860 if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
861 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
863 if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
864 my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
865 #endif
869 void log_relay(int family, struct dhcp_relay *relay)
871 inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
872 inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
874 if (relay->interface)
875 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
876 else
877 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
880 #endif