• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
4  * 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 
28 #include <sys/ioctl.h>
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/sysctl.h>
33 #include <sys/types.h>
34 
35 #include <arpa/inet.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <net/route.h>
39 #include <netinet/in.h>
40 #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
47 
48 #include <errno.h>
49 #include <fnmatch.h>
50 #include <stddef.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <syslog.h>
55 #include <unistd.h>
56 
57 #include "config.h"
58 #include "common.h"
59 #include "configure.h"
60 #include "dhcp.h"
61 #include "if-options.h"
62 #include "net.h"
63 
64 #ifndef RT_ROUNDUP
65 #define RT_ROUNDUP(a)							      \
66 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
67 #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
68 #endif
69 
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 
75 static int r_fd = -1;
76 static char *link_buf;
77 static ssize_t link_buflen;
78 
79 int
if_init(_unused struct interface * iface)80 if_init(_unused struct interface *iface)
81 {
82 	/* BSD promotes secondary address by default */
83 	return 0;
84 }
85 
86 int
if_conf(_unused struct interface * iface)87 if_conf(_unused struct interface *iface)
88 {
89 	/* No extra checks needed on BSD */
90 	return 0;
91 }
92 
93 #ifdef DEBUG_MEMORY
94 static void
cleanup(void)95 cleanup(void)
96 {
97 
98 	free(link_buf);
99 }
100 #endif
101 
102 int
init_sockets(void)103 init_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 
114 int
getifssid(const char * ifname,char * ssid)115 getifssid(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;
141 	memset(nwid, 0, sizeof(nwid));
142 	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 
152 int
if_address(const struct interface * iface,const struct in_addr * address,const struct in_addr * netmask,const struct in_addr * broadcast,int action)153 if_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 {
157 	int retval;
158 	struct ifaliasreq ifa;
159 	union {
160 		struct sockaddr *sa;
161 		struct sockaddr_in *sin;
162 	} _s;
163 
164 	memset(&ifa, 0, sizeof(ifa));
165 	strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
166 
167 #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 	}
173 
174 	ADDADDR(ifa.ifra_addr, address);
175 	ADDADDR(ifa.ifra_mask, netmask);
176 	if (action >= 0 && broadcast) {
177 		ADDADDR(ifa.ifra_broadaddr, broadcast);
178 	}
179 #undef ADDADDR
180 
181 	if (action < 0)
182 		retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
183 	else
184 		retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
185 	return retval;
186 }
187 
188 /* ARGSUSED4 */
189 int
if_route(const struct rt * rt,int action)190 if_route(const struct rt *rt, int action)
191 {
192 	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;
204 		char buffer[sizeof(su) * 4];
205 	} rtm;
206 	char *bp = rtm.buffer;
207 	size_t l;
208 	int retval = 0;
209 
210 #define ADDSU(_su) {							      \
211 		l = RT_ROUNDUP(_su.sa.sa_len);				      \
212 		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 	}
222 
223 	memset(&rtm, 0, sizeof(rtm));
224 	rtm.hdr.rtm_version = RTM_VERSION;
225 	rtm.hdr.rtm_seq = 1;
226 	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;
232 	rtm.hdr.rtm_flags = RTF_UP;
233 	/* None interface subnet routes are static. */
234 	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))
237 		rtm.hdr.rtm_flags |= RTF_STATIC;
238 	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
239 	if (rt->dest.s_addr == rt->gate.s_addr &&
240 	    rt->net.s_addr == INADDR_BROADCAST)
241 		rtm.hdr.rtm_flags |= RTF_HOST;
242 	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;
248 	}
249 
250 	ADDADDR(&rt->dest);
251 	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);
257 		link_addr(rt->iface->name, &su.sdl);
258 		ADDSU(su);
259 	} else
260 		ADDADDR(&rt->gate);
261 
262 	if (rtm.hdr.rtm_addrs & RTA_NETMASK)
263 		ADDADDR(&rt->net);
264 
265 	if (rtm.hdr.rtm_addrs & RTA_IFA)
266 		ADDADDR(&rt->iface->addr);
267 
268 	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
269 	if (write(r_fd, &rtm, l) == -1)
270 		retval = -1;
271 	return retval;
272 }
273 
274 int
open_link_socket(void)275 open_link_socket(void)
276 {
277 	int fd;
278 
279 #ifdef DEBUG_MEMORY
280 	if (link_buf == NULL)
281 		atexit(cleanup);
282 #endif
283 
284 	fd = socket(PF_ROUTE, SOCK_RAW, 0);
285 	if (fd != -1) {
286 		set_cloexec(fd);
287 		set_nonblock(fd);
288 	}
289 	return fd;
290 }
291 
292 static void
get_addrs(int type,char * cp,struct sockaddr ** sa)293 get_addrs(int type, char *cp, struct sockaddr **sa)
294 {
295 	int i;
296 
297 	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
305 			RT_ADVANCE(cp, sa[i]);
306 		} else
307 			sa[i] = NULL;
308 	}
309 }
310 
311 int
manage_link(int fd)312 manage_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 
329 	for (;;) {
330 		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);
340 		if (bytes == -1) {
341 			if (errno == EAGAIN)
342 				return 0;
343 			if (errno == EINTR)
344 				continue;
345 			return -1;
346 		}
347 		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));
367 				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);
388 				break;
389 			case RTM_DELETE:
390 				if (~rtm->rtm_addrs &
391 				    (RTA_DST | RTA_GATEWAY | RTA_NETMASK))
392 					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 			}
444 		}
445 	}
446 }
447