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