Annotation of embedaddon/dnsmasq/src/dhcp-common.c, revision 1.1.1.4
1.1.1.4 ! misho 1: /* dnsmasq is Copyright (c) 2000-2021 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: {
1.1.1.4 ! misho 23: /* These each hold a DHCP option max size 255
! 24: and get a terminating zero added */
! 25: daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
! 26: daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ);
! 27: daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
1.1 misho 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: {
1.1.1.4 ! misho 41: ssize_t sz, new_sz;
1.1 misho 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:
1.1.1.4 ! misho 68: while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
! 69:
! 70: /* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway.
! 71: If that happens we get EAGAIN here because the socket is non-blocking.
! 72: Use the result of the original testing recvmsg as long as the buffer
! 73: was big enough. There's a small race here that may lose the odd packet,
! 74: but it's UDP anyway. */
! 75:
! 76: if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
! 77: new_sz = sz;
1.1 misho 78:
1.1.1.4 ! misho 79: return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
1.1 misho 80: }
81:
82: struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
83: {
84: struct tag_if *exprs;
85: struct dhcp_netid_list *list;
86:
87: for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
88: if (match_netid(exprs->tag, tags, 1))
89: for (list = exprs->set; list; list = list->next)
90: {
91: list->list->next = tags;
92: tags = list->list;
93: }
94:
95: return tags;
96: }
97:
98:
99: struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
100: {
101: struct dhcp_netid *tagif = run_tag_if(tags);
102: struct dhcp_opt *opt;
103: struct dhcp_opt *tmp;
104:
105: /* flag options which are valid with the current tag set (sans context tags) */
106: for (opt = opts; opt; opt = opt->next)
107: {
108: opt->flags &= ~DHOPT_TAGOK;
109: if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
110: match_netid(opt->netid, tagif, 0))
111: opt->flags |= DHOPT_TAGOK;
112: }
113:
114: /* now flag options which are valid, including the context tags,
115: otherwise valid options are inhibited if we found a higher priority one above */
116: if (context_tags)
117: {
118: struct dhcp_netid *last_tag;
119:
120: for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
121: last_tag->next = tags;
122: tagif = run_tag_if(context_tags);
123:
124: /* reset stuff with tag:!<tag> which now matches. */
125: for (opt = opts; opt; opt = opt->next)
126: if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
127: (opt->flags & DHOPT_TAGOK) &&
128: !match_netid(opt->netid, tagif, 0))
129: opt->flags &= ~DHOPT_TAGOK;
130:
131: for (opt = opts; opt; opt = opt->next)
132: if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
133: match_netid(opt->netid, tagif, 0))
134: {
135: struct dhcp_opt *tmp;
136: for (tmp = opts; tmp; tmp = tmp->next)
137: if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
138: break;
139: if (!tmp)
140: opt->flags |= DHOPT_TAGOK;
141: }
142: }
143:
144: /* now flag untagged options which are not overridden by tagged ones */
145: for (opt = opts; opt; opt = opt->next)
146: if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
147: {
148: for (tmp = opts; tmp; tmp = tmp->next)
149: if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
150: break;
151: if (!tmp)
152: opt->flags |= DHOPT_TAGOK;
153: else if (!tmp->netid)
154: my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
155: }
156:
157: /* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
158: for (opt = opts; opt; opt = opt->next)
159: if (opt->flags & DHOPT_TAGOK)
160: for (tmp = opt->next; tmp; tmp = tmp->next)
161: if (tmp->opt == opt->opt)
162: tmp->flags &= ~DHOPT_TAGOK;
163:
164: return tagif;
165: }
166:
167: /* Is every member of check matched by a member of pool?
168: If tagnotneeded, untagged is OK */
169: int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
170: {
171: struct dhcp_netid *tmp1;
172:
173: if (!check && !tagnotneeded)
174: return 0;
175:
176: for (; check; check = check->next)
177: {
178: /* '#' for not is for backwards compat. */
179: if (check->net[0] != '!' && check->net[0] != '#')
180: {
181: for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
182: if (strcmp(check->net, tmp1->net) == 0)
183: break;
184: if (!tmp1)
185: return 0;
186: }
187: else
188: for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
189: if (strcmp((check->net)+1, tmp1->net) == 0)
190: return 0;
191: }
192: return 1;
193: }
194:
195: /* return domain or NULL if none. */
196: char *strip_hostname(char *hostname)
197: {
198: char *dot = strchr(hostname, '.');
199:
200: if (!dot)
201: return NULL;
202:
203: *dot = 0; /* truncate */
204: if (strlen(dot+1) != 0)
205: return dot+1;
206:
207: return NULL;
208: }
209:
210: void log_tags(struct dhcp_netid *netid, u32 xid)
211: {
212: if (netid && option_bool(OPT_LOG_OPTS))
213: {
214: char *s = daemon->namebuff;
215: for (*s = 0; netid; netid = netid->next)
216: {
217: /* kill dupes. */
218: struct dhcp_netid *n;
219:
220: for (n = netid->next; n; n = n->next)
221: if (strcmp(netid->net, n->net) == 0)
222: break;
223:
224: if (!n)
225: {
226: strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
227: if (netid->next)
228: strncat (s, ", ", (MAXDNAME-1) - strlen(s));
229: }
230: }
231: my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
232: }
233: }
234:
235: int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
236: {
237: int i;
238:
239: if (o->len > len)
240: return 0;
241:
242: if (o->len == 0)
243: return 1;
244:
245: if (o->flags & DHOPT_HEX)
246: {
247: if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
248: return 1;
249: }
250: else
251: for (i = 0; i <= (len - o->len); )
252: {
253: if (memcmp(o->val, p + i, o->len) == 0)
254: return 1;
255:
256: if (o->flags & DHOPT_STRING)
257: i++;
258: else
259: i += o->len;
260: }
261:
262: return 0;
263: }
264:
1.1.1.2 misho 265: int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
266: {
267: struct hwaddr_config *conf_addr;
268:
269: for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
270: if (conf_addr->wildcard_mask == 0 &&
271: conf_addr->hwaddr_len == len &&
272: (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
273: memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
274: return 1;
275:
276: return 0;
277: }
278:
279: static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
280: {
281: if (!context) /* called via find_config() from lease_update_from_configs() */
282: return 1;
283:
284: #ifdef HAVE_DHCP6
1.1.1.4 ! misho 285: if (context->flags & CONTEXT_V6)
! 286: {
! 287: struct addrlist *addr_list;
1.1.1.2 misho 288:
1.1.1.4 ! misho 289: if (!(config->flags & CONFIG_ADDR6))
! 290: return 1;
! 291:
! 292: for (; context; context = context->current)
! 293: for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
! 294: {
! 295: if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
! 296: return 1;
! 297:
! 298: if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
! 299: return 1;
! 300: }
! 301: }
! 302: else
1.1.1.2 misho 303: #endif
1.1.1.4 ! misho 304: {
! 305: if (!(config->flags & CONFIG_ADDR))
1.1.1.2 misho 306: return 1;
1.1.1.4 ! misho 307:
! 308: for (; context; context = context->current)
! 309: if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
! 310: return 1;
! 311: }
1.1.1.2 misho 312:
313: return 0;
314: }
315:
1.1.1.4 ! misho 316: static struct dhcp_config *find_config_match(struct dhcp_config *configs,
! 317: struct dhcp_context *context,
! 318: unsigned char *clid, int clid_len,
! 319: unsigned char *hwaddr, int hw_len,
! 320: int hw_type, char *hostname,
! 321: struct dhcp_netid *tags, int tag_not_needed)
1.1.1.2 misho 322: {
323: int count, new;
324: struct dhcp_config *config, *candidate;
325: struct hwaddr_config *conf_addr;
326:
327: if (clid)
328: for (config = configs; config; config = config->next)
329: if (config->flags & CONFIG_CLID)
330: {
331: if (config->clid_len == clid_len &&
332: memcmp(config->clid, clid, clid_len) == 0 &&
1.1.1.4 ! misho 333: is_config_in_context(context, config) &&
! 334: match_netid(config->filter, tags, tag_not_needed))
! 335:
1.1.1.2 misho 336: return config;
337:
338: /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
339: cope with that here. This is IPv4 only. context==NULL implies IPv4,
340: see lease_update_from_configs() */
341: if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
342: memcmp(config->clid, clid+1, clid_len-1) == 0 &&
1.1.1.4 ! misho 343: is_config_in_context(context, config) &&
! 344: match_netid(config->filter, tags, tag_not_needed))
1.1.1.2 misho 345: return config;
346: }
347:
348:
349: if (hwaddr)
350: for (config = configs; config; config = config->next)
351: if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
1.1.1.4 ! misho 352: is_config_in_context(context, config) &&
! 353: match_netid(config->filter, tags, tag_not_needed))
1.1.1.2 misho 354: return config;
355:
356: if (hostname && context)
357: for (config = configs; config; config = config->next)
358: if ((config->flags & CONFIG_NAME) &&
359: hostname_isequal(config->hostname, hostname) &&
1.1.1.4 ! misho 360: is_config_in_context(context, config) &&
! 361: match_netid(config->filter, tags, tag_not_needed))
1.1.1.2 misho 362: return config;
363:
364:
365: if (!hwaddr)
366: return NULL;
367:
368: /* use match with fewest wildcard octets */
369: for (candidate = NULL, count = 0, config = configs; config; config = config->next)
1.1.1.4 ! misho 370: if (is_config_in_context(context, config) &&
! 371: match_netid(config->filter, tags, tag_not_needed))
1.1.1.2 misho 372: for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
373: if (conf_addr->wildcard_mask != 0 &&
374: conf_addr->hwaddr_len == hw_len &&
375: (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
376: (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
377: {
378: count = new;
379: candidate = config;
380: }
381:
382: return candidate;
383: }
384:
1.1.1.4 ! misho 385: /* Find tagged configs first. */
! 386: struct dhcp_config *find_config(struct dhcp_config *configs,
! 387: struct dhcp_context *context,
! 388: unsigned char *clid, int clid_len,
! 389: unsigned char *hwaddr, int hw_len,
! 390: int hw_type, char *hostname, struct dhcp_netid *tags)
! 391: {
! 392: struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
! 393:
! 394: if (!ret)
! 395: ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
! 396:
! 397: return ret;
! 398: }
! 399:
1.1 misho 400: void dhcp_update_configs(struct dhcp_config *configs)
401: {
402: /* Some people like to keep all static IP addresses in /etc/hosts.
403: This goes through /etc/hosts and sets static addresses for any DHCP config
404: records which don't have an address and whose name matches.
405: We take care to maintain the invariant that any IP address can appear
406: in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
407: restore the status-quo ante first. */
408:
409: struct dhcp_config *config, *conf_tmp;
410: struct crec *crec;
411: int prot = AF_INET;
412:
413: for (config = configs; config; config = config->next)
1.1.1.4 ! misho 414: {
1.1 misho 415: if (config->flags & CONFIG_ADDR_HOSTS)
1.1.1.4 ! misho 416: config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
! 417: #ifdef HAVE_DHCP6
! 418: if (config->flags & CONFIG_ADDR6_HOSTS)
! 419: config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
! 420: #endif
! 421: }
1.1 misho 422:
423: #ifdef HAVE_DHCP6
424: again:
425: #endif
426:
427: if (daemon->port != 0)
428: for (config = configs; config; config = config->next)
429: {
430: int conflags = CONFIG_ADDR;
431: int cacheflags = F_IPV4;
432:
433: #ifdef HAVE_DHCP6
434: if (prot == AF_INET6)
435: {
436: conflags = CONFIG_ADDR6;
437: cacheflags = F_IPV6;
438: }
439: #endif
440: if (!(config->flags & conflags) &&
441: (config->flags & CONFIG_NAME) &&
442: (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
443: (crec->flags & F_HOSTS))
444: {
445: if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
446: {
447: /* use primary (first) address */
1.1.1.2 misho 448: while (crec && !(crec->flags & F_REVERSE))
449: crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
450: if (!crec)
451: continue; /* should be never */
1.1.1.4 ! misho 452: inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
1.1.1.2 misho 453: my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
454: config->hostname, daemon->addrbuff);
1.1 misho 455: }
456:
457: if (prot == AF_INET &&
1.1.1.4 ! misho 458: (!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config))
1.1 misho 459: {
1.1.1.4 ! misho 460: config->addr = crec->addr.addr4;
1.1 misho 461: config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
462: continue;
463: }
464:
465: #ifdef HAVE_DHCP6
466: if (prot == AF_INET6 &&
1.1.1.4 ! misho 467: (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config))
1.1 misho 468: {
1.1.1.4 ! misho 469: /* host must have exactly one address if comming from /etc/hosts. */
! 470: if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
! 471: {
! 472: config->addr6->next = NULL;
! 473: config->addr6->flags = 0;
! 474: }
! 475:
! 476: if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
! 477: {
! 478: memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ);
! 479: config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
! 480: }
! 481:
1.1 misho 482: continue;
483: }
484: #endif
485:
1.1.1.4 ! misho 486: inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
1.1 misho 487: my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
488: daemon->addrbuff, config->hostname);
489:
490:
491: }
492: }
493:
494: #ifdef HAVE_DHCP6
495: if (prot == AF_INET)
496: {
497: prot = AF_INET6;
498: goto again;
499: }
500: #endif
501:
502: }
503:
504: #ifdef HAVE_LINUX_NETWORK
1.1.1.2 misho 505: char *whichdevice(void)
1.1 misho 506: {
507: /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
508: to that device. This is for the use case of (eg) OpenStack, which runs a new
509: dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
510: individual processes don't always see the packets they should.
1.1.1.2 misho 511: SO_BINDTODEVICE is only available Linux.
512:
513: Note that if wildcards are used in --interface, or --interface is not used at all,
514: or a configured interface doesn't yet exist, then more interfaces may arrive later,
515: so we can't safely assert there is only one interface and proceed.
516: */
1.1 misho 517:
518: struct irec *iface, *found;
1.1.1.2 misho 519: struct iname *if_tmp;
520:
521: if (!daemon->if_names)
522: return NULL;
1.1 misho 523:
1.1.1.2 misho 524: for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
525: if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
526: return NULL;
527:
1.1 misho 528: for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
529: if (iface->dhcp_ok)
530: {
531: if (!found)
532: found = iface;
533: else if (strcmp(found->name, iface->name) != 0)
1.1.1.2 misho 534: return NULL; /* more than one. */
1.1 misho 535: }
1.1.1.2 misho 536:
1.1 misho 537: if (found)
1.1.1.2 misho 538: return found->name;
539:
540: return NULL;
541: }
542:
543: void bindtodevice(char *device, int fd)
544: {
1.1.1.4 ! misho 545: size_t len = strlen(device)+1;
! 546: if (len > IFNAMSIZ)
! 547: len = IFNAMSIZ;
1.1.1.2 misho 548: /* only allowed by root. */
1.1.1.4 ! misho 549: if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
1.1.1.2 misho 550: errno != EPERM)
551: die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
1.1 misho 552: }
553: #endif
554:
555: static const struct opttab_t {
556: char *name;
557: u16 val, size;
558: } opttab[] = {
559: { "netmask", 1, OT_ADDR_LIST },
560: { "time-offset", 2, 4 },
561: { "router", 3, OT_ADDR_LIST },
562: { "dns-server", 6, OT_ADDR_LIST },
563: { "log-server", 7, OT_ADDR_LIST },
564: { "lpr-server", 9, OT_ADDR_LIST },
565: { "hostname", 12, OT_INTERNAL | OT_NAME },
566: { "boot-file-size", 13, 2 | OT_DEC },
567: { "domain-name", 15, OT_NAME },
568: { "swap-server", 16, OT_ADDR_LIST },
569: { "root-path", 17, OT_NAME },
570: { "extension-path", 18, OT_NAME },
571: { "ip-forward-enable", 19, 1 },
572: { "non-local-source-routing", 20, 1 },
573: { "policy-filter", 21, OT_ADDR_LIST },
574: { "max-datagram-reassembly", 22, 2 | OT_DEC },
575: { "default-ttl", 23, 1 | OT_DEC },
576: { "mtu", 26, 2 | OT_DEC },
577: { "all-subnets-local", 27, 1 },
578: { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
579: { "router-discovery", 31, 1 },
580: { "router-solicitation", 32, OT_ADDR_LIST },
581: { "static-route", 33, OT_ADDR_LIST },
582: { "trailer-encapsulation", 34, 1 },
583: { "arp-timeout", 35, 4 | OT_DEC },
584: { "ethernet-encap", 36, 1 },
585: { "tcp-ttl", 37, 1 },
586: { "tcp-keepalive", 38, 4 | OT_DEC },
587: { "nis-domain", 40, OT_NAME },
588: { "nis-server", 41, OT_ADDR_LIST },
589: { "ntp-server", 42, OT_ADDR_LIST },
590: { "vendor-encap", 43, OT_INTERNAL },
591: { "netbios-ns", 44, OT_ADDR_LIST },
592: { "netbios-dd", 45, OT_ADDR_LIST },
593: { "netbios-nodetype", 46, 1 },
594: { "netbios-scope", 47, 0 },
595: { "x-windows-fs", 48, OT_ADDR_LIST },
596: { "x-windows-dm", 49, OT_ADDR_LIST },
597: { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
598: { "lease-time", 51, OT_INTERNAL | OT_TIME },
599: { "option-overload", 52, OT_INTERNAL },
600: { "message-type", 53, OT_INTERNAL | OT_DEC },
601: { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
602: { "parameter-request", 55, OT_INTERNAL },
603: { "message", 56, OT_INTERNAL },
604: { "max-message-size", 57, OT_INTERNAL },
1.1.1.3 misho 605: { "T1", 58, OT_TIME},
606: { "T2", 59, OT_TIME},
1.1 misho 607: { "vendor-class", 60, 0 },
608: { "client-id", 61, OT_INTERNAL },
609: { "nis+-domain", 64, OT_NAME },
610: { "nis+-server", 65, OT_ADDR_LIST },
611: { "tftp-server", 66, OT_NAME },
612: { "bootfile-name", 67, OT_NAME },
613: { "mobile-ip-home", 68, OT_ADDR_LIST },
614: { "smtp-server", 69, OT_ADDR_LIST },
615: { "pop3-server", 70, OT_ADDR_LIST },
616: { "nntp-server", 71, OT_ADDR_LIST },
617: { "irc-server", 74, OT_ADDR_LIST },
618: { "user-class", 77, 0 },
1.1.1.4 ! misho 619: { "rapid-commit", 80, 0 },
1.1 misho 620: { "FQDN", 81, OT_INTERNAL },
621: { "agent-id", 82, OT_INTERNAL },
622: { "client-arch", 93, 2 | OT_DEC },
623: { "client-interface-id", 94, 0 },
624: { "client-machine-id", 97, 0 },
625: { "subnet-select", 118, OT_INTERNAL },
626: { "domain-search", 119, OT_RFC1035_NAME },
627: { "sip-server", 120, 0 },
628: { "classless-static-route", 121, 0 },
629: { "vendor-id-encap", 125, 0 },
1.1.1.4 ! misho 630: { "tftp-server-address", 150, OT_ADDR_LIST },
1.1 misho 631: { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
632: { NULL, 0, 0 }
633: };
634:
635: #ifdef HAVE_DHCP6
636: static const struct opttab_t opttab6[] = {
637: { "client-id", 1, OT_INTERNAL },
638: { "server-id", 2, OT_INTERNAL },
639: { "ia-na", 3, OT_INTERNAL },
640: { "ia-ta", 4, OT_INTERNAL },
641: { "iaaddr", 5, OT_INTERNAL },
642: { "oro", 6, OT_INTERNAL },
643: { "preference", 7, OT_INTERNAL | OT_DEC },
644: { "unicast", 12, OT_INTERNAL },
645: { "status", 13, OT_INTERNAL },
646: { "rapid-commit", 14, OT_INTERNAL },
647: { "user-class", 15, OT_INTERNAL | OT_CSTRING },
648: { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
649: { "vendor-opts", 17, OT_INTERNAL },
650: { "sip-server-domain", 21, OT_RFC1035_NAME },
651: { "sip-server", 22, OT_ADDR_LIST },
652: { "dns-server", 23, OT_ADDR_LIST },
653: { "domain-search", 24, OT_RFC1035_NAME },
654: { "nis-server", 27, OT_ADDR_LIST },
655: { "nis+-server", 28, OT_ADDR_LIST },
656: { "nis-domain", 29, OT_RFC1035_NAME },
657: { "nis+-domain", 30, OT_RFC1035_NAME },
658: { "sntp-server", 31, OT_ADDR_LIST },
659: { "information-refresh-time", 32, OT_TIME },
660: { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
1.1.1.4 ! misho 661: { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
1.1 misho 662: { "bootfile-url", 59, OT_NAME },
663: { "bootfile-param", 60, OT_CSTRING },
664: { NULL, 0, 0 }
665: };
666: #endif
667:
668:
669:
670: void display_opts(void)
671: {
672: int i;
673:
674: printf(_("Known DHCP options:\n"));
675:
676: for (i = 0; opttab[i].name; i++)
677: if (!(opttab[i].size & OT_INTERNAL))
678: printf("%3d %s\n", opttab[i].val, opttab[i].name);
679: }
680:
681: #ifdef HAVE_DHCP6
682: void display_opts6(void)
683: {
684: int i;
685: printf(_("Known DHCPv6 options:\n"));
686:
687: for (i = 0; opttab6[i].name; i++)
688: if (!(opttab6[i].size & OT_INTERNAL))
689: printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
690: }
691: #endif
692:
1.1.1.2 misho 693: int lookup_dhcp_opt(int prot, char *name)
1.1 misho 694: {
695: const struct opttab_t *t;
696: int i;
697:
1.1.1.2 misho 698: (void)prot;
699:
1.1 misho 700: #ifdef HAVE_DHCP6
701: if (prot == AF_INET6)
702: t = opttab6;
703: else
704: #endif
705: t = opttab;
706:
707: for (i = 0; t[i].name; i++)
708: if (strcasecmp(t[i].name, name) == 0)
709: return t[i].val;
710:
1.1.1.2 misho 711: return -1;
1.1 misho 712: }
713:
1.1.1.2 misho 714: int lookup_dhcp_len(int prot, int val)
1.1 misho 715: {
716: const struct opttab_t *t;
717: int i;
718:
1.1.1.2 misho 719: (void)prot;
720:
1.1 misho 721: #ifdef HAVE_DHCP6
722: if (prot == AF_INET6)
723: t = opttab6;
724: else
725: #endif
726: t = opttab;
727:
728: for (i = 0; t[i].name; i++)
729: if (val == t[i].val)
730: return t[i].size & ~OT_DEC;
731:
732: return 0;
733: }
734:
735: char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
736: {
737: int o, i, j, nodecode = 0;
738: const struct opttab_t *ot = opttab;
739:
740: #ifdef HAVE_DHCP6
741: if (prot == AF_INET6)
742: ot = opttab6;
743: #endif
744:
745: for (o = 0; ot[o].name; o++)
746: if (ot[o].val == opt)
747: {
748: if (buf)
749: {
750: memset(buf, 0, buf_len);
751:
752: if (ot[o].size & OT_ADDR_LIST)
753: {
1.1.1.4 ! misho 754: union all_addr addr;
1.1 misho 755: int addr_len = INADDRSZ;
756:
757: #ifdef HAVE_DHCP6
758: if (prot == AF_INET6)
759: addr_len = IN6ADDRSZ;
760: #endif
761: for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
762: {
763: if (i != 0)
764: strncat(buf, ", ", buf_len - strlen(buf));
765: /* align */
766: memcpy(&addr, &val[i], addr_len);
767: inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
768: strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
769: }
770: }
771: else if (ot[o].size & OT_NAME)
772: for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
773: {
774: char c = val[i];
775: if (isprint((int)c))
776: buf[j++] = c;
777: }
778: #ifdef HAVE_DHCP6
779: /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
780: else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
781: {
782: i = 0, j = 0;
783: while (i < opt_len && val[i] != 0)
784: {
785: int k, l = i + val[i] + 1;
786: for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
787: {
788: char c = val[k];
789: if (isprint((int)c))
790: buf[j++] = c;
791: }
792: i = l;
793: if (val[i] != 0 && j < buf_len)
794: buf[j++] = '.';
795: }
796: }
797: else if ((ot[o].size & OT_CSTRING))
798: {
799: int k, len;
800: unsigned char *p;
801:
802: i = 0, j = 0;
803: while (1)
804: {
805: p = &val[i];
806: GETSHORT(len, p);
807: for (k = 0; k < len && j < buf_len; k++)
808: {
809: char c = *p++;
810: if (isprint((int)c))
811: buf[j++] = c;
812: }
813: i += len +2;
814: if (i >= opt_len)
815: break;
816:
817: if (j < buf_len)
818: buf[j++] = ',';
819: }
820: }
821: #endif
822: else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
823: {
824: unsigned int dec = 0;
825:
826: for (i = 0; i < opt_len; i++)
827: dec = (dec << 8) | val[i];
828:
829: if (ot[o].size & OT_TIME)
830: prettyprint_time(buf, dec);
831: else
832: sprintf(buf, "%u", dec);
833: }
834: else
835: nodecode = 1;
836: }
837: break;
838: }
839:
840: if (opt_len != 0 && buf && (!ot[o].name || nodecode))
841: {
842: int trunc = 0;
843: if (opt_len > 14)
844: {
845: trunc = 1;
846: opt_len = 14;
847: }
848: print_mac(buf, val, opt_len);
849: if (trunc)
850: strncat(buf, "...", buf_len - strlen(buf));
851:
852:
853: }
854:
855: return ot[o].name ? ot[o].name : "";
856:
857: }
858:
859: void log_context(int family, struct dhcp_context *context)
860: {
861: /* Cannot use dhcp_buff* for RA contexts */
862:
863: void *start = &context->start;
864: void *end = &context->end;
865: char *template = "", *p = daemon->namebuff;
866:
867: *p = 0;
868:
869: #ifdef HAVE_DHCP6
870: if (family == AF_INET6)
871: {
872: struct in6_addr subnet = context->start6;
873: if (!(context->flags & CONTEXT_TEMPLATE))
874: setaddr6part(&subnet, 0);
875: inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
876: start = &context->start6;
877: end = &context->end6;
878: }
879: #endif
880:
881: if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
882: strcpy(daemon->namebuff, _(", prefix deprecated"));
883: else
884: {
885: p += sprintf(p, _(", lease time "));
886: prettyprint_time(p, context->lease_time);
887: p += strlen(p);
888: }
889:
890: #ifdef HAVE_DHCP6
891: if (context->flags & CONTEXT_CONSTRUCTED)
892: {
893: char ifrn_name[IFNAMSIZ];
894:
895: template = p;
896: p += sprintf(p, ", ");
897:
1.1.1.2 misho 898: if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
899: sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
1.1 misho 900: }
1.1.1.2 misho 901: else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
1.1 misho 902: {
903: template = p;
904: p += sprintf(p, ", ");
1.1.1.2 misho 905:
1.1 misho 906: sprintf(p, "template for %s", context->template_interface);
907: }
908: #endif
909:
1.1.1.2 misho 910: if (!(context->flags & CONTEXT_OLD) &&
911: ((context->flags & CONTEXT_DHCP) || family == AF_INET))
1.1 misho 912: {
1.1.1.2 misho 913: #ifdef HAVE_DHCP6
914: if (context->flags & CONTEXT_RA_STATELESS)
915: {
916: if (context->flags & CONTEXT_TEMPLATE)
1.1.1.4 ! misho 917: strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
1.1.1.2 misho 918: else
919: strcpy(daemon->dhcp_buff, daemon->addrbuff);
920: }
921: else
922: #endif
1.1.1.4 ! misho 923: inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
! 924: inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
1.1 misho 925: my_syslog(MS_DHCP | LOG_INFO,
1.1.1.2 misho 926: (context->flags & CONTEXT_RA_STATELESS) ?
927: _("%s stateless on %s%.0s%.0s%s") :
928: (context->flags & CONTEXT_STATIC) ?
929: _("%s, static leases only on %.0s%s%s%.0s") :
930: (context->flags & CONTEXT_PROXY) ?
931: _("%s, proxy on subnet %.0s%s%.0s%.0s") :
932: _("%s, IP range %s -- %s%s%.0s"),
933: (family != AF_INET) ? "DHCPv6" : "DHCP",
1.1 misho 934: daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
935: }
936:
937: #ifdef HAVE_DHCP6
1.1.1.2 misho 938: if (context->flags & CONTEXT_TEMPLATE)
939: {
940: strcpy(daemon->addrbuff, context->template_interface);
941: template = "";
942: }
943:
944: if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
1.1 misho 945: my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
1.1.1.2 misho 946:
1.1 misho 947: if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
948: my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
949: #endif
950:
951: }
952:
1.1.1.2 misho 953: void log_relay(int family, struct dhcp_relay *relay)
954: {
955: inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
956: inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
957:
958: if (relay->interface)
959: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
960: else
961: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
962: }
963:
1.1 misho 964: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>