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
75static int r_fd = -1;
76static char *link_buf;
77static ssize_t link_buflen;
78
79int
80if_init(_unused struct interface *iface)
81{
82	/* 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
93#ifdef DEBUG_MEMORY
94static void
95cleanup(void)
96{
97
98	free(link_buf);
99}
100#endif
101
102int
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;
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
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{
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 */
189int
190if_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
274int
275open_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
292static void
293get_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
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
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