]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/dhcp-common.c
Allow trailing '*' wildcard in interface names.
[people/ms/dnsmasq.git] / src / dhcp-common.c
1 /* dnsmasq is Copyright (c) 2000-2013 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(256);
26 daemon->dhcp_buff2 = safe_malloc(256);
27 daemon->dhcp_buff3 = safe_malloc(256);
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;
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 ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
69
70 return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
71 }
72
73 struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
74 {
75 struct tag_if *exprs;
76 struct dhcp_netid_list *list;
77
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)
81 {
82 list->list->next = tags;
83 tags = list->list;
84 }
85
86 return tags;
87 }
88
89
90 struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
91 {
92 struct dhcp_netid *tagif = run_tag_if(tags);
93 struct dhcp_opt *opt;
94
95 /* flag options which are valid with the current tag set (sans context tags) */
96 for (opt = opts; opt; opt = opt->next)
97 {
98 opt->flags &= ~DHOPT_TAGOK;
99 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
100 match_netid(opt->netid, tagif, 0))
101 opt->flags |= DHOPT_TAGOK;
102 }
103
104 /* now flag options which are valid, including the context tags,
105 otherwise valid options are inhibited if we found a higher priority one above */
106 if (context_tags)
107 {
108 struct dhcp_netid *last_tag;
109
110 for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
111 last_tag->next = tags;
112 tagif = run_tag_if(context_tags);
113
114 /* reset stuff with tag:!<tag> which now matches. */
115 for (opt = opts; opt; opt = opt->next)
116 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
117 (opt->flags & DHOPT_TAGOK) &&
118 !match_netid(opt->netid, tagif, 0))
119 opt->flags &= ~DHOPT_TAGOK;
120
121 for (opt = opts; opt; opt = opt->next)
122 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
123 match_netid(opt->netid, tagif, 0))
124 {
125 struct dhcp_opt *tmp;
126 for (tmp = opts; tmp; tmp = tmp->next)
127 if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
128 break;
129 if (!tmp)
130 opt->flags |= DHOPT_TAGOK;
131 }
132 }
133
134 /* now flag untagged options which are not overridden by tagged ones */
135 for (opt = opts; opt; opt = opt->next)
136 if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
137 {
138 struct dhcp_opt *tmp;
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);
146 }
147
148 return tagif;
149 }
150
151 /* Is every member of check matched by a member of pool?
152 If tagnotneeded, untagged is OK */
153 int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
154 {
155 struct dhcp_netid *tmp1;
156
157 if (!check && !tagnotneeded)
158 return 0;
159
160 for (; check; check = check->next)
161 {
162 /* '#' for not is for backwards compat. */
163 if (check->net[0] != '!' && check->net[0] != '#')
164 {
165 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
166 if (strcmp(check->net, tmp1->net) == 0)
167 break;
168 if (!tmp1)
169 return 0;
170 }
171 else
172 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
173 if (strcmp((check->net)+1, tmp1->net) == 0)
174 return 0;
175 }
176 return 1;
177 }
178
179 /* return domain or NULL if none. */
180 char *strip_hostname(char *hostname)
181 {
182 char *dot = strchr(hostname, '.');
183
184 if (!dot)
185 return NULL;
186
187 *dot = 0; /* truncate */
188 if (strlen(dot+1) != 0)
189 return dot+1;
190
191 return NULL;
192 }
193
194 void log_tags(struct dhcp_netid *netid, u32 xid)
195 {
196 if (netid && option_bool(OPT_LOG_OPTS))
197 {
198 char *s = daemon->namebuff;
199 for (*s = 0; netid; netid = netid->next)
200 {
201 /* kill dupes. */
202 struct dhcp_netid *n;
203
204 for (n = netid->next; n; n = n->next)
205 if (strcmp(netid->net, n->net) == 0)
206 break;
207
208 if (!n)
209 {
210 strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
211 if (netid->next)
212 strncat (s, ", ", (MAXDNAME-1) - strlen(s));
213 }
214 }
215 my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
216 }
217 }
218
219 int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
220 {
221 int i;
222
223 if (o->len > len)
224 return 0;
225
226 if (o->len == 0)
227 return 1;
228
229 if (o->flags & DHOPT_HEX)
230 {
231 if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
232 return 1;
233 }
234 else
235 for (i = 0; i <= (len - o->len); )
236 {
237 if (memcmp(o->val, p + i, o->len) == 0)
238 return 1;
239
240 if (o->flags & DHOPT_STRING)
241 i++;
242 else
243 i += o->len;
244 }
245
246 return 0;
247 }
248
249 void dhcp_update_configs(struct dhcp_config *configs)
250 {
251 /* Some people like to keep all static IP addresses in /etc/hosts.
252 This goes through /etc/hosts and sets static addresses for any DHCP config
253 records which don't have an address and whose name matches.
254 We take care to maintain the invariant that any IP address can appear
255 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
256 restore the status-quo ante first. */
257
258 struct dhcp_config *config, *conf_tmp;
259 struct crec *crec;
260 int prot = AF_INET;
261
262 for (config = configs; config; config = config->next)
263 if (config->flags & CONFIG_ADDR_HOSTS)
264 config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
265
266 #ifdef HAVE_DHCP6
267 again:
268 #endif
269
270 if (daemon->port != 0)
271 for (config = configs; config; config = config->next)
272 {
273 int conflags = CONFIG_ADDR;
274 int cacheflags = F_IPV4;
275
276 #ifdef HAVE_DHCP6
277 if (prot == AF_INET6)
278 {
279 conflags = CONFIG_ADDR6;
280 cacheflags = F_IPV6;
281 }
282 #endif
283 if (!(config->flags & conflags) &&
284 (config->flags & CONFIG_NAME) &&
285 (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
286 (crec->flags & F_HOSTS))
287 {
288 if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
289 {
290 /* use primary (first) address */
291 while (crec && !(crec->flags & F_REVERSE))
292 crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
293 if (!crec)
294 continue; /* should be never */
295 inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
296 my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
297 config->hostname, daemon->addrbuff);
298 }
299
300 if (prot == AF_INET &&
301 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
302 {
303 config->addr = crec->addr.addr.addr.addr4;
304 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
305 continue;
306 }
307
308 #ifdef HAVE_DHCP6
309 if (prot == AF_INET6 &&
310 (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
311 {
312 memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
313 config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
314 continue;
315 }
316 #endif
317
318 inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
319 my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
320 daemon->addrbuff, config->hostname);
321
322
323 }
324 }
325
326 #ifdef HAVE_DHCP6
327 if (prot == AF_INET)
328 {
329 prot = AF_INET6;
330 goto again;
331 }
332 #endif
333
334 }
335
336 #ifdef HAVE_LINUX_NETWORK
337 void bindtodevice(int fd)
338 {
339 /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
340 to that device. This is for the use case of (eg) OpenStack, which runs a new
341 dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
342 individual processes don't always see the packets they should.
343 SO_BINDTODEVICE is only available Linux. */
344
345 struct irec *iface, *found;
346
347 for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
348 if (iface->dhcp_ok)
349 {
350 if (!found)
351 found = iface;
352 else if (strcmp(found->name, iface->name) != 0)
353 {
354 /* more than one. */
355 found = NULL;
356 break;
357 }
358 }
359
360 if (found)
361 {
362 struct ifreq ifr;
363 strcpy(ifr.ifr_name, found->name);
364 /* only allowed by root. */
365 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
366 errno != EPERM)
367 die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
368 }
369 }
370 #endif
371
372 static const struct opttab_t {
373 char *name;
374 u16 val, size;
375 } opttab[] = {
376 { "netmask", 1, OT_ADDR_LIST },
377 { "time-offset", 2, 4 },
378 { "router", 3, OT_ADDR_LIST },
379 { "dns-server", 6, OT_ADDR_LIST },
380 { "log-server", 7, OT_ADDR_LIST },
381 { "lpr-server", 9, OT_ADDR_LIST },
382 { "hostname", 12, OT_INTERNAL | OT_NAME },
383 { "boot-file-size", 13, 2 | OT_DEC },
384 { "domain-name", 15, OT_NAME },
385 { "swap-server", 16, OT_ADDR_LIST },
386 { "root-path", 17, OT_NAME },
387 { "extension-path", 18, OT_NAME },
388 { "ip-forward-enable", 19, 1 },
389 { "non-local-source-routing", 20, 1 },
390 { "policy-filter", 21, OT_ADDR_LIST },
391 { "max-datagram-reassembly", 22, 2 | OT_DEC },
392 { "default-ttl", 23, 1 | OT_DEC },
393 { "mtu", 26, 2 | OT_DEC },
394 { "all-subnets-local", 27, 1 },
395 { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
396 { "router-discovery", 31, 1 },
397 { "router-solicitation", 32, OT_ADDR_LIST },
398 { "static-route", 33, OT_ADDR_LIST },
399 { "trailer-encapsulation", 34, 1 },
400 { "arp-timeout", 35, 4 | OT_DEC },
401 { "ethernet-encap", 36, 1 },
402 { "tcp-ttl", 37, 1 },
403 { "tcp-keepalive", 38, 4 | OT_DEC },
404 { "nis-domain", 40, OT_NAME },
405 { "nis-server", 41, OT_ADDR_LIST },
406 { "ntp-server", 42, OT_ADDR_LIST },
407 { "vendor-encap", 43, OT_INTERNAL },
408 { "netbios-ns", 44, OT_ADDR_LIST },
409 { "netbios-dd", 45, OT_ADDR_LIST },
410 { "netbios-nodetype", 46, 1 },
411 { "netbios-scope", 47, 0 },
412 { "x-windows-fs", 48, OT_ADDR_LIST },
413 { "x-windows-dm", 49, OT_ADDR_LIST },
414 { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
415 { "lease-time", 51, OT_INTERNAL | OT_TIME },
416 { "option-overload", 52, OT_INTERNAL },
417 { "message-type", 53, OT_INTERNAL | OT_DEC },
418 { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
419 { "parameter-request", 55, OT_INTERNAL },
420 { "message", 56, OT_INTERNAL },
421 { "max-message-size", 57, OT_INTERNAL },
422 { "T1", 58, OT_INTERNAL | OT_TIME},
423 { "T2", 59, OT_INTERNAL | OT_TIME},
424 { "vendor-class", 60, 0 },
425 { "client-id", 61, OT_INTERNAL },
426 { "nis+-domain", 64, OT_NAME },
427 { "nis+-server", 65, OT_ADDR_LIST },
428 { "tftp-server", 66, OT_NAME },
429 { "bootfile-name", 67, OT_NAME },
430 { "mobile-ip-home", 68, OT_ADDR_LIST },
431 { "smtp-server", 69, OT_ADDR_LIST },
432 { "pop3-server", 70, OT_ADDR_LIST },
433 { "nntp-server", 71, OT_ADDR_LIST },
434 { "irc-server", 74, OT_ADDR_LIST },
435 { "user-class", 77, 0 },
436 { "FQDN", 81, OT_INTERNAL },
437 { "agent-id", 82, OT_INTERNAL },
438 { "client-arch", 93, 2 | OT_DEC },
439 { "client-interface-id", 94, 0 },
440 { "client-machine-id", 97, 0 },
441 { "subnet-select", 118, OT_INTERNAL },
442 { "domain-search", 119, OT_RFC1035_NAME },
443 { "sip-server", 120, 0 },
444 { "classless-static-route", 121, 0 },
445 { "vendor-id-encap", 125, 0 },
446 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
447 { NULL, 0, 0 }
448 };
449
450 #ifdef HAVE_DHCP6
451 static const struct opttab_t opttab6[] = {
452 { "client-id", 1, OT_INTERNAL },
453 { "server-id", 2, OT_INTERNAL },
454 { "ia-na", 3, OT_INTERNAL },
455 { "ia-ta", 4, OT_INTERNAL },
456 { "iaaddr", 5, OT_INTERNAL },
457 { "oro", 6, OT_INTERNAL },
458 { "preference", 7, OT_INTERNAL | OT_DEC },
459 { "unicast", 12, OT_INTERNAL },
460 { "status", 13, OT_INTERNAL },
461 { "rapid-commit", 14, OT_INTERNAL },
462 { "user-class", 15, OT_INTERNAL | OT_CSTRING },
463 { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
464 { "vendor-opts", 17, OT_INTERNAL },
465 { "sip-server-domain", 21, OT_RFC1035_NAME },
466 { "sip-server", 22, OT_ADDR_LIST },
467 { "dns-server", 23, OT_ADDR_LIST },
468 { "domain-search", 24, OT_RFC1035_NAME },
469 { "nis-server", 27, OT_ADDR_LIST },
470 { "nis+-server", 28, OT_ADDR_LIST },
471 { "nis-domain", 29, OT_RFC1035_NAME },
472 { "nis+-domain", 30, OT_RFC1035_NAME },
473 { "sntp-server", 31, OT_ADDR_LIST },
474 { "information-refresh-time", 32, OT_TIME },
475 { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
476 { "ntp-server", 56, OT_ADDR_LIST },
477 { "bootfile-url", 59, OT_NAME },
478 { "bootfile-param", 60, OT_CSTRING },
479 { NULL, 0, 0 }
480 };
481 #endif
482
483
484
485 void display_opts(void)
486 {
487 int i;
488
489 printf(_("Known DHCP options:\n"));
490
491 for (i = 0; opttab[i].name; i++)
492 if (!(opttab[i].size & OT_INTERNAL))
493 printf("%3d %s\n", opttab[i].val, opttab[i].name);
494 }
495
496 #ifdef HAVE_DHCP6
497 void display_opts6(void)
498 {
499 int i;
500 printf(_("Known DHCPv6 options:\n"));
501
502 for (i = 0; opttab6[i].name; i++)
503 if (!(opttab6[i].size & OT_INTERNAL))
504 printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
505 }
506 #endif
507
508 u16 lookup_dhcp_opt(int prot, char *name)
509 {
510 const struct opttab_t *t;
511 int i;
512
513 #ifdef HAVE_DHCP6
514 if (prot == AF_INET6)
515 t = opttab6;
516 else
517 #endif
518 t = opttab;
519
520 for (i = 0; t[i].name; i++)
521 if (strcasecmp(t[i].name, name) == 0)
522 return t[i].val;
523
524 return 0;
525 }
526
527 u16 lookup_dhcp_len(int prot, u16 val)
528 {
529 const struct opttab_t *t;
530 int i;
531
532 #ifdef HAVE_DHCP6
533 if (prot == AF_INET6)
534 t = opttab6;
535 else
536 #endif
537 t = opttab;
538
539 for (i = 0; t[i].name; i++)
540 if (val == t[i].val)
541 return t[i].size & ~OT_DEC;
542
543 return 0;
544 }
545
546 char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
547 {
548 int o, i, j, nodecode = 0;
549 const struct opttab_t *ot = opttab;
550
551 #ifdef HAVE_DHCP6
552 if (prot == AF_INET6)
553 ot = opttab6;
554 #endif
555
556 for (o = 0; ot[o].name; o++)
557 if (ot[o].val == opt)
558 {
559 if (buf)
560 {
561 memset(buf, 0, buf_len);
562
563 if (ot[o].size & OT_ADDR_LIST)
564 {
565 struct all_addr addr;
566 int addr_len = INADDRSZ;
567
568 #ifdef HAVE_DHCP6
569 if (prot == AF_INET6)
570 addr_len = IN6ADDRSZ;
571 #endif
572 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
573 {
574 if (i != 0)
575 strncat(buf, ", ", buf_len - strlen(buf));
576 /* align */
577 memcpy(&addr, &val[i], addr_len);
578 inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
579 strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
580 }
581 }
582 else if (ot[o].size & OT_NAME)
583 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
584 {
585 char c = val[i];
586 if (isprint((int)c))
587 buf[j++] = c;
588 }
589 #ifdef HAVE_DHCP6
590 /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
591 else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
592 {
593 i = 0, j = 0;
594 while (i < opt_len && val[i] != 0)
595 {
596 int k, l = i + val[i] + 1;
597 for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
598 {
599 char c = val[k];
600 if (isprint((int)c))
601 buf[j++] = c;
602 }
603 i = l;
604 if (val[i] != 0 && j < buf_len)
605 buf[j++] = '.';
606 }
607 }
608 else if ((ot[o].size & OT_CSTRING))
609 {
610 int k, len;
611 unsigned char *p;
612
613 i = 0, j = 0;
614 while (1)
615 {
616 p = &val[i];
617 GETSHORT(len, p);
618 for (k = 0; k < len && j < buf_len; k++)
619 {
620 char c = *p++;
621 if (isprint((int)c))
622 buf[j++] = c;
623 }
624 i += len +2;
625 if (i >= opt_len)
626 break;
627
628 if (j < buf_len)
629 buf[j++] = ',';
630 }
631 }
632 #endif
633 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
634 {
635 unsigned int dec = 0;
636
637 for (i = 0; i < opt_len; i++)
638 dec = (dec << 8) | val[i];
639
640 if (ot[o].size & OT_TIME)
641 prettyprint_time(buf, dec);
642 else
643 sprintf(buf, "%u", dec);
644 }
645 else
646 nodecode = 1;
647 }
648 break;
649 }
650
651 if (opt_len != 0 && buf && (!ot[o].name || nodecode))
652 {
653 int trunc = 0;
654 if (opt_len > 14)
655 {
656 trunc = 1;
657 opt_len = 14;
658 }
659 print_mac(buf, val, opt_len);
660 if (trunc)
661 strncat(buf, "...", buf_len - strlen(buf));
662
663
664 }
665
666 return ot[o].name ? ot[o].name : "";
667
668 }
669
670 void log_context(int family, struct dhcp_context *context)
671 {
672 /* Cannot use dhcp_buff* for RA contexts */
673
674 void *start = &context->start;
675 void *end = &context->end;
676 char *template = "", *p = daemon->namebuff;
677
678 *p = 0;
679
680 #ifdef HAVE_DHCP6
681 if (family == AF_INET6)
682 {
683 struct in6_addr subnet = context->start6;
684 if (!(context->flags & CONTEXT_TEMPLATE))
685 setaddr6part(&subnet, 0);
686 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
687 start = &context->start6;
688 end = &context->end6;
689 }
690 #endif
691
692 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
693 strcpy(daemon->namebuff, _(", prefix deprecated"));
694 else
695 {
696 p += sprintf(p, _(", lease time "));
697 prettyprint_time(p, context->lease_time);
698 p += strlen(p);
699 }
700
701 #ifdef HAVE_DHCP6
702 if (context->flags & CONTEXT_CONSTRUCTED)
703 {
704 char ifrn_name[IFNAMSIZ];
705
706 template = p;
707 p += sprintf(p, ", ");
708
709 if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
710 sprintf(p, "constructed for %s", ifrn_name);
711 }
712 else if (context->flags & CONTEXT_TEMPLATE)
713 {
714 template = p;
715 p += sprintf(p, ", ");
716
717 sprintf(p, "template for %s", context->template_interface);
718 }
719 #endif
720
721 if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
722 {
723 inet_ntop(family, start, daemon->dhcp_buff, 256);
724 inet_ntop(family, end, daemon->dhcp_buff3, 256);
725 my_syslog(MS_DHCP | LOG_INFO,
726 (context->flags & CONTEXT_RA_STATELESS) ?
727 _("%s stateless on %s%.0s%.0s%s") :
728 (context->flags & CONTEXT_STATIC) ?
729 _("%s, static leases only on %.0s%s%s%.0s") :
730 (context->flags & CONTEXT_PROXY) ?
731 _("%s, proxy on subnet %.0s%s%.0s%.0s") :
732 _("%s, IP range %s -- %s%s%.0s"),
733 (family != AF_INET) ? "DHCPv6" : "DHCP",
734 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
735 }
736
737 #ifdef HAVE_DHCP6
738 if (context->flags & CONTEXT_RA_NAME)
739 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
740
741 if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
742 my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
743 #endif
744
745 }
746
747
748 #endif