]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/dhcp.c
import of dnsmasq-2.16.tar.gz
[people/ms/dnsmasq.git] / src / dhcp.c
CommitLineData
9e4abcb5
SK
1/* dnsmasq is Copyright (c) 2000-2003 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/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
3be34541 17void dhcp_init(struct daemon *daemon)
44a2a316
SK
18{
19 int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
20 struct sockaddr_in saddr;
fd9fa481 21 int flags, oneopt = 1, zeroopt = 0;
3be34541 22 struct dhcp_config *configs, *cp;
dfa666f2 23
44a2a316 24 if (fd == -1)
1cff166d 25 die ("cannot create DHCP socket : %s", NULL);
44a2a316 26
fd9fa481
SK
27 if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
28 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
44a2a316 29#if defined(IP_PKTINFO)
3be34541 30 setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
44a2a316 31#elif defined(IP_RECVIF)
3be34541 32 setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
44a2a316 33#endif
3be34541 34 setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
44a2a316
SK
35 die("failed to set options on DHCP socket: %s", NULL);
36
37 saddr.sin_family = AF_INET;
38 saddr.sin_port = htons(DHCP_SERVER_PORT);
39 saddr.sin_addr.s_addr = INADDR_ANY;
3be34541
SK
40#ifdef HAVE_SOCKADDR_SA_LEN
41 saddr.sin_len = sizeof(struct sockaddr_in);
42#endif
43
44a2a316
SK
44 if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
45 die("failed to bind DHCP server socket: %s", NULL);
46
3be34541
SK
47 daemon->dhcpfd = fd;
48
49 if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
50 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
51 setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
52 die("cannot create ICMP raw socket: %s.", NULL);
53
54 daemon->dhcp_icmp_fd = fd;
44a2a316
SK
55
56#ifdef HAVE_BPF
3be34541
SK
57 {
58 int i = 0;
59 while (1)
60 {
61 char filename[50];
62 sprintf(filename, "/dev/bpf%d", i++);
63 if ((fd = open(filename, O_RDWR, 0)) != -1)
64 break;
65 if (errno != EBUSY)
66 die("cannot create DHCP BPF socket: %s", NULL);
67 }
68 }
44a2a316 69#else
3be34541
SK
70 /* since we don't ever use the packet socket for reception,
71 and it receives copies of _all_ IP packets, then that data
72 will build up in kernel buffers, wasting memory. Set the
73 socket receive buffer size to one to avoid that. (zero is
74 rejected as non-sensical by some BSD kernels) */
75 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 ||
fd9fa481
SK
76 (flags = fcntl(fd, F_GETFL, 0)) == -1 ||
77 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
3be34541
SK
78 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1)
79 die("cannot create DHCP packet socket: %s. "
80 "Is CONFIG_PACKET enabled in your kernel?", NULL);
44a2a316
SK
81#endif
82
3be34541
SK
83 daemon->dhcp_raw_fd = fd;
84
dfa666f2
SK
85 /* If the same IP appears in more than one host config, then DISCOVER
86 for one of the hosts will get the address, but REQUEST will be NAKed,
87 since the address is reserved by the other one -> protocol loop. */
3be34541 88 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
dfa666f2
SK
89 for (cp = configs->next; cp; cp = cp->next)
90 if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
3be34541
SK
91 die("duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr));
92
93 daemon->dhcp_packet = safe_malloc(sizeof(struct udp_dhcp_packet));
94 /* These two each hold a DHCP option max size 256
95 and get a terminating zero added */
96 daemon->dhcp_buff = safe_malloc(257);
97 daemon->dhcp_buff2 = safe_malloc(257);
98
44a2a316
SK
99}
100
3be34541 101void dhcp_packet(struct daemon *daemon, time_t now)
9e4abcb5 102{
3be34541
SK
103 struct udp_dhcp_packet *rawpacket = daemon->dhcp_packet;
104 struct dhcp_packet *mess = &rawpacket->data;
44a2a316
SK
105 struct dhcp_context *context;
106 struct iname *tmp;
107 struct ifreq ifr;
108 struct msghdr msg;
109 struct iovec iov[2];
110 struct cmsghdr *cmptr;
111 int sz, newlen, iface_index = 0;
3be34541 112 struct in_addr iface_netmask, iface_addr, iface_broadcast;
44a2a316
SK
113#ifdef HAVE_BPF
114 unsigned char iface_hwaddr[ETHER_ADDR_LEN];
9e4abcb5
SK
115#endif
116
44a2a316
SK
117 union {
118 struct cmsghdr align; /* this ensures alignment */
119#ifdef IP_PKTINFO
120 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
121#else
122 char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
9e4abcb5 123#endif
44a2a316
SK
124 } control_u;
125
3be34541
SK
126 iov[0].iov_base = (char *)mess;
127 iov[0].iov_len = sizeof(struct dhcp_packet);
9e4abcb5 128
44a2a316
SK
129 msg.msg_control = control_u.control;
130 msg.msg_controllen = sizeof(control_u);
131 msg.msg_flags = 0;
132 msg.msg_name = NULL;
133 msg.msg_namelen = 0;
134 msg.msg_iov = iov;
135 msg.msg_iovlen = 1;
136
3be34541 137 sz = recvmsg(daemon->dhcpfd, &msg, 0);
44a2a316
SK
138
139 if (sz < (int)(sizeof(*mess) - sizeof(mess->options)))
140 return;
141
142#if defined (IP_PKTINFO)
143 if (msg.msg_controllen < sizeof(struct cmsghdr))
144 return;
145 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
146 if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
147 iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
148
8a911ccc 149 if (!(ifr.ifr_ifindex = iface_index) ||
3be34541 150 ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
44a2a316 151 return;
9e4abcb5 152
44a2a316
SK
153#elif defined(IP_RECVIF)
154 if (msg.msg_controllen < sizeof(struct cmsghdr))
155 return;
156 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
157 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
158 iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
159
160 if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
161 return;
162
163#else
3be34541
SK
164 {
165 struct iname *name;
fd9fa481 166 for (name = daemon->if_names; name->isloop; name = name->next);
3be34541
SK
167 strcpy(ifr.ifr_name, name->name);
168 }
9e4abcb5
SK
169#endif
170
171#ifdef HAVE_BPF
44a2a316 172 ifr.ifr_addr.sa_family = AF_LINK;
3be34541 173 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0)
44a2a316
SK
174 return;
175 memcpy(iface_hwaddr, LLADDR((struct sockaddr_dl *)&ifr.ifr_addr), ETHER_ADDR_LEN);
176#endif
177
178 ifr.ifr_addr.sa_family = AF_INET;
3be34541 179 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) < 0 )
44a2a316
SK
180 return;
181 iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
182
183 /* enforce available interface configuration */
3be34541 184 for (tmp = daemon->if_except; tmp; tmp = tmp->next)
44a2a316
SK
185 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
186 return;
187
3be34541 188 if (daemon->if_names || daemon->if_addrs)
44a2a316 189 {
3be34541 190 for (tmp = daemon->if_names; tmp; tmp = tmp->next)
44a2a316
SK
191 if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
192 break;
193 if (!tmp)
3be34541 194 for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
44a2a316
SK
195 if (tmp->addr.sa.sa_family == AF_INET &&
196 tmp->addr.in.sin_addr.s_addr == iface_addr.s_addr)
197 break;
198 if (!tmp)
199 return;
200 }
201
3be34541
SK
202 iface_netmask.s_addr = 0;
203 iface_broadcast.s_addr = 0;
44a2a316 204
3be34541 205 for (context = daemon->dhcp; context; context = context->next)
44a2a316 206 {
3be34541
SK
207 /* Fill in missing netmask and broadcast address values for any approriate
208 dhcp-ranges which match this interface and don't have them. */
209 if (!context->netmask.s_addr)
210 {
211 if (!iface_netmask.s_addr && ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
212 iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
213
214 if (iface_netmask.s_addr &&
36717eee
SK
215 (is_same_net(iface_addr, context->start, iface_netmask) ||
216 is_same_net(iface_addr, context->end, iface_netmask)))
217 {
218 context->netmask = iface_netmask;
219 if (!(is_same_net(iface_addr, context->start, iface_netmask) &&
220 is_same_net(iface_addr, context->end, iface_netmask)))
221 {
222 strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
223 strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
224 syslog(LOG_WARNING, "DHCP range %s -- %s is not consistent with netmask %s",
225 daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(iface_netmask));
226 }
227 }
3be34541
SK
228 }
229
230 /* Determine "default" default routes. These are to this server or the relay agent.
231 Also broadcast addresses, if not specified */
232 if (context->netmask.s_addr)
233 {
234 if (is_same_net(iface_addr, context->start, context->netmask))
235 {
236 if (!context->router.s_addr)
237 context->router = iface_addr;
238 if (!context->broadcast.s_addr)
239 {
240 if (!iface_broadcast.s_addr && ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
241 iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
36717eee
SK
242 if (iface_broadcast.s_addr &&
243 is_same_net(iface_broadcast, context->start, context->netmask))
3be34541
SK
244 context->broadcast = iface_broadcast;
245 else
246 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
247 }
248 }
249 else if (mess->giaddr.s_addr && is_same_net(mess->giaddr, context->start, context->netmask))
250 {
251 if (!context->router.s_addr)
252 context->router = mess->giaddr;
253 /* fill in missing broadcast addresses for relayed ranges */
254 if (!context->broadcast.s_addr)
255 context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
256 }
257 }
44a2a316
SK
258 }
259
44a2a316 260 lease_prune(NULL, now); /* lose any expired leases */
3be34541 261 newlen = dhcp_reply(daemon, iface_addr, ifr.ifr_name, sz, now);
44a2a316 262 lease_update_file(0, now);
fd9fa481 263 lease_update_dns(daemon);
44a2a316
SK
264
265 if (newlen == 0)
266 return;
267
268 if (mess->giaddr.s_addr || mess->ciaddr.s_addr)
269 {
3be34541 270 /* To send to BOOTP relay or configured client, use the IP packet */
44a2a316
SK
271
272 struct sockaddr_in dest;
273 dest.sin_family = AF_INET;
3be34541
SK
274#ifdef HAVE_SOCKADDR_SA_LEN
275 dest.sin_len = sizeof(struct sockaddr_in);
276#endif
277
44a2a316
SK
278 if (mess->giaddr.s_addr)
279 {
280 dest.sin_port = htons(DHCP_SERVER_PORT);
281 dest.sin_addr = mess->giaddr;
9e4abcb5 282 }
44a2a316
SK
283 else
284 {
285 dest.sin_port = htons(DHCP_CLIENT_PORT);
286 dest.sin_addr = mess->ciaddr;
287 }
288
fd9fa481
SK
289 while(sendto(daemon->dhcpfd, mess, newlen, 0,
290 (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
291 retry_send());
44a2a316
SK
292 }
293 else
294 {
295 /* Hairy stuff, packet either has to go to the
296 net broadcast or the destination can't reply to ARP yet,
297 but we do know the physical address.
298 Build the packet by steam, and send directly, bypassing
299 the kernel IP stack */
300
301 u32 i, sum;
302 unsigned char hwdest[ETHER_ADDR_LEN];
303
304 if (ntohs(mess->flags) & 0x8000)
305 {
306 memset(hwdest, 255, ETHER_ADDR_LEN);
307 rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST;
308 }
309 else
310 {
311 memcpy(hwdest, mess->chaddr, ETHER_ADDR_LEN);
312 rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr;
313 }
314
315 rawpacket->ip.ip_p = IPPROTO_UDP;
316 rawpacket->ip.ip_src.s_addr = iface_addr.s_addr;
317 rawpacket->ip.ip_len = htons(sizeof(struct ip) +
318 sizeof(struct udphdr) +
319 newlen) ;
320 rawpacket->ip.ip_hl = sizeof(struct ip) / 4;
321 rawpacket->ip.ip_v = IPVERSION;
322 rawpacket->ip.ip_tos = 0;
323 rawpacket->ip.ip_id = htons(0);
324 rawpacket->ip.ip_off = htons(0x4000); /* don't fragment */
325 rawpacket->ip.ip_ttl = IPDEFTTL;
326 rawpacket->ip.ip_sum = 0;
327 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
328 sum += ((u16 *)&rawpacket->ip)[i];
329 while (sum>>16)
330 sum = (sum & 0xffff) + (sum >> 16);
331 rawpacket->ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
332
333 rawpacket->udp.uh_sport = htons(DHCP_SERVER_PORT);
334 rawpacket->udp.uh_dport = htons(DHCP_CLIENT_PORT);
335 ((u8 *)&rawpacket->data)[newlen] = 0; /* for checksum, in case length is odd. */
336 rawpacket->udp.uh_sum = 0;
337 rawpacket->udp.uh_ulen = sum = htons(sizeof(struct udphdr) + newlen);
338 sum += htons(IPPROTO_UDP);
339 for (i = 0; i < 4; i++)
340 sum += ((u16 *)&rawpacket->ip.ip_src)[i];
341 for (i = 0; i < (sizeof(struct udphdr) + newlen + 1) / 2; i++)
342 sum += ((u16 *)&rawpacket->udp)[i];
343 while (sum>>16)
344 sum = (sum & 0xffff) + (sum >> 16);
345 rawpacket->udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
346
347 {
348#ifdef HAVE_BPF
349 struct ether_header header;
350
351 header.ether_type = htons(ETHERTYPE_IP);
352 memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN);
353 memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN);
354
3be34541 355 ioctl(daemon->dhcp_raw_fd, BIOCSETIF, &ifr);
44a2a316
SK
356
357 iov[0].iov_base = (char *)&header;
358 iov[0].iov_len = sizeof(struct ether_header);
359 iov[1].iov_base = (char *)rawpacket;
360 iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
fd9fa481
SK
361 while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 &&
362 errno == EINTR);
44a2a316
SK
363#else
364 struct sockaddr_ll dest;
365
366 dest.sll_family = AF_PACKET;
367 dest.sll_halen = ETHER_ADDR_LEN;
368 dest.sll_ifindex = iface_index;
369 dest.sll_protocol = htons(ETHERTYPE_IP);
370 memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
fd9fa481
SK
371 while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
372 0, (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
373 errno == EINTR);
44a2a316
SK
374#endif
375 }
9e4abcb5
SK
376 }
377}
378
379int address_available(struct dhcp_context *context, struct in_addr taddr)
380{
36717eee
SK
381 /* Check is an address is OK for this network, check all
382 possible ranges. */
9e4abcb5 383
36717eee 384 unsigned int start, end, addr = ntohl(taddr.s_addr);
9e4abcb5 385
36717eee
SK
386 for (; context; context = context->current)
387 {
388 start = ntohl(context->start.s_addr);
389 end = ntohl(context->end.s_addr);
9e4abcb5 390
36717eee
SK
391 if (!context->static_only &&
392 addr >= start &&
393 addr <= end)
394 return 1;
395 }
9e4abcb5 396
36717eee 397 return 0;
9e4abcb5 398}
dfa666f2
SK
399
400struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
401{
402 struct dhcp_config *config;
403
404 for (config = configs; config; config = config->next)
405 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
406 return config;
407
408 return NULL;
409}
9e4abcb5 410
3be34541 411int address_allocate(struct dhcp_context *context, struct daemon *daemon,
a84fa1d0 412 struct in_addr *addrp, unsigned char *hwaddr)
9e4abcb5 413{
feba5c1d 414 /* Find a free address: exclude anything in use and anything allocated to
9e4abcb5
SK
415 a particular hwaddr/clientid/hostname in our configuration */
416
a84fa1d0 417 struct in_addr start, addr ;
feba5c1d 418 unsigned int i, j;
a84fa1d0 419
36717eee
SK
420 for (; context; context = context->current)
421 if (!context->static_only)
9e4abcb5 422 {
36717eee
SK
423 /* pick a seed based on hwaddr then iterate until we find a free address. */
424 for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
425 j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
426
427 start.s_addr = addr.s_addr =
428 htonl(ntohl(context->start.s_addr) +
429 (j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
430
431 do {
432 if (!lease_find_by_addr(addr) &&
433 !config_find_by_address(daemon->dhcp_conf, addr))
434 {
435 if (icmp_ping(daemon, addr))
436 /* perturb address selection so that we are
437 less likely to try this address again. */
438 context->addr_epoch++;
439 else
440 {
441 *addrp = addr;
442 return 1;
443 }
444 }
3be34541 445
36717eee
SK
446 addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
447
448 if (addr.s_addr == htonl(ntohl(context->end.s_addr) + 1))
449 addr = context->start;
450
451 } while (addr.s_addr != start.s_addr);
452 }
9e4abcb5
SK
453 return 0;
454}
455
456static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
457{
458 if (!context)
459 return 1;
33820b7e 460 if (!(config->flags & CONFIG_ADDR))
9e4abcb5 461 return 1;
a84fa1d0 462 if (is_same_net(config->addr, context->start, context->netmask))
9e4abcb5
SK
463 return 1;
464
465 return 0;
466}
467
468struct dhcp_config *find_config(struct dhcp_config *configs,
469 struct dhcp_context *context,
470 unsigned char *clid, int clid_len,
471 unsigned char *hwaddr, char *hostname)
472{
473 struct dhcp_config *config;
474
475 if (clid_len)
476 for (config = configs; config; config = config->next)
33820b7e
SK
477 if (config->flags & CONFIG_CLID)
478 {
479 if (config->clid_len == clid_len &&
480 memcmp(config->clid, clid, clid_len) == 0 &&
481 is_addr_in_context(context, config))
482 return config;
483
484 /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
485 cope with that here */
486 if (*clid == 0 && config->clid_len == clid_len-1 &&
487 memcmp(config->clid, clid+1, clid_len-1) == 0 &&
488 is_addr_in_context(context, config))
489 return config;
490 }
491
9e4abcb5 492 for (config = configs; config; config = config->next)
33820b7e
SK
493 if ((config->flags & CONFIG_HWADDR) &&
494 memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
9e4abcb5
SK
495 is_addr_in_context(context, config))
496 return config;
497
498 if (hostname)
499 for (config = configs; config; config = config->next)
33820b7e
SK
500 if ((config->flags & CONFIG_NAME) &&
501 hostname_isequal(config->hostname, hostname) &&
9e4abcb5
SK
502 is_addr_in_context(context, config))
503 return config;
504
505 return NULL;
506}
507
3be34541 508void dhcp_read_ethers(struct daemon *daemon)
44a2a316
SK
509{
510 FILE *f = fopen(ETHERSFILE, "r");
33820b7e 511 unsigned int flags, e0, e1, e2, e3, e4, e5;
3be34541 512 char *buff = daemon->namebuff;
33820b7e 513 char *ip, *cp;
44a2a316 514 struct in_addr addr;
33820b7e 515 unsigned char hwaddr[ETHER_ADDR_LEN];
3be34541 516 struct dhcp_config *config, *configs = daemon->dhcp_conf;
33820b7e 517 int count = 0;
44a2a316
SK
518
519 if (!f)
33820b7e
SK
520 {
521 syslog(LOG_ERR, "failed to read " ETHERSFILE ":%m");
3be34541 522 return;
33820b7e
SK
523 }
524
44a2a316
SK
525 while (fgets(buff, MAXDNAME, f))
526 {
33820b7e 527 while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
44a2a316
SK
528 buff[strlen(buff)-1] = 0;
529
530 if ((*buff == '#') || (*buff == '+'))
531 continue;
532
33820b7e
SK
533 for (ip = buff; *ip && !isspace(*ip); ip++);
534 for(; *ip && isspace(*ip); ip++)
44a2a316
SK
535 *ip = 0;
536 if (!*ip)
537 continue;
538
539 if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5))
540 continue;
541
33820b7e
SK
542 hwaddr[0] = e0;
543 hwaddr[1] = e1;
544 hwaddr[2] = e2;
545 hwaddr[3] = e3;
546 hwaddr[4] = e4;
547 hwaddr[5] = e5;
548
44a2a316
SK
549 /* check for name or dotted-quad */
550 for (cp = ip; *cp; cp++)
551 if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
552 break;
553
554 if (!*cp)
555 {
44a2a316 556 if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
1cff166d 557 continue;
33820b7e 558 flags = CONFIG_ADDR;
1cff166d
SK
559
560 for (config = configs; config; config = config->next)
33820b7e 561 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
1cff166d 562 break;
44a2a316
SK
563 }
564 else
565 {
1cff166d
SK
566 if (!canonicalise(ip))
567 continue;
33820b7e 568 flags = CONFIG_NAME;
1cff166d
SK
569
570 for (config = configs; config; config = config->next)
33820b7e 571 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip))
1cff166d 572 break;
44a2a316
SK
573 }
574
1cff166d
SK
575 if (!config)
576 {
33820b7e
SK
577 for (config = configs; config; config = config->next)
578 if ((config->flags & CONFIG_HWADDR) &&
579 memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
580 break;
581
582 if (!config)
583 {
584 if (!(config = malloc(sizeof(struct dhcp_config))))
585 continue;
586 config->flags = 0;
587 config->next = configs;
588 configs = config;
589 }
590
591 config->flags |= flags;
592
593 if (flags & CONFIG_NAME)
594 {
595 if ((config->hostname = malloc(strlen(ip)+1)))
596 strcpy(config->hostname, ip);
597 else
598 config->flags &= ~CONFIG_NAME;
599 }
600
601 if (flags & CONFIG_ADDR)
602 config->addr = addr;
1cff166d 603 }
33820b7e 604
de37951c 605 config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
33820b7e 606 memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
1cff166d 607
33820b7e 608 count++;
44a2a316
SK
609 }
610
611 fclose(f);
33820b7e
SK
612
613 syslog(LOG_INFO, "read " ETHERSFILE " - %d addresses", count);
3be34541
SK
614
615 daemon->dhcp_conf = configs;
44a2a316
SK
616}
617
618void dhcp_update_configs(struct dhcp_config *configs)
1ab84e2f 619{
44a2a316
SK
620 /* Some people like to keep all static IP addresses in /etc/hosts.
621 This goes through /etc/hosts and sets static addresses for any DHCP config
622 records which don't have an address and whose name matches. */
623
1ab84e2f
SK
624 struct dhcp_config *config;
625 struct crec *crec;
44a2a316 626
1ab84e2f 627 for (config = configs; config; config = config->next)
33820b7e
SK
628 if (!(config->flags & CONFIG_ADDR) &&
629 (config->flags & CONFIG_NAME) &&
1ab84e2f
SK
630 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
631 (crec->flags & F_HOSTS))
33820b7e 632 {
fd9fa481 633 config->addr = crec->addr.addr.addr.addr4;
33820b7e
SK
634 config->flags |= CONFIG_ADDR;
635 }
1ab84e2f 636}
44a2a316 637