• 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 char * ifname,const struct in_addr * destination,const struct in_addr * netmask,const struct in_addr * gateway,_unused int metric,int action)101 if_route(const char *ifname, const struct in_addr *destination,
102 	 const struct in_addr *netmask, const struct in_addr *gateway,
103 	 _unused int metric, int action)
104 {
105 	int s;
106 	static int seq;
107 	union sockunion {
108 		struct sockaddr sa;
109 		struct sockaddr_in sin;
110 #ifdef INET6
111 		struct sockaddr_in6 sin6;
112 #endif
113 		struct sockaddr_dl sdl;
114 		struct sockaddr_storage ss;
115 	} su;
116 	struct rtm
117 	{
118 		struct rt_msghdr hdr;
119 		char buffer[sizeof(su) * 3];
120 	} rtm;
121 	char *bp = rtm.buffer;
122 	size_t l;
123 	unsigned char *hwaddr;
124 	size_t hwlen = 0;
125 	int retval = 0;
126 
127 	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
128 		return -1;
129 
130 	memset(&rtm, 0, sizeof(rtm));
131 	rtm.hdr.rtm_version = RTM_VERSION;
132 	rtm.hdr.rtm_seq = ++seq;
133 	if (action == 0)
134 		rtm.hdr.rtm_type = RTM_CHANGE;
135 	else if (action > 0)
136 		rtm.hdr.rtm_type = RTM_ADD;
137 	else
138 		rtm.hdr.rtm_type = RTM_DELETE;
139 	rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
140 	if (netmask->s_addr == INADDR_BROADCAST)
141 		rtm.hdr.rtm_flags |= RTF_HOST;
142 
143 	/* This order is important */
144 	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
145 
146 #define ADDADDR(_addr) \
147 	memset (&su, 0, sizeof(su)); \
148 	su.sin.sin_family = AF_INET; \
149 	su.sin.sin_len = sizeof(su.sin); \
150 	memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
151 	l = SA_SIZE (&(su.sa)); \
152 	memcpy (bp, &(su), l); \
153 	bp += l;
154 
155 	ADDADDR(destination);
156 
157 	if (gateway->s_addr == INADDR_ANY) {
158 		/* Make us a link layer socket */
159 		hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
160 		do_interface(ifname, hwaddr, &hwlen, NULL, 0, 0);
161 		memset(&su, 0, sizeof(su));
162 		su.sdl.sdl_len = sizeof(su.sdl);
163 		su.sdl.sdl_family = AF_LINK;
164 		su.sdl.sdl_nlen = strlen(ifname);
165 		memcpy(&su.sdl.sdl_data, ifname, (size_t)su.sdl.sdl_nlen);
166 		su.sdl.sdl_alen = hwlen;
167 		memcpy(((unsigned char *)&su.sdl.sdl_data) + su.sdl.sdl_nlen,
168 		       hwaddr, (size_t)su.sdl.sdl_alen);
169 
170 		l = SA_SIZE(&(su.sa));
171 		memcpy(bp, &su, l);
172 		bp += l;
173 		free(hwaddr);
174 	} else {
175 		rtm.hdr.rtm_flags |= RTF_GATEWAY;
176 		ADDADDR(gateway);
177 	}
178 
179 	ADDADDR(netmask);
180 #undef ADDADDR
181 
182 	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
183 	if (write(s, &rtm, l) == -1)
184 		retval = -1;
185 	close(s);
186 	return retval;
187 }
188 
189 int
open_link_socket(struct interface * iface)190 open_link_socket(struct interface *iface)
191 {
192 	int fd;
193 
194 	fd = socket(PF_ROUTE, SOCK_RAW, 0);
195 	if (fd == -1)
196 		return -1;
197 	set_cloexec(fd);
198 	if (iface->link_fd != -1)
199 		close(iface->link_fd);
200 	iface->link_fd = fd;
201 	return 0;
202 }
203 
204 #define BUFFER_LEN	2048
205 int
link_changed(struct interface * iface)206 link_changed(struct interface *iface)
207 {
208 	char buffer[2048], *p;
209 	ssize_t bytes;
210 	struct rt_msghdr *rtm;
211 	struct if_msghdr *ifm;
212 	int i;
213 
214 	if ((i = if_nametoindex(iface->name)) == -1)
215 		return -1;
216 	for (;;) {
217 		bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
218 		if (bytes == -1) {
219 			if (errno == EAGAIN)
220 				return 0;
221 			if (errno == EINTR)
222 				continue;
223 			return -1;
224 		}
225 		for (p = buffer; bytes > 0;
226 		     bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
227 		     p += ((struct rt_msghdr *)p)->rtm_msglen)
228 		{
229 			rtm = (struct rt_msghdr *)p;
230 			if (rtm->rtm_type != RTM_IFINFO)
231 				continue;
232 			ifm = (struct if_msghdr *)p;
233 			if (ifm->ifm_index != i)
234 				continue;
235 
236 			/* Link changed */
237 			return 1;
238 		}
239 	}
240 	return 0;
241 }
242