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