1 /* dnsmasq is Copyright (c) 2000-2009 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 struct iface_param {
22 struct in_addr relay, primary;
23 struct dhcp_context* current;
24 int ind;
25 };
26
27 static int complete_context(struct in_addr local, int if_index, struct in_addr netmask,
28 struct in_addr broadcast, void* vparam);
29
dhcp_init(void)30 void dhcp_init(void) {
31 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
32 struct sockaddr_in saddr;
33 int oneopt = 1;
34 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
35 int mtu = IP_PMTUDISC_DONT;
36 #endif
37
38 if (fd == -1) die(_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
39
40 if (!fix_fd(fd) ||
41 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
42 setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
43 #endif
44 #if defined(HAVE_LINUX_NETWORK)
45 setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
46 #else
47 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
48 #endif
49 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
50 die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
51
52 /* When bind-interfaces is set, there might be more than one dnmsasq
53 instance binding port 67. That's OK if they serve different networks.
54 Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
55 if (daemon->options & OPT_NOWILD) {
56 #ifdef SO_REUSEPORT
57 int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
58 #else
59 int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
60 #endif
61 if (rc == -1)
62 die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
63 }
64
65 memset(&saddr, 0, sizeof(saddr));
66 saddr.sin_family = AF_INET;
67 saddr.sin_port = htons(daemon->dhcp_server_port);
68 saddr.sin_addr.s_addr = INADDR_ANY;
69
70 if (bind(fd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in)))
71 die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
72
73 #ifdef __ANDROID__
74 if (setsockopt(fd, SOL_SOCKET, SO_MARK, &daemon->listen_mark, sizeof(daemon->listen_mark)) == -1)
75 die(_("failed to set DHCP socket mark: %s"), NULL, EC_BADNET);
76 #endif /* __ANDROID__ */
77
78 daemon->dhcpfd = fd;
79
80 check_dhcp_hosts(1);
81
82 daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
83 daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
84 }
85
dhcp_packet(time_t now)86 void dhcp_packet(time_t now) {
87 struct dhcp_packet* mess;
88 struct dhcp_context* context;
89 struct iname* tmp;
90 struct ifreq ifr;
91 struct msghdr msg;
92 struct sockaddr_in dest;
93 struct cmsghdr* cmptr;
94 struct iovec iov;
95 ssize_t sz;
96 int iface_index = 0, unicast_dest = 0, is_inform = 0;
97 struct in_addr iface_addr, *addrp = NULL;
98 struct iface_param parm;
99
100 union {
101 struct cmsghdr align; /* this ensures alignment */
102 #if defined(HAVE_LINUX_NETWORK)
103 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
104 #endif
105 } control_u;
106
107 msg.msg_control = NULL;
108 msg.msg_controllen = 0;
109 msg.msg_name = NULL;
110 msg.msg_namelen = 0;
111 msg.msg_iov = &daemon->dhcp_packet;
112 msg.msg_iovlen = 1;
113
114 while (1) {
115 msg.msg_flags = 0;
116 while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR)
117 ;
118
119 if (sz == -1) return;
120
121 if (!(msg.msg_flags & MSG_TRUNC)) break;
122
123 /* Very new Linux kernels return the actual size needed,
124 older ones always return truncated size */
125 if ((size_t) sz == daemon->dhcp_packet.iov_len) {
126 if (!expand_buf(&daemon->dhcp_packet, sz + 100)) return;
127 } else {
128 expand_buf(&daemon->dhcp_packet, sz);
129 break;
130 }
131 }
132
133 /* expand_buf may have moved buffer */
134 mess = (struct dhcp_packet*) daemon->dhcp_packet.iov_base;
135 msg.msg_controllen = sizeof(control_u);
136 msg.msg_control = control_u.control;
137 msg.msg_flags = 0;
138 msg.msg_name = &dest;
139 msg.msg_namelen = sizeof(dest);
140
141 while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR)
142 ;
143
144 if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
145 return;
146
147 #if defined(HAVE_LINUX_NETWORK)
148 if (msg.msg_controllen >= sizeof(struct cmsghdr))
149 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
150 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) {
151 iface_index = ((struct in_pktinfo*) CMSG_DATA(cmptr))->ipi_ifindex;
152 if (((struct in_pktinfo*) CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
153 unicast_dest = 1;
154 }
155 #endif
156
157 if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name)) return;
158
159 #ifdef MSG_BCAST
160 /* OpenBSD tells us when a packet was broadcast */
161 if (!(msg.msg_flags & MSG_BCAST)) unicast_dest = 1;
162 #endif
163
164 ifr.ifr_addr.sa_family = AF_INET;
165 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1) {
166 addrp = &iface_addr;
167 iface_addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr;
168 }
169
170 if (!iface_check(AF_INET, (struct all_addr*) addrp, ifr.ifr_name, &iface_index)) return;
171
172 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
173 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) return;
174
175 /* interface may have been changed by alias in iface_check */
176 if (!addrp) {
177 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1) {
178 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"),
179 ifr.ifr_name);
180 return;
181 } else
182 iface_addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr;
183 }
184
185 /* unlinked contexts are marked by context->current == context */
186 for (context = daemon->dhcp; context; context = context->next) context->current = context;
187
188 parm.relay = mess->giaddr;
189 parm.primary = iface_addr;
190 parm.current = NULL;
191 parm.ind = iface_index;
192
193 if (!iface_enumerate(&parm, complete_context, NULL)) return;
194 lease_prune(NULL, now); /* lose any expired leases */
195 iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t) sz, now,
196 unicast_dest, &is_inform);
197 lease_update_file(now);
198 lease_update_dns();
199
200 if (iov.iov_len == 0) return;
201
202 msg.msg_name = &dest;
203 msg.msg_namelen = sizeof(dest);
204 msg.msg_control = NULL;
205 msg.msg_controllen = 0;
206 msg.msg_iov = &iov;
207 iov.iov_base = daemon->dhcp_packet.iov_base;
208
209 /* packet buffer may have moved */
210 mess = (struct dhcp_packet*) daemon->dhcp_packet.iov_base;
211
212 if (mess->giaddr.s_addr) {
213 /* Send to BOOTP relay */
214 dest.sin_port = htons(daemon->dhcp_server_port);
215 dest.sin_addr = mess->giaddr;
216 } else if (mess->ciaddr.s_addr) {
217 /* If the client's idea of its own address tallys with
218 the source address in the request packet, we believe the
219 source port too, and send back to that. If we're replying
220 to a DHCPINFORM, trust the source address always. */
221 if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) || dest.sin_port == 0 ||
222 dest.sin_addr.s_addr == 0) {
223 dest.sin_port = htons(daemon->dhcp_client_port);
224 dest.sin_addr = mess->ciaddr;
225 }
226 }
227 #if defined(HAVE_LINUX_NETWORK)
228 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
229 mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0) {
230 /* broadcast to 255.255.255.255 (or mac address invalid) */
231 struct in_pktinfo* pkt;
232 msg.msg_control = control_u.control;
233 msg.msg_controllen = sizeof(control_u);
234 cmptr = CMSG_FIRSTHDR(&msg);
235 pkt = (struct in_pktinfo*) CMSG_DATA(cmptr);
236 pkt->ipi_ifindex = iface_index;
237 pkt->ipi_spec_dst.s_addr = 0;
238 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
239 cmptr->cmsg_level = SOL_IP;
240 cmptr->cmsg_type = IP_PKTINFO;
241 dest.sin_addr.s_addr = INADDR_BROADCAST;
242 dest.sin_port = htons(daemon->dhcp_client_port);
243 } else {
244 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
245 struct sockaddr limits size to 14 bytes. */
246 struct arpreq req;
247 dest.sin_addr = mess->yiaddr;
248 dest.sin_port = htons(daemon->dhcp_client_port);
249 *((struct sockaddr_in*) &req.arp_pa) = dest;
250 req.arp_ha.sa_family = mess->htype;
251 memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
252 strncpy(req.arp_dev, ifr.ifr_name, 16);
253 req.arp_flags = ATF_COM;
254 ioctl(daemon->dhcpfd, SIOCSARP, &req);
255 }
256 #endif
257
258 while (sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send())
259 ;
260 }
261
262 /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
263 of each interface (and any relay address) and does the following things:
264
265 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
266 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
267 3) Fills in local (this host) and router (this host or relay) addresses.
268 4) Links contexts which are valid for hosts directly connected to the arrival interface on
269 ->current.
270
271 Note that the current chain may be superceded later for configured hosts or those coming via
272 gateways. */
273
complete_context(struct in_addr local,int if_index,struct in_addr netmask,struct in_addr broadcast,void * vparam)274 static int complete_context(struct in_addr local, int if_index, struct in_addr netmask,
275 struct in_addr broadcast, void* vparam) {
276 struct dhcp_context* context;
277 struct iface_param* param = vparam;
278
279 for (context = daemon->dhcp; context; context = context->next) {
280 if (!(context->flags & CONTEXT_NETMASK) && (is_same_net(local, context->start, netmask) ||
281 is_same_net(local, context->end, netmask))) {
282 if (context->netmask.s_addr != netmask.s_addr &&
283 !(is_same_net(local, context->start, netmask) &&
284 is_same_net(local, context->end, netmask))) {
285 strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
286 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
287 my_syslog(MS_DHCP | LOG_WARNING,
288 _("DHCP range %s -- %s is not consistent with netmask %s"),
289 daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
290 }
291 context->netmask = netmask;
292 }
293
294 if (context->netmask.s_addr) {
295 if (is_same_net(local, context->start, context->netmask) &&
296 is_same_net(local, context->end, context->netmask)) {
297 /* link it onto the current chain if we've not seen it before */
298 if (if_index == param->ind && context->current == context) {
299 context->router = local;
300 context->local = local;
301 context->current = param->current;
302 param->current = context;
303 }
304
305 if (!(context->flags & CONTEXT_BRDCAST)) {
306 if (is_same_net(broadcast, context->start, context->netmask))
307 context->broadcast = broadcast;
308 else
309 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
310 }
311 } else if (param->relay.s_addr &&
312 is_same_net(param->relay, context->start, context->netmask)) {
313 context->router = param->relay;
314 context->local = param->primary;
315 /* fill in missing broadcast addresses for relayed ranges */
316 if (!(context->flags & CONTEXT_BRDCAST))
317 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
318 }
319 }
320 }
321
322 return 1;
323 }
324
address_available(struct dhcp_context * context,struct in_addr taddr,struct dhcp_netid * netids)325 struct dhcp_context* address_available(struct dhcp_context* context, struct in_addr taddr,
326 struct dhcp_netid* netids) {
327 /* Check is an address is OK for this network, check all
328 possible ranges. Make sure that the address isn't in use
329 by the server itself. */
330
331 unsigned int start, end, addr = ntohl(taddr.s_addr);
332 struct dhcp_context* tmp;
333
334 for (tmp = context; tmp; tmp = tmp->current)
335 if (taddr.s_addr == context->router.s_addr) return NULL;
336
337 for (tmp = context; tmp; tmp = tmp->current) {
338 start = ntohl(tmp->start.s_addr);
339 end = ntohl(tmp->end.s_addr);
340
341 if (!(tmp->flags & CONTEXT_STATIC) && addr >= start && addr <= end &&
342 match_netid(tmp->filter, netids, 1))
343 return tmp;
344 }
345
346 return NULL;
347 }
348
narrow_context(struct dhcp_context * context,struct in_addr taddr,struct dhcp_netid * netids)349 struct dhcp_context* narrow_context(struct dhcp_context* context, struct in_addr taddr,
350 struct dhcp_netid* netids) {
351 /* We start of with a set of possible contexts, all on the current physical interface.
352 These are chained on ->current.
353 Here we have an address, and return the actual context correponding to that
354 address. Note that none may fit, if the address came a dhcp-host and is outside
355 any dhcp-range. In that case we return a static range if possible, or failing that,
356 any context on the correct subnet. (If there's more than one, this is a dodgy
357 configuration: maybe there should be a warning.) */
358
359 struct dhcp_context* tmp;
360
361 if (!(tmp = address_available(context, taddr, netids))) {
362 for (tmp = context; tmp; tmp = tmp->current)
363 if (is_same_net(taddr, tmp->start, tmp->netmask) && (tmp->flags & CONTEXT_STATIC))
364 break;
365
366 if (!tmp)
367 for (tmp = context; tmp; tmp = tmp->current)
368 if (is_same_net(taddr, tmp->start, tmp->netmask)) break;
369 }
370
371 /* Only one context allowed now */
372 if (tmp) tmp->current = NULL;
373
374 return tmp;
375 }
376
config_find_by_address(struct dhcp_config * configs,struct in_addr addr)377 struct dhcp_config* config_find_by_address(struct dhcp_config* configs, struct in_addr addr) {
378 struct dhcp_config* config;
379
380 for (config = configs; config; config = config->next)
381 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) return config;
382
383 return NULL;
384 }
385
386 /* Is every member of check matched by a member of pool?
387 If tagnotneeded, untagged is OK */
match_netid(struct dhcp_netid * check,struct dhcp_netid * pool,int tagnotneeded)388 int match_netid(struct dhcp_netid* check, struct dhcp_netid* pool, int tagnotneeded) {
389 struct dhcp_netid* tmp1;
390
391 if (!check && !tagnotneeded) return 0;
392
393 for (; check; check = check->next) {
394 if (check->net[0] != '#') {
395 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
396 if (strcmp(check->net, tmp1->net) == 0) break;
397 if (!tmp1) return 0;
398 } else
399 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
400 if (strcmp((check->net) + 1, tmp1->net) == 0) return 0;
401 }
402 return 1;
403 }
404
address_allocate(struct dhcp_context * context,struct in_addr * addrp,unsigned char * hwaddr,int hw_len,struct dhcp_netid * netids,time_t now)405 int address_allocate(struct dhcp_context* context, struct in_addr* addrp, unsigned char* hwaddr,
406 int hw_len, struct dhcp_netid* netids, time_t now) {
407 /* Find a free address: exclude anything in use and anything allocated to
408 a particular hwaddr/clientid/hostname in our configuration.
409 Try to return from contexts which match netids first. */
410
411 struct in_addr start, addr;
412 struct dhcp_context *c, *d;
413 int i, pass;
414 unsigned int j;
415
416 /* hash hwaddr */
417 for (j = 0, i = 0; i < hw_len; i++) j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
418
419 for (pass = 0; pass <= 1; pass++)
420 for (c = context; c; c = c->current)
421 if (c->flags & CONTEXT_STATIC)
422 continue;
423 else if (!match_netid(c->filter, netids, pass))
424 continue;
425 else {
426 /* pick a seed based on hwaddr then iterate until we find a free address. */
427 start.s_addr = addr.s_addr = htonl(
428 ntohl(c->start.s_addr) +
429 ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
430
431 do {
432 /* eliminate addresses in use by the server. */
433 for (d = context; d; d = d->current)
434 if (addr.s_addr == d->router.s_addr) break;
435
436 /* Addresses which end in .255 and .0 are broken in Windows even when using
437 supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
438 then 192.168.0.255 is a valid IP address, but not for Windows as it's
439 in the class C range. See KB281579. We therefore don't allocate these
440 addresses to avoid hard-to-diagnose problems. Thanks Bill. */
441 if (!d && !lease_find_by_addr(addr) &&
442 !config_find_by_address(daemon->dhcp_conf, addr) &&
443 (!IN_CLASSC(ntohl(addr.s_addr)) || ((ntohl(addr.s_addr) & 0xff) != 0xff &&
444 ((ntohl(addr.s_addr) & 0xff) != 0x0)))) {
445 struct ping_result *r, *victim = NULL;
446 int count,
447 max = (int) (0.6 * (((float) PING_CACHE_TIME) / ((float) PING_WAIT)));
448
449 *addrp = addr;
450
451 if (daemon->options & OPT_NO_PING) return 1;
452
453 /* check if we failed to ping addr sometime in the last
454 PING_CACHE_TIME seconds. If so, assume the same situation still exists.
455 This avoids problems when a stupid client bangs
456 on us repeatedly. As a final check, if we did more
457 than 60% of the possible ping checks in the last
458 PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
459 for (count = 0, r = daemon->ping_results; r; r = r->next)
460 if (difftime(now, r->time) > (float) PING_CACHE_TIME)
461 victim = r; /* old record */
462 else if (++count == max || r->addr.s_addr == addr.s_addr)
463 return 1;
464
465 if (icmp_ping(addr))
466 /* address in use: perturb address selection so that we are
467 less likely to try this address again. */
468 c->addr_epoch++;
469 else {
470 /* at this point victim may hold an expired record */
471 if (!victim) {
472 if ((victim = whine_malloc(sizeof(struct ping_result)))) {
473 victim->next = daemon->ping_results;
474 daemon->ping_results = victim;
475 }
476 }
477
478 /* record that this address is OK for 30s
479 without more ping checks */
480 if (victim) {
481 victim->addr = addr;
482 victim->time = now;
483 }
484 return 1;
485 }
486 }
487
488 addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
489
490 if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1)) addr = c->start;
491
492 } while (addr.s_addr != start.s_addr);
493 }
494 return 0;
495 }
496
is_addr_in_context(struct dhcp_context * context,struct dhcp_config * config)497 static int is_addr_in_context(struct dhcp_context* context, struct dhcp_config* config) {
498 if (!context) /* called via find_config() from lease_update_from_configs() */
499 return 1;
500 if (!(config->flags & CONFIG_ADDR)) return 1;
501 for (; context; context = context->current)
502 if (is_same_net(config->addr, context->start, context->netmask)) return 1;
503
504 return 0;
505 }
506
config_has_mac(struct dhcp_config * config,unsigned char * hwaddr,int len,int type)507 int config_has_mac(struct dhcp_config* config, unsigned char* hwaddr, int len, int type) {
508 struct hwaddr_config* conf_addr;
509
510 for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
511 if (conf_addr->wildcard_mask == 0 && conf_addr->hwaddr_len == len &&
512 (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
513 memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
514 return 1;
515
516 return 0;
517 }
518
find_config(struct dhcp_config * configs,struct dhcp_context * context,unsigned char * clid,int clid_len,unsigned char * hwaddr,int hw_len,int hw_type,char * hostname)519 struct dhcp_config* find_config(struct dhcp_config* configs, struct dhcp_context* context,
520 unsigned char* clid, int clid_len, unsigned char* hwaddr,
521 int hw_len, int hw_type, char* hostname) {
522 int count, new;
523 struct dhcp_config *config, *candidate;
524 struct hwaddr_config* conf_addr;
525
526 if (clid)
527 for (config = configs; config; config = config->next)
528 if (config->flags & CONFIG_CLID) {
529 if (config->clid_len == clid_len && memcmp(config->clid, clid, clid_len) == 0 &&
530 is_addr_in_context(context, config))
531 return config;
532
533 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
534 cope with that here */
535 if (*clid == 0 && config->clid_len == clid_len - 1 &&
536 memcmp(config->clid, clid + 1, clid_len - 1) == 0 &&
537 is_addr_in_context(context, config))
538 return config;
539 }
540
541 for (config = configs; config; config = config->next)
542 if (config_has_mac(config, hwaddr, hw_len, hw_type) && is_addr_in_context(context, config))
543 return config;
544
545 if (hostname && context)
546 for (config = configs; config; config = config->next)
547 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, hostname) &&
548 is_addr_in_context(context, config))
549 return config;
550
551 /* use match with fewest wildcast octets */
552 for (candidate = NULL, count = 0, config = configs; config; config = config->next)
553 if (is_addr_in_context(context, config))
554 for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
555 if (conf_addr->wildcard_mask != 0 && conf_addr->hwaddr_len == hw_len &&
556 (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
557 (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len,
558 conf_addr->wildcard_mask)) > count) {
559 count = new;
560 candidate = config;
561 }
562
563 return candidate;
564 }
565
check_dhcp_hosts(int fatal)566 void check_dhcp_hosts(int fatal) {
567 /* If the same IP appears in more than one host config, then DISCOVER
568 for one of the hosts will get the address, but REQUEST will be NAKed,
569 since the address is reserved by the other one -> protocol loop.
570 Also check that FQDNs match the domain we are using. */
571
572 struct dhcp_config *configs, *cp;
573
574 for (configs = daemon->dhcp_conf; configs; configs = configs->next) {
575 char* domain;
576
577 if ((configs->flags & DHOPT_BANK) || fatal) {
578 for (cp = configs->next; cp; cp = cp->next)
579 if ((configs->flags & cp->flags & CONFIG_ADDR) &&
580 configs->addr.s_addr == cp->addr.s_addr) {
581 if (fatal)
582 die(_("duplicate IP address %s in dhcp-config directive."),
583 inet_ntoa(cp->addr), EC_BADCONF);
584 else
585 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
586 inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
587 configs->flags &= ~CONFIG_ADDR;
588 }
589
590 /* split off domain part */
591 if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
592 configs->domain = domain;
593 }
594 }
595 }
596
dhcp_update_configs(struct dhcp_config * configs)597 void dhcp_update_configs(struct dhcp_config* configs) {
598 /* Some people like to keep all static IP addresses in /etc/hosts.
599 This goes through /etc/hosts and sets static addresses for any DHCP config
600 records which don't have an address and whose name matches.
601 We take care to maintain the invariant that any IP address can appear
602 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
603 restore the status-quo ante first. */
604
605 struct dhcp_config* config;
606 struct crec* crec;
607
608 for (config = configs; config; config = config->next)
609 if (config->flags & CONFIG_ADDR_HOSTS) config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
610
611 if (daemon->port != 0)
612 for (config = configs; config; config = config->next)
613 if (!(config->flags & CONFIG_ADDR) && (config->flags & CONFIG_NAME) &&
614 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
615 (crec->flags & F_HOSTS)) {
616 if (cache_find_by_name(crec, config->hostname, 0, F_IPV4)) {
617 /* use primary (first) address */
618 while (crec && !(crec->flags & F_REVERSE))
619 crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
620 if (!crec) continue; /* should be never */
621 my_syslog(MS_DHCP | LOG_WARNING,
622 _("%s has more than one address in hostsfile, using %s for DHCP"),
623 config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
624 }
625
626 if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
627 my_syslog(MS_DHCP | LOG_WARNING,
628 _("duplicate IP address %s (%s) in dhcp-config directive"),
629 inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
630 else {
631 config->addr = crec->addr.addr.addr.addr4;
632 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
633 }
634 }
635 }
636
637 /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
638 for this address. If it has a domain part, that must match the set domain and
639 it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
640 so check here that the domain name is legal as a hostname. */
host_from_dns(struct in_addr addr)641 char* host_from_dns(struct in_addr addr) {
642 struct crec* lookup;
643 char* hostname = NULL;
644 char *d1, *d2;
645
646 if (daemon->port == 0) return NULL; /* DNS disabled. */
647
648 lookup = cache_find_by_addr(NULL, (struct all_addr*) &addr, 0, F_IPV4);
649 if (lookup && (lookup->flags & F_HOSTS)) {
650 hostname = daemon->dhcp_buff;
651 strncpy(hostname, cache_get_name(lookup), 256);
652 hostname[255] = 0;
653 d1 = strip_hostname(hostname);
654 d2 = get_domain(addr);
655 if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
656 hostname = NULL;
657 }
658
659 return hostname;
660 }
661
662 /* return domain or NULL if none. */
strip_hostname(char * hostname)663 char* strip_hostname(char* hostname) {
664 char* dot = strchr(hostname, '.');
665
666 if (!dot) return NULL;
667
668 *dot = 0; /* truncate */
669 if (strlen(dot + 1) != 0) return dot + 1;
670
671 return NULL;
672 }
673
674 #endif
675