blob: 237f839efc65691d7fa6ba0a2b2f733862db5221 [file] [log] [blame]
Simon Kelley4cb1b322012-02-06 14:30:41 +00001/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_DHCP
20
21void dhcp_common_init(void)
22{
23 /* These each hold a DHCP option max size 255
24 and get a terminating zero added */
25 daemon->dhcp_buff = safe_malloc(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 */
Simon Kelleyc5ad4e72012-02-24 16:06:20 +000056 if ((size_t)sz == msg->msg_iov->iov_len)
Simon Kelley4cb1b322012-02-06 14:30:41 +000057 {
Simon Kelleyc5ad4e72012-02-24 16:06:20 +000058 if (!expand_buf(msg->msg_iov, sz + 100))
Simon Kelley4cb1b322012-02-06 14:30:41 +000059 return -1;
60 }
61 else
62 {
Simon Kelleyc5ad4e72012-02-24 16:06:20 +000063 expand_buf(msg->msg_iov, sz);
Simon Kelley4cb1b322012-02-06 14:30:41 +000064 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;
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,
Simon Kelley6caacac2012-02-15 21:58:33 +0000105 otherwise valid options are inhibited if we found a higher priority one above */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000106 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
Simon Kelleya8131112012-03-31 21:35:12 +0100114 /* 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
Simon Kelley4cb1b322012-02-06 14:30:41 +0000121 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 */
153int 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. */
180char *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
194void 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
Simon Kelley3634c542012-02-08 14:22:37 +0000219int 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}
Simon Kelleyceae00d2012-02-09 21:28:14 +0000248
Simon Kelleyceae00d2012-02-09 21:28:14 +0000249void 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
Simon Kelley35239a32012-09-24 15:09:33 +0100258 struct dhcp_config *config, *conf_tmp;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000259 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
Simon Kelley35239a32012-09-24 15:09:33 +0100300 if (prot == AF_INET &&
301 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000302 {
303 config->addr = crec->addr.addr.addr.addr4;
304 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
305 continue;
306 }
307
308#ifdef HAVE_DHCP6
Simon Kelley35239a32012-09-24 15:09:33 +0100309 if (prot == AF_INET6 &&
310 (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000311 {
Simon Kelleye44ddca2012-02-18 17:08:50 +0000312 memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
Simon Kelleyceae00d2012-02-09 21:28:14 +0000313 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}
Simon Kelley4cb1b322012-02-06 14:30:41 +0000335
Simon Kelley9380ba72012-04-16 14:41:56 +0100336#ifdef HAVE_LINUX_NETWORK
337void 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;
Simon Kelleyb191a772012-10-24 14:16:00 +0100346
Simon Kelley9380ba72012-04-16 14:41:56 +0100347 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)
Simon Kelleyb191a772012-10-24 14:16:00 +0100361 {
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 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100369}
370#endif
Simon Kelley40ef23b2012-03-13 21:59:28 +0000371
372static 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 },
Simon Kelley23245c02012-07-18 16:21:11 +0100415 { "lease-time", 51, OT_INTERNAL | OT_TIME },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000416 { "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 },
Simon Kelley23245c02012-07-18 16:21:11 +0100422 { "T1", 58, OT_INTERNAL | OT_TIME},
423 { "T2", 59, OT_INTERNAL | OT_TIME},
Simon Kelley40ef23b2012-03-13 21:59:28 +0000424 { "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
451static 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 },
Simon Kelley23245c02012-07-18 16:21:11 +0100474 { "information-refresh-time", 32, OT_TIME },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000475 { "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
485void 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
497void 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
508u16 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 (!(t[i].size & OT_INTERNAL) &&
522 strcasecmp(t[i].name, name) == 0)
523 return t[i].val;
524
525 return 0;
526}
527
528u16 lookup_dhcp_len(int prot, u16 val)
529{
530 const struct opttab_t *t;
531 int i;
532
533#ifdef HAVE_DHCP6
534 if (prot == AF_INET6)
535 t = opttab6;
536 else
537#endif
538 t = opttab;
539
540 for (i = 0; t[i].name; i++)
541 if (val == t[i].val)
542 {
543 if (t[i].size & OT_INTERNAL)
544 return 0;
545
546 return t[i].size & ~OT_DEC;
547 }
548
549 return 0;
550}
551
552char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
553{
554 int o, i, j, nodecode = 0;
555 const struct opttab_t *ot = opttab;
556
557#ifdef HAVE_DHCP6
558 if (prot == AF_INET6)
559 ot = opttab6;
560#endif
561
562 for (o = 0; ot[o].name; o++)
563 if (ot[o].val == opt)
564 {
565 if (buf)
566 {
567 memset(buf, 0, buf_len);
568
569 if (ot[o].size & OT_ADDR_LIST)
570 {
571 struct all_addr addr;
572 int addr_len = INADDRSZ;
573
574#ifdef HAVE_DHCP6
575 if (prot == AF_INET6)
576 addr_len = IN6ADDRSZ;
577#endif
578 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
579 {
580 if (i != 0)
581 strncat(buf, ", ", buf_len - strlen(buf));
582 /* align */
583 memcpy(&addr, &val[i], addr_len);
584 inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
585 strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
586 }
587 }
588 else if (ot[o].size & OT_NAME)
589 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
590 {
591 char c = val[i];
592 if (isprint((int)c))
593 buf[j++] = c;
594 }
595#ifdef HAVE_DHCP6
596 /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
597 else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
598 {
599 i = 0, j = 0;
600 while (i < opt_len && val[i] != 0)
601 {
602 int k, l = i + val[i] + 1;
603 for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
604 {
605 char c = val[k];
606 if (isprint((int)c))
607 buf[j++] = c;
608 }
609 i = l;
610 if (val[i] != 0 && j < buf_len)
611 buf[j++] = '.';
612 }
613 }
614 else if ((ot[o].size & OT_CSTRING))
615 {
616 int k, len;
617 unsigned char *p;
618
619 i = 0, j = 0;
620 while (1)
621 {
622 p = &val[i];
623 GETSHORT(len, p);
624 for (k = 0; k < len && j < buf_len; k++)
625 {
626 char c = *p++;
627 if (isprint((int)c))
628 buf[j++] = c;
629 }
630 i += len +2;
631 if (i >= opt_len)
632 break;
633
634 if (j < buf_len)
635 buf[j++] = ',';
636 }
637 }
638#endif
Simon Kelley23245c02012-07-18 16:21:11 +0100639 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000640 {
641 unsigned int dec = 0;
642
643 for (i = 0; i < opt_len; i++)
644 dec = (dec << 8) | val[i];
645
Simon Kelley23245c02012-07-18 16:21:11 +0100646 if (ot[o].size & OT_TIME)
647 prettyprint_time(buf, dec);
648 else
649 sprintf(buf, "%u", dec);
Simon Kelley40ef23b2012-03-13 21:59:28 +0000650 }
651 else
652 nodecode = 1;
653 }
654 break;
655 }
656
657 if (opt_len != 0 && buf && (!ot[o].name || nodecode))
658 {
659 int trunc = 0;
660 if (opt_len > 14)
661 {
662 trunc = 1;
663 opt_len = 14;
664 }
665 print_mac(buf, val, opt_len);
666 if (trunc)
667 strncat(buf, "...", buf_len - strlen(buf));
668
669
670 }
671
672 return ot[o].name ? ot[o].name : "";
673
674}
675
Simon Kelley1f776932012-12-16 19:46:08 +0000676void log_context(int family, struct dhcp_context *context)
677{
678 /* Cannot use dhcp_buff* for RA contexts */
679
680 void *start = &context->start;
681 void *end = &context->end;
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000682 char *template = "", *p = daemon->namebuff;
Simon Kelleyc1be9172012-12-17 22:37:30 +0000683
684 *p = 0;
685
Simon Kelley1f776932012-12-16 19:46:08 +0000686#ifdef HAVE_DHCP6
687 if (family == AF_INET6)
688 {
689 struct in6_addr subnet = context->start6;
690 if (!(context->flags & CONTEXT_TEMPLATE))
691 setaddr6part(&subnet, 0);
692 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
693 start = &context->start6;
694 end = &context->end6;
695 }
696#endif
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000697
698 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
699 strcpy(daemon->namebuff, _(", prefix deprecated"));
700 else
Simon Kelley1f776932012-12-16 19:46:08 +0000701 {
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000702 p += sprintf(p, _(", lease time "));
703 prettyprint_time(p, context->lease_time);
704 p += strlen(p);
705 }
706
Simon Kelleyc1be9172012-12-17 22:37:30 +0000707#ifdef HAVE_DHCP6
708 if (context->flags & CONTEXT_CONSTRUCTED)
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000709 {
710 char ifrn_name[IFNAMSIZ];
711
712 template = p;
713 p += sprintf(p, ", ");
714
715 if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
716 sprintf(p, "constructed for %s", ifrn_name);
717 }
718 else if (context->flags & CONTEXT_TEMPLATE)
719 {
720 template = p;
721 p += sprintf(p, ", ");
722
723 sprintf(p, "template for %s%s", context->template_interface,
724 (context->flags & CONTEXT_WILDCARD) ? "*" : "");
725 }
Simon Kelleyc1be9172012-12-17 22:37:30 +0000726#endif
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000727
Simon Kelley1f776932012-12-16 19:46:08 +0000728 if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
729 {
730 inet_ntop(family, start, daemon->dhcp_buff, 256);
731 inet_ntop(family, end, daemon->dhcp_buff3, 256);
732 my_syslog(MS_DHCP | LOG_INFO,
733 (context->flags & CONTEXT_RA_STATELESS) ?
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000734 _("%s stateless on %s%.0s%.0s%s") :
Simon Kelley1f776932012-12-16 19:46:08 +0000735 (context->flags & CONTEXT_STATIC) ?
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000736 _("%s, static leases only on %.0s%s%s%.0s") :
Simon Kelley1f776932012-12-16 19:46:08 +0000737 (context->flags & CONTEXT_PROXY) ?
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000738 _("%s, proxy on subnet %.0s%s%.0s%.0s") :
739 _("%s, IP range %s -- %s%s%.0s"),
Simon Kelley1f776932012-12-16 19:46:08 +0000740 (family != AF_INET) ? "DHCPv6" : "DHCP",
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000741 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
Simon Kelley1f776932012-12-16 19:46:08 +0000742 }
743
Simon Kelleyc1be9172012-12-17 22:37:30 +0000744#ifdef HAVE_DHCP6
Simon Kelley1f776932012-12-16 19:46:08 +0000745 if (context->flags & CONTEXT_RA_NAME)
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000746 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
Simon Kelley1f776932012-12-16 19:46:08 +0000747
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000748 if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
749 my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
Simon Kelleyc1be9172012-12-17 22:37:30 +0000750#endif
751
Simon Kelley1f776932012-12-16 19:46:08 +0000752}
753
754
Simon Kelley4cb1b322012-02-06 14:30:41 +0000755#endif