1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * rtutil.c 26 * - routing table routines 27 */ 28 29/* 30 * Modification History 31 * 32 * June 23, 2009 Dieter Siegmund (dieter@apple.com) 33 * - split out from ipconfigd.c 34 */ 35 36 37#include "rtutil.h" 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <unistd.h> 42#include <string.h> 43#include <syslog.h> 44#include <sys/types.h> 45#include <sys/param.h> 46#include <sys/sysctl.h> 47#include <sys/errno.h> 48#include <sys/socket.h> 49#include <net/route.h> 50#include <net/if_dl.h> 51#define KERNEL_PRIVATE 52#include <sys/ioctl.h> 53#undef KERNEL_PRIVATE 54#include <mach/boolean.h> 55#include "symbol_scope.h" 56#include "util.h" 57#include "arp.h" 58#include "mylog.h" 59#include "globals.h" 60 61STATIC void 62set_sockaddr_in(struct sockaddr_in * sin_p, struct in_addr iaddr) 63{ 64 sin_p->sin_len = sizeof(*sin_p); 65 sin_p->sin_family = AF_INET; 66 sin_p->sin_addr = iaddr; 67} 68 69/* 70 * Function: subnet_route 71 * Purpose: 72 * Add/remove/get the specified subnet route. 73 * Returns: 74 * TRUE if operation was successful, FALSE otherwise. 75 */ 76STATIC boolean_t 77subnet_route(int cmd, struct in_addr gateway, struct in_addr netaddr, 78 struct in_addr netmask, const char * ifname) 79{ 80 int len; 81 boolean_t ret = TRUE; 82 struct rt_msghdr * rtm; 83 struct { 84 struct rt_msghdr hdr; 85 struct sockaddr_in dst; 86 struct sockaddr_in gway; 87 struct sockaddr_in mask; 88 struct sockaddr_dl ifp; 89 struct sockaddr_in ifa; 90 } rtmsg; 91 int sockfd = -1; 92 93 sockfd = arp_open_routing_socket(); 94 if (sockfd < 0) { 95 my_log(LOG_NOTICE, "subnet_route: open routing socket failed, %s", 96 strerror(errno)); 97 ret = FALSE; 98 goto done; 99 } 100 101 memset(&rtmsg, 0, sizeof(rtmsg)); 102 rtm = &rtmsg.hdr; 103 rtm->rtm_type = cmd; 104 rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_CLONING; 105 rtm->rtm_version = RTM_VERSION; 106 rtm->rtm_seq = arp_get_next_seq(); 107 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 108 set_sockaddr_in(&rtmsg.dst, netaddr); 109 set_sockaddr_in(&rtmsg.gway, gateway); 110 set_sockaddr_in(&rtmsg.mask, netmask); 111 112 len = sizeof(rtmsg); 113 if (ifname != NULL) { 114 rtm->rtm_addrs |= RTA_IFP | RTA_IFA; 115 /* copy the interface name */ 116 rtmsg.ifp.sdl_len = sizeof(rtmsg.ifp); 117 rtmsg.ifp.sdl_family = AF_LINK; 118 rtmsg.ifp.sdl_nlen = strlen(ifname); 119 bcopy(ifname, rtmsg.ifp.sdl_data, rtmsg.ifp.sdl_nlen); 120 /* and the interface address (which is the gateway) */ 121 set_sockaddr_in(&rtmsg.ifa, gateway); 122 } 123 else { 124 /* no ifp/ifa information */ 125 len -= sizeof(rtmsg.ifp) + sizeof(rtmsg.ifa); 126 } 127 rtm->rtm_msglen = len; 128 if (write(sockfd, &rtmsg, len) < 0) { 129 int error = errno; 130 131 switch (error) { 132 case ESRCH: 133 case EEXIST: 134 my_log(LOG_DEBUG, "subnet_route: write routing socket failed, %s", 135 strerror(error)); 136 break; 137 default: 138 my_log(LOG_NOTICE, "subnet_route: write routing socket failed, %s", 139 strerror(error)); 140 break; 141 } 142 ret = FALSE; 143 } 144 done: 145 if (sockfd >= 0) { 146 close(sockfd); 147 } 148 return (ret); 149} 150 151PRIVATE_EXTERN boolean_t 152subnet_route_add(struct in_addr gateway, struct in_addr netaddr, 153 struct in_addr netmask, const char * ifname) 154{ 155 return (subnet_route(RTM_ADD, gateway, netaddr, netmask, ifname)); 156} 157 158#define N_MIB 6 159 160STATIC int 161flush_dynamic_routes(int s) 162{ 163 char * buf = NULL; 164 int i; 165 char * lim; 166 int mib[N_MIB]; 167 size_t needed; 168 char * next; 169 struct rt_msghdr * rtm; 170 struct sockaddr_in *sin; 171 172 mib[0] = CTL_NET; 173 mib[1] = PF_ROUTE; 174 mib[2] = 0; 175 mib[3] = AF_INET; 176 mib[4] = NET_RT_FLAGS; 177 mib[5] = RTF_DYNAMIC; 178 for (i = 0; i < 3; i++) { 179 if (sysctl(mib, N_MIB, NULL, &needed, NULL, 0) < 0) { 180 break; 181 } 182 if ((buf = malloc(needed)) == NULL) { 183 break; 184 } 185 if (sysctl(mib, N_MIB, buf, &needed, NULL, 0) >= 0) { 186 break; 187 } 188 free(buf); 189 buf = NULL; 190 } 191 if (buf == NULL) { 192 return (-1); 193 } 194 lim = buf + needed; 195 for (next = buf; next < lim; next += rtm->rtm_msglen) { 196 /* ALIGN: assume kernel provides necessary alignment */ 197 rtm = (struct rt_msghdr *)(void *)next; 198 sin = (struct sockaddr_in *)(rtm + 1); 199 200 rtm->rtm_type = RTM_DELETE; 201 rtm->rtm_seq = arp_get_next_seq(); 202 if (write(s, rtm, rtm->rtm_msglen) < 0) { 203 my_log(LOG_NOTICE, 204 "IPConfiguration: removing dynamic route for " 205 IP_FORMAT " failed, %s", 206 IP_LIST(&sin->sin_addr), 207 strerror(errno)); 208 } 209 else if (G_IPConfiguration_verbose) { 210 my_log(LOG_DEBUG, 211 "IPConfiguration: removed dynamic route for " IP_FORMAT, 212 IP_LIST(&sin->sin_addr)); 213 } 214 } 215 free(buf); 216 return (0); 217} 218 219PRIVATE_EXTERN void 220flush_routes(int if_index, const struct in_addr ip, 221 const struct in_addr broadcast) 222{ 223 int s; 224 225 s = arp_open_routing_socket(); 226 if (s < 0) { 227 return; 228 } 229 230 /* remove permanent arp entries for the IP and IP broadcast. 231 * - do these first because they require reading from the routing socket 232 * - flushing only requires writing to the routing socket 233 */ 234 if (ip.s_addr) { 235 (void)arp_delete(s, ip, 0); 236 } 237 if (broadcast.s_addr) { 238 (void)arp_delete(s, broadcast, 0); 239 } 240 241 /* blow away all non-permanent arp entries */ 242 (void)arp_flush(s, FALSE, if_index); 243 244 (void)flush_dynamic_routes(s); 245 close(s); 246 return; 247} 248