]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/dhcp.c
import of dnsmasq-2.33.tar.gz
[people/ms/dnsmasq.git] / src / dhcp.c
1 /* dnsmasq is Copyright (c) 2000-2006 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.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11 */
12
13 #include "dnsmasq.h"
14
15 struct iface_param {
16 struct in_addr relay, primary;
17 struct dhcp_context *current;
18 int ind;
19 };
20
21 static int complete_context(struct daemon *daemon, struct in_addr local, int if_index,
22 struct in_addr netmask, struct in_addr broadcast, void *vparam);
23
24 void dhcp_init(struct daemon *daemon)
25 {
26 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
27 struct sockaddr_in saddr;
28 int oneopt = 1;
29 struct dhcp_config *configs, *cp;
30
31 if (fd == -1)
32 die (_("cannot create DHCP socket : %s"), NULL);
33
34 if (!fix_fd(fd) ||
35 #if defined(HAVE_LINUX_NETWORK)
36 setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
37 #elif defined(IP_RECVIF)
38 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
39 #endif
40 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
41 die(_("failed to set options on DHCP socket: %s"), NULL);
42
43 /* When bind-interfaces is set, there might be more than one dnmsasq
44 instance binding port 67. That's Ok if they serve different networks.
45 Need to set REUSEADDR to make this posible. */
46 if ((daemon->options & OPT_NOWILD) &&
47 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)) == -1)
48 die(_("failed to set SO_REUSEADDR on DHCP socket: %s"), NULL);
49
50 memset(&saddr, 0, sizeof(saddr));
51 saddr.sin_family = AF_INET;
52 saddr.sin_port = htons(DHCP_SERVER_PORT);
53 saddr.sin_addr.s_addr = INADDR_ANY;
54 #ifdef HAVE_SOCKADDR_SA_LEN
55 saddr.sin_len = sizeof(struct sockaddr_in);
56 #endif
57
58 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
59 die(_("failed to bind DHCP server socket: %s"), NULL);
60
61 daemon->dhcpfd = fd;
62
63 #ifndef HAVE_LINUX_NETWORK
64 /* When we're not using capabilities, we need to do this here before
65 we drop root. Also, set buffer size small, to avoid wasting
66 kernel buffers */
67
68 if (daemon->options & OPT_NO_PING)
69 daemon->dhcp_icmp_fd = -1;
70 else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
71 setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
72 die(_("cannot create ICMP raw socket: %s."), NULL);
73
74 /* Make BPF raw send socket */
75 init_bpf(daemon);
76 #endif
77
78 /* If the same IP appears in more than one host config, then DISCOVER
79 for one of the hosts will get the address, but REQUEST will be NAKed,
80 since the address is reserved by the other one -> protocol loop. */
81 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
82 for (cp = configs->next; cp; cp = cp->next)
83 if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
84 die(_("duplicate IP address %s in dhcp-config directive."), inet_ntoa(cp->addr));
85
86 daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
87 daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
88 /* These two each hold a DHCP option max size 255
89 and get a terminating zero added */
90 daemon->dhcp_buff = safe_malloc(256);
91 daemon->dhcp_buff2 = safe_malloc(256);
92 daemon->ping_results = NULL;
93 }
94
95 void dhcp_packet(struct daemon *daemon, time_t now)
96 {
97 struct dhcp_packet *mess;
98 struct dhcp_context *context;
99 struct iname *tmp;
100 struct ifreq ifr;
101 struct msghdr msg;
102 struct sockaddr_in dest;
103 struct cmsghdr *cmptr;
104 struct iovec iov;
105 ssize_t sz;
106 int iface_index = 0, unicast_dest = 0;
107 struct in_addr iface_addr;
108 struct iface_param parm;
109
110 union {
111 struct cmsghdr align; /* this ensures alignment */
112 #ifdef HAVE_LINUX_NETWORK
113 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
114 #else
115 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
116 #endif
117 } control_u;
118
119 msg.msg_control = control_u.control;
120 msg.msg_controllen = sizeof(control_u);
121 msg.msg_name = NULL;
122 msg.msg_namelen = 0;
123 msg.msg_iov = &daemon->dhcp_packet;
124 msg.msg_iovlen = 1;
125
126 do
127 {
128 msg.msg_flags = 0;
129 while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
130 }
131 while (sz != -1 && (msg.msg_flags & MSG_TRUNC) &&
132 expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
133
134 /* expand_buf may have moved buffer */
135 mess = daemon->dhcp_packet.iov_base;
136 msg.msg_controllen = sizeof(control_u);
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)) && errno == EINTR);
142
143 if ((msg.msg_flags & MSG_TRUNC) ||
144 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 return;
150 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
151 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
152 {
153 iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
154 if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
155 unicast_dest = 1;
156 }
157
158 if (!(ifr.ifr_ifindex = iface_index) ||
159 ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
160 return;
161
162 #elif defined(IP_RECVIF)
163 if (msg.msg_controllen < sizeof(struct cmsghdr))
164 return;
165 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
166 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
167 iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
168
169 if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
170 return;
171
172 #else
173 {
174 struct iname *name;
175 for (name = daemon->if_names; name->isloop; name = name->next);
176 strcpy(ifr.ifr_name, name->name);
177 iface_index = if_nametoindex(name->name);
178 }
179 #endif
180
181 ifr.ifr_addr.sa_family = AF_INET;
182 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0 )
183 return;
184 iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
185
186 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
187 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
188 return;
189
190 if (!iface_check(daemon, AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
191 return;
192
193 /* unlinked contexts are marked by context->current == context */
194 for (context = daemon->dhcp; context; context = context->next)
195 context->current = context;
196
197 parm.relay = mess->giaddr;
198 parm.primary = iface_addr;
199 parm.current = NULL;
200 parm.ind = iface_index;
201
202 if (!iface_enumerate(daemon, &parm, complete_context, NULL))
203 return;
204 lease_prune(NULL, now); /* lose any expired leases */
205 iov.iov_len = dhcp_reply(daemon, parm.current, ifr.ifr_name, (size_t)sz, now, unicast_dest);
206 lease_update_file(daemon, now);
207 lease_update_dns(daemon);
208 lease_collect(daemon);
209
210 if (iov.iov_len == 0)
211 return;
212
213 msg.msg_name = &dest;
214 msg.msg_namelen = sizeof(dest);
215 msg.msg_control = NULL;
216 msg.msg_controllen = 0;
217 msg.msg_iov = &iov;
218 iov.iov_base = daemon->dhcp_packet.iov_base;
219
220 /* packet buffer may have moved */
221 mess = daemon->dhcp_packet.iov_base;
222
223 #ifdef HAVE_SOCKADDR_SA_LEN
224 dest.sin_len = sizeof(struct sockaddr_in);
225 #endif
226
227 if (mess->giaddr.s_addr)
228 {
229 /* Send to BOOTP relay */
230 dest.sin_port = htons(DHCP_SERVER_PORT);
231 dest.sin_addr = mess->giaddr;
232 }
233 else if (mess->ciaddr.s_addr)
234 {
235 /* If the client's idea of its own address tallys with
236 the source address in the request packet, we believe the
237 source port too, and send back to that. */
238 if (dest.sin_addr.s_addr != mess->ciaddr.s_addr || !dest.sin_port)
239 {
240 dest.sin_port = htons(DHCP_CLIENT_PORT);
241 dest.sin_addr = mess->ciaddr;
242 }
243 }
244 #ifdef HAVE_LINUX_NETWORK
245 else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
246 mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
247 {
248 /* broadcast to 255.255.255.255 (or mac address invalid) */
249 struct in_pktinfo *pkt;
250 msg.msg_control = control_u.control;
251 msg.msg_controllen = sizeof(control_u);
252 cmptr = CMSG_FIRSTHDR(&msg);
253 dest.sin_addr.s_addr = INADDR_BROADCAST;
254 dest.sin_port = htons(DHCP_CLIENT_PORT);
255 pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
256 pkt->ipi_ifindex = iface_index;
257 pkt->ipi_spec_dst.s_addr = 0;
258 msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
259 cmptr->cmsg_level = SOL_IP;
260 cmptr->cmsg_type = IP_PKTINFO;
261 }
262 else
263 {
264 /* unicast to unconfigured client. Inject mac address direct into ARP cache.
265 struct sockaddr limits size to 14 bytes. */
266 struct arpreq req;
267 dest.sin_addr = mess->yiaddr;
268 dest.sin_port = htons(DHCP_CLIENT_PORT);
269 *((struct sockaddr_in *)&req.arp_pa) = dest;
270 req.arp_ha.sa_family = mess->htype;
271 memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
272 strncpy(req.arp_dev, ifr.ifr_name, 16);
273 req.arp_flags = ATF_COM;
274 ioctl(daemon->dhcpfd, SIOCSARP, &req);
275 }
276 #else
277 else
278 {
279 send_via_bpf(daemon, mess, iov.iov_len, iface_addr, &ifr);
280 return;
281 }
282 #endif
283
284 while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
285 }
286
287 /* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
288 of each interface (and any relay address) and does the following things:
289
290 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived.
291 2) Fills in any netmask and broadcast addresses which have not been explicitly configured.
292 3) Fills in local (this host) and router (this host or relay) addresses.
293 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
294
295 Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
296
297 static int complete_context(struct daemon *daemon, struct in_addr local, int if_index,
298 struct in_addr netmask, struct in_addr broadcast, void *vparam)
299 {
300 struct dhcp_context *context;
301 struct iface_param *param = vparam;
302
303 if (if_index != param->ind)
304 return 1; /* no for us. */
305
306 for (context = daemon->dhcp; context; context = context->next)
307 {
308 if (!(context->flags & CONTEXT_NETMASK) &&
309 (is_same_net(local, context->start, netmask) ||
310 is_same_net(local, context->end, netmask)))
311 {
312 if (context->netmask.s_addr != netmask.s_addr &&
313 !(is_same_net(local, context->start, netmask) &&
314 is_same_net(local, context->end, netmask)))
315 {
316 strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
317 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
318 syslog(LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
319 daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
320 }
321 context->netmask = netmask;
322 }
323
324 if (context->netmask.s_addr)
325 {
326 if (is_same_net(local, context->start, context->netmask) &&
327 is_same_net(local, context->end, context->netmask))
328 {
329 /* link it onto the current chain if we've not seen it before */
330 if (context->current == context)
331 {
332 context->router = local;
333 context->local = local;
334 context->current = param->current;
335 param->current = context;
336 }
337
338 if (!(context->flags & CONTEXT_BRDCAST))
339 {
340 if (is_same_net(broadcast, context->start, context->netmask))
341 context->broadcast = broadcast;
342 else
343 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
344 }
345 }
346 else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
347 {
348 context->router = param->relay;
349 context->local = param->primary;
350 /* fill in missing broadcast addresses for relayed ranges */
351 if (!(context->flags & CONTEXT_BRDCAST))
352 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
353 }
354
355 }
356 }
357
358 return 1;
359 }
360
361 struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr taddr)
362 {
363 /* Check is an address is OK for this network, check all
364 possible ranges. Make sure that the address isn't in use
365 by the server itself. */
366
367 unsigned int start, end, addr = ntohl(taddr.s_addr);
368 struct dhcp_context *tmp;
369
370 for (tmp = context; tmp; tmp = tmp->current)
371 if (taddr.s_addr == context->router.s_addr)
372 return NULL;
373
374 for (tmp = context; tmp; tmp = tmp->current)
375 {
376 start = ntohl(tmp->start.s_addr);
377 end = ntohl(tmp->end.s_addr);
378
379 if (!(tmp->flags & CONTEXT_STATIC) &&
380 addr >= start &&
381 addr <= end)
382 return tmp;
383 }
384
385 return NULL;
386 }
387
388 struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr)
389 {
390 /* We start of with a set of possible contexts, all on the current physical interface.
391 These are chained on ->current.
392 Here we have an address, and return the actual context correponding to that
393 address. Note that none may fit, if the address came a dhcp-host and is outside
394 any dhcp-range. In that case we return a static range if possible, or failing that,
395 any context on the correct subnet. (If there's more than one, this is a dodgy
396 configuration: maybe there should be a warning.) */
397
398 struct dhcp_context *tmp;
399
400 if ((tmp = address_available(context, taddr)))
401 return tmp;
402
403 for (tmp = context; tmp; tmp = tmp->current)
404 if (is_same_net(taddr, tmp->start, tmp->netmask) &&
405 (tmp->flags & CONTEXT_STATIC))
406 return tmp;
407
408 for (tmp = context; tmp; tmp = tmp->current)
409 if (is_same_net(taddr, tmp->start, tmp->netmask))
410 return tmp;
411
412 return NULL;
413 }
414
415 struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
416 {
417 struct dhcp_config *config;
418
419 for (config = configs; config; config = config->next)
420 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
421 return config;
422
423 return NULL;
424 }
425
426 /* Is every member of check matched by a member of pool?
427 If negonly, match unless there's a negative tag which matches. */
428 int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly)
429 {
430 struct dhcp_netid *tmp1;
431
432 if (!check && !negonly)
433 return 0;
434
435 for (; check; check = check->next)
436 {
437 if (check->net[0] != '#')
438 {
439 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
440 if (strcmp(check->net, tmp1->net) == 0)
441 break;
442 if (!tmp1 || negonly)
443 return 0;
444 }
445 else
446 for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
447 if (strcmp((check->net)+1, tmp1->net) == 0)
448 return 0;
449 }
450 return 1;
451 }
452
453 int address_allocate(struct dhcp_context *context, struct daemon *daemon,
454 struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
455 struct dhcp_netid *netids, time_t now)
456 {
457 /* Find a free address: exclude anything in use and anything allocated to
458 a particular hwaddr/clientid/hostname in our configuration.
459 Try to return from contexts which match netids first. */
460
461 struct in_addr start, addr;
462 struct dhcp_context *c, *d;
463 int i, pass;
464 unsigned int j;
465
466 /* hash hwaddr */
467 for (j = 0, i = 0; i < hw_len; i++)
468 j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
469
470 for (pass = 0; pass <= 1; pass++)
471 for (c = context; c; c = c->current)
472 if (c->flags & CONTEXT_STATIC)
473 continue;
474 else if (!match_netid(c->filter, netids, pass))
475 continue;
476 else
477 {
478 /* pick a seed based on hwaddr then iterate until we find a free address. */
479 start.s_addr = addr.s_addr =
480 htonl(ntohl(c->start.s_addr) +
481 ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
482
483 do {
484 /* eliminate addresses in use by the server. */
485 for (d = context; d; d = d->current)
486 if (addr.s_addr == d->router.s_addr)
487 break;
488
489 if (!d &&
490 !lease_find_by_addr(addr) &&
491 !config_find_by_address(daemon->dhcp_conf, addr))
492 {
493 struct ping_result *r, *victim = NULL;
494 int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
495 ((float)PING_WAIT)));
496
497 *addrp = addr;
498
499 if (daemon->options & OPT_NO_PING)
500 return 1;
501
502 /* check if we failed to ping addr sometime in the last
503 PING_CACHE_TIME seconds. If so, assume the same situation still exists.
504 This avoids problems when a stupid client bangs
505 on us repeatedly. As a final check, if we did more
506 than 60% of the possible ping checks in the last
507 PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
508 for (count = 0, r = daemon->ping_results; r; r = r->next)
509 if (difftime(now, r->time) > (float)PING_CACHE_TIME)
510 victim = r; /* old record */
511 else if (++count == max || r->addr.s_addr == addr.s_addr)
512 return 1;
513
514 if (icmp_ping(daemon, addr))
515 /* address in use: perturb address selection so that we are
516 less likely to try this address again. */
517 c->addr_epoch++;
518 else
519 {
520 /* at this point victim may hold an expired record */
521 if (!victim)
522 {
523 if ((victim = malloc(sizeof(struct ping_result))))
524 {
525 victim->next = daemon->ping_results;
526 daemon->ping_results = victim;
527 }
528 }
529
530 /* record that this address is OK for 30s
531 without more ping checks */
532 if (victim)
533 {
534 victim->addr = addr;
535 victim->time = now;
536 }
537 return 1;
538 }
539 }
540
541 addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
542
543 if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
544 addr = c->start;
545
546 } while (addr.s_addr != start.s_addr);
547 }
548 return 0;
549 }
550
551 static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
552 {
553 if (!context) /* called via find_config() from lease_update_from_configs() */
554 return 1;
555 if (!(config->flags & CONFIG_ADDR))
556 return 1;
557 for (; context; context = context->current)
558 if (is_same_net(config->addr, context->start, context->netmask))
559 return 1;
560
561 return 0;
562 }
563
564
565 struct dhcp_config *find_config(struct dhcp_config *configs,
566 struct dhcp_context *context,
567 unsigned char *clid, int clid_len,
568 unsigned char *hwaddr, int hw_len,
569 int hw_type, char *hostname)
570 {
571 struct dhcp_config *config;
572
573 if (clid)
574 for (config = configs; config; config = config->next)
575 if (config->flags & CONFIG_CLID)
576 {
577 if (config->clid_len == clid_len &&
578 memcmp(config->clid, clid, clid_len) == 0 &&
579 is_addr_in_context(context, config))
580 return config;
581
582 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
583 cope with that here */
584 if (*clid == 0 && config->clid_len == clid_len-1 &&
585 memcmp(config->clid, clid+1, clid_len-1) == 0 &&
586 is_addr_in_context(context, config))
587 return config;
588 }
589
590
591 for (config = configs; config; config = config->next)
592 if ((config->flags & CONFIG_HWADDR) &&
593 config->wildcard_mask == 0 &&
594 config->hwaddr_len == hw_len &&
595 (config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
596 memcmp(config->hwaddr, hwaddr, hw_len) == 0 &&
597 is_addr_in_context(context, config))
598 return config;
599
600 if (hostname && context)
601 for (config = configs; config; config = config->next)
602 if ((config->flags & CONFIG_NAME) &&
603 hostname_isequal(config->hostname, hostname) &&
604 is_addr_in_context(context, config))
605 return config;
606
607 for (config = configs; config; config = config->next)
608 if ((config->flags & CONFIG_HWADDR) &&
609 config->wildcard_mask != 0 &&
610 config->hwaddr_len == hw_len &&
611 (config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
612 is_addr_in_context(context, config) &&
613 memcmp_masked(config->hwaddr, hwaddr, hw_len, config->wildcard_mask))
614 return config;
615
616 return NULL;
617 }
618
619 void dhcp_read_ethers(struct daemon *daemon)
620 {
621 FILE *f = fopen(ETHERSFILE, "r");
622 unsigned int flags;
623 char *buff = daemon->namebuff;
624 char *ip, *cp;
625 struct in_addr addr;
626 unsigned char hwaddr[ETHER_ADDR_LEN];
627 struct dhcp_config **up, *tmp;
628 struct dhcp_config *config, *configs = daemon->dhcp_conf;
629 int count = 0, lineno = 0;
630
631 addr.s_addr = 0; /* eliminate warning */
632
633 if (!f)
634 {
635 syslog(LOG_ERR, _("failed to read %s:%m"), ETHERSFILE);
636 return;
637 }
638
639 /* This can be called again on SIGHUP, so remove entries created last time round. */
640 for (up = &daemon->dhcp_conf, config = configs; config; config = tmp)
641 {
642 tmp = config->next;
643 if (config->flags & CONFIG_FROM_ETHERS)
644 {
645 *up = tmp;
646 /* cannot have a clid */
647 if (config->flags & CONFIG_NAME)
648 free(config->hostname);
649 free(config);
650 }
651 else
652 up = &config->next;
653 }
654
655 while (fgets(buff, MAXDNAME, f))
656 {
657 lineno++;
658
659 while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
660 buff[strlen(buff)-1] = 0;
661
662 if ((*buff == '#') || (*buff == '+'))
663 continue;
664
665 for (ip = buff; *ip && !isspace(*ip); ip++);
666 for(; *ip && isspace(*ip); ip++)
667 *ip = 0;
668 if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
669 {
670 syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
671 continue;
672 }
673
674 /* check for name or dotted-quad */
675 for (cp = ip; *cp; cp++)
676 if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
677 break;
678
679 if (!*cp)
680 {
681 if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
682 {
683 syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
684 continue;
685 }
686
687 flags = CONFIG_ADDR;
688
689 for (config = configs; config; config = config->next)
690 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
691 break;
692 }
693 else
694 {
695 if (!canonicalise(ip))
696 {
697 syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
698 continue;
699 }
700
701 flags = CONFIG_NAME;
702
703 for (config = configs; config; config = config->next)
704 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip))
705 break;
706 }
707
708 if (!config)
709 {
710 for (config = configs; config; config = config->next)
711 if ((config->flags & CONFIG_HWADDR) &&
712 config->wildcard_mask == 0 &&
713 config->hwaddr_len == ETHER_ADDR_LEN &&
714 (config->hwaddr_type == ARPHRD_ETHER || config->hwaddr_type == 0) &&
715 memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
716 break;
717
718 if (!config)
719 {
720 if (!(config = malloc(sizeof(struct dhcp_config))))
721 continue;
722 config->flags = CONFIG_FROM_ETHERS;
723 config->wildcard_mask = 0;
724 config->next = configs;
725 configs = config;
726 }
727
728 config->flags |= flags;
729
730 if (flags & CONFIG_NAME)
731 {
732 if ((config->hostname = malloc(strlen(ip)+1)))
733 strcpy(config->hostname, ip);
734 else
735 config->flags &= ~CONFIG_NAME;
736 }
737
738 if (flags & CONFIG_ADDR)
739 config->addr = addr;
740 }
741
742 config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
743 memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
744 config->hwaddr_len = ETHER_ADDR_LEN;
745 config->hwaddr_type = ARPHRD_ETHER;
746 count++;
747 }
748
749 fclose(f);
750
751 syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
752
753 daemon->dhcp_conf = configs;
754 }
755
756 void dhcp_update_configs(struct dhcp_config *configs)
757 {
758 /* Some people like to keep all static IP addresses in /etc/hosts.
759 This goes through /etc/hosts and sets static addresses for any DHCP config
760 records which don't have an address and whose name matches.
761 We take care to maintain the invariant that any IP address can appear
762 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
763 restore the status-quo ante first. */
764
765 struct dhcp_config *config;
766 struct crec *crec;
767
768 for (config = configs; config; config = config->next)
769 if (config->flags & CONFIG_ADDR_HOSTS)
770 config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
771
772 for (config = configs; config; config = config->next)
773 if (!(config->flags & CONFIG_ADDR) &&
774 (config->flags & CONFIG_NAME) &&
775 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
776 (crec->flags & F_HOSTS))
777 {
778 if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
779 syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
780 inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
781 else
782 {
783 config->addr = crec->addr.addr.addr.addr4;
784 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
785 }
786 }
787 }
788
789 /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
790 for this address. If it has a domain part, that must match the set domain and
791 it gets stripped. */
792 char *host_from_dns(struct daemon *daemon, struct in_addr addr)
793 {
794 struct crec *lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
795 char *hostname = NULL;
796
797 if (lookup && (lookup->flags & F_HOSTS))
798 {
799 hostname = daemon->dhcp_buff;
800 strncpy(hostname, cache_get_name(lookup), 256);
801 hostname[255] = 0;
802 hostname = strip_hostname(daemon, hostname);
803 }
804
805 return hostname;
806 }
807
808 char *strip_hostname(struct daemon *daemon, char *hostname)
809 {
810 char *dot = strchr(hostname, '.');
811 if (dot)
812 {
813 if (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix))
814 {
815 syslog(LOG_WARNING, _("Ignoring DHCP host name %s because it has an illegal domain part"), hostname);
816 hostname = NULL;
817 }
818 else
819 {
820 *dot = 0; /* truncate */
821 if (strlen(hostname) == 0)
822 hostname = NULL; /* nothing left */
823 }
824 }
825 return hostname;
826 }