1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley 2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is free software; you can redistribute it and/or modify 4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat it under the terms of the GNU General Public License as published by 5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat the Free Software Foundation; version 2 dated June, 1991, or 6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (at your option) version 3 dated 29 June, 2007. 7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is distributed in the hope that it will be useful, 9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat but WITHOUT ANY WARRANTY; without even the implied warranty of 10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat GNU General Public License for more details. 12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat You should have received a copy of the GNU General Public License 14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat along with this program. If not, see <http://www.gnu.org/licenses/>. 15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/ 16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include "dnsmasq.h" 18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_DHCP 20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct iface_param { 22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr relay, primary; 23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *current; 24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int ind; 25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}; 26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int complete_context(struct in_addr local, int if_index, 28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr netmask, struct in_addr broadcast, void *vparam); 29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid dhcp_init(void) 31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sockaddr_in saddr; 34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int oneopt = 1; 35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int mtu = IP_PMTUDISC_DONT; 37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (fd == -1) 40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET); 41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!fix_fd(fd) || 43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 || 45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 || 48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 || 50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1) 52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET); 53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* When bind-interfaces is set, there might be more than one dnmsasq 55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat instance binding port 67. That's OK if they serve different networks. 56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */ 57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->options & OPT_NOWILD) 58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef SO_REUSEPORT 60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt)); 61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#else 62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)); 63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (rc == -1) 65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET); 66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memset(&saddr, 0, sizeof(saddr)); 69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat saddr.sin_family = AF_INET; 70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat saddr.sin_port = htons(daemon->dhcp_server_port); 71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat saddr.sin_addr.s_addr = INADDR_ANY; 72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOCKADDR_SA_LEN 73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat saddr.sin_len = sizeof(struct sockaddr_in); 74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))) 77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET); 78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->dhcpfd = fd; 80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_BSD_NETWORK) 82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* When we're not using capabilities, we need to do this here before 83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat we drop root. Also, set buffer size small, to avoid wasting 84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat kernel buffers */ 85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->options & OPT_NO_PING) 87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->dhcp_icmp_fd = -1; 88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 || 89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 ) 90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat die(_("cannot create ICMP raw socket: %s."), NULL, EC_BADNET); 91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Make BPF raw send socket */ 93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat init_bpf(); 94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat check_dhcp_hosts(1); 97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet); 99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len); 100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid dhcp_packet(time_t now) 103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_packet *mess; 105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *context; 106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iname *tmp; 107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ifreq ifr; 108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct msghdr msg; 109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sockaddr_in dest; 110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct cmsghdr *cmptr; 111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iovec iov; 112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t sz; 113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int iface_index = 0, unicast_dest = 0, is_inform = 0; 114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr iface_addr, *addrp = NULL; 115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iface_param parm; 116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat union { 118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct cmsghdr align; /* this ensures alignment */ 119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; 121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK) 122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(unsigned int))]; 123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_BSD_NETWORK) 124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; 125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } control_u; 127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = NULL; 129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = 0; 130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_name = NULL; 131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_namelen = 0; 132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iov = &daemon->dhcp_packet; 133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iovlen = 1; 134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_flags = 0; 138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR); 139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (sz == -1) 141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(msg.msg_flags & MSG_TRUNC)) 144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Very new Linux kernels return the actual size needed, 147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat older ones always return truncated size */ 148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((size_t)sz == daemon->dhcp_packet.iov_len) 149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!expand_buf(&daemon->dhcp_packet, sz + 100)) 151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat expand_buf(&daemon->dhcp_packet, sz); 156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* expand_buf may have moved buffer */ 161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; 162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = sizeof(control_u); 163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = control_u.control; 164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_flags = 0; 165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_name = &dest; 166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_namelen = sizeof(dest); 167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR); 169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))) 171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined (HAVE_LINUX_NETWORK) 174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (msg.msg_controllen >= sizeof(struct cmsghdr)) 175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) 177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; 179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST) 180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unicast_dest = 1; 181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_BSD_NETWORK) 184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (msg.msg_controllen >= sizeof(struct cmsghdr)) 185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; 188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK) 191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (msg.msg_controllen >= sizeof(struct cmsghdr)) 192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) 194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iface_index = *((unsigned int *)CMSG_DATA(cmptr)); 195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name)) 199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef MSG_BCAST 202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* OpenBSD tells us when a packet was broadcast */ 203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(msg.msg_flags & MSG_BCAST)) 204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unicast_dest = 1; 205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ifr.ifr_addr.sa_family = AF_INET; 208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 ) 209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addrp = &iface_addr; 211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index)) 215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) 218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0)) 219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* interface may have been changed by alias in iface_check */ 222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!addrp) 223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1) 225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name); 227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; 231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* unlinked contexts are marked by context->current == context */ 234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (context = daemon->dhcp; context; context = context->next) 235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->current = context; 236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat parm.relay = mess->giaddr; 238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat parm.primary = iface_addr; 239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat parm.current = NULL; 240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat parm.ind = iface_index; 241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!iface_enumerate(&parm, complete_context, NULL)) 243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lease_prune(NULL, now); /* lose any expired leases */ 245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, 246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat now, unicast_dest, &is_inform); 247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lease_update_file(now); 248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lease_update_dns(); 249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (iov.iov_len == 0) 251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_name = &dest; 254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_namelen = sizeof(dest); 255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = NULL; 256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = 0; 257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iov = &iov; 258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov.iov_base = daemon->dhcp_packet.iov_base; 259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* packet buffer may have moved */ 261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; 262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOCKADDR_SA_LEN 264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_len = sizeof(struct sockaddr_in); 265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (mess->giaddr.s_addr) 268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Send to BOOTP relay */ 270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = htons(daemon->dhcp_server_port); 271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr = mess->giaddr; 272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (mess->ciaddr.s_addr) 274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* If the client's idea of its own address tallys with 276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat the source address in the request packet, we believe the 277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat source port too, and send back to that. If we're replying 278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat to a DHCPINFORM, trust the source address always. */ 279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) || 280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port == 0 || dest.sin_addr.s_addr == 0) 281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = htons(daemon->dhcp_client_port); 283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr = mess->ciaddr; 284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#if defined(HAVE_LINUX_NETWORK) 287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 || 288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0) 289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* broadcast to 255.255.255.255 (or mac address invalid) */ 291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_pktinfo *pkt; 292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = control_u.control; 293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = sizeof(control_u); 294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat cmptr = CMSG_FIRSTHDR(&msg); 295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat pkt = (struct in_pktinfo *)CMSG_DATA(cmptr); 296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat pkt->ipi_ifindex = iface_index; 297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat pkt->ipi_spec_dst.s_addr = 0; 298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat cmptr->cmsg_level = SOL_IP; 300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat cmptr->cmsg_type = IP_PKTINFO; 301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr.s_addr = INADDR_BROADCAST; 302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = htons(daemon->dhcp_client_port); 303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* unicast to unconfigured client. Inject mac address direct into ARP cache. 307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sockaddr limits size to 14 bytes. */ 308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct arpreq req; 309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr = mess->yiaddr; 310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = htons(daemon->dhcp_client_port); 311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *((struct sockaddr_in *)&req.arp_pa) = dest; 312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.arp_ha.sa_family = mess->htype; 313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen); 314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncpy(req.arp_dev, ifr.ifr_name, 16); 315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.arp_flags = ATF_COM; 316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ioctl(daemon->dhcpfd, SIOCSARP, &req); 317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_SOLARIS_NETWORK) 319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER) 320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* broadcast to 255.255.255.255 (or mac address invalid) */ 322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr.s_addr = INADDR_BROADCAST; 323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = htons(daemon->dhcp_client_port); 324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* note that we don't specify the interface here: that's done by the 325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat IP_BOUND_IF sockopt lower down. */ 326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* unicast to unconfigured client. Inject mac address direct into ARP cache. 330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Note that this only works for ethernet on solaris, because we use SIOCSARP 331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat and not SIOCSXARP, which would be perfect, except that it returns ENXIO 332ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mysteriously. Bah. Fall back to broadcast for other net types. */ 333ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct arpreq req; 334ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr = mess->yiaddr; 335ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = htons(daemon->dhcp_client_port); 336ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *((struct sockaddr_in *)&req.arp_pa) = dest; 337ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.arp_ha.sa_family = AF_UNSPEC; 338ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen); 339ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.arp_flags = ATF_COM; 340ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ioctl(daemon->dhcpfd, SIOCSARP, &req); 341ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 342ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#elif defined(HAVE_BSD_NETWORK) 343ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 344ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 345ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat send_via_bpf(mess, iov.iov_len, iface_addr, &ifr); 346ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 347ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 348ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 349ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 350ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#ifdef HAVE_SOLARIS_NETWORK 351ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index)); 352ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 353ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 354ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send()); 355ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 356ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 357ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple 358ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat of each interface (and any relay address) and does the following things: 359ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 360ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1) Discards stuff for interfaces other than the one on which a DHCP packet just arrived. 361ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 2) Fills in any netmask and broadcast addresses which have not been explicitly configured. 362ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 3) Fills in local (this host) and router (this host or relay) addresses. 363ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current. 364ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 365ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Note that the current chain may be superceded later for configured hosts or those coming via gateways. */ 366ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 367ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int complete_context(struct in_addr local, int if_index, 368ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr netmask, struct in_addr broadcast, void *vparam) 369ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 370ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *context; 371ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iface_param *param = vparam; 372ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 373ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (context = daemon->dhcp; context; context = context->next) 374ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 375ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(context->flags & CONTEXT_NETMASK) && 376ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (is_same_net(local, context->start, netmask) || 377ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_same_net(local, context->end, netmask))) 378ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 379ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (context->netmask.s_addr != netmask.s_addr && 380ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !(is_same_net(local, context->start, netmask) && 381ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_same_net(local, context->end, netmask))) 382ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 383ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(daemon->dhcp_buff, inet_ntoa(context->start)); 384ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(daemon->dhcp_buff2, inet_ntoa(context->end)); 385ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"), 386ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask)); 387ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 388ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->netmask = netmask; 389ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 390ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 391ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (context->netmask.s_addr) 392ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 393ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_same_net(local, context->start, context->netmask) && 394ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_same_net(local, context->end, context->netmask)) 395ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 396ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* link it onto the current chain if we've not seen it before */ 397ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (if_index == param->ind && context->current == context) 398ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 399ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->router = local; 400ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->local = local; 401ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->current = param->current; 402ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat param->current = context; 403ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 404ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 405ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(context->flags & CONTEXT_BRDCAST)) 406ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 407ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_same_net(broadcast, context->start, context->netmask)) 408ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->broadcast = broadcast; 409ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 410ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; 411ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 412ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 413ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask)) 414ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 415ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->router = param->relay; 416ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->local = param->primary; 417ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* fill in missing broadcast addresses for relayed ranges */ 418ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(context->flags & CONTEXT_BRDCAST)) 419ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; 420ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 421ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 422ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 423ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 424ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 425ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 426ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 427ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 428ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_context *address_available(struct dhcp_context *context, 429ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr taddr, 430ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_netid *netids) 431ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 432ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Check is an address is OK for this network, check all 433ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat possible ranges. Make sure that the address isn't in use 434ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat by the server itself. */ 435ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 436ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int start, end, addr = ntohl(taddr.s_addr); 437ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *tmp; 438ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 439ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp = context; tmp; tmp = tmp->current) 440ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (taddr.s_addr == context->router.s_addr) 441ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 442ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 443ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp = context; tmp; tmp = tmp->current) 444ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 445ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat start = ntohl(tmp->start.s_addr); 446ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat end = ntohl(tmp->end.s_addr); 447ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 448ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(tmp->flags & CONTEXT_STATIC) && 449ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr >= start && 450ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr <= end && 451ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat match_netid(tmp->filter, netids, 1)) 452ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return tmp; 453ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 454ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 455ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 456ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 457ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 458ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_context *narrow_context(struct dhcp_context *context, 459ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr taddr, 460ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_netid *netids) 461ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 462ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* We start of with a set of possible contexts, all on the current physical interface. 463ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat These are chained on ->current. 464ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Here we have an address, and return the actual context correponding to that 465ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat address. Note that none may fit, if the address came a dhcp-host and is outside 466ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat any dhcp-range. In that case we return a static range if possible, or failing that, 467ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat any context on the correct subnet. (If there's more than one, this is a dodgy 468ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat configuration: maybe there should be a warning.) */ 469ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 470ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *tmp; 471ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 472ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(tmp = address_available(context, taddr, netids))) 473ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 474ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp = context; tmp; tmp = tmp->current) 475ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_same_net(taddr, tmp->start, tmp->netmask) && 476ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (tmp->flags & CONTEXT_STATIC)) 477ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 478ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 479ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!tmp) 480ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp = context; tmp; tmp = tmp->current) 481ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_same_net(taddr, tmp->start, tmp->netmask)) 482ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 483ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 484ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 485ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Only one context allowed now */ 486ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (tmp) 487ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat tmp->current = NULL; 488ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 489ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return tmp; 490ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 491ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 492ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr) 493ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 494ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_config *config; 495ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 496ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = configs; config; config = config->next) 497ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) 498ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return config; 499ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 500ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 501ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 502ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 503ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* Is every member of check matched by a member of pool? 504ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat If tagnotneeded, untagged is OK */ 505ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded) 506ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 507ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_netid *tmp1; 508ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 509ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!check && !tagnotneeded) 510ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 511ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 512ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (; check; check = check->next) 513ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 514ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (check->net[0] != '#') 515ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 516ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp1 = pool; tmp1; tmp1 = tmp1->next) 517ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strcmp(check->net, tmp1->net) == 0) 518ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 519ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!tmp1) 520ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 521ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 522ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 523ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (tmp1 = pool; tmp1; tmp1 = tmp1->next) 524ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strcmp((check->net)+1, tmp1->net) == 0) 525ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 526ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 527ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 528ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 529ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 530ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint address_allocate(struct dhcp_context *context, 531ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr *addrp, unsigned char *hwaddr, int hw_len, 532ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_netid *netids, time_t now) 533ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 534ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Find a free address: exclude anything in use and anything allocated to 535ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat a particular hwaddr/clientid/hostname in our configuration. 536ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Try to return from contexts which match netids first. */ 537ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 538ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr start, addr; 539ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *c, *d; 540ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int i, pass; 541ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int j; 542ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 543ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* hash hwaddr */ 544ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (j = 0, i = 0; i < hw_len; i++) 545ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16); 546ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 547ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (pass = 0; pass <= 1; pass++) 548ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (c = context; c; c = c->current) 549ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (c->flags & CONTEXT_STATIC) 550ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 551ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (!match_netid(c->filter, netids, pass)) 552ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 553ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 554ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 555ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* pick a seed based on hwaddr then iterate until we find a free address. */ 556ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat start.s_addr = addr.s_addr = 557ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat htonl(ntohl(c->start.s_addr) + 558ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr)))); 559ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 560ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat do { 561ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* eliminate addresses in use by the server. */ 562ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (d = context; d; d = d->current) 563ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (addr.s_addr == d->router.s_addr) 564ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 565ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 566ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Addresses which end in .255 and .0 are broken in Windows even when using 567ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0 568ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat then 192.168.0.255 is a valid IP address, but not for Windows as it's 569ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat in the class C range. See KB281579. We therefore don't allocate these 570ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addresses to avoid hard-to-diagnose problems. Thanks Bill. */ 571ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!d && 572ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !lease_find_by_addr(addr) && 573ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat !config_find_by_address(daemon->dhcp_conf, addr) && 574ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (!IN_CLASSC(ntohl(addr.s_addr)) || 575ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0)))) 576ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 577ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ping_result *r, *victim = NULL; 578ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/ 579ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ((float)PING_WAIT))); 580ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 581ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *addrp = addr; 582ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 583ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->options & OPT_NO_PING) 584ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 585ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 586ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* check if we failed to ping addr sometime in the last 587ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat PING_CACHE_TIME seconds. If so, assume the same situation still exists. 588ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This avoids problems when a stupid client bangs 589ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat on us repeatedly. As a final check, if we did more 590ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat than 60% of the possible ping checks in the last 591ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat PING_CACHE_TIME, we are in high-load mode, so don't do any more. */ 592ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (count = 0, r = daemon->ping_results; r; r = r->next) 593ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (difftime(now, r->time) > (float)PING_CACHE_TIME) 594ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat victim = r; /* old record */ 595ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (++count == max || r->addr.s_addr == addr.s_addr) 596ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 597ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 598ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (icmp_ping(addr)) 599ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* address in use: perturb address selection so that we are 600ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat less likely to try this address again. */ 601ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat c->addr_epoch++; 602ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 603ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 604ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* at this point victim may hold an expired record */ 605ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!victim) 606ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 607ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((victim = whine_malloc(sizeof(struct ping_result)))) 608ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 609ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat victim->next = daemon->ping_results; 610ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->ping_results = victim; 611ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 612ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 613ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 614ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* record that this address is OK for 30s 615ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat without more ping checks */ 616ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (victim) 617ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 618ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat victim->addr = addr; 619ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat victim->time = now; 620ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 621ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 622ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 623ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 624ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 625ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.s_addr = htonl(ntohl(addr.s_addr) + 1); 626ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 627ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1)) 628ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr = c->start; 629ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 630ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } while (addr.s_addr != start.s_addr); 631ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 632ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 633ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 634ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 635ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config) 636ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 637ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!context) /* called via find_config() from lease_update_from_configs() */ 638ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 639ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(config->flags & CONFIG_ADDR)) 640ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 641ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (; context; context = context->current) 642ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_same_net(config->addr, context->start, context->netmask)) 643ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 644ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 645ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 646ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 647ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 648ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type) 649ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 650ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct hwaddr_config *conf_addr; 651ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 652ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) 653ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (conf_addr->wildcard_mask == 0 && 654ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat conf_addr->hwaddr_len == len && 655ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) && 656ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcmp(conf_addr->hwaddr, hwaddr, len) == 0) 657ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 658ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 659ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 660ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 661ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 662ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_config *find_config(struct dhcp_config *configs, 663ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_context *context, 664ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *clid, int clid_len, 665ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *hwaddr, int hw_len, 666ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int hw_type, char *hostname) 667ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 668ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int count, new; 669ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_config *config, *candidate; 670ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct hwaddr_config *conf_addr; 671ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 672ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (clid) 673ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = configs; config; config = config->next) 674ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config->flags & CONFIG_CLID) 675ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 676ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config->clid_len == clid_len && 677ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcmp(config->clid, clid, clid_len) == 0 && 678ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_addr_in_context(context, config)) 679ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return config; 680ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 681ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and 682ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat cope with that here */ 683ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (*clid == 0 && config->clid_len == clid_len-1 && 684ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcmp(config->clid, clid+1, clid_len-1) == 0 && 685ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_addr_in_context(context, config)) 686ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return config; 687ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 688ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 689ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 690ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = configs; config; config = config->next) 691ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config_has_mac(config, hwaddr, hw_len, hw_type) && 692ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_addr_in_context(context, config)) 693ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return config; 694ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 695ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (hostname && context) 696ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = configs; config; config = config->next) 697ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((config->flags & CONFIG_NAME) && 698ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname_isequal(config->hostname, hostname) && 699ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat is_addr_in_context(context, config)) 700ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return config; 701ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 702ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* use match with fewest wildcast octets */ 703ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (candidate = NULL, count = 0, config = configs; config; config = config->next) 704ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (is_addr_in_context(context, config)) 705ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) 706ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (conf_addr->wildcard_mask != 0 && 707ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat conf_addr->hwaddr_len == hw_len && 708ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) && 709ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count) 710ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 711ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat count = new; 712ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat candidate = config; 713ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 714ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 715ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return candidate; 716ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 717ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 718ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid dhcp_read_ethers(void) 719ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 720ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat FILE *f = fopen(ETHERSFILE, "r"); 721ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int flags; 722ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *buff = daemon->namebuff; 723ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *ip, *cp; 724ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr addr; 725ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char hwaddr[ETHER_ADDR_LEN]; 726ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_config **up, *tmp; 727ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_config *config; 728ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int count = 0, lineno = 0; 729ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 730ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.s_addr = 0; /* eliminate warning */ 731ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 732ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!f) 733ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 734ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno)); 735ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return; 736ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 737ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 738ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* This can be called again on SIGHUP, so remove entries created last time round. */ 739ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (up = &daemon->dhcp_conf, config = daemon->dhcp_conf; config; config = tmp) 740ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 741ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat tmp = config->next; 742ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config->flags & CONFIG_FROM_ETHERS) 743ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 744ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *up = tmp; 745ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* cannot have a clid */ 746ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config->flags & CONFIG_NAME) 747ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(config->hostname); 748ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(config->hwaddr); 749ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(config); 750ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 751ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 752ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat up = &config->next; 753ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 754ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 755ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (fgets(buff, MAXDNAME, f)) 756ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 757ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *host = NULL; 758ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 759ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lineno++; 760ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 761ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1])) 762ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat buff[strlen(buff)-1] = 0; 763ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 764ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((*buff == '#') || (*buff == '+') || (*buff == 0)) 765ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 766ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 767ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (ip = buff; *ip && !isspace((int)*ip); ip++); 768ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for(; *ip && isspace((int)*ip); ip++) 769ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *ip = 0; 770ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN) 771ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 772ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); 773ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 774ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 775ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 776ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* check for name or dotted-quad */ 777ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cp = ip; *cp; cp++) 778ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(*cp == '.' || (*cp >='0' && *cp <= '9'))) 779ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 780ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 781ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!*cp) 782ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 783ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1) 784ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 785ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); 786ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 787ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 788ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 789ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat flags = CONFIG_ADDR; 790ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 791ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = daemon->dhcp_conf; config; config = config->next) 792ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr) 793ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 794ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 795ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 796ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 797ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int nomem; 798ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host)) 799ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 800ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!nomem) 801ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); 802ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(host); 803ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 804ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 805ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 806ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat flags = CONFIG_NAME; 807ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 808ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = daemon->dhcp_conf; config; config = config->next) 809ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host)) 810ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 811ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 812ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 813ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config && (config->flags & CONFIG_FROM_ETHERS)) 814ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 815ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno); 816ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 817ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 818ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 819ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!config) 820ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 821ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = daemon->dhcp_conf; config; config = config->next) 822ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 823ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct hwaddr_config *conf_addr = config->hwaddr; 824ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (conf_addr && 825ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat conf_addr->next == NULL && 826ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat conf_addr->wildcard_mask == 0 && 827ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat conf_addr->hwaddr_len == ETHER_ADDR_LEN && 828ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) && 829ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0) 830ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 831ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 832ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 833ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!config) 834ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 835ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(config = whine_malloc(sizeof(struct dhcp_config)))) 836ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; 837ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->flags = CONFIG_FROM_ETHERS; 838ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hwaddr = NULL; 839ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->domain = NULL; 840ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->next = daemon->dhcp_conf; 841ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat daemon->dhcp_conf = config; 842ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 843ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 844ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->flags |= flags; 845ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 846ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (flags & CONFIG_NAME) 847ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 848ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hostname = host; 849ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat host = NULL; 850ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 851ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 852ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (flags & CONFIG_ADDR) 853ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->addr = addr; 854ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 855ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 856ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->flags |= CONFIG_NOCLID; 857ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!config->hwaddr) 858ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hwaddr = whine_malloc(sizeof(struct hwaddr_config)); 859ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config->hwaddr) 860ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 861ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN); 862ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hwaddr->hwaddr_len = ETHER_ADDR_LEN; 863ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hwaddr->hwaddr_type = ARPHRD_ETHER; 864ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hwaddr->wildcard_mask = 0; 865ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hwaddr->next = NULL; 866ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 867ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat count++; 868ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 869ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(host); 870ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 871ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 872ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 873ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat fclose(f); 874ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 875ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count); 876ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 877ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 878ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid check_dhcp_hosts(int fatal) 879ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 880ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* If the same IP appears in more than one host config, then DISCOVER 881ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for one of the hosts will get the address, but REQUEST will be NAKed, 882ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat since the address is reserved by the other one -> protocol loop. 883ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat Also check that FQDNs match the domain we are using. */ 884ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 885ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_config *configs, *cp; 886ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 887ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (configs = daemon->dhcp_conf; configs; configs = configs->next) 888ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 889ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *domain; 890ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 891ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((configs->flags & DHOPT_BANK) || fatal) 892ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 893ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (cp = configs->next; cp; cp = cp->next) 894ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr) 895ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 896ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (fatal) 897ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat die(_("duplicate IP address %s in dhcp-config directive."), 898ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat inet_ntoa(cp->addr), EC_BADCONF); 899ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 900ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."), 901ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat inet_ntoa(cp->addr), daemon->dhcp_hosts_file); 902ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat configs->flags &= ~CONFIG_ADDR; 903ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 904ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 905ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* split off domain part */ 906ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname))) 907ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat configs->domain = domain; 908ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 909ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 910ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 911ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 912ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatvoid dhcp_update_configs(struct dhcp_config *configs) 913ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 914ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* Some people like to keep all static IP addresses in /etc/hosts. 915ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This goes through /etc/hosts and sets static addresses for any DHCP config 916ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat records which don't have an address and whose name matches. 917ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat We take care to maintain the invariant that any IP address can appear 918ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP, 919ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat restore the status-quo ante first. */ 920ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 921ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_config *config; 922ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct crec *crec; 923ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 924ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = configs; config; config = config->next) 925ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config->flags & CONFIG_ADDR_HOSTS) 926ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS); 927ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 928ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 929ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->port != 0) 930ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (config = configs; config; config = config->next) 931ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(config->flags & CONFIG_ADDR) && 932ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (config->flags & CONFIG_NAME) && 933ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) && 934ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (crec->flags & F_HOSTS)) 935ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 936ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (cache_find_by_name(crec, config->hostname, 0, F_IPV4)) 937ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 938ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* use primary (first) address */ 939ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (crec && !(crec->flags & F_REVERSE)) 940ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4); 941ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!crec) 942ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat continue; /* should be never */ 943ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), 944ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->hostname, inet_ntoa(crec->addr.addr.addr.addr4)); 945ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 946ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 947ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (config_find_by_address(configs, crec->addr.addr.addr.addr4)) 948ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), 949ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat inet_ntoa(crec->addr.addr.addr.addr4), config->hostname); 950ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 951ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 952ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->addr = crec->addr.addr.addr.addr4; 953ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS; 954ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 955ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 956ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 957ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 958ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts 959ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for this address. If it has a domain part, that must match the set domain and 960ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat it gets stripped. The set of legal domain names is bigger than the set of legal hostnames 961ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat so check here that the domain name is legal as a hostname. */ 962ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatchar *host_from_dns(struct in_addr addr) 963ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 964ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct crec *lookup; 965ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *hostname = NULL; 966ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *d1, *d2; 967ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 968ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (daemon->port == 0) 969ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; /* DNS disabled. */ 970ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 971ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4); 972ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (lookup && (lookup->flags & F_HOSTS)) 973ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 974ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname = daemon->dhcp_buff; 975ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strncpy(hostname, cache_get_name(lookup), 256); 976ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname[255] = 0; 977ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat d1 = strip_hostname(hostname); 978ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat d2 = get_domain(addr); 979ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2)))) 980ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat hostname = NULL; 981ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 982ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 983ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return hostname; 984ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 985ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 986ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* return domain or NULL if none. */ 987ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatchar *strip_hostname(char *hostname) 988ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 989ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *dot = strchr(hostname, '.'); 990ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 991ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!dot) 992ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 993ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 994ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *dot = 0; /* truncate */ 995ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (strlen(dot+1) != 0) 996ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return dot+1; 997ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 998ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return NULL; 999ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 1000ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1001ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#endif 1002ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 1003