• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright 2006-2008 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/types.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <sys/param.h>
33 
34 #include <arpa/inet.h>
35 #include <net/if_dl.h>
36 #include <net/if_types.h>
37 #include <net/route.h>
38 #include <netinet/in.h>
39 
40 #include <errno.h>
41 #include <stddef.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 #include "config.h"
48 #include "common.h"
49 #include "dhcp.h"
50 #include "net.h"
51 
52 /* Darwin doesn't define this for some very odd reason */
53 #ifndef SA_SIZE
54 # define SA_SIZE(sa)						\
55 	(  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?	\
56 	   sizeof(long)		:				\
57 	   1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
58 #endif
59 
60 int
if_address(const char * ifname,const struct in_addr * address,const struct in_addr * netmask,const struct in_addr * broadcast,int action)61 if_address(const char *ifname, const struct in_addr *address,
62 	   const struct in_addr *netmask, const struct in_addr *broadcast,
63 	   int action)
64 {
65 	int s;
66 	int retval;
67 	struct ifaliasreq ifa;
68 	union {
69 		struct sockaddr *sa;
70 		struct sockaddr_in *sin;
71 	} _s;
72 
73 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
74 		return -1;
75 
76 	memset(&ifa, 0, sizeof(ifa));
77 	strlcpy(ifa.ifra_name, ifname, sizeof(ifa.ifra_name));
78 
79 #define ADDADDR(_var, _addr) \
80 	_s.sa = &_var; \
81 	_s.sin->sin_family = AF_INET; \
82 	_s.sin->sin_len = sizeof(*_s.sin); \
83 	memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));
84 
85 	ADDADDR(ifa.ifra_addr, address);
86 	ADDADDR(ifa.ifra_mask, netmask);
87 	if (action >= 0) {
88 		ADDADDR(ifa.ifra_broadaddr, broadcast);
89 	}
90 #undef ADDADDR
91 
92 	if (action < 0)
93 		retval = ioctl(s, SIOCDIFADDR, &ifa);
94 	else
95 		retval = ioctl(s, SIOCAIFADDR, &ifa);
96 	close(s);
97 	return retval;
98 }
99 
100 int
if_route(const struct interface * iface,const struct in_addr * dest,const struct in_addr * net,const struct in_addr * gate,_unused int metric,int action)101 if_route(const struct interface *iface, const struct in_addr *dest,
102 	 const struct in_addr *net, const struct in_addr *gate,
103 	 _unused int metric, int action)
104 {
105 	int s;
106 	union sockunion {
107 		struct sockaddr sa;
108 		struct sockaddr_in sin;
109 #ifdef INET6
110 		struct sockaddr_in6 sin6;
111 #endif
112 		struct sockaddr_dl sdl;
113 		struct sockaddr_storage ss;
114 	} su;
115 	struct rtm
116 	{
117 		struct rt_msghdr hdr;
118 		char buffer[sizeof(su) * 4];
119 	} rtm;
120 	char *bp = rtm.buffer, *p;
121 	size_t l;
122 	int retval = 0;
123 
124 #define ADDSU(_su) { \
125 	l = SA_SIZE(&(_su.sa)); \
126 	memcpy(bp, &(_su), l); \
127 	bp += l; \
128 }
129 #define ADDADDR(_addr) { \
130 	memset (&su, 0, sizeof(su)); \
131 	su.sin.sin_family = AF_INET; \
132 	su.sin.sin_len = sizeof(su.sin); \
133 	memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
134 	ADDSU(su); \
135 }
136 
137 	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
138 		return -1;
139 
140 	memset(&rtm, 0, sizeof(rtm));
141 	rtm.hdr.rtm_version = RTM_VERSION;
142 	rtm.hdr.rtm_seq = 1;
143 	if (action == 0)
144 		rtm.hdr.rtm_type = RTM_CHANGE;
145 	else if (action > 0)
146 		rtm.hdr.rtm_type = RTM_ADD;
147 	else
148 		rtm.hdr.rtm_type = RTM_DELETE;
149 	rtm.hdr.rtm_flags = RTF_UP;
150 	/* None interface subnet routes are static. */
151 	if (gate->s_addr != INADDR_ANY ||
152 	    net->s_addr != iface->net.s_addr ||
153 	    dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
154 		rtm.hdr.rtm_flags |= RTF_STATIC;
155 	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
156 	if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
157 		rtm.hdr.rtm_flags |= RTF_HOST;
158 	else {
159 		rtm.hdr.rtm_addrs |= RTA_NETMASK;
160 		if (rtm.hdr.rtm_flags & RTF_STATIC)
161 			rtm.hdr.rtm_flags |= RTF_GATEWAY;
162 		if (action >= 0)
163 			rtm.hdr.rtm_addrs |= RTA_IFA;
164 	}
165 
166 	ADDADDR(dest);
167 	if (rtm.hdr.rtm_flags & RTF_HOST ||
168 	    !(rtm.hdr.rtm_flags & RTF_STATIC))
169 	{
170 		/* Make us a link layer socket for the host gateway */
171 		memset(&su, 0, sizeof(su));
172 		su.sdl.sdl_len = sizeof(struct sockaddr_dl);
173 		link_addr(iface->name, &su.sdl);
174 		ADDSU(su);
175 	} else
176 		ADDADDR(gate);
177 
178 	if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
179 		/* Ensure that netmask is set correctly */
180 		memset(&su, 0, sizeof(su));
181 		su.sin.sin_family = AF_INET;
182 		su.sin.sin_len = sizeof(su.sin);
183 		memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
184 		p = su.sa.sa_len + (char *)&su;
185 		for (su.sa.sa_len = 0; p > (char *)&su;)
186 			if (*--p != 0) {
187 				su.sa.sa_len = 1 + p - (char *)&su;
188 				break;
189 			}
190 		ADDSU(su);
191 	}
192 
193 	if (rtm.hdr.rtm_addrs & RTA_IFA)
194 		ADDADDR(&iface->addr);
195 
196 	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
197 	if (write(s, &rtm, l) == -1)
198 		retval = -1;
199 	close(s);
200 	return retval;
201 }
202 
203 int
open_link_socket(struct interface * iface)204 open_link_socket(struct interface *iface)
205 {
206 	int fd;
207 
208 	fd = socket(PF_ROUTE, SOCK_RAW, 0);
209 	if (fd == -1)
210 		return -1;
211 	set_cloexec(fd);
212 	if (iface->link_fd != -1)
213 		close(iface->link_fd);
214 	iface->link_fd = fd;
215 	return 0;
216 }
217 
218 #define BUFFER_LEN	2048
219 int
link_changed(struct interface * iface)220 link_changed(struct interface *iface)
221 {
222 	char buffer[2048], *p;
223 	ssize_t bytes;
224 	struct rt_msghdr *rtm;
225 	struct if_msghdr *ifm;
226 	int i;
227 
228 	if ((i = if_nametoindex(iface->name)) == -1)
229 		return -1;
230 	for (;;) {
231 		bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
232 		if (bytes == -1) {
233 			if (errno == EAGAIN)
234 				return 0;
235 			if (errno == EINTR)
236 				continue;
237 			return -1;
238 		}
239 		for (p = buffer; bytes > 0;
240 		     bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
241 		     p += ((struct rt_msghdr *)p)->rtm_msglen)
242 		{
243 			rtm = (struct rt_msghdr *)p;
244 			if (rtm->rtm_type != RTM_IFINFO)
245 				continue;
246 			ifm = (struct if_msghdr *)p;
247 			if (ifm->ifm_index != i)
248 				continue;
249 
250 			/* Link changed */
251 			return 1;
252 		}
253 	}
254 	return 0;
255 }
256