1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright 2006-2008 Roy Marples <roy (at) 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 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 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 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 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