PageRenderTime 29ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/release/src/router/dnsmasq/src/dhcp-common.c

https://gitlab.com/envieidoc/tomato
C | 905 lines | 717 code | 130 blank | 58 comment | 267 complexity | e2d08c17afc6fafe3984838fe15ab18e MD5 | raw file
  1. /* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 dated June, 1991, or
  5. (at your option) version 3 dated 29 June, 2007.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. #include "dnsmasq.h"
  14. #ifdef HAVE_DHCP
  15. void dhcp_common_init(void)
  16. {
  17. /* These each hold a DHCP option max size 255
  18. and get a terminating zero added */
  19. daemon->dhcp_buff = safe_malloc(256);
  20. daemon->dhcp_buff2 = safe_malloc(256);
  21. daemon->dhcp_buff3 = safe_malloc(256);
  22. /* dhcp_packet is used by v4 and v6, outpacket only by v6
  23. sizeof(struct dhcp_packet) is as good an initial size as any,
  24. even for v6 */
  25. expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
  26. #ifdef HAVE_DHCP6
  27. if (daemon->dhcp6)
  28. expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
  29. #endif
  30. }
  31. ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
  32. {
  33. ssize_t sz;
  34. while (1)
  35. {
  36. msg->msg_flags = 0;
  37. while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
  38. if (sz == -1)
  39. return -1;
  40. if (!(msg->msg_flags & MSG_TRUNC))
  41. break;
  42. /* Very new Linux kernels return the actual size needed,
  43. older ones always return truncated size */
  44. if ((size_t)sz == msg->msg_iov->iov_len)
  45. {
  46. if (!expand_buf(msg->msg_iov, sz + 100))
  47. return -1;
  48. }
  49. else
  50. {
  51. expand_buf(msg->msg_iov, sz);
  52. break;
  53. }
  54. }
  55. while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
  56. return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
  57. }
  58. struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
  59. {
  60. struct tag_if *exprs;
  61. struct dhcp_netid_list *list;
  62. for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
  63. if (match_netid(exprs->tag, tags, 1))
  64. for (list = exprs->set; list; list = list->next)
  65. {
  66. list->list->next = tags;
  67. tags = list->list;
  68. }
  69. return tags;
  70. }
  71. struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
  72. {
  73. struct dhcp_netid *tagif = run_tag_if(tags);
  74. struct dhcp_opt *opt;
  75. struct dhcp_opt *tmp;
  76. /* flag options which are valid with the current tag set (sans context tags) */
  77. for (opt = opts; opt; opt = opt->next)
  78. {
  79. opt->flags &= ~DHOPT_TAGOK;
  80. if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
  81. match_netid(opt->netid, tagif, 0))
  82. opt->flags |= DHOPT_TAGOK;
  83. }
  84. /* now flag options which are valid, including the context tags,
  85. otherwise valid options are inhibited if we found a higher priority one above */
  86. if (context_tags)
  87. {
  88. struct dhcp_netid *last_tag;
  89. for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
  90. last_tag->next = tags;
  91. tagif = run_tag_if(context_tags);
  92. /* reset stuff with tag:!<tag> which now matches. */
  93. for (opt = opts; opt; opt = opt->next)
  94. if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
  95. (opt->flags & DHOPT_TAGOK) &&
  96. !match_netid(opt->netid, tagif, 0))
  97. opt->flags &= ~DHOPT_TAGOK;
  98. for (opt = opts; opt; opt = opt->next)
  99. if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
  100. match_netid(opt->netid, tagif, 0))
  101. {
  102. struct dhcp_opt *tmp;
  103. for (tmp = opts; tmp; tmp = tmp->next)
  104. if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
  105. break;
  106. if (!tmp)
  107. opt->flags |= DHOPT_TAGOK;
  108. }
  109. }
  110. /* now flag untagged options which are not overridden by tagged ones */
  111. for (opt = opts; opt; opt = opt->next)
  112. if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
  113. {
  114. for (tmp = opts; tmp; tmp = tmp->next)
  115. if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
  116. break;
  117. if (!tmp)
  118. opt->flags |= DHOPT_TAGOK;
  119. else if (!tmp->netid)
  120. my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
  121. }
  122. /* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
  123. for (opt = opts; opt; opt = opt->next)
  124. if (opt->flags & DHOPT_TAGOK)
  125. for (tmp = opt->next; tmp; tmp = tmp->next)
  126. if (tmp->opt == opt->opt)
  127. tmp->flags &= ~DHOPT_TAGOK;
  128. return tagif;
  129. }
  130. /* Is every member of check matched by a member of pool?
  131. If tagnotneeded, untagged is OK */
  132. int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
  133. {
  134. struct dhcp_netid *tmp1;
  135. if (!check && !tagnotneeded)
  136. return 0;
  137. for (; check; check = check->next)
  138. {
  139. /* '#' for not is for backwards compat. */
  140. if (check->net[0] != '!' && check->net[0] != '#')
  141. {
  142. for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
  143. if (strcmp(check->net, tmp1->net) == 0)
  144. break;
  145. if (!tmp1)
  146. return 0;
  147. }
  148. else
  149. for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
  150. if (strcmp((check->net)+1, tmp1->net) == 0)
  151. return 0;
  152. }
  153. return 1;
  154. }
  155. /* return domain or NULL if none. */
  156. char *strip_hostname(char *hostname)
  157. {
  158. char *dot = strchr(hostname, '.');
  159. if (!dot)
  160. return NULL;
  161. *dot = 0; /* truncate */
  162. if (strlen(dot+1) != 0)
  163. return dot+1;
  164. return NULL;
  165. }
  166. void log_tags(struct dhcp_netid *netid, u32 xid)
  167. {
  168. if (netid && option_bool(OPT_LOG_OPTS))
  169. {
  170. char *s = daemon->namebuff;
  171. for (*s = 0; netid; netid = netid->next)
  172. {
  173. /* kill dupes. */
  174. struct dhcp_netid *n;
  175. for (n = netid->next; n; n = n->next)
  176. if (strcmp(netid->net, n->net) == 0)
  177. break;
  178. if (!n)
  179. {
  180. strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
  181. if (netid->next)
  182. strncat (s, ", ", (MAXDNAME-1) - strlen(s));
  183. }
  184. }
  185. my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
  186. }
  187. }
  188. int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
  189. {
  190. int i;
  191. if (o->len > len)
  192. return 0;
  193. if (o->len == 0)
  194. return 1;
  195. if (o->flags & DHOPT_HEX)
  196. {
  197. if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
  198. return 1;
  199. }
  200. else
  201. for (i = 0; i <= (len - o->len); )
  202. {
  203. if (memcmp(o->val, p + i, o->len) == 0)
  204. return 1;
  205. if (o->flags & DHOPT_STRING)
  206. i++;
  207. else
  208. i += o->len;
  209. }
  210. return 0;
  211. }
  212. int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
  213. {
  214. struct hwaddr_config *conf_addr;
  215. for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
  216. if (conf_addr->wildcard_mask == 0 &&
  217. conf_addr->hwaddr_len == len &&
  218. (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
  219. memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
  220. return 1;
  221. return 0;
  222. }
  223. static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
  224. {
  225. if (!context) /* called via find_config() from lease_update_from_configs() */
  226. return 1;
  227. if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
  228. return 1;
  229. #ifdef HAVE_DHCP6
  230. if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
  231. return 1;
  232. #endif
  233. for (; context; context = context->current)
  234. #ifdef HAVE_DHCP6
  235. if (context->flags & CONTEXT_V6)
  236. {
  237. if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
  238. return 1;
  239. }
  240. else
  241. #endif
  242. if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
  243. return 1;
  244. return 0;
  245. }
  246. struct dhcp_config *find_config(struct dhcp_config *configs,
  247. struct dhcp_context *context,
  248. unsigned char *clid, int clid_len,
  249. unsigned char *hwaddr, int hw_len,
  250. int hw_type, char *hostname)
  251. {
  252. int count, new;
  253. struct dhcp_config *config, *candidate;
  254. struct hwaddr_config *conf_addr;
  255. if (clid)
  256. for (config = configs; config; config = config->next)
  257. if (config->flags & CONFIG_CLID)
  258. {
  259. if (config->clid_len == clid_len &&
  260. memcmp(config->clid, clid, clid_len) == 0 &&
  261. is_config_in_context(context, config))
  262. return config;
  263. /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
  264. cope with that here. This is IPv4 only. context==NULL implies IPv4,
  265. see lease_update_from_configs() */
  266. if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
  267. memcmp(config->clid, clid+1, clid_len-1) == 0 &&
  268. is_config_in_context(context, config))
  269. return config;
  270. }
  271. if (hwaddr)
  272. for (config = configs; config; config = config->next)
  273. if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
  274. is_config_in_context(context, config))
  275. return config;
  276. if (hostname && context)
  277. for (config = configs; config; config = config->next)
  278. if ((config->flags & CONFIG_NAME) &&
  279. hostname_isequal(config->hostname, hostname) &&
  280. is_config_in_context(context, config))
  281. return config;
  282. if (!hwaddr)
  283. return NULL;
  284. /* use match with fewest wildcard octets */
  285. for (candidate = NULL, count = 0, config = configs; config; config = config->next)
  286. if (is_config_in_context(context, config))
  287. for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
  288. if (conf_addr->wildcard_mask != 0 &&
  289. conf_addr->hwaddr_len == hw_len &&
  290. (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
  291. (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
  292. {
  293. count = new;
  294. candidate = config;
  295. }
  296. return candidate;
  297. }
  298. void dhcp_update_configs(struct dhcp_config *configs)
  299. {
  300. /* Some people like to keep all static IP addresses in /etc/hosts.
  301. This goes through /etc/hosts and sets static addresses for any DHCP config
  302. records which don't have an address and whose name matches.
  303. We take care to maintain the invariant that any IP address can appear
  304. in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
  305. restore the status-quo ante first. */
  306. struct dhcp_config *config, *conf_tmp;
  307. struct crec *crec;
  308. int prot = AF_INET;
  309. for (config = configs; config; config = config->next)
  310. if (config->flags & CONFIG_ADDR_HOSTS)
  311. config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
  312. #ifdef HAVE_DHCP6
  313. again:
  314. #endif
  315. if (daemon->port != 0)
  316. for (config = configs; config; config = config->next)
  317. {
  318. int conflags = CONFIG_ADDR;
  319. int cacheflags = F_IPV4;
  320. #ifdef HAVE_DHCP6
  321. if (prot == AF_INET6)
  322. {
  323. conflags = CONFIG_ADDR6;
  324. cacheflags = F_IPV6;
  325. }
  326. #endif
  327. if (!(config->flags & conflags) &&
  328. (config->flags & CONFIG_NAME) &&
  329. (crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
  330. (crec->flags & F_HOSTS))
  331. {
  332. if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
  333. {
  334. /* use primary (first) address */
  335. while (crec && !(crec->flags & F_REVERSE))
  336. crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
  337. if (!crec)
  338. continue; /* should be never */
  339. inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
  340. my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
  341. config->hostname, daemon->addrbuff);
  342. }
  343. if (prot == AF_INET &&
  344. (!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
  345. {
  346. config->addr = crec->addr.addr.addr.addr4;
  347. config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
  348. continue;
  349. }
  350. #ifdef HAVE_DHCP6
  351. if (prot == AF_INET6 &&
  352. (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
  353. {
  354. memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
  355. config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
  356. continue;
  357. }
  358. #endif
  359. inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
  360. my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
  361. daemon->addrbuff, config->hostname);
  362. }
  363. }
  364. #ifdef HAVE_DHCP6
  365. if (prot == AF_INET)
  366. {
  367. prot = AF_INET6;
  368. goto again;
  369. }
  370. #endif
  371. }
  372. #ifdef HAVE_LINUX_NETWORK
  373. char *whichdevice(void)
  374. {
  375. /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
  376. to that device. This is for the use case of (eg) OpenStack, which runs a new
  377. dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
  378. individual processes don't always see the packets they should.
  379. SO_BINDTODEVICE is only available Linux.
  380. Note that if wildcards are used in --interface, or --interface is not used at all,
  381. or a configured interface doesn't yet exist, then more interfaces may arrive later,
  382. so we can't safely assert there is only one interface and proceed.
  383. */
  384. struct irec *iface, *found;
  385. struct iname *if_tmp;
  386. if (!daemon->if_names)
  387. return NULL;
  388. for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
  389. if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
  390. return NULL;
  391. for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
  392. if (iface->dhcp_ok)
  393. {
  394. if (!found)
  395. found = iface;
  396. else if (strcmp(found->name, iface->name) != 0)
  397. return NULL; /* more than one. */
  398. }
  399. if (found)
  400. return found->name;
  401. return NULL;
  402. }
  403. void bindtodevice(char *device, int fd)
  404. {
  405. struct ifreq ifr;
  406. strcpy(ifr.ifr_name, device);
  407. /* only allowed by root. */
  408. if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
  409. errno != EPERM)
  410. die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
  411. }
  412. #endif
  413. static const struct opttab_t {
  414. char *name;
  415. u16 val, size;
  416. } opttab[] = {
  417. { "netmask", 1, OT_ADDR_LIST },
  418. { "time-offset", 2, 4 },
  419. { "router", 3, OT_ADDR_LIST },
  420. { "dns-server", 6, OT_ADDR_LIST },
  421. { "log-server", 7, OT_ADDR_LIST },
  422. { "lpr-server", 9, OT_ADDR_LIST },
  423. { "hostname", 12, OT_INTERNAL | OT_NAME },
  424. { "boot-file-size", 13, 2 | OT_DEC },
  425. { "domain-name", 15, OT_NAME },
  426. { "swap-server", 16, OT_ADDR_LIST },
  427. { "root-path", 17, OT_NAME },
  428. { "extension-path", 18, OT_NAME },
  429. { "ip-forward-enable", 19, 1 },
  430. { "non-local-source-routing", 20, 1 },
  431. { "policy-filter", 21, OT_ADDR_LIST },
  432. { "max-datagram-reassembly", 22, 2 | OT_DEC },
  433. { "default-ttl", 23, 1 | OT_DEC },
  434. { "mtu", 26, 2 | OT_DEC },
  435. { "all-subnets-local", 27, 1 },
  436. { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
  437. { "router-discovery", 31, 1 },
  438. { "router-solicitation", 32, OT_ADDR_LIST },
  439. { "static-route", 33, OT_ADDR_LIST },
  440. { "trailer-encapsulation", 34, 1 },
  441. { "arp-timeout", 35, 4 | OT_DEC },
  442. { "ethernet-encap", 36, 1 },
  443. { "tcp-ttl", 37, 1 },
  444. { "tcp-keepalive", 38, 4 | OT_DEC },
  445. { "nis-domain", 40, OT_NAME },
  446. { "nis-server", 41, OT_ADDR_LIST },
  447. { "ntp-server", 42, OT_ADDR_LIST },
  448. { "vendor-encap", 43, OT_INTERNAL },
  449. { "netbios-ns", 44, OT_ADDR_LIST },
  450. { "netbios-dd", 45, OT_ADDR_LIST },
  451. { "netbios-nodetype", 46, 1 },
  452. { "netbios-scope", 47, 0 },
  453. { "x-windows-fs", 48, OT_ADDR_LIST },
  454. { "x-windows-dm", 49, OT_ADDR_LIST },
  455. { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
  456. { "lease-time", 51, OT_INTERNAL | OT_TIME },
  457. { "option-overload", 52, OT_INTERNAL },
  458. { "message-type", 53, OT_INTERNAL | OT_DEC },
  459. { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
  460. { "parameter-request", 55, OT_INTERNAL },
  461. { "message", 56, OT_INTERNAL },
  462. { "max-message-size", 57, OT_INTERNAL },
  463. { "T1", 58, OT_TIME},
  464. { "T2", 59, OT_TIME},
  465. { "vendor-class", 60, 0 },
  466. { "client-id", 61, OT_INTERNAL },
  467. { "nis+-domain", 64, OT_NAME },
  468. { "nis+-server", 65, OT_ADDR_LIST },
  469. { "tftp-server", 66, OT_NAME },
  470. { "bootfile-name", 67, OT_NAME },
  471. { "mobile-ip-home", 68, OT_ADDR_LIST },
  472. { "smtp-server", 69, OT_ADDR_LIST },
  473. { "pop3-server", 70, OT_ADDR_LIST },
  474. { "nntp-server", 71, OT_ADDR_LIST },
  475. { "irc-server", 74, OT_ADDR_LIST },
  476. { "user-class", 77, 0 },
  477. { "FQDN", 81, OT_INTERNAL },
  478. { "agent-id", 82, OT_INTERNAL },
  479. { "client-arch", 93, 2 | OT_DEC },
  480. { "client-interface-id", 94, 0 },
  481. { "client-machine-id", 97, 0 },
  482. { "subnet-select", 118, OT_INTERNAL },
  483. { "domain-search", 119, OT_RFC1035_NAME },
  484. { "sip-server", 120, 0 },
  485. { "classless-static-route", 121, 0 },
  486. { "vendor-id-encap", 125, 0 },
  487. { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
  488. { NULL, 0, 0 }
  489. };
  490. #ifdef HAVE_DHCP6
  491. static const struct opttab_t opttab6[] = {
  492. { "client-id", 1, OT_INTERNAL },
  493. { "server-id", 2, OT_INTERNAL },
  494. { "ia-na", 3, OT_INTERNAL },
  495. { "ia-ta", 4, OT_INTERNAL },
  496. { "iaaddr", 5, OT_INTERNAL },
  497. { "oro", 6, OT_INTERNAL },
  498. { "preference", 7, OT_INTERNAL | OT_DEC },
  499. { "unicast", 12, OT_INTERNAL },
  500. { "status", 13, OT_INTERNAL },
  501. { "rapid-commit", 14, OT_INTERNAL },
  502. { "user-class", 15, OT_INTERNAL | OT_CSTRING },
  503. { "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
  504. { "vendor-opts", 17, OT_INTERNAL },
  505. { "sip-server-domain", 21, OT_RFC1035_NAME },
  506. { "sip-server", 22, OT_ADDR_LIST },
  507. { "dns-server", 23, OT_ADDR_LIST },
  508. { "domain-search", 24, OT_RFC1035_NAME },
  509. { "nis-server", 27, OT_ADDR_LIST },
  510. { "nis+-server", 28, OT_ADDR_LIST },
  511. { "nis-domain", 29, OT_RFC1035_NAME },
  512. { "nis+-domain", 30, OT_RFC1035_NAME },
  513. { "sntp-server", 31, OT_ADDR_LIST },
  514. { "information-refresh-time", 32, OT_TIME },
  515. { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
  516. { "ntp-server", 56, OT_ADDR_LIST },
  517. { "bootfile-url", 59, OT_NAME },
  518. { "bootfile-param", 60, OT_CSTRING },
  519. { NULL, 0, 0 }
  520. };
  521. #endif
  522. void display_opts(void)
  523. {
  524. int i;
  525. printf(_("Known DHCP options:\n"));
  526. for (i = 0; opttab[i].name; i++)
  527. if (!(opttab[i].size & OT_INTERNAL))
  528. printf("%3d %s\n", opttab[i].val, opttab[i].name);
  529. }
  530. #ifdef HAVE_DHCP6
  531. void display_opts6(void)
  532. {
  533. int i;
  534. printf(_("Known DHCPv6 options:\n"));
  535. for (i = 0; opttab6[i].name; i++)
  536. if (!(opttab6[i].size & OT_INTERNAL))
  537. printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
  538. }
  539. #endif
  540. int lookup_dhcp_opt(int prot, char *name)
  541. {
  542. const struct opttab_t *t;
  543. int i;
  544. (void)prot;
  545. #ifdef HAVE_DHCP6
  546. if (prot == AF_INET6)
  547. t = opttab6;
  548. else
  549. #endif
  550. t = opttab;
  551. for (i = 0; t[i].name; i++)
  552. if (strcasecmp(t[i].name, name) == 0)
  553. return t[i].val;
  554. return -1;
  555. }
  556. int lookup_dhcp_len(int prot, int val)
  557. {
  558. const struct opttab_t *t;
  559. int i;
  560. (void)prot;
  561. #ifdef HAVE_DHCP6
  562. if (prot == AF_INET6)
  563. t = opttab6;
  564. else
  565. #endif
  566. t = opttab;
  567. for (i = 0; t[i].name; i++)
  568. if (val == t[i].val)
  569. return t[i].size & ~OT_DEC;
  570. return 0;
  571. }
  572. char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
  573. {
  574. int o, i, j, nodecode = 0;
  575. const struct opttab_t *ot = opttab;
  576. #ifdef HAVE_DHCP6
  577. if (prot == AF_INET6)
  578. ot = opttab6;
  579. #endif
  580. for (o = 0; ot[o].name; o++)
  581. if (ot[o].val == opt)
  582. {
  583. if (buf)
  584. {
  585. memset(buf, 0, buf_len);
  586. if (ot[o].size & OT_ADDR_LIST)
  587. {
  588. struct all_addr addr;
  589. int addr_len = INADDRSZ;
  590. #ifdef HAVE_DHCP6
  591. if (prot == AF_INET6)
  592. addr_len = IN6ADDRSZ;
  593. #endif
  594. for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
  595. {
  596. if (i != 0)
  597. strncat(buf, ", ", buf_len - strlen(buf));
  598. /* align */
  599. memcpy(&addr, &val[i], addr_len);
  600. inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
  601. strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
  602. }
  603. }
  604. else if (ot[o].size & OT_NAME)
  605. for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
  606. {
  607. char c = val[i];
  608. if (isprint((int)c))
  609. buf[j++] = c;
  610. }
  611. #ifdef HAVE_DHCP6
  612. /* We don't handle compressed rfc1035 names, so no good in IPv4 land */
  613. else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
  614. {
  615. i = 0, j = 0;
  616. while (i < opt_len && val[i] != 0)
  617. {
  618. int k, l = i + val[i] + 1;
  619. for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
  620. {
  621. char c = val[k];
  622. if (isprint((int)c))
  623. buf[j++] = c;
  624. }
  625. i = l;
  626. if (val[i] != 0 && j < buf_len)
  627. buf[j++] = '.';
  628. }
  629. }
  630. else if ((ot[o].size & OT_CSTRING))
  631. {
  632. int k, len;
  633. unsigned char *p;
  634. i = 0, j = 0;
  635. while (1)
  636. {
  637. p = &val[i];
  638. GETSHORT(len, p);
  639. for (k = 0; k < len && j < buf_len; k++)
  640. {
  641. char c = *p++;
  642. if (isprint((int)c))
  643. buf[j++] = c;
  644. }
  645. i += len +2;
  646. if (i >= opt_len)
  647. break;
  648. if (j < buf_len)
  649. buf[j++] = ',';
  650. }
  651. }
  652. #endif
  653. else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
  654. {
  655. unsigned int dec = 0;
  656. for (i = 0; i < opt_len; i++)
  657. dec = (dec << 8) | val[i];
  658. if (ot[o].size & OT_TIME)
  659. prettyprint_time(buf, dec);
  660. else
  661. sprintf(buf, "%u", dec);
  662. }
  663. else
  664. nodecode = 1;
  665. }
  666. break;
  667. }
  668. if (opt_len != 0 && buf && (!ot[o].name || nodecode))
  669. {
  670. int trunc = 0;
  671. if (opt_len > 14)
  672. {
  673. trunc = 1;
  674. opt_len = 14;
  675. }
  676. print_mac(buf, val, opt_len);
  677. if (trunc)
  678. strncat(buf, "...", buf_len - strlen(buf));
  679. }
  680. return ot[o].name ? ot[o].name : "";
  681. }
  682. void log_context(int family, struct dhcp_context *context)
  683. {
  684. /* Cannot use dhcp_buff* for RA contexts */
  685. void *start = &context->start;
  686. void *end = &context->end;
  687. char *template = "", *p = daemon->namebuff;
  688. *p = 0;
  689. #ifdef HAVE_DHCP6
  690. if (family == AF_INET6)
  691. {
  692. struct in6_addr subnet = context->start6;
  693. if (!(context->flags & CONTEXT_TEMPLATE))
  694. setaddr6part(&subnet, 0);
  695. inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
  696. start = &context->start6;
  697. end = &context->end6;
  698. }
  699. #endif
  700. if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
  701. strcpy(daemon->namebuff, _(", prefix deprecated"));
  702. else
  703. {
  704. p += sprintf(p, _(", lease time "));
  705. prettyprint_time(p, context->lease_time);
  706. p += strlen(p);
  707. }
  708. #ifdef HAVE_DHCP6
  709. if (context->flags & CONTEXT_CONSTRUCTED)
  710. {
  711. char ifrn_name[IFNAMSIZ];
  712. template = p;
  713. p += sprintf(p, ", ");
  714. if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
  715. sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
  716. }
  717. else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
  718. {
  719. template = p;
  720. p += sprintf(p, ", ");
  721. sprintf(p, "template for %s", context->template_interface);
  722. }
  723. #endif
  724. if (!(context->flags & CONTEXT_OLD) &&
  725. ((context->flags & CONTEXT_DHCP) || family == AF_INET))
  726. {
  727. #ifdef HAVE_DHCP6
  728. if (context->flags & CONTEXT_RA_STATELESS)
  729. {
  730. if (context->flags & CONTEXT_TEMPLATE)
  731. strncpy(daemon->dhcp_buff, context->template_interface, 256);
  732. else
  733. strcpy(daemon->dhcp_buff, daemon->addrbuff);
  734. }
  735. else
  736. #endif
  737. inet_ntop(family, start, daemon->dhcp_buff, 256);
  738. inet_ntop(family, end, daemon->dhcp_buff3, 256);
  739. my_syslog(MS_DHCP | LOG_INFO,
  740. (context->flags & CONTEXT_RA_STATELESS) ?
  741. _("%s stateless on %s%.0s%.0s%s") :
  742. (context->flags & CONTEXT_STATIC) ?
  743. _("%s, static leases only on %.0s%s%s%.0s") :
  744. (context->flags & CONTEXT_PROXY) ?
  745. _("%s, proxy on subnet %.0s%s%.0s%.0s") :
  746. _("%s, IP range %s -- %s%s%.0s"),
  747. (family != AF_INET) ? "DHCPv6" : "DHCP",
  748. daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
  749. }
  750. #ifdef HAVE_DHCP6
  751. if (context->flags & CONTEXT_TEMPLATE)
  752. {
  753. strcpy(daemon->addrbuff, context->template_interface);
  754. template = "";
  755. }
  756. if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
  757. my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
  758. if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
  759. my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
  760. #endif
  761. }
  762. void log_relay(int family, struct dhcp_relay *relay)
  763. {
  764. inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
  765. inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
  766. if (relay->interface)
  767. my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
  768. else
  769. my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
  770. }
  771. #endif