blob: 7c837c6a36c6696b961c0b6aa616ac3a0233061a [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
Simon Kelley4cb1b322012-02-06 14:30:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_DHCP
20
21void dhcp_common_init(void)
22{
Simon Kelleybf4e62c2016-07-22 21:37:59 +010023 /* 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);
Simon Kelley4cb1b322012-02-06 14:30:41 +000028
29 /* dhcp_packet is used by v4 and v6, outpacket only by v6
30 sizeof(struct dhcp_packet) is as good an initial size as any,
31 even for v6 */
32 expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
33#ifdef HAVE_DHCP6
34 if (daemon->dhcp6)
35 expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
36#endif
37}
38
39ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
40{
Simon Kelley4890bcd2020-04-28 14:02:53 +010041 ssize_t sz, new_sz;
Simon Kelley4cb1b322012-02-06 14:30:41 +000042
43 while (1)
44 {
45 msg->msg_flags = 0;
46 while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
47
48 if (sz == -1)
49 return -1;
50
51 if (!(msg->msg_flags & MSG_TRUNC))
52 break;
53
54 /* Very new Linux kernels return the actual size needed,
55 older ones always return truncated size */
Simon Kelleyc5ad4e72012-02-24 16:06:20 +000056 if ((size_t)sz == msg->msg_iov->iov_len)
Simon Kelley4cb1b322012-02-06 14:30:41 +000057 {
Simon Kelleyc5ad4e72012-02-24 16:06:20 +000058 if (!expand_buf(msg->msg_iov, sz + 100))
Simon Kelley4cb1b322012-02-06 14:30:41 +000059 return -1;
60 }
61 else
62 {
Simon Kelleyc5ad4e72012-02-24 16:06:20 +000063 expand_buf(msg->msg_iov, sz);
Simon Kelley4cb1b322012-02-06 14:30:41 +000064 break;
65 }
66 }
67
Simon Kelley4890bcd2020-04-28 14:02:53 +010068 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. */
Simon Kelley4cb1b322012-02-06 14:30:41 +000075
Simon Kelley4890bcd2020-04-28 14:02:53 +010076 if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
77 new_sz = sz;
78
79 return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
Simon Kelley4cb1b322012-02-06 14:30:41 +000080}
81
Tarun Kundu12e3b2e2024-08-15 16:16:53 -070082/* like match_netid() except that the check can have a trailing * for wildcard */
83/* started as a direct copy of match_netid() */
84int 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
Simon Kelley4cb1b322012-02-06 14:30:41 +0000112struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
113{
114 struct tag_if *exprs;
115 struct dhcp_netid_list *list;
116
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700117 /* this now uses match_netid_wild() above so that tag_if can
118 * be used to set a 'group of interfaces' tag.
119 */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000120 for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700121 if (match_netid_wild(exprs->tag, tags))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000122 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
132struct 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;
Simon Kelley96c727f2013-04-02 21:35:41 +0100136 struct dhcp_opt *tmp;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000137
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,
Simon Kelley6caacac2012-02-15 21:58:33 +0000148 otherwise valid options are inhibited if we found a higher priority one above */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000149 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
Simon Kelleya8131112012-03-31 21:35:12 +0100157 /* 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
Simon Kelley4cb1b322012-02-06 14:30:41 +0000164 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 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000181 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
Simon Kelley96c727f2013-04-02 21:35:41 +0100190 /* 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
Simon Kelley4cb1b322012-02-06 14:30:41 +0000197 return tagif;
198}
199
200/* Is every member of check matched by a member of pool?
201 If tagnotneeded, untagged is OK */
202int 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. */
229char *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
243void 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
Simon Kelley3634c542012-02-08 14:22:37 +0000268int 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}
Simon Kelleyceae00d2012-02-09 21:28:14 +0000297
Simon Kelley89500e32013-09-20 16:29:20 +0100298int 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
312static 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;
Simon Kelleye7c0d7b2021-02-28 17:56:54 +0000316
317 if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
318 return 1;
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100319
320#ifdef HAVE_DHCP6
Simon Kelley137286e2020-02-06 22:09:30 +0000321 if (context->flags & CONTEXT_V6)
322 {
323 struct addrlist *addr_list;
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100324
Simon Kelleye7c0d7b2021-02-28 17:56:54 +0000325 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 }
Simon Kelley137286e2020-02-06 22:09:30 +0000335 }
336 else
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100337#endif
Simon Kelley137286e2020-02-06 22:09:30 +0000338 {
Simon Kelley137286e2020-02-06 22:09:30 +0000339 for (; context; context = context->current)
340 if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
341 return 1;
342 }
Simon Kelley89500e32013-09-20 16:29:20 +0100343
Simon Kelley89500e32013-09-20 16:29:20 +0100344 return 0;
345}
346
Simon Kelley52ec7832020-02-07 21:05:54 +0000347static 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)
Simon Kelley89500e32013-09-20 16:29:20 +0100353{
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 &&
Simon Kelley52ec7832020-02-07 21:05:54 +0000364 is_config_in_context(context, config) &&
365 match_netid(config->filter, tags, tag_not_needed))
366
Simon Kelley89500e32013-09-20 16:29:20 +0100367 return config;
368
369 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
René van Dorst53c4c5c2013-10-18 13:53:05 +0100370 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 &&
Simon Kelley89500e32013-09-20 16:29:20 +0100373 memcmp(config->clid, clid+1, clid_len-1) == 0 &&
Simon Kelley52ec7832020-02-07 21:05:54 +0000374 is_config_in_context(context, config) &&
375 match_netid(config->filter, tags, tag_not_needed))
Simon Kelley89500e32013-09-20 16:29:20 +0100376 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) &&
Simon Kelley52ec7832020-02-07 21:05:54 +0000383 is_config_in_context(context, config) &&
384 match_netid(config->filter, tags, tag_not_needed))
Simon Kelley89500e32013-09-20 16:29:20 +0100385 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) &&
Simon Kelley52ec7832020-02-07 21:05:54 +0000391 is_config_in_context(context, config) &&
392 match_netid(config->filter, tags, tag_not_needed))
Simon Kelley89500e32013-09-20 16:29:20 +0100393 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)
Simon Kelley52ec7832020-02-07 21:05:54 +0000401 if (is_config_in_context(context, config) &&
402 match_netid(config->filter, tags, tag_not_needed))
Simon Kelley89500e32013-09-20 16:29:20 +0100403 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
Simon Kelley52ec7832020-02-07 21:05:54 +0000416/* Find tagged configs first. */
417struct 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
Simon Kelleyceae00d2012-02-09 21:28:14 +0000431void 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
Simon Kelley35239a32012-09-24 15:09:33 +0100440 struct dhcp_config *config, *conf_tmp;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000441 struct crec *crec;
442 int prot = AF_INET;
443
444 for (config = configs; config; config = config->next)
Steven Silotid2d49902019-01-17 22:52:13 +0000445 {
Simon Kelleyceae00d2012-02-09 21:28:14 +0000446 if (config->flags & CONFIG_ADDR_HOSTS)
Steven Siloti18eac672019-01-13 22:56:36 +0000447 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
Steven Silotid2d49902019-01-17 22:52:13 +0000452 }
Simon Kelleyceae00d2012-02-09 21:28:14 +0000453
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 */
Simon Kelley00238fb2013-12-18 13:24:12 +0000479 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 */
Simon Kelleycc921df2019-01-02 22:48:59 +0000483 inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley00238fb2013-12-18 13:24:12 +0000484 my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
485 config->hostname, daemon->addrbuff);
Simon Kelleyceae00d2012-02-09 21:28:14 +0000486 }
487
Simon Kelley35239a32012-09-24 15:09:33 +0100488 if (prot == AF_INET &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000489 (!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000490 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000491 config->addr = crec->addr.addr4;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000492 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
493 continue;
494 }
495
496#ifdef HAVE_DHCP6
Simon Kelley35239a32012-09-24 15:09:33 +0100497 if (prot == AF_INET6 &&
Simon Kelley79aba0f2020-02-03 23:58:45 +0000498 (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000499 {
Simon Kelley137286e2020-02-06 22:09:30 +0000500 /* 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
Simon Kelleyceae00d2012-02-09 21:28:14 +0000513 continue;
514 }
515#endif
516
Simon Kelleycc921df2019-01-02 22:48:59 +0000517 inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelleyceae00d2012-02-09 21:28:14 +0000518 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}
Simon Kelley4cb1b322012-02-06 14:30:41 +0000534
Simon Kelley9380ba72012-04-16 14:41:56 +0100535#ifdef HAVE_LINUX_NETWORK
Simon Kelley3b3f4412013-10-11 16:33:28 +0100536char *whichdevice(void)
Simon Kelley9380ba72012-04-16 14:41:56 +0100537{
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.
Simon Kelleye2ba0df2013-05-31 17:04:25 +0100542 SO_BINDTODEVICE is only available Linux.
543
Simon Kelley8584c502013-10-10 21:15:23 +0100544 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.
Simon Kelleye2ba0df2013-05-31 17:04:25 +0100547*/
Simon Kelley9380ba72012-04-16 14:41:56 +0100548
549 struct irec *iface, *found;
Simon Kelleye2ba0df2013-05-31 17:04:25 +0100550 struct iname *if_tmp;
Simon Kelley3b3f4412013-10-11 16:33:28 +0100551
Simon Kelley8584c502013-10-10 21:15:23 +0100552 if (!daemon->if_names)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100553 return NULL;
554
Simon Kelleye2ba0df2013-05-31 17:04:25 +0100555 for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700556 if (if_tmp->name && (!(if_tmp->flags & INAME_USED) || strchr(if_tmp->name, '*')))
Simon Kelley3b3f4412013-10-11 16:33:28 +0100557 return NULL;
Simon Kelleye2ba0df2013-05-31 17:04:25 +0100558
Simon Kelley9380ba72012-04-16 14:41:56 +0100559 for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700560 if (iface->dhcp4_ok || iface->dhcp6_ok)
Simon Kelley9380ba72012-04-16 14:41:56 +0100561 {
562 if (!found)
563 found = iface;
564 else if (strcmp(found->name, iface->name) != 0)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100565 return NULL; /* more than one. */
Simon Kelley9380ba72012-04-16 14:41:56 +0100566 }
Simon Kelley3b3f4412013-10-11 16:33:28 +0100567
Simon Kelley9380ba72012-04-16 14:41:56 +0100568 if (found)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700569 {
570 char *ret = safe_malloc(strlen(found->name)+1);
571 strcpy(ret, found->name);
572 return ret;
573 }
574
Simon Kelley3b3f4412013-10-11 16:33:28 +0100575 return NULL;
576}
577
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700578static int bindtodevice(char *device, int fd)
Simon Kelley3b3f4412013-10-11 16:33:28 +0100579{
Petr Menšík47b45b22018-08-15 18:17:00 +0200580 size_t len = strlen(device)+1;
581 if (len > IFNAMSIZ)
582 len = IFNAMSIZ;
Simon Kelley3b3f4412013-10-11 16:33:28 +0100583 /* only allowed by root. */
Petr Menšík47b45b22018-08-15 18:17:00 +0200584 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
Simon Kelley3b3f4412013-10-11 16:33:28 +0100585 errno != EPERM)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700586 return 2;
587
588 return 1;
589}
590
591int 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;
Simon Kelley9380ba72012-04-16 14:41:56 +0100613}
614#endif
Simon Kelley40ef23b2012-03-13 21:59:28 +0000615
616static 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 },
Simon Kelley23245c02012-07-18 16:21:11 +0100659 { "lease-time", 51, OT_INTERNAL | OT_TIME },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000660 { "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 },
Simon Kelleyca85a282015-05-13 22:33:04 +0100666 { "T1", 58, OT_TIME},
667 { "T2", 59, OT_TIME},
Simon Kelley40ef23b2012-03-13 21:59:28 +0000668 { "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 },
Simon Kelley734d5312018-03-23 23:09:53 +0000680 { "rapid-commit", 80, 0 },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000681 { "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 },
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700686 { "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 */
Simon Kelley40ef23b2012-03-13 21:59:28 +0000689 { "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 },
Ville Skyttä0c211c42019-12-05 17:11:09 +0000694 { "tftp-server-address", 150, OT_ADDR_LIST },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000695 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
696 { NULL, 0, 0 }
697};
698
699#ifdef HAVE_DHCP6
700static 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 },
Simon Kelley23245c02012-07-18 16:21:11 +0100723 { "information-refresh-time", 32, OT_TIME },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000724 { "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700725 { "posix-timezone", 41, OT_NAME }, /* RFC 4833, Sec. 3 */
726 { "tzdb-timezone", 42, OT_NAME }, /* RFC 4833, Sec. 3 */
Vladislav Grishenkodded78b2020-03-08 15:34:34 +0000727 { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
Simon Kelley40ef23b2012-03-13 21:59:28 +0000728 { "bootfile-url", 59, OT_NAME },
729 { "bootfile-param", 60, OT_CSTRING },
730 { NULL, 0, 0 }
731};
732#endif
733
734
735
736void 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
748void 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
Simon Kelleybd08ae62013-04-19 10:22:06 +0100759int lookup_dhcp_opt(int prot, char *name)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000760{
761 const struct opttab_t *t;
762 int i;
763
Vladislav Grishenko408c3682013-09-24 16:18:49 +0100764 (void)prot;
765
Simon Kelley40ef23b2012-03-13 21:59:28 +0000766#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++)
Simon Kelleyc7961072013-02-28 15:17:58 +0000774 if (strcasecmp(t[i].name, name) == 0)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000775 return t[i].val;
776
Simon Kelleybd08ae62013-04-19 10:22:06 +0100777 return -1;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000778}
779
Simon Kelleybd08ae62013-04-19 10:22:06 +0100780int lookup_dhcp_len(int prot, int val)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000781{
782 const struct opttab_t *t;
783 int i;
784
Vladislav Grishenko408c3682013-09-24 16:18:49 +0100785 (void)prot;
786
Simon Kelley40ef23b2012-03-13 21:59:28 +0000787#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)
Simon Kelleyc7961072013-02-28 15:17:58 +0000796 return t[i].size & ~OT_DEC;
797
798 return 0;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000799}
800
801char *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 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000820 union all_addr addr;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000821 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];
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700841 if (isprint((unsigned char)c))
Simon Kelley40ef23b2012-03-13 21:59:28 +0000842 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];
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700855 if (isprint((unsigned char)c))
Simon Kelley40ef23b2012-03-13 21:59:28 +0000856 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++;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700876 if (isprint((unsigned char)c))
Simon Kelley40ef23b2012-03-13 21:59:28 +0000877 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
Simon Kelley23245c02012-07-18 16:21:11 +0100888 else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
Simon Kelley40ef23b2012-03-13 21:59:28 +0000889 {
890 unsigned int dec = 0;
891
892 for (i = 0; i < opt_len; i++)
893 dec = (dec << 8) | val[i];
894
Simon Kelley23245c02012-07-18 16:21:11 +0100895 if (ot[o].size & OT_TIME)
896 prettyprint_time(buf, dec);
897 else
898 sprintf(buf, "%u", dec);
Simon Kelley40ef23b2012-03-13 21:59:28 +0000899 }
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
Simon Kelley1f776932012-12-16 19:46:08 +0000925void 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;
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000931 char *template = "", *p = daemon->namebuff;
Simon Kelleyc1be9172012-12-17 22:37:30 +0000932
933 *p = 0;
934
Simon Kelley1f776932012-12-16 19:46:08 +0000935#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
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000946
947 if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
948 strcpy(daemon->namebuff, _(", prefix deprecated"));
949 else
Simon Kelley1f776932012-12-16 19:46:08 +0000950 {
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000951 p += sprintf(p, _(", lease time "));
952 prettyprint_time(p, context->lease_time);
953 p += strlen(p);
954 }
955
Simon Kelleyc1be9172012-12-17 22:37:30 +0000956#ifdef HAVE_DHCP6
957 if (context->flags & CONTEXT_CONSTRUCTED)
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000958 {
959 char ifrn_name[IFNAMSIZ];
960
961 template = p;
962 p += sprintf(p, ", ");
963
Simon Kelleya8105592013-09-25 15:36:00 +0100964 if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
Simon Kelleyef1a94a2013-07-26 13:59:03 +0100965 sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000966 }
Simon Kelley903650a2013-10-03 11:43:09 +0100967 else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000968 {
969 template = p;
970 p += sprintf(p, ", ");
Simon Kelley903650a2013-10-03 11:43:09 +0100971
Simon Kelley49333cb2013-03-15 20:30:51 +0000972 sprintf(p, "template for %s", context->template_interface);
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000973 }
Simon Kelleyc1be9172012-12-17 22:37:30 +0000974#endif
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +0000975
Simon Kelleyef1a94a2013-07-26 13:59:03 +0100976 if (!(context->flags & CONTEXT_OLD) &&
977 ((context->flags & CONTEXT_DHCP) || family == AF_INET))
Simon Kelley1f776932012-12-16 19:46:08 +0000978 {
Simon Kelley903650a2013-10-03 11:43:09 +0100979#ifdef HAVE_DHCP6
980 if (context->flags & CONTEXT_RA_STATELESS)
981 {
982 if (context->flags & CONTEXT_TEMPLATE)
Simon Kelleybf4e62c2016-07-22 21:37:59 +0100983 strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
Simon Kelley903650a2013-10-03 11:43:09 +0100984 else
985 strcpy(daemon->dhcp_buff, daemon->addrbuff);
986 }
987 else
988#endif
Simon Kelleybf4e62c2016-07-22 21:37:59 +0100989 inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
990 inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
Simon Kelley1f776932012-12-16 19:46:08 +0000991 my_syslog(MS_DHCP | LOG_INFO,
Simon Kelley903650a2013-10-03 11:43:09 +0100992 (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",
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +00001000 daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
Simon Kelley1f776932012-12-16 19:46:08 +00001001 }
1002
Simon Kelleyc1be9172012-12-17 22:37:30 +00001003#ifdef HAVE_DHCP6
Simon Kelleye4e9b342013-10-02 11:00:45 +01001004 if (context->flags & CONTEXT_TEMPLATE)
1005 {
1006 strcpy(daemon->addrbuff, context->template_interface);
1007 template = "";
1008 }
Simon Kelley903650a2013-10-03 11:43:09 +01001009
Simon Kelleyef1a94a2013-07-26 13:59:03 +01001010 if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +00001011 my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
Simon Kelleyef1a94a2013-07-26 13:59:03 +01001012
Simon Kelleyb1a1b6d2013-01-11 16:28:50 +00001013 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);
Simon Kelleyc1be9172012-12-17 22:37:30 +00001015#endif
1016
Simon Kelley1f776932012-12-16 19:46:08 +00001017}
Simon Kelley1f776932012-12-16 19:46:08 +00001018
Simon Kelleyff7eea22013-09-04 18:01:38 +01001019void log_relay(int family, struct dhcp_relay *relay)
1020{
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001021 int broadcast = relay->server.addr4.s_addr == 0;
Simon Kelleyff7eea22013-09-04 18:01:38 +01001022 inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001023 inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
Simon Kelleyff7eea22013-09-04 18:01:38 +01001024
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001025 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;
1030
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
Simon Kelleyff7eea22013-09-04 18:01:38 +01001042 if (relay->interface)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001043 {
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 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01001049 else
1050 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
1051}
1052
Simon Kelley4cb1b322012-02-06 14:30:41 +00001053#endif