blob: f4fd0889bc21b6cffaf0c79d4077657307b48811 [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
Simon Kelley4cb1b322012-02-06 14:30:41 +00002
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;
Simon Kelley96c727f2013-04-02 21:35:41 +010094 struct dhcp_opt *tmp;
Simon Kelley4cb1b322012-02-06 14:30:41 +000095
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,
Simon Kelley6caacac2012-02-15 21:58:33 +0000106 otherwise valid options are inhibited if we found a higher priority one above */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000107 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
Simon Kelleya8131112012-03-31 21:35:12 +0100115 /* 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
Simon Kelley4cb1b322012-02-06 14:30:41 +0000122 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 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000139 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
Simon Kelley96c727f2013-04-02 21:35:41 +0100148 /* 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
Simon Kelley4cb1b322012-02-06 14:30:41 +0000155 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
Simon Kelley3634c542012-02-08 14:22:37 +0000226int 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}
Simon Kelleyceae00d2012-02-09 21:28:14 +0000255
Simon Kelleyceae00d2012-02-09 21:28:14 +0000256void 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
Simon Kelley35239a32012-09-24 15:09:33 +0100265 struct dhcp_config *config, *conf_tmp;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000266 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
Simon Kelley35239a32012-09-24 15:09:33 +0100307 if (prot == AF_INET &&
308 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000309 {
310 config->addr = crec->addr.addr.addr.addr4;
311 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
312 continue;
313 }
314
315#ifdef HAVE_DHCP6
Simon Kelley35239a32012-09-24 15:09:33 +0100316 if (prot == AF_INET6 &&
317 (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000318 {
Simon Kelleye44ddca2012-02-18 17:08:50 +0000319 memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
Simon Kelleyceae00d2012-02-09 21:28:14 +0000320 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}
Simon Kelley4cb1b322012-02-06 14:30:41 +0000342
Simon Kelley9380ba72012-04-16 14:41:56 +0100343#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.
350 SO_BINDTODEVICE is only available Linux. */
351
352 struct irec *iface, *found;
Simon Kelleyb191a772012-10-24 14:16:00 +0100353
Simon Kelley9380ba72012-04-16 14:41:56 +0100354 for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
355 if (iface->dhcp_ok)
356 {
357 if (!found)
358 found = iface;
359 else if (strcmp(found->name, iface->name) != 0)
360 {
361 /* more than one. */
362 found = NULL;
363 break;
364 }
365 }
366
367 if (found)
Simon Kelleyb191a772012-10-24 14:16:00 +0100368 {
369 struct ifreq ifr;
370 strcpy(ifr.ifr_name, found->name);
371 /* only allowed by root. */
372 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
373 errno != EPERM)
374 die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
375 }
Simon Kelley9380ba72012-04-16 14:41:56 +0100376}
377#endif
Simon Kelley40ef23b2012-03-13 21:59:28 +0000378
379static const struct opttab_t {
380 char *name;
381 u16 val, size;
382} opttab[] = {
383 { "netmask", 1, OT_ADDR_LIST },
384 { "time-offset", 2, 4 },
385 { "router", 3, OT_ADDR_LIST },
386 { "dns-server", 6, OT_ADDR_LIST },
387 { "log-server", 7, OT_ADDR_LIST },
388 { "lpr-server", 9, OT_ADDR_LIST },
389 { "hostname", 12, OT_INTERNAL | OT_NAME },
390 { "boot-file-size", 13, 2 | OT_DEC },
391 { "domain-name", 15, OT_NAME },
392 { "swap-server", 16, OT_ADDR_LIST },
393 { "root-path", 17, OT_NAME },
394 { "extension-path", 18, OT_NAME },
395 { "ip-forward-enable", 19, 1 },
396 { "non-local-source-routing", 20, 1 },
397 { "policy-filter", 21, OT_ADDR_LIST },
398 { "max-datagram-reassembly", 22, 2 | OT_DEC },
399 { "default-ttl", 23, 1 | OT_DEC },
400 { "mtu", 26, 2 | OT_DEC },
401 { "all-subnets-local", 27, 1 },
402 { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
403 { "router-discovery", 31, 1 },
404 { "router-solicitation", 32, OT_ADDR_LIST },
405 { "static-route", 33, OT_ADDR_LIST },
406 { "trailer-encapsulation", 34, 1 },
407 { "arp-timeout", 35, 4 | OT_DEC },
408 { "ethernet-encap", 36, 1 },
409 { "tcp-ttl", 37, 1 },
410 { "tcp-keepalive", 38, 4 | OT_DEC },
411 { "nis-domain", 40, OT_NAME },
412 { "nis-server", 41, OT_ADDR_LIST },
413 { "ntp-server", 42, OT_ADDR_LIST },
414 { "vendor-encap", 43, OT_INTERNAL },
415 { "netbios-ns", 44, OT_ADDR_LIST },
416 { "netbios-dd", 45, OT_ADDR_LIST },
417 { "netbios-nodetype", 46, 1 },
418 { "netbios-scope", 47, 0 },
419 { "x-windows-fs", 48, OT_ADDR_LIST },
420 { "x-windows-dm", 49, OT_ADDR_LIST },
421 { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
Simon Kelley23245c02012-07-18 16:21:11 +0100422 { "lease-time", 51, OT_INTERNAL | OT_TIME },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000423 { "option-overload", 52, OT_INTERNAL },
424 { "message-type", 53, OT_INTERNAL | OT_DEC },
425 { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
426 { "parameter-request", 55, OT_INTERNAL },
427 { "message", 56, OT_INTERNAL },
428 { "max-message-size", 57, OT_INTERNAL },
Simon Kelley23245c02012-07-18 16:21:11 +0100429 { "T1", 58, OT_INTERNAL | OT_TIME},
430 { "T2", 59, OT_INTERNAL | OT_TIME},
Simon Kelley40ef23b2012-03-13 21:59:28 +0000431 { "vendor-class", 60, 0 },
432 { "client-id", 61, OT_INTERNAL },
433 { "nis+-domain", 64, OT_NAME },
434 { "nis+-server", 65, OT_ADDR_LIST },
435 { "tftp-server", 66, OT_NAME },
436 { "bootfile-name", 67, OT_NAME },
437 { "mobile-ip-home", 68, OT_ADDR_LIST },
438 { "smtp-server", 69, OT_ADDR_LIST },
439 { "pop3-server", 70, OT_ADDR_LIST },
440 { "nntp-server", 71, OT_ADDR_LIST },
441 { "irc-server", 74, OT_ADDR_LIST },
442 { "user-class", 77, 0 },
443 { "FQDN", 81, OT_INTERNAL },
444 { "agent-id", 82, OT_INTERNAL },
445 { "client-arch", 93, 2 | OT_DEC },
446 { "client-interface-id", 94, 0 },
447 { "client-machine-id", 97, 0 },
448 { "subnet-select", 118, OT_INTERNAL },
449 { "domain-search", 119, OT_RFC1035_NAME },
450 { "sip-server", 120, 0 },
451 { "classless-static-route", 121, 0 },
452 { "vendor-id-encap", 125, 0 },
453 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
454 { NULL, 0, 0 }
455};
456
457#ifdef HAVE_DHCP6
458static const struct opttab_t opttab6[] = {
459 { "client-id", 1, OT_INTERNAL },
460 { "server-id", 2, OT_INTERNAL },
461 { "ia-na", 3, OT_INTERNAL },
462 { "ia-ta", 4, OT_INTERNAL },
463 { "iaaddr", 5, OT_INTERNAL },
464 { "oro", 6, OT_INTERNAL },
465 { "preference", 7, OT_INTERNAL | OT_DEC },
466 { "unicast", 12, OT_INTERNAL },
467 { "status", 13, OT_INTERNAL },
468 { "rapid-commit", 14, OT_INTERNAL },
469 { "user-class", 15, OT_INTERNAL | OT_CSTRING },
470 { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
471 { "vendor-opts", 17, OT_INTERNAL },
472 { "sip-server-domain", 21, OT_RFC1035_NAME },
473 { "sip-server", 22, OT_ADDR_LIST },
474 { "dns-server", 23, OT_ADDR_LIST },
475 { "domain-search", 24, OT_RFC1035_NAME },
476 { "nis-server", 27, OT_ADDR_LIST },
477 { "nis+-server", 28, OT_ADDR_LIST },
478 { "nis-domain", 29, OT_RFC1035_NAME },
479 { "nis+-domain", 30, OT_RFC1035_NAME },
480 { "sntp-server", 31, OT_ADDR_LIST },
Simon Kelley23245c02012-07-18 16:21:11 +0100481 { "information-refresh-time", 32, OT_TIME },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000482 { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
483 { "ntp-server", 56, OT_ADDR_LIST },
484 { "bootfile-url", 59, OT_NAME },
485 { "bootfile-param", 60, OT_CSTRING },
486 { NULL, 0, 0 }
487};
488#endif
489
490
491
492void display_opts(void)
493{
494 int i;
495
496 printf(_("Known DHCP options:\n"));
497
498 for (i = 0; opttab[i].name; i++)
499 if (!(opttab[i].size & OT_INTERNAL))
500 printf("%3d %s\n", opttab[i].val, opttab[i].name);
501}
502
503#ifdef HAVE_DHCP6
504void display_opts6(void)
505{
506 int i;
507 printf(_("Known DHCPv6 options:\n"));
508
509 for (i = 0; opttab6[i].name; i++)
510 if (!(opttab6[i].size & OT_INTERNAL))
511 printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
512}
513#endif
514
515u16 lookup_dhcp_opt(int prot, char *name)
516{
517 const struct opttab_t *t;
518 int i;
519
520#ifdef HAVE_DHCP6
521 if (prot == AF_INET6)
522 t = opttab6;
523 else
524#endif
525 t = opttab;
526
527 for (i = 0; t[i].name; i++)
Simon Kelleyc7961072013-02-28 15:17:58 +0000528 if (strcasecmp(t[i].name, name) == 0)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000529 return t[i].val;
530
531 return 0;
532}
533
534u16 lookup_dhcp_len(int prot, u16 val)
535{
536 const struct opttab_t *t;
537 int i;
538
539#ifdef HAVE_DHCP6
540 if (prot == AF_INET6)
541 t = opttab6;
542 else
543#endif
544 t = opttab;
545
546 for (i = 0; t[i].name; i++)
547 if (val == t[i].val)
Simon Kelleyc7961072013-02-28 15:17:58 +0000548 return t[i].size & ~OT_DEC;
549
550 return 0;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000551}
552
553char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
554{
555 int o, i, j, nodecode = 0;
556 const struct opttab_t *ot = opttab;
557
558#ifdef HAVE_DHCP6
559 if (prot == AF_INET6)
560 ot = opttab6;
561#endif
562
563 for (o = 0; ot[o].name; o++)
564 if (ot[o].val == opt)
565 {
566 if (buf)
567 {
568 memset(buf, 0, buf_len);
569
570 if (ot[o].size & OT_ADDR_LIST)
571 {
572 struct all_addr addr;
573 int addr_len = INADDRSZ;
574
575#ifdef HAVE_DHCP6
576 if (prot == AF_INET6)
577 addr_len = IN6ADDRSZ;
578#endif
579 for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
580 {
581 if (i != 0)
582 strncat(buf, ", ", buf_len - strlen(buf));
583 /* align */
584 memcpy(&addr, &val[i], addr_len);
585 inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
586 strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
587 }
588 }
589 else if (ot[o].size & OT_NAME)
590 for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
591 {
592 char c = val[i];
593 if (isprint((int)c))
594 buf[j++] = c;
595 }
596#ifdef HAVE_DHCP6
597 /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
598 else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
599 {
600 i = 0, j = 0;
601 while (i < opt_len && val[i] != 0)
602 {
603 int k, l = i + val[i] + 1;
604 for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
605 {
606 char c = val[k];
607 if (isprint((int)c))
608 buf[j++] = c;
609 }
610 i = l;
611 if (val[i] != 0 && j < buf_len)
612 buf[j++] = '.';
613 }
614 }
615 else if ((ot[o].size & OT_CSTRING))
616 {
617 int k, len;
618 unsigned char *p;
619
620 i = 0, j = 0;
621 while (1)
622 {
623 p = &val[i];
624 GETSHORT(len, p);
625 for (k = 0; k < len && j < buf_len; k++)
626 {
627 char c = *p++;
628 if (isprint((int)c))
629 buf[j++] = c;
630 }
631 i += len +2;
632 if (i >= opt_len)
633 break;
634
635 if (j < buf_len)
636 buf[j++] = ',';
637 }
638 }
639#endif
Simon Kelley23245c02012-07-18 16:21:11 +0100640 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000641 {
642 unsigned int dec = 0;
643
644 for (i = 0; i < opt_len; i++)
645 dec = (dec << 8) | val[i];
646
Simon Kelley23245c02012-07-18 16:21:11 +0100647 if (ot[o].size & OT_TIME)
648 prettyprint_time(buf, dec);
649 else
650 sprintf(buf, "%u", dec);
Simon Kelley40ef23b2012-03-13 21:59:28 +0000651 }
652 else
653 nodecode = 1;
654 }
655 break;
656 }
657
658 if (opt_len != 0 && buf && (!ot[o].name || nodecode))
659 {
660 int trunc = 0;
661 if (opt_len > 14)
662 {
663 trunc = 1;
664 opt_len = 14;
665 }
666 print_mac(buf, val, opt_len);
667 if (trunc)
668 strncat(buf, "...", buf_len - strlen(buf));
669
670
671 }
672
673 return ot[o].name ? ot[o].name : "";
674
675}
676
Simon Kelley1f776932012-12-16 19:46:08 +0000677void log_context(int family, struct dhcp_context *context)
678{
679 /* Cannot use dhcp_buff* for RA contexts */
680
681 void *start = &context->start;
682 void *end = &context->end;
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000683 char *template = "", *p = daemon->namebuff;
Simon Kelleyc1be9172012-12-17 22:37:30 +0000684
685 *p = 0;
686
Simon Kelley1f776932012-12-16 19:46:08 +0000687#ifdef HAVE_DHCP6
688 if (family == AF_INET6)
689 {
690 struct in6_addr subnet = context->start6;
691 if (!(context->flags & CONTEXT_TEMPLATE))
692 setaddr6part(&subnet, 0);
693 inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
694 start = &context->start6;
695 end = &context->end6;
696 }
697#endif
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000698
699 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
700 strcpy(daemon->namebuff, _(", prefix deprecated"));
701 else
Simon Kelley1f776932012-12-16 19:46:08 +0000702 {
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000703 p += sprintf(p, _(", lease time "));
704 prettyprint_time(p, context->lease_time);
705 p += strlen(p);
706 }
707
Simon Kelleyc1be9172012-12-17 22:37:30 +0000708#ifdef HAVE_DHCP6
709 if (context->flags & CONTEXT_CONSTRUCTED)
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000710 {
711 char ifrn_name[IFNAMSIZ];
712
713 template = p;
714 p += sprintf(p, ", ");
715
716 if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
717 sprintf(p, "constructed for %s", ifrn_name);
718 }
719 else if (context->flags & CONTEXT_TEMPLATE)
720 {
721 template = p;
722 p += sprintf(p, ", ");
723
Simon Kelley49333cb2013-03-15 20:30:51 +0000724 sprintf(p, "template for %s", context->template_interface);
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000725 }
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