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