blob: c3ffcace8df812fb4daa426747d826809d7e7c07 [file] [log] [blame]
The Android Open Source Projectf7c54212009-03-03 19:29:22 -08001/*
2 * dhcpcd - DHCP client daemon
Dmitry Shmidta3a22602012-07-23 16:45:46 -07003 * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -08004 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080028#include <sys/ioctl.h>
29#include <sys/param.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080030#include <sys/socket.h>
31#include <sys/stat.h>
32#include <sys/sysctl.h>
33#include <sys/types.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080034
35#include <arpa/inet.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080036#include <net/if.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080037#include <net/if_dl.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080038#include <net/route.h>
39#include <netinet/in.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080040#ifdef __DragonFly__
41# include <netproto/802_11/ieee80211_ioctl.h>
42#elif __APPLE__
43 /* FIXME: Add apple includes so we can work out SSID */
44#else
45# include <net80211/ieee80211_ioctl.h>
46#endif
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080047
48#include <errno.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080049#include <fnmatch.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080050#include <stddef.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080054#include <syslog.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080055#include <unistd.h>
56
57#include "config.h"
58#include "common.h"
Dmitry Shmidte86eee12011-01-24 16:27:51 -080059#include "configure.h"
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080060#include "dhcp.h"
Dmitry Shmidte86eee12011-01-24 16:27:51 -080061#include "if-options.h"
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080062#include "net.h"
63
Dmitry Shmidta3a22602012-07-23 16:45:46 -070064#ifndef RT_ROUNDUP
65#define RT_ROUNDUP(a) \
Dmitry Shmidte86eee12011-01-24 16:27:51 -080066 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
Dmitry Shmidta3a22602012-07-23 16:45:46 -070067#define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
68#endif
Dmitry Shmidte86eee12011-01-24 16:27:51 -080069
70/* FIXME: Why do we need to check for sa_family 255 */
71#define COPYOUT(sin, sa) \
72 sin.s_addr = ((sa) != NULL) ? \
73 (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
74
75static int r_fd = -1;
76static char *link_buf;
77static ssize_t link_buflen;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080078
79int
Dmitry Shmidte86eee12011-01-24 16:27:51 -080080if_init(_unused struct interface *iface)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080081{
Dmitry Shmidte86eee12011-01-24 16:27:51 -080082 /* BSD promotes secondary address by default */
83 return 0;
84}
85
86int
87if_conf(_unused struct interface *iface)
88{
89 /* No extra checks needed on BSD */
90 return 0;
91}
92
Dmitry Shmidta3a22602012-07-23 16:45:46 -070093#ifdef DEBUG_MEMORY
94static void
95cleanup(void)
96{
97
98 free(link_buf);
99}
100#endif
101
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800102int
103init_sockets(void)
104{
105 if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
106 return -1;
107 set_cloexec(socket_afnet);
108 if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
109 return -1;
110 set_cloexec(r_fd);
111 return 0;
112}
113
114int
115getifssid(const char *ifname, char *ssid)
116{
117 int retval = -1;
118#if defined(SIOCG80211NWID)
119 struct ifreq ifr;
120 struct ieee80211_nwid nwid;
121#elif defined(IEEE80211_IOC_SSID)
122 struct ieee80211req ireq;
123 char nwid[IEEE80211_NWID_LEN + 1];
124#endif
125
126#if defined(SIOCG80211NWID) /* NetBSD */
127 memset(&ifr, 0, sizeof(ifr));
128 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
129 memset(&nwid, 0, sizeof(nwid));
130 ifr.ifr_data = (void *)&nwid;
131 if (ioctl(socket_afnet, SIOCG80211NWID, &ifr) == 0) {
132 retval = nwid.i_len;
133 memcpy(ssid, nwid.i_nwid, nwid.i_len);
134 ssid[nwid.i_len] = '\0';
135 }
136#elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
137 memset(&ireq, 0, sizeof(ireq));
138 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
139 ireq.i_type = IEEE80211_IOC_SSID;
140 ireq.i_val = -1;
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700141 memset(nwid, 0, sizeof(nwid));
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800142 ireq.i_data = &nwid;
143 if (ioctl(socket_afnet, SIOCG80211, &ireq) == 0) {
144 retval = ireq.i_len;
145 memcpy(ssid, nwid, ireq.i_len);
146 ssid[ireq.i_len] = '\0';
147 }
148#endif
149 return retval;
150}
151
152int
153if_address(const struct interface *iface, const struct in_addr *address,
154 const struct in_addr *netmask, const struct in_addr *broadcast,
155 int action)
156{
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800157 int retval;
158 struct ifaliasreq ifa;
159 union {
160 struct sockaddr *sa;
161 struct sockaddr_in *sin;
162 } _s;
163
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800164 memset(&ifa, 0, sizeof(ifa));
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800165 strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800166
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800167#define ADDADDR(_var, _addr) { \
168 _s.sa = &_var; \
169 _s.sin->sin_family = AF_INET; \
170 _s.sin->sin_len = sizeof(*_s.sin); \
171 memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
172 }
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800173
174 ADDADDR(ifa.ifra_addr, address);
175 ADDADDR(ifa.ifra_mask, netmask);
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800176 if (action >= 0 && broadcast) {
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800177 ADDADDR(ifa.ifra_broadaddr, broadcast);
178 }
179#undef ADDADDR
180
181 if (action < 0)
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800182 retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800183 else
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800184 retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800185 return retval;
186}
187
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800188/* ARGSUSED4 */
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800189int
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700190if_route(const struct rt *rt, int action)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800191{
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800192 union sockunion {
193 struct sockaddr sa;
194 struct sockaddr_in sin;
195#ifdef INET6
196 struct sockaddr_in6 sin6;
197#endif
198 struct sockaddr_dl sdl;
199 struct sockaddr_storage ss;
200 } su;
201 struct rtm
202 {
203 struct rt_msghdr hdr;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800204 char buffer[sizeof(su) * 4];
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800205 } rtm;
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700206 char *bp = rtm.buffer;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800207 size_t l;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800208 int retval = 0;
209
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800210#define ADDSU(_su) { \
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700211 l = RT_ROUNDUP(_su.sa.sa_len); \
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800212 memcpy(bp, &(_su), l); \
213 bp += l; \
214 }
215#define ADDADDR(_a) { \
216 memset (&su, 0, sizeof(su)); \
217 su.sin.sin_family = AF_INET; \
218 su.sin.sin_len = sizeof(su.sin); \
219 memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \
220 ADDSU(su); \
221 }
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800222
223 memset(&rtm, 0, sizeof(rtm));
224 rtm.hdr.rtm_version = RTM_VERSION;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800225 rtm.hdr.rtm_seq = 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800226 if (action == 0)
227 rtm.hdr.rtm_type = RTM_CHANGE;
228 else if (action > 0)
229 rtm.hdr.rtm_type = RTM_ADD;
230 else
231 rtm.hdr.rtm_type = RTM_DELETE;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800232 rtm.hdr.rtm_flags = RTF_UP;
233 /* None interface subnet routes are static. */
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700234 if (rt->gate.s_addr != INADDR_ANY ||
235 rt->net.s_addr != rt->iface->net.s_addr ||
236 rt->dest.s_addr != (rt->iface->addr.s_addr & rt->iface->net.s_addr))
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800237 rtm.hdr.rtm_flags |= RTF_STATIC;
238 rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700239 if (rt->dest.s_addr == rt->gate.s_addr &&
240 rt->net.s_addr == INADDR_BROADCAST)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800241 rtm.hdr.rtm_flags |= RTF_HOST;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800242 else {
243 rtm.hdr.rtm_addrs |= RTA_NETMASK;
244 if (rtm.hdr.rtm_flags & RTF_STATIC)
245 rtm.hdr.rtm_flags |= RTF_GATEWAY;
246 if (action >= 0)
247 rtm.hdr.rtm_addrs |= RTA_IFA;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800248 }
249
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700250 ADDADDR(&rt->dest);
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800251 if (rtm.hdr.rtm_flags & RTF_HOST ||
252 !(rtm.hdr.rtm_flags & RTF_STATIC))
253 {
254 /* Make us a link layer socket for the host gateway */
255 memset(&su, 0, sizeof(su));
256 su.sdl.sdl_len = sizeof(struct sockaddr_dl);
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700257 link_addr(rt->iface->name, &su.sdl);
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800258 ADDSU(su);
259 } else
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700260 ADDADDR(&rt->gate);
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800261
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700262 if (rtm.hdr.rtm_addrs & RTA_NETMASK)
263 ADDADDR(&rt->net);
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800264
265 if (rtm.hdr.rtm_addrs & RTA_IFA)
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700266 ADDADDR(&rt->iface->addr);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800267
268 rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800269 if (write(r_fd, &rtm, l) == -1)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800270 retval = -1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800271 return retval;
272}
273
274int
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800275open_link_socket(void)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800276{
277 int fd;
278
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700279#ifdef DEBUG_MEMORY
280 if (link_buf == NULL)
281 atexit(cleanup);
282#endif
283
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800284 fd = socket(PF_ROUTE, SOCK_RAW, 0);
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800285 if (fd != -1) {
286 set_cloexec(fd);
287 set_nonblock(fd);
288 }
289 return fd;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800290}
291
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800292static void
293get_addrs(int type, char *cp, struct sockaddr **sa)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800294{
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800295 int i;
296
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800297 for (i = 0; i < RTAX_MAX; i++) {
298 if (type & (1 << i)) {
299 sa[i] = (struct sockaddr *)cp;
300#ifdef DEBUG
301 printf ("got %d %d %s\n", i, sa[i]->sa_family,
302 inet_ntoa(((struct sockaddr_in *)sa[i])->
303 sin_addr));
304#endif
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700305 RT_ADVANCE(cp, sa[i]);
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800306 } else
307 sa[i] = NULL;
308 }
309}
310
311int
312manage_link(int fd)
313{
314 char *p, *e, *cp;
315 char ifname[IF_NAMESIZE];
316 ssize_t bytes;
317 struct rt_msghdr *rtm;
318 struct if_announcemsghdr *ifan;
319 struct if_msghdr *ifm;
320 struct ifa_msghdr *ifam;
321 struct rt rt;
322 struct sockaddr *sa, *rti_info[RTAX_MAX];
323 int len;
324#ifdef RTM_CHGADDR
325 struct sockaddr_dl sdl;
326 unsigned char *hwaddr;
327#endif
328
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800329 for (;;) {
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800330 if (ioctl(fd, FIONREAD, &len) == -1)
331 return -1;
332 if (link_buflen < len) {
333 p = realloc(link_buf, len);
334 if (p == NULL)
335 return -1;
336 link_buf = p;
337 link_buflen = len;
338 }
339 bytes = read(fd, link_buf, link_buflen);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800340 if (bytes == -1) {
341 if (errno == EAGAIN)
342 return 0;
343 if (errno == EINTR)
344 continue;
345 return -1;
346 }
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800347 e = link_buf + bytes;
348 for (p = link_buf; p < e; p += rtm->rtm_msglen) {
349 rtm = (struct rt_msghdr *)(void *)p;
350 switch(rtm->rtm_type) {
351#ifdef RTM_IFANNOUNCE
352 case RTM_IFANNOUNCE:
353 ifan = (struct if_announcemsghdr *)(void *)p;
354 switch(ifan->ifan_what) {
355 case IFAN_ARRIVAL:
356 handle_interface(1, ifan->ifan_name);
357 break;
358 case IFAN_DEPARTURE:
359 handle_interface(-1, ifan->ifan_name);
360 break;
361 }
362 break;
363#endif
364 case RTM_IFINFO:
365 ifm = (struct if_msghdr *)(void *)p;
366 memset(ifname, 0, sizeof(ifname));
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700367 if (!(if_indextoname(ifm->ifm_index, ifname)))
368 break;
369 switch (ifm->ifm_data.ifi_link_state) {
370 case LINK_STATE_DOWN:
371 len = -1;
372 break;
373 case LINK_STATE_UP:
374 len = 1;
375 break;
376 default:
377 /* handle_carrier will re-load
378 * the interface flags and check for
379 * IFF_RUNNING as some drivers that
380 * don't handle link state also don't
381 * set IFF_RUNNING when this routing
382 * message is generated.
383 * As such, it is a race ...*/
384 len = 0;
385 break;
386 }
387 handle_carrier(len, ifm->ifm_flags, ifname);
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800388 break;
389 case RTM_DELETE:
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700390 if (~rtm->rtm_addrs &
391 (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800392 break;
393 if (rtm->rtm_pid == getpid())
394 break;
395 cp = (char *)(void *)(rtm + 1);
396 sa = (struct sockaddr *)(void *)cp;
397 if (sa->sa_family != AF_INET)
398 break;
399 get_addrs(rtm->rtm_addrs, cp, rti_info);
400 rt.iface = NULL;
401 rt.next = NULL;
402 COPYOUT(rt.dest, rti_info[RTAX_DST]);
403 COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
404 COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
405 route_deleted(&rt);
406 break;
407#ifdef RTM_CHGADDR
408 case RTM_CHGADDR: /* FALLTHROUGH */
409#endif
410 case RTM_DELADDR: /* FALLTHROUGH */
411 case RTM_NEWADDR:
412 ifam = (struct ifa_msghdr *)(void *)p;
413 if (!if_indextoname(ifam->ifam_index, ifname))
414 break;
415 cp = (char *)(void *)(ifam + 1);
416 get_addrs(ifam->ifam_addrs, cp, rti_info);
417 if (rti_info[RTAX_IFA] == NULL)
418 break;
419 switch (rti_info[RTAX_IFA]->sa_family) {
420#ifdef RTM_CHGADDR
421 case AF_LINK:
422 if (rtm->rtm_type != RTM_CHGADDR)
423 break;
424 memcpy(&sdl, rti_info[RTAX_IFA],
425 rti_info[RTAX_IFA]->sa_len);
426 hwaddr = xmalloc(sdl.sdl_alen);
427 memcpy(hwaddr, LLADDR(&sdl),
428 sdl.sdl_alen);
429 handle_hwaddr(ifname, hwaddr,
430 sdl.sdl_alen);
431 break;
432#endif
433 case AF_INET:
434 case 255: /* FIXME: Why 255? */
435 COPYOUT(rt.dest, rti_info[RTAX_IFA]);
436 COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
437 COPYOUT(rt.gate, rti_info[RTAX_BRD]);
438 handle_ifa(rtm->rtm_type, ifname,
439 &rt.dest, &rt.net, &rt.gate);
440 break;
441 }
442 break;
443 }
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800444 }
445 }
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800446}