Annotation of embedaddon/dnsmasq/src/dhcp-common.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
1.1 misho 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: struct dhcp_opt *tmp;
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,
106: otherwise valid options are inhibited if we found a higher priority one above */
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:
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:
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: {
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: /* 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:
155: return tagif;
156: }
157:
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)
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. */
187: char *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:
201: void 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:
226: int 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: }
255:
1.1.1.2 ! misho 256: int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
! 257: {
! 258: struct hwaddr_config *conf_addr;
! 259:
! 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;
! 266:
! 267: return 0;
! 268: }
! 269:
! 270: static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
! 271: {
! 272: if (!context) /* called via find_config() from lease_update_from_configs() */
! 273: return 1;
! 274:
! 275: if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
! 276: return 1;
! 277:
! 278: #ifdef HAVE_DHCP6
! 279: if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
! 280: return 1;
! 281: #endif
! 282:
! 283: for (; context; context = context->current)
! 284: #ifdef HAVE_DHCP6
! 285: if (context->flags & CONTEXT_V6)
! 286: {
! 287: if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
! 288: return 1;
! 289: }
! 290: else
! 291: #endif
! 292: if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
! 293: return 1;
! 294:
! 295: return 0;
! 296: }
! 297:
! 298: struct dhcp_config *find_config(struct dhcp_config *configs,
! 299: struct dhcp_context *context,
! 300: unsigned char *clid, int clid_len,
! 301: unsigned char *hwaddr, int hw_len,
! 302: int hw_type, char *hostname)
! 303: {
! 304: int count, new;
! 305: struct dhcp_config *config, *candidate;
! 306: struct hwaddr_config *conf_addr;
! 307:
! 308: if (clid)
! 309: for (config = configs; config; config = config->next)
! 310: if (config->flags & CONFIG_CLID)
! 311: {
! 312: if (config->clid_len == clid_len &&
! 313: memcmp(config->clid, clid, clid_len) == 0 &&
! 314: is_config_in_context(context, config))
! 315: return config;
! 316:
! 317: /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
! 318: cope with that here. This is IPv4 only. context==NULL implies IPv4,
! 319: see lease_update_from_configs() */
! 320: if ((!context || !(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;
! 324: }
! 325:
! 326:
! 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;
! 332:
! 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;
! 339:
! 340:
! 341: if (!hwaddr)
! 342: return NULL;
! 343:
! 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)
! 352: {
! 353: count = new;
! 354: candidate = config;
! 355: }
! 356:
! 357: return candidate;
! 358: }
! 359:
1.1 misho 360: void dhcp_update_configs(struct dhcp_config *configs)
361: {
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. */
368:
369: struct dhcp_config *config, *conf_tmp;
370: struct crec *crec;
371: int prot = AF_INET;
372:
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);
376:
377: #ifdef HAVE_DHCP6
378: again:
379: #endif
380:
381: if (daemon->port != 0)
382: for (config = configs; config; config = config->next)
383: {
384: int conflags = CONFIG_ADDR;
385: int cacheflags = F_IPV4;
386:
387: #ifdef HAVE_DHCP6
388: if (prot == AF_INET6)
389: {
390: conflags = CONFIG_ADDR6;
391: cacheflags = F_IPV6;
392: }
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))
398: {
399: if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
400: {
401: /* use primary (first) address */
1.1.1.2 ! misho 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);
1.1 misho 409: }
410:
411: if (prot == AF_INET &&
412: (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
413: {
414: config->addr = crec->addr.addr.addr.addr4;
415: config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
416: continue;
417: }
418:
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))
422: {
423: memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
424: config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
425: continue;
426: }
427: #endif
428:
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);
432:
433:
434: }
435: }
436:
437: #ifdef HAVE_DHCP6
438: if (prot == AF_INET)
439: {
440: prot = AF_INET6;
441: goto again;
442: }
443: #endif
444:
445: }
446:
447: #ifdef HAVE_LINUX_NETWORK
1.1.1.2 ! misho 448: char *whichdevice(void)
1.1 misho 449: {
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.
1.1.1.2 ! misho 454: SO_BINDTODEVICE is only available Linux.
! 455:
! 456: Note that if wildcards are used in --interface, or --interface is not used at all,
! 457: or a configured interface doesn't yet exist, then more interfaces may arrive later,
! 458: so we can't safely assert there is only one interface and proceed.
! 459: */
1.1 misho 460:
461: struct irec *iface, *found;
1.1.1.2 ! misho 462: struct iname *if_tmp;
! 463:
! 464: if (!daemon->if_names)
! 465: return NULL;
1.1 misho 466:
1.1.1.2 ! misho 467: for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
! 468: if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
! 469: return NULL;
! 470:
1.1 misho 471: for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
472: if (iface->dhcp_ok)
473: {
474: if (!found)
475: found = iface;
476: else if (strcmp(found->name, iface->name) != 0)
1.1.1.2 ! misho 477: return NULL; /* more than one. */
1.1 misho 478: }
1.1.1.2 ! misho 479:
1.1 misho 480: if (found)
1.1.1.2 ! misho 481: return found->name;
! 482:
! 483: return NULL;
! 484: }
! 485:
! 486: void bindtodevice(char *device, int fd)
! 487: {
! 488: struct ifreq ifr;
! 489:
! 490: strcpy(ifr.ifr_name, device);
! 491: /* only allowed by root. */
! 492: if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
! 493: errno != EPERM)
! 494: die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
1.1 misho 495: }
496: #endif
497:
498: static const struct opttab_t {
499: char *name;
500: u16 val, size;
501: } opttab[] = {
502: { "netmask", 1, OT_ADDR_LIST },
503: { "time-offset", 2, 4 },
504: { "router", 3, OT_ADDR_LIST },
505: { "dns-server", 6, OT_ADDR_LIST },
506: { "log-server", 7, OT_ADDR_LIST },
507: { "lpr-server", 9, OT_ADDR_LIST },
508: { "hostname", 12, OT_INTERNAL | OT_NAME },
509: { "boot-file-size", 13, 2 | OT_DEC },
510: { "domain-name", 15, OT_NAME },
511: { "swap-server", 16, OT_ADDR_LIST },
512: { "root-path", 17, OT_NAME },
513: { "extension-path", 18, OT_NAME },
514: { "ip-forward-enable", 19, 1 },
515: { "non-local-source-routing", 20, 1 },
516: { "policy-filter", 21, OT_ADDR_LIST },
517: { "max-datagram-reassembly", 22, 2 | OT_DEC },
518: { "default-ttl", 23, 1 | OT_DEC },
519: { "mtu", 26, 2 | OT_DEC },
520: { "all-subnets-local", 27, 1 },
521: { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
522: { "router-discovery", 31, 1 },
523: { "router-solicitation", 32, OT_ADDR_LIST },
524: { "static-route", 33, OT_ADDR_LIST },
525: { "trailer-encapsulation", 34, 1 },
526: { "arp-timeout", 35, 4 | OT_DEC },
527: { "ethernet-encap", 36, 1 },
528: { "tcp-ttl", 37, 1 },
529: { "tcp-keepalive", 38, 4 | OT_DEC },
530: { "nis-domain", 40, OT_NAME },
531: { "nis-server", 41, OT_ADDR_LIST },
532: { "ntp-server", 42, OT_ADDR_LIST },
533: { "vendor-encap", 43, OT_INTERNAL },
534: { "netbios-ns", 44, OT_ADDR_LIST },
535: { "netbios-dd", 45, OT_ADDR_LIST },
536: { "netbios-nodetype", 46, 1 },
537: { "netbios-scope", 47, 0 },
538: { "x-windows-fs", 48, OT_ADDR_LIST },
539: { "x-windows-dm", 49, OT_ADDR_LIST },
540: { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
541: { "lease-time", 51, OT_INTERNAL | OT_TIME },
542: { "option-overload", 52, OT_INTERNAL },
543: { "message-type", 53, OT_INTERNAL | OT_DEC },
544: { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
545: { "parameter-request", 55, OT_INTERNAL },
546: { "message", 56, OT_INTERNAL },
547: { "max-message-size", 57, OT_INTERNAL },
548: { "T1", 58, OT_INTERNAL | OT_TIME},
549: { "T2", 59, OT_INTERNAL | OT_TIME},
550: { "vendor-class", 60, 0 },
551: { "client-id", 61, OT_INTERNAL },
552: { "nis+-domain", 64, OT_NAME },
553: { "nis+-server", 65, OT_ADDR_LIST },
554: { "tftp-server", 66, OT_NAME },
555: { "bootfile-name", 67, OT_NAME },
556: { "mobile-ip-home", 68, OT_ADDR_LIST },
557: { "smtp-server", 69, OT_ADDR_LIST },
558: { "pop3-server", 70, OT_ADDR_LIST },
559: { "nntp-server", 71, OT_ADDR_LIST },
560: { "irc-server", 74, OT_ADDR_LIST },
561: { "user-class", 77, 0 },
562: { "FQDN", 81, OT_INTERNAL },
563: { "agent-id", 82, OT_INTERNAL },
564: { "client-arch", 93, 2 | OT_DEC },
565: { "client-interface-id", 94, 0 },
566: { "client-machine-id", 97, 0 },
567: { "subnet-select", 118, OT_INTERNAL },
568: { "domain-search", 119, OT_RFC1035_NAME },
569: { "sip-server", 120, 0 },
570: { "classless-static-route", 121, 0 },
571: { "vendor-id-encap", 125, 0 },
572: { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
573: { NULL, 0, 0 }
574: };
575:
576: #ifdef HAVE_DHCP6
577: static const struct opttab_t opttab6[] = {
578: { "client-id", 1, OT_INTERNAL },
579: { "server-id", 2, OT_INTERNAL },
580: { "ia-na", 3, OT_INTERNAL },
581: { "ia-ta", 4, OT_INTERNAL },
582: { "iaaddr", 5, OT_INTERNAL },
583: { "oro", 6, OT_INTERNAL },
584: { "preference", 7, OT_INTERNAL | OT_DEC },
585: { "unicast", 12, OT_INTERNAL },
586: { "status", 13, OT_INTERNAL },
587: { "rapid-commit", 14, OT_INTERNAL },
588: { "user-class", 15, OT_INTERNAL | OT_CSTRING },
589: { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
590: { "vendor-opts", 17, OT_INTERNAL },
591: { "sip-server-domain", 21, OT_RFC1035_NAME },
592: { "sip-server", 22, OT_ADDR_LIST },
593: { "dns-server", 23, OT_ADDR_LIST },
594: { "domain-search", 24, OT_RFC1035_NAME },
595: { "nis-server", 27, OT_ADDR_LIST },
596: { "nis+-server", 28, OT_ADDR_LIST },
597: { "nis-domain", 29, OT_RFC1035_NAME },
598: { "nis+-domain", 30, OT_RFC1035_NAME },
599: { "sntp-server", 31, OT_ADDR_LIST },
600: { "information-refresh-time", 32, OT_TIME },
601: { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
602: { "ntp-server", 56, OT_ADDR_LIST },
603: { "bootfile-url", 59, OT_NAME },
604: { "bootfile-param", 60, OT_CSTRING },
605: { NULL, 0, 0 }
606: };
607: #endif
608:
609:
610:
611: void display_opts(void)
612: {
613: int i;
614:
615: printf(_("Known DHCP options:\n"));
616:
617: for (i = 0; opttab[i].name; i++)
618: if (!(opttab[i].size & OT_INTERNAL))
619: printf("%3d %s\n", opttab[i].val, opttab[i].name);
620: }
621:
622: #ifdef HAVE_DHCP6
623: void display_opts6(void)
624: {
625: int i;
626: printf(_("Known DHCPv6 options:\n"));
627:
628: for (i = 0; opttab6[i].name; i++)
629: if (!(opttab6[i].size & OT_INTERNAL))
630: printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
631: }
632: #endif
633:
1.1.1.2 ! misho 634: int lookup_dhcp_opt(int prot, char *name)
1.1 misho 635: {
636: const struct opttab_t *t;
637: int i;
638:
1.1.1.2 ! misho 639: (void)prot;
! 640:
1.1 misho 641: #ifdef HAVE_DHCP6
642: if (prot == AF_INET6)
643: t = opttab6;
644: else
645: #endif
646: t = opttab;
647:
648: for (i = 0; t[i].name; i++)
649: if (strcasecmp(t[i].name, name) == 0)
650: return t[i].val;
651:
1.1.1.2 ! misho 652: return -1;
1.1 misho 653: }
654:
1.1.1.2 ! misho 655: int lookup_dhcp_len(int prot, int val)
1.1 misho 656: {
657: const struct opttab_t *t;
658: int i;
659:
1.1.1.2 ! misho 660: (void)prot;
! 661:
1.1 misho 662: #ifdef HAVE_DHCP6
663: if (prot == AF_INET6)
664: t = opttab6;
665: else
666: #endif
667: t = opttab;
668:
669: for (i = 0; t[i].name; i++)
670: if (val == t[i].val)
671: return t[i].size & ~OT_DEC;
672:
673: return 0;
674: }
675:
676: char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
677: {
678: int o, i, j, nodecode = 0;
679: const struct opttab_t *ot = opttab;
680:
681: #ifdef HAVE_DHCP6
682: if (prot == AF_INET6)
683: ot = opttab6;
684: #endif
685:
686: for (o = 0; ot[o].name; o++)
687: if (ot[o].val == opt)
688: {
689: if (buf)
690: {
691: memset(buf, 0, buf_len);
692:
693: if (ot[o].size & OT_ADDR_LIST)
694: {
695: struct all_addr addr;
696: int addr_len = INADDRSZ;
697:
698: #ifdef HAVE_DHCP6
699: if (prot == AF_INET6)
700: addr_len = IN6ADDRSZ;
701: #endif
702: for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
703: {
704: if (i != 0)
705: strncat(buf, ", ", buf_len - strlen(buf));
706: /* align */
707: memcpy(&addr, &val[i], addr_len);
708: inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
709: strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
710: }
711: }
712: else if (ot[o].size & OT_NAME)
713: for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
714: {
715: char c = val[i];
716: if (isprint((int)c))
717: buf[j++] = c;
718: }
719: #ifdef HAVE_DHCP6
720: /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
721: else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
722: {
723: i = 0, j = 0;
724: while (i < opt_len && val[i] != 0)
725: {
726: int k, l = i + val[i] + 1;
727: for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
728: {
729: char c = val[k];
730: if (isprint((int)c))
731: buf[j++] = c;
732: }
733: i = l;
734: if (val[i] != 0 && j < buf_len)
735: buf[j++] = '.';
736: }
737: }
738: else if ((ot[o].size & OT_CSTRING))
739: {
740: int k, len;
741: unsigned char *p;
742:
743: i = 0, j = 0;
744: while (1)
745: {
746: p = &val[i];
747: GETSHORT(len, p);
748: for (k = 0; k < len && j < buf_len; k++)
749: {
750: char c = *p++;
751: if (isprint((int)c))
752: buf[j++] = c;
753: }
754: i += len +2;
755: if (i >= opt_len)
756: break;
757:
758: if (j < buf_len)
759: buf[j++] = ',';
760: }
761: }
762: #endif
763: else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
764: {
765: unsigned int dec = 0;
766:
767: for (i = 0; i < opt_len; i++)
768: dec = (dec << 8) | val[i];
769:
770: if (ot[o].size & OT_TIME)
771: prettyprint_time(buf, dec);
772: else
773: sprintf(buf, "%u", dec);
774: }
775: else
776: nodecode = 1;
777: }
778: break;
779: }
780:
781: if (opt_len != 0 && buf && (!ot[o].name || nodecode))
782: {
783: int trunc = 0;
784: if (opt_len > 14)
785: {
786: trunc = 1;
787: opt_len = 14;
788: }
789: print_mac(buf, val, opt_len);
790: if (trunc)
791: strncat(buf, "...", buf_len - strlen(buf));
792:
793:
794: }
795:
796: return ot[o].name ? ot[o].name : "";
797:
798: }
799:
800: void log_context(int family, struct dhcp_context *context)
801: {
802: /* Cannot use dhcp_buff* for RA contexts */
803:
804: void *start = &context->start;
805: void *end = &context->end;
806: char *template = "", *p = daemon->namebuff;
807:
808: *p = 0;
809:
810: #ifdef HAVE_DHCP6
811: if (family == AF_INET6)
812: {
813: struct in6_addr subnet = context->start6;
814: if (!(context->flags & CONTEXT_TEMPLATE))
815: setaddr6part(&subnet, 0);
816: inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
817: start = &context->start6;
818: end = &context->end6;
819: }
820: #endif
821:
822: if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
823: strcpy(daemon->namebuff, _(", prefix deprecated"));
824: else
825: {
826: p += sprintf(p, _(", lease time "));
827: prettyprint_time(p, context->lease_time);
828: p += strlen(p);
829: }
830:
831: #ifdef HAVE_DHCP6
832: if (context->flags & CONTEXT_CONSTRUCTED)
833: {
834: char ifrn_name[IFNAMSIZ];
835:
836: template = p;
837: p += sprintf(p, ", ");
838:
1.1.1.2 ! misho 839: if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
! 840: sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
1.1 misho 841: }
1.1.1.2 ! misho 842: else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
1.1 misho 843: {
844: template = p;
845: p += sprintf(p, ", ");
1.1.1.2 ! misho 846:
1.1 misho 847: sprintf(p, "template for %s", context->template_interface);
848: }
849: #endif
850:
1.1.1.2 ! misho 851: if (!(context->flags & CONTEXT_OLD) &&
! 852: ((context->flags & CONTEXT_DHCP) || family == AF_INET))
1.1 misho 853: {
1.1.1.2 ! misho 854: #ifdef HAVE_DHCP6
! 855: if (context->flags & CONTEXT_RA_STATELESS)
! 856: {
! 857: if (context->flags & CONTEXT_TEMPLATE)
! 858: strncpy(daemon->dhcp_buff, context->template_interface, 256);
! 859: else
! 860: strcpy(daemon->dhcp_buff, daemon->addrbuff);
! 861: }
! 862: else
! 863: #endif
! 864: inet_ntop(family, start, daemon->dhcp_buff, 256);
1.1 misho 865: inet_ntop(family, end, daemon->dhcp_buff3, 256);
866: my_syslog(MS_DHCP | LOG_INFO,
1.1.1.2 ! misho 867: (context->flags & CONTEXT_RA_STATELESS) ?
! 868: _("%s stateless on %s%.0s%.0s%s") :
! 869: (context->flags & CONTEXT_STATIC) ?
! 870: _("%s, static leases only on %.0s%s%s%.0s") :
! 871: (context->flags & CONTEXT_PROXY) ?
! 872: _("%s, proxy on subnet %.0s%s%.0s%.0s") :
! 873: _("%s, IP range %s -- %s%s%.0s"),
! 874: (family != AF_INET) ? "DHCPv6" : "DHCP",
1.1 misho 875: daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
876: }
877:
878: #ifdef HAVE_DHCP6
1.1.1.2 ! misho 879: if (context->flags & CONTEXT_TEMPLATE)
! 880: {
! 881: strcpy(daemon->addrbuff, context->template_interface);
! 882: template = "";
! 883: }
! 884:
! 885: if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
1.1 misho 886: my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
1.1.1.2 ! misho 887:
1.1 misho 888: if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
889: my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
890: #endif
891:
892: }
893:
1.1.1.2 ! misho 894: void log_relay(int family, struct dhcp_relay *relay)
! 895: {
! 896: inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
! 897: inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
! 898:
! 899: if (relay->interface)
! 900: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
! 901: else
! 902: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
! 903: }
! 904:
1.1 misho 905: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>