1 /*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2013 Antti Kantee <pooka@iki.fi>
4 * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
5 * All rights reserved
6
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/cprng.h>
31 #include <sys/ioctl.h>
32 #include <sys/kmem.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <net/if_dl.h>
40 #include <net/if_types.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/in.h>
43 #include <netinet/ip.h>
44 #include <netinet/udp.h>
45 #include <net/if_media.h>
46
47 #include "dhcp_common.h"
48 #include "dhcp_dhcp.h"
49 #include "dhcp_if-options.h"
50 #include "dhcp_net.h"
51
52 static char hwaddr_buffer[(HWADDR_LEN * 3) + 1];
53
54 struct socket *socket_afnet;
55
56 int
inet_ntocidr(struct in_addr address)57 inet_ntocidr(struct in_addr address)
58 {
59 int cidr = 0;
60 uint32_t mask = htonl(address.s_addr);
61
62 while (mask) {
63 cidr++;
64 mask <<= 1;
65 }
66 return cidr;
67 }
68
69 int
inet_cidrtoaddr(int cidr,struct in_addr * addr)70 inet_cidrtoaddr(int cidr, struct in_addr *addr)
71 {
72 int ocets;
73
74 if (cidr < 1 || cidr > 32) {
75 return EINVAL;
76 }
77 ocets = (cidr + 7) / 8;
78
79 addr->s_addr = 0;
80 if (ocets > 0) {
81 memset(&addr->s_addr, 255, (size_t)ocets - 1);
82 memset((unsigned char *)&addr->s_addr + (ocets - 1),
83 (256 - (1 << (32 - cidr) % 8)), 1);
84 }
85
86 return 0;
87 }
88
89 uint32_t
get_netmask(uint32_t addr)90 get_netmask(uint32_t addr)
91 {
92 uint32_t dst;
93
94 if (addr == 0)
95 return 0;
96
97 dst = htonl(addr);
98 if (IN_CLASSA(dst))
99 return ntohl(IN_CLASSA_NET);
100 if (IN_CLASSB(dst))
101 return ntohl(IN_CLASSB_NET);
102 if (IN_CLASSC(dst))
103 return ntohl(IN_CLASSC_NET);
104
105 return 0;
106 }
107
108 char *
hwaddr_ntoa(const unsigned char * hwaddr,size_t hwlen)109 hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
110 {
111 char *p = hwaddr_buffer;
112 size_t i;
113
114 for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
115 if (i > 0)
116 *p ++= ':';
117 p += snprintf(p, 3, "%.2x", hwaddr[i]);
118 }
119
120 *p ++= '\0';
121
122 return hwaddr_buffer;
123 }
124
125 size_t
hwaddr_aton(unsigned char * buffer,const char * addr)126 hwaddr_aton(unsigned char *buffer, const char *addr)
127 {
128 char c[3];
129 const char *p = addr;
130 unsigned char *bp = buffer;
131 size_t len = 0;
132
133 c[2] = '\0';
134 while (*p) {
135 c[0] = *p++;
136 c[1] = *p++;
137 /* Ensure that digits are hex */
138 if (isxdigit((unsigned char)c[0]) == 0 ||
139 isxdigit((unsigned char)c[1]) == 0)
140 {
141 return EINVAL;
142 }
143 /* We should have at least two entries 00:01 */
144 if (len == 0 && *p == '\0') {
145 return EINVAL;
146 }
147 /* Ensure that next data is EOL or a seperator with data */
148 if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
149 return EINVAL;
150 }
151 if (*p)
152 p++;
153 if (bp)
154 *bp++ = (unsigned char)strtoll(c, NULL, 16);
155 len++;
156 }
157 return len;
158 }
159
160 int
init_interface(const char * ifname,struct interface ** ifacep)161 init_interface(const char *ifname, struct interface **ifacep)
162 {
163 struct ifnet *ifp;
164 struct ifreq ifr;
165 struct interface *iface = NULL;
166 int error;
167
168 ifp = ifunit(ifname);
169 if (!ifp)
170 return EXDEV;
171
172 memset(&ifr, 0, sizeof(ifr));
173 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
174 if ((error = ifioctl(socket_afnet, SIOCGIFFLAGS, &ifr, curlwp)) != 0)
175 goto eexit;
176
177 iface = kmem_zalloc(sizeof(*iface), KM_SLEEP);
178 strlcpy(iface->name, ifname, sizeof(iface->name));
179 iface->ifp = ifp;
180 iface->flags = ifr.ifr_flags;
181 /* We reserve the 100 range for virtual interfaces, if and when
182 * we can work them out. */
183 iface->metric = 200 + iface->ifp->if_index;
184 if (getifssid(ifname, iface->ssid) == 0) {
185 iface->wireless = 1;
186 iface->metric += 100;
187 }
188
189 if (ifioctl(socket_afnet, SIOCGIFMTU, &ifr, curlwp) != 0)
190 goto eexit;
191 /* Ensure that the MTU is big enough for DHCP */
192 if (ifr.ifr_mtu < MTU_MIN) {
193 ifr.ifr_mtu = MTU_MIN;
194 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
195 if ((error = ifioctl(socket_afnet,
196 SIOCSIFMTU, &ifr, curlwp)) != 0)
197 goto eexit;
198 }
199
200 /* 0 is a valid fd, so init to -1 */
201 iface->raw_fd = -1;
202 iface->udp_fd = -1;
203 iface->arp_fd = -1;
204
205 eexit:
206 if (error) {
207 kmem_free(iface, sizeof(*iface));
208 iface = NULL;
209 }
210
211 *ifacep = iface;
212 return error;
213 }
214
215 int
carrier_status(struct interface * iface)216 carrier_status(struct interface *iface)
217 {
218 int ret;
219 struct ifreq ifr;
220 struct ifmediareq ifmr;
221
222 memset(&ifr, 0, sizeof(ifr));
223 strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
224
225 if ((ret = ifioctl(socket_afnet, SIOCGIFFLAGS, &ifr, curlwp)) != 0)
226 return ret;
227 iface->flags = ifr.ifr_flags;
228
229 ret = -1;
230 memset(&ifmr, 0, sizeof(ifmr));
231 strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
232 if (ifioctl(socket_afnet, SIOCGIFMEDIA, &ifmr, curlwp) == 0 &&
233 ifmr.ifm_status & IFM_AVALID)
234 ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
235 if (ret != 0)
236 ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0;
237 return ret;
238 }
239
240 void
up_interface(struct interface * iface)241 up_interface(struct interface *iface)
242 {
243
244 if_up(iface->ifp);
245 }
246
247 int
do_address(const char * ifname,struct in_addr * addr,struct in_addr * net,struct in_addr * dst,int act)248 do_address(const char *ifname,
249 struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
250 {
251 const struct sockaddr_in *a, *n, *d;
252 struct ifnet *ifp = ifunit(ifname);
253 struct ifaddr *ifa;
254 int retval;
255
256 if (ifp == NULL)
257 return 0;
258
259 retval = 0;
260 IFADDR_FOREACH(ifa, ifp) {
261 if (ifa->ifa_addr->sa_family != AF_INET)
262 continue;
263
264 a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
265 n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
266 if (ifa->ifa_flags & IFF_POINTOPOINT)
267 d = (const struct sockaddr_in *)(void *)
268 ifa->ifa_dstaddr;
269 else
270 d = NULL;
271 if (act == 1) {
272 addr->s_addr = a->sin_addr.s_addr;
273 net->s_addr = n->sin_addr.s_addr;
274 if (dst) {
275 if (ifa->ifa_flags & IFF_POINTOPOINT)
276 dst->s_addr = d->sin_addr.s_addr;
277 else
278 dst->s_addr = INADDR_ANY;
279 }
280 retval = 1;
281 break;
282 }
283 if (addr->s_addr == a->sin_addr.s_addr &&
284 (net == NULL || net->s_addr == n->sin_addr.s_addr))
285 {
286 retval = 1;
287 break;
288 }
289 }
290
291 return retval;
292 }
293
294 int
do_mtu(const char * ifname,short int mtu)295 do_mtu(const char *ifname, short int mtu)
296 {
297 struct ifreq ifr;
298
299 memset(&ifr, 0, sizeof(ifr));
300 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
301 ifr.ifr_mtu = mtu;
302 if (ifioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr, curlwp))
303 return -1;
304 return ifr.ifr_mtu;
305 }
306
307 void
free_routes(struct rt * routes)308 free_routes(struct rt *routes)
309 {
310 struct rt *r;
311
312 while (routes) {
313 r = routes->next;
314 kmem_free(routes, sizeof(*r));
315 routes = r;
316 }
317 }
318
319 struct udp_dhcp_packet
320 {
321 struct ip ip;
322 struct udphdr udp;
323 struct dhcp_message dhcp;
324 };
325 const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
326
327 static uint16_t
checksum(const void * data,uint16_t len)328 checksum(const void *data, uint16_t len)
329 {
330 const uint8_t *addr = data;
331 uint32_t sum = 0;
332
333 while (len > 1) {
334 sum += addr[0] * 256 + addr[1];
335 addr += 2;
336 len -= 2;
337 }
338
339 if (len == 1)
340 sum += *addr * 256;
341
342 sum = (sum >> 16) + (sum & 0xffff);
343 sum += (sum >> 16);
344
345 sum = htons(sum);
346
347 return ~sum;
348 }
349
350 ssize_t
make_udp_packet(uint8_t ** packet,const uint8_t * data,size_t length,struct in_addr source,struct in_addr dest)351 make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
352 struct in_addr source, struct in_addr dest)
353 {
354 struct udp_dhcp_packet *udpp;
355 struct ip *ip;
356 struct udphdr *udp;
357
358 udpp = kmem_zalloc(sizeof(*udpp), KM_SLEEP);
359 ip = &udpp->ip;
360 udp = &udpp->udp;
361
362 /* OK, this is important :)
363 * We copy the data to our packet and then create a small part of the
364 * ip structure and an invalid ip_len (basically udp length).
365 * We then fill the udp structure and put the checksum
366 * of the whole packet into the udp checksum.
367 * Finally we complete the ip structure and ip checksum.
368 * If we don't do the ordering like so then the udp checksum will be
369 * broken, so find another way of doing it! */
370
371 memcpy(&udpp->dhcp, data, length);
372
373 ip->ip_p = IPPROTO_UDP;
374 ip->ip_src.s_addr = source.s_addr;
375 if (dest.s_addr == 0)
376 ip->ip_dst.s_addr = INADDR_BROADCAST;
377 else
378 ip->ip_dst.s_addr = dest.s_addr;
379
380 udp->uh_sport = htons(DHCP_CLIENT_PORT);
381 udp->uh_dport = htons(DHCP_SERVER_PORT);
382 udp->uh_ulen = htons(sizeof(*udp) + length);
383 ip->ip_len = udp->uh_ulen;
384 udp->uh_sum = checksum(udpp, sizeof(*udpp));
385
386 ip->ip_v = IPVERSION;
387 ip->ip_hl = sizeof(*ip) >> 2;
388 ip->ip_id = cprng_fast32() & UINT16_MAX;
389 ip->ip_ttl = IPDEFTTL;
390 ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
391 ip->ip_sum = checksum(ip, sizeof(*ip));
392
393 *packet = (uint8_t *)udpp;
394 return sizeof(*ip) + sizeof(*udp) + length;
395 }
396
397 ssize_t
get_udp_data(const uint8_t ** data,const uint8_t * udp)398 get_udp_data(const uint8_t **data, const uint8_t *udp)
399 {
400 struct udp_dhcp_packet packet;
401
402 memcpy(&packet, udp, sizeof(packet));
403 *data = udp + offsetof(struct udp_dhcp_packet, dhcp);
404 return ntohs(packet.ip.ip_len) -
405 sizeof(packet.ip) -
406 sizeof(packet.udp);
407 }
408
409 int
valid_udp_packet(const uint8_t * data,size_t data_len,struct in_addr * from)410 valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
411 {
412 struct udp_dhcp_packet packet;
413 uint16_t bytes, udpsum;
414
415 if (data_len < sizeof(packet.ip)) {
416 if (from)
417 from->s_addr = INADDR_ANY;
418 return EINVAL;
419 }
420 memcpy(&packet, data, MIN(data_len, sizeof(packet)));
421 if (from)
422 from->s_addr = packet.ip.ip_src.s_addr;
423 if (data_len > sizeof(packet)) {
424 return EINVAL;
425 }
426 if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
427 return EINVAL;
428 }
429
430 bytes = ntohs(packet.ip.ip_len);
431 if (data_len < bytes) {
432 return EINVAL;
433 }
434 udpsum = packet.udp.uh_sum;
435 packet.udp.uh_sum = 0;
436 packet.ip.ip_hl = 0;
437 packet.ip.ip_v = 0;
438 packet.ip.ip_tos = 0;
439 packet.ip.ip_len = packet.udp.uh_ulen;
440 packet.ip.ip_id = 0;
441 packet.ip.ip_off = 0;
442 packet.ip.ip_ttl = 0;
443 packet.ip.ip_sum = 0;
444 if (udpsum && checksum(&packet, bytes) != udpsum) {
445 return EINVAL;
446 }
447
448 return 0;
449 }
450