dhcp.c revision ffd68729961f7383f2e35494a03ccdef20f86c98
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley 2a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 3a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt This program is free software; you can redistribute it and/or modify 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt it under the terms of the GNU General Public License as published by 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt the Free Software Foundation; version 2 dated June, 1991, or 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt (at your option) version 3 dated 29 June, 2007. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt This program is distributed in the hope that it will be useful, 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt but WITHOUT ANY WARRANTY; without even the implied warranty of 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt GNU General Public License for more details. 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt You should have received a copy of the GNU General Public License 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt along with this program. If not, see <http://www.gnu.org/licenses/>. 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt*/ 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "dnsmasq.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_DHCP 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct iface_param { 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr relay, primary; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dhcp_context *current; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ind; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int complete_context(struct in_addr local, int if_index, 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr netmask, struct in_addr broadcast, void *vparam); 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid dhcp_init(void) 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in saddr; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int oneopt = 1; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int mtu = IP_PMTUDISC_DONT; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (fd == -1) 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET); 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!fix_fd(fd) || 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 || 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_LINUX_NETWORK) 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 || 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 || 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1) 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET); 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* When bind-interfaces is set, there might be more than one dnmsasq 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt instance binding port 67. That's OK if they serve different networks. 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */ 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (daemon->options & OPT_NOWILD) 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef SO_REUSEPORT 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt)); 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)); 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rc == -1) 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET); 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memset(&saddr, 0, sizeof(saddr)); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt saddr.sin_family = AF_INET; 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt saddr.sin_port = htons(daemon->dhcp_server_port); 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt saddr.sin_addr.s_addr = INADDR_ANY; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_SOCKADDR_SA_LEN 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt saddr.sin_len = sizeof(struct sockaddr_in); 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))) 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET); 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt daemon->dhcpfd = fd; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_BSD_NETWORK) 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* When we're not using capabilities, we need to do this here before 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt we drop root. Also, set buffer size small, to avoid wasting 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt kernel buffers */ 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (daemon->options & OPT_NO_PING) 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt daemon->dhcp_icmp_fd = -1; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 || 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 ) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET); 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Make BPF raw send socket */ 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt init_bpf(); 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt check_dhcp_hosts(1); 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len); 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid dhcp_packet(time_t now) 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dhcp_packet *mess; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dhcp_context *context; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct iname *tmp; 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ifreq ifr; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct msghdr msg; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in dest; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct cmsghdr *cmptr; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct iovec iov; 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ssize_t sz; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int iface_index = 0, unicast_dest = 0, is_inform = 0; 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr iface_addr, *addrp = NULL; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct iface_param parm; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt union { 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct cmsghdr align; /* this ensures alignment */ 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_LINUX_NETWORK) 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_SOLARIS_NETWORK) 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char control[CMSG_SPACE(sizeof(unsigned int))]; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_BSD_NETWORK) 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } control_u; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_control = NULL; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_controllen = 0; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_name = NULL; 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_namelen = 0; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_iov = &daemon->dhcp_packet; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_iovlen = 1; 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (1) 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt msg.msg_flags = 0; 1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR); 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sz == -1) 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(msg.msg_flags & MSG_TRUNC)) 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Very new Linux kernels return the actual size needed, 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt older ones always return truncated size */ 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((size_t)sz == daemon->dhcp_packet.iov_len) 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!expand_buf(&daemon->dhcp_packet, sz + 100)) 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt expand_buf(&daemon->dhcp_packet, sz); 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* expand_buf may have moved buffer */ 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_controllen = sizeof(control_u); 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_control = control_u.control; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_flags = 0; 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_name = &dest; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_namelen = sizeof(dest); 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))) 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined (HAVE_LINUX_NETWORK) 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg.msg_controllen >= sizeof(struct cmsghdr)) 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST) 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unicast_dest = 1; 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_BSD_NETWORK) 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg.msg_controllen >= sizeof(struct cmsghdr)) 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_SOLARIS_NETWORK) 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg.msg_controllen >= sizeof(struct cmsghdr)) 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface_index = *((unsigned int *)CMSG_DATA(cmptr)); 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name)) 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef MSG_BCAST 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* OpenBSD tells us when a packet was broadcast */ 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(msg.msg_flags & MSG_BCAST)) 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unicast_dest = 1; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ifr.ifr_addr.sa_family = AF_INET; 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 ) 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addrp = &iface_addr; 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index)) 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* interface may have been changed by alias in iface_check */ 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!addrp) 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1) 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name); 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* unlinked contexts are marked by context->current == context */ 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (context = daemon->dhcp; context; context = context->next) 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->current = context; 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt parm.relay = mess->giaddr; 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt parm.primary = iface_addr; 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt parm.current = NULL; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt parm.ind = iface_index; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface_enumerate(&parm, complete_context, NULL)) 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt lease_prune(NULL, now); /* lose any expired leases */ 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt now, unicast_dest, &is_inform); 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt lease_update_file(now); 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt lease_update_dns(); 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iov.iov_len == 0) 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_name = &dest; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_namelen = sizeof(dest); 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_control = NULL; 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_controllen = 0; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_iov = &iov; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iov.iov_base = daemon->dhcp_packet.iov_base; 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* packet buffer may have moved */ 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_SOCKADDR_SA_LEN 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_len = sizeof(struct sockaddr_in); 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mess->giaddr.s_addr) 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Send to BOOTP relay */ 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(daemon->dhcp_server_port); 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr = mess->giaddr; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (mess->ciaddr.s_addr) 27450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt { 27550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt /* If the client's idea of its own address tallys with 27650b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt the source address in the request packet, we believe the 27750b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt source port too, and send back to that. If we're replying 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt to a DHCPINFORM, trust the source address always. */ 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) || 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port == 0 || dest.sin_addr.s_addr == 0) 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(daemon->dhcp_client_port); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr = mess->ciaddr; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(HAVE_LINUX_NETWORK) 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 || 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0) 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* broadcast to 255.255.255.255 (or mac address invalid) */ 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_pktinfo *pkt; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_control = control_u.control; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_controllen = sizeof(control_u); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cmptr = CMSG_FIRSTHDR(&msg); 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pkt = (struct in_pktinfo *)CMSG_DATA(cmptr); 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pkt->ipi_ifindex = iface_index; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pkt->ipi_spec_dst.s_addr = 0; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cmptr->cmsg_level = SOL_IP; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cmptr->cmsg_type = IP_PKTINFO; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr.s_addr = INADDR_BROADCAST; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(daemon->dhcp_client_port); 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* unicast to unconfigured client. Inject mac address direct into ARP cache. 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr limits size to 14 bytes. */ 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct arpreq req; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr = mess->yiaddr; 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(daemon->dhcp_client_port); 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *((struct sockaddr_in *)&req.arp_pa) = dest; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req.arp_ha.sa_family = mess->htype; 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen); 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strncpy(req.arp_dev, ifr.ifr_name, 16); 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req.arp_flags = ATF_COM; 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ioctl(daemon->dhcpfd, SIOCSARP, &req); 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_SOLARIS_NETWORK) 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER) 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* broadcast to 255.255.255.255 (or mac address invalid) */ 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr.s_addr = INADDR_BROADCAST; 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(daemon->dhcp_client_port); 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* note that we don't specify the interface here: that's done by the 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IP_BOUND_IF sockopt lower down. */ 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* unicast to unconfigured client. Inject mac address direct into ARP cache. 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Note that this only works for ethernet on solaris, because we use SIOCSARP 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt and not SIOCSXARP, which would be perfect, except that it returns ENXIO 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mysteriously. Bah. Fall back to broadcast for other net types. */ 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct arpreq req; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr = mess->yiaddr; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(daemon->dhcp_client_port); 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *((struct sockaddr_in *)&req.arp_pa) = dest; 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req.arp_ha.sa_family = AF_UNSPEC; 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen); 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt req.arp_flags = ATF_COM; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ioctl(daemon->dhcpfd, SIOCSARP, &req); 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#elif defined(HAVE_BSD_NETWORK) 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt send_via_bpf(mess, iov.iov_len, iface_addr, &ifr); 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HAVE_SOLARIS_NETWORK 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index)); 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send()); 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt of each interface (and any relay address) and does the following things: 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived. 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2) Fills in any netmask and broadcast addresses which have not been explicitly configured. 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3) Fills in local (this host) and router (this host or relay) addresses. 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current. 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Note that the current chain may be superceded later for configured hosts or those coming via gateways. */ 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int complete_context(struct in_addr local, int if_index, 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr netmask, struct in_addr broadcast, void *vparam) 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dhcp_context *context; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct iface_param *param = vparam; 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (context = daemon->dhcp; context; context = context->next) 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(context->flags & CONTEXT_NETMASK) && 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (is_same_net(local, context->start, netmask) || 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt is_same_net(local, context->end, netmask))) 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (context->netmask.s_addr != netmask.s_addr && 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(is_same_net(local, context->start, netmask) && 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt is_same_net(local, context->end, netmask))) 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strcpy(daemon->dhcp_buff, inet_ntoa(context->start)); 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strcpy(daemon->dhcp_buff2, inet_ntoa(context->end)); 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"), 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask)); 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->netmask = netmask; 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (context->netmask.s_addr) 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (is_same_net(local, context->start, context->netmask) && 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt is_same_net(local, context->end, context->netmask)) 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* link it onto the current chain if we've not seen it before */ 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (if_index == param->ind && context->current == context) 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->router = local; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->local = local; 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->current = param->current; 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt param->current = context; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(context->flags & CONTEXT_BRDCAST)) 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (is_same_net(broadcast, context->start, context->netmask)) 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->broadcast = broadcast; 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask)) 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->router = param->relay; 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->local = param->primary; 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* fill in missing broadcast addresses for relayed ranges */ 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(context->flags & CONTEXT_BRDCAST)) 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct dhcp_context *address_available(struct dhcp_context *context, 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct in_addr taddr, 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dhcp_netid *netids) 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Check is an address is OK for this network, check all 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt possible ranges. Make sure that the address isn't in use 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt by the server itself. */ 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned int start, end, addr = ntohl(taddr.s_addr); 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct dhcp_context *tmp; 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (tmp = context; tmp; tmp = tmp->current) 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (taddr.s_addr == context->router.s_addr) 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (tmp = context; tmp; tmp = tmp->current) 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt start = ntohl(tmp->start.s_addr); 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = ntohl(tmp->end.s_addr); 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!(tmp->flags & CONTEXT_STATIC) && 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr >= start && 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr <= end && 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt match_netid(tmp->filter, netids, 1)) 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return tmp; 45361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 45461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 45561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 45661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt} 45761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 45861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct dhcp_context *narrow_context(struct dhcp_context *context, 45961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct in_addr taddr, 46061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt struct dhcp_netid *netids) 46161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{ 46261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt /* We start of with a set of possible contexts, all on the current physical interface. 46361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt These are chained on ->current. 464a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt Here we have an address, and return the actual context correponding to that 465a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt address. Note that none may fit, if the address came a dhcp-host and is outside 466a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt any dhcp-range. In that case we return a static range if possible, or failing that, 467a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt any context on the correct subnet. (If there's more than one, this is a dodgy 468a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt configuration: maybe there should be a warning.) */ 469a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 470a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_context *tmp; 471a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 472a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!(tmp = address_available(context, taddr, netids))) 473a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 474a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (tmp = context; tmp; tmp = tmp->current) 475a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (is_same_net(taddr, tmp->start, tmp->netmask) && 476a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (tmp->flags & CONTEXT_STATIC)) 477a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 478a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 479a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!tmp) 480a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (tmp = context; tmp; tmp = tmp->current) 481a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (is_same_net(taddr, tmp->start, tmp->netmask)) 482a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 483a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 484a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 485a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Only one context allowed now */ 486a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (tmp) 487a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tmp->current = NULL; 488a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 489a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return tmp; 490a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 491a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 492a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstruct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr) 493a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 494a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_config *config; 495a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 496a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (config = configs; config; config = config->next) 497a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) 498a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return config; 499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 500a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return NULL; 501a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 502a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 503a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt/* Is every member of check matched by a member of pool? 504a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt If tagnotneeded, untagged is OK */ 505a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded) 506a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 507a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_netid *tmp1; 508a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!check && !tagnotneeded) 510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; 511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (; check; check = check->next) 513a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 514a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (check->net[0] != '#') 515a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 516a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (tmp1 = pool; tmp1; tmp1 = tmp1->next) 517a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (strcmp(check->net, tmp1->net) == 0) 518a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!tmp1) 520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; 521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else 523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (tmp1 = pool; tmp1; tmp1 = tmp1->next) 524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (strcmp((check->net)+1, tmp1->net) == 0) 525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; 526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint address_allocate(struct dhcp_context *context, 531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct in_addr *addrp, unsigned char *hwaddr, int hw_len, 532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_netid *netids, time_t now) 533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Find a free address: exclude anything in use and anything allocated to 535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt a particular hwaddr/clientid/hostname in our configuration. 536a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt Try to return from contexts which match netids first. */ 537a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 538a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct in_addr start, addr; 539a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_context *c, *d; 540a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int i, pass; 541a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt unsigned int j; 542a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 543a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* hash hwaddr */ 544a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (j = 0, i = 0; i < hw_len; i++) 545a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16); 546a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 547a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (pass = 0; pass <= 1; pass++) 548a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (c = context; c; c = c->current) 549a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (c->flags & CONTEXT_STATIC) 550a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt continue; 551a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (!match_netid(c->filter, netids, pass)) 552a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt continue; 553a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else 554a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 555a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* pick a seed based on hwaddr then iterate until we find a free address. */ 556a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt start.s_addr = addr.s_addr = 557a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt htonl(ntohl(c->start.s_addr) + 558a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr)))); 559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 560a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt do { 561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* eliminate addresses in use by the server. */ 562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (d = context; d; d = d->current) 563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (addr.s_addr == d->router.s_addr) 564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt break; 565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 566a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* Addresses which end in .255 and .0 are broken in Windows even when using 567a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0 568a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt then 192.168.0.255 is a valid IP address, but not for Windows as it's 569a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt in the class C range. See KB281579. We therefore don't allocate these 570a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt addresses to avoid hard-to-diagnose problems. Thanks Bill. */ 571a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!d && 572a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt !lease_find_by_addr(addr) && 573a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt !config_find_by_address(daemon->dhcp_conf, addr) && 574a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (!IN_CLASSC(ntohl(addr.s_addr)) || 575a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0)))) 576a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 577a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct ping_result *r, *victim = NULL; 578a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/ 579a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt ((float)PING_WAIT))); 580a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 581a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *addrp = addr; 582a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 583a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (daemon->options & OPT_NO_PING) 584a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 585a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 586a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* check if we failed to ping addr sometime in the last 587a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt PING_CACHE_TIME seconds. If so, assume the same situation still exists. 588a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt This avoids problems when a stupid client bangs 589a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt on us repeatedly. As a final check, if we did more 590a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt than 60% of the possible ping checks in the last 591a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt PING_CACHE_TIME, we are in high-load mode, so don't do any more. */ 592a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (count = 0, r = daemon->ping_results; r; r = r->next) 593a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (difftime(now, r->time) > (float)PING_CACHE_TIME) 594a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt victim = r; /* old record */ 595a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else if (++count == max || r->addr.s_addr == addr.s_addr) 596a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 597a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 598a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (icmp_ping(addr)) 599a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* address in use: perturb address selection so that we are 600a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt less likely to try this address again. */ 601a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt c->addr_epoch++; 602a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else 603a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 604a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* at this point victim may hold an expired record */ 605a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!victim) 606a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 607a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if ((victim = whine_malloc(sizeof(struct ping_result)))) 608a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 609a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt victim->next = daemon->ping_results; 610a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt daemon->ping_results = victim; 611a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 612a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 613a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 614a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* record that this address is OK for 30s 615a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt without more ping checks */ 616a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (victim) 617a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 618a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt victim->addr = addr; 619a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt victim->time = now; 620a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 621a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 622a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 623a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 624a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 625a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 626a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 627a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1)) 628a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt addr = c->start; 629a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 630a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } while (addr.s_addr != start.s_addr); 631a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 632a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; 633a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 634a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 635a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config) 636a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 637a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!context) /* called via find_config() from lease_update_from_configs() */ 638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 639a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!(config->flags & CONFIG_ADDR)) 640a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 641a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (; context; context = context->current) 642a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (is_same_net(config->addr, context->start, context->netmask)) 643a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 644a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 645a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; 646a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 647a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 648a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtint config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type) 649a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 650a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct hwaddr_config *conf_addr; 651a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 652a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) 653a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (conf_addr->wildcard_mask == 0 && 654a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt conf_addr->hwaddr_len == len && 655a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) && 656a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt memcmp(conf_addr->hwaddr, hwaddr, len) == 0) 657a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 1; 658a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 659a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return 0; 660a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 661a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 662a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstruct dhcp_config *find_config(struct dhcp_config *configs, 663a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_context *context, 664a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt unsigned char *clid, int clid_len, 665a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt unsigned char *hwaddr, int hw_len, 666a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int hw_type, char *hostname) 667a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 668a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int count, new; 669a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_config *config, *candidate; 670a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct hwaddr_config *conf_addr; 671a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 672a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (clid) 673a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (config = configs; config; config = config->next) 674a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (config->flags & CONFIG_CLID) 675a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 676a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (config->clid_len == clid_len && 677a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt memcmp(config->clid, clid, clid_len) == 0 && 678a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt is_addr_in_context(context, config)) 679a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return config; 680a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 681a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and 682a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt cope with that here */ 683a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (*clid == 0 && config->clid_len == clid_len-1 && 684a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt memcmp(config->clid, clid+1, clid_len-1) == 0 && 685a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt is_addr_in_context(context, config)) 686a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return config; 687a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 688a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 689a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 690a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (config = configs; config; config = config->next) 691a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (config_has_mac(config, hwaddr, hw_len, hw_type) && 692a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt is_addr_in_context(context, config)) 693a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return config; 694a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 695a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (hostname && context) 696a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (config = configs; config; config = config->next) 697a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if ((config->flags & CONFIG_NAME) && 698a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt hostname_isequal(config->hostname, hostname) && 699a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt is_addr_in_context(context, config)) 700a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return config; 701a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 702a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* use match with fewest wildcast octets */ 703a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (candidate = NULL, count = 0, config = configs; config; config = config->next) 704a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (is_addr_in_context(context, config)) 705a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) 706a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (conf_addr->wildcard_mask != 0 && 707a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt conf_addr->hwaddr_len == hw_len && 708a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) && 709a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count) 710a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 711a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt count = new; 712a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt candidate = config; 713a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 714a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 715a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return candidate; 716a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt} 717a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 718a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtvoid dhcp_read_ethers(void) 719a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{ 720a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt FILE *f = fopen(ETHERSFILE, "r"); 721a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt unsigned int flags; 722a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char *buff = daemon->namebuff; 723a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char *ip, *cp; 724a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct in_addr addr; 725a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt unsigned char hwaddr[ETHER_ADDR_LEN]; 726a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_config **up, *tmp; 727a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt struct dhcp_config *config; 728a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt int count = 0, lineno = 0; 729a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 730a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt addr.s_addr = 0; /* eliminate warning */ 731a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 732a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!f) 733a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 734a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno)); 735a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt return; 736a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 737a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 738a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* This can be called again on SIGHUP, so remove entries created last time round. */ 739a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp) 740a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 741a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt tmp = config->next; 742a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (config->flags & CONFIG_FROM_ETHERS) 743a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 744a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *up = tmp; 745a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* cannot have a clid */ 746a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (config->flags & CONFIG_NAME) 747a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt free(config->hostname); 748a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt free(config->hwaddr); 749a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt free(config); 750a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 751a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt else 752a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt up = &config->next; 753a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 754a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 755a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt while (fgets(buff, MAXDNAME, f)) 756a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 757a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt char *host = NULL; 758a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 759a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt lineno++; 760a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 761a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1])) 762a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt buff[strlen(buff)-1] = 0; 763a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 764a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if ((*buff == '#') || (*buff == '+') || (*buff == 0)) 765a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt continue; 766a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 767a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (ip = buff; *ip && !isspace((int)*ip); ip++); 768a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for(; *ip && isspace((int)*ip); ip++) 769a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt *ip = 0; 770a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN) 771a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt { 772a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); 773a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt continue; 774a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt } 775a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt 776a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt /* check for name or dotted-quad */ 777a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt for (cp = ip; *cp; cp++) 778a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt if (!(*cp == '.' || (*cp >='0' && *cp <= '9'))) 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 780 781 if (!*cp) 782 { 783 if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1) 784 { 785 my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); 786 continue; 787 } 788 789 flags = CONFIG_ADDR; 790 791 for (config = daemon->dhcp_conf; config; config = config->next) 792 if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) 793 break; 794 } 795 else 796 { 797 int nomem; 798 if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host)) 799 { 800 if (!nomem) 801 my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); 802 free(host); 803 continue; 804 } 805 806 flags = CONFIG_NAME; 807 808 for (config = daemon->dhcp_conf; config; config = config->next) 809 if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host)) 810 break; 811 } 812 813 if (config && (config->flags & CONFIG_FROM_ETHERS)) 814 { 815 my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno); 816 continue; 817 } 818 819 if (!config) 820 { 821 for (config = daemon->dhcp_conf; config; config = config->next) 822 { 823 struct hwaddr_config *conf_addr = config->hwaddr; 824 if (conf_addr && 825 conf_addr->next == NULL && 826 conf_addr->wildcard_mask == 0 && 827 conf_addr->hwaddr_len == ETHER_ADDR_LEN && 828 (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) && 829 memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0) 830 break; 831 } 832 833 if (!config) 834 { 835 if (!(config = whine_malloc(sizeof(struct dhcp_config)))) 836 continue; 837 config->flags = CONFIG_FROM_ETHERS; 838 config->hwaddr = NULL; 839 config->domain = NULL; 840 config->next = daemon->dhcp_conf; 841 daemon->dhcp_conf = config; 842 } 843 844 config->flags |= flags; 845 846 if (flags & CONFIG_NAME) 847 { 848 config->hostname = host; 849 host = NULL; 850 } 851 852 if (flags & CONFIG_ADDR) 853 config->addr = addr; 854 } 855 856 config->flags |= CONFIG_NOCLID; 857 if (!config->hwaddr) 858 config->hwaddr = whine_malloc(sizeof(struct hwaddr_config)); 859 if (config->hwaddr) 860 { 861 memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN); 862 config->hwaddr->hwaddr_len = ETHER_ADDR_LEN; 863 config->hwaddr->hwaddr_type = ARPHRD_ETHER; 864 config->hwaddr->wildcard_mask = 0; 865 config->hwaddr->next = NULL; 866 } 867 count++; 868 869 free(host); 870 871 } 872 873 fclose(f); 874 875 my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count); 876} 877 878void check_dhcp_hosts(int fatal) 879{ 880 /* If the same IP appears in more than one host config, then DISCOVER 881 for one of the hosts will get the address, but REQUEST will be NAKed, 882 since the address is reserved by the other one -> protocol loop. 883 Also check that FQDNs match the domain we are using. */ 884 885 struct dhcp_config *configs, *cp; 886 887 for (configs = daemon->dhcp_conf; configs; configs = configs->next) 888 { 889 char *domain; 890 891 if ((configs->flags & DHOPT_BANK) || fatal) 892 { 893 for (cp = configs->next; cp; cp = cp->next) 894 if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr) 895 { 896 if (fatal) 897 die(_("duplicate IP address %s in dhcp-config directive."), 898 inet_ntoa(cp->addr), EC_BADCONF); 899 else 900 my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."), 901 inet_ntoa(cp->addr), daemon->dhcp_hosts_file); 902 configs->flags &= ~CONFIG_ADDR; 903 } 904 905 /* split off domain part */ 906 if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname))) 907 configs->domain = domain; 908 } 909 } 910} 911 912void dhcp_update_configs(struct dhcp_config *configs) 913{ 914 /* Some people like to keep all static IP addresses in /etc/hosts. 915 This goes through /etc/hosts and sets static addresses for any DHCP config 916 records which don't have an address and whose name matches. 917 We take care to maintain the invariant that any IP address can appear 918 in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, 919 restore the status-quo ante first. */ 920 921 struct dhcp_config *config; 922 struct crec *crec; 923 924 for (config = configs; config; config = config->next) 925 if (config->flags & CONFIG_ADDR_HOSTS) 926 config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS); 927 928 929 if (daemon->port != 0) 930 for (config = configs; config; config = config->next) 931 if (!(config->flags & CONFIG_ADDR) && 932 (config->flags & CONFIG_NAME) && 933 (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) && 934 (crec->flags & F_HOSTS)) 935 { 936 if (cache_find_by_name(crec, config->hostname, 0, F_IPV4)) 937 { 938 /* use primary (first) address */ 939 while (crec && !(crec->flags & F_REVERSE)) 940 crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4); 941 if (!crec) 942 continue; /* should be never */ 943 my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 944 config->hostname, inet_ntoa(crec->addr.addr.addr.addr4)); 945 } 946 947 if (config_find_by_address(configs, crec->addr.addr.addr.addr4)) 948 my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 949 inet_ntoa(crec->addr.addr.addr.addr4), config->hostname); 950 else 951 { 952 config->addr = crec->addr.addr.addr.addr4; 953 config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS; 954 } 955 } 956} 957 958/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts 959 for this address. If it has a domain part, that must match the set domain and 960 it gets stripped. The set of legal domain names is bigger than the set of legal hostnames 961 so check here that the domain name is legal as a hostname. */ 962char *host_from_dns(struct in_addr addr) 963{ 964 struct crec *lookup; 965 char *hostname = NULL; 966 char *d1, *d2; 967 968 if (daemon->port == 0) 969 return NULL; /* DNS disabled. */ 970 971 lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4); 972 if (lookup && (lookup->flags & F_HOSTS)) 973 { 974 hostname = daemon->dhcp_buff; 975 strncpy(hostname, cache_get_name(lookup), 256); 976 hostname[255] = 0; 977 d1 = strip_hostname(hostname); 978 d2 = get_domain(addr); 979 if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2)))) 980 hostname = NULL; 981 } 982 983 return hostname; 984} 985 986/* return domain or NULL if none. */ 987char *strip_hostname(char *hostname) 988{ 989 char *dot = strchr(hostname, '.'); 990 991 if (!dot) 992 return NULL; 993 994 *dot = 0; /* truncate */ 995 if (strlen(dot+1) != 0) 996 return dot+1; 997 998 return NULL; 999} 1000 1001#endif 1002 1003