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