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