1/* 2 * Copyright (c) 1999 - 2008, 2011 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 * inetroute.c 25 * - get a list of internet network routes 26 */ 27 28/* 29 * Modification History 30 * 31 * Dieter Siegmund (dieter@apple.com) Tue Jul 14 11:33:50 PDT 1998 32 * - created 33 */ 34#include <sys/param.h> 35#include <sys/socket.h> 36#include <sys/mbuf.h> 37#include <net/if.h> 38#include <net/if_dl.h> 39#include <net/if_types.h> 40#include <net/route.h> 41#include <netinet/in.h> 42#include <sys/sysctl.h> 43#include <netdb.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <unistd.h> 48#include <sys/cdefs.h> 49#include <sys/types.h> 50#include <sys/socket.h> 51#include <arpa/inet.h> /* has inet_ntoa, etc. */ 52 53#include "inetroute.h" 54#include "util.h" 55 56#define INDEX_NONE -1 57 58static __inline__ void * 59next_sockaddr(struct sockaddr * sa) 60{ 61 int offset; 62 63 offset = (sa->sa_len != 0) 64 ? roundup(sa->sa_len, sizeof(uint32_t)) 65 : sizeof(uint32_t); 66 return (((caddr_t)(sa) + offset)); 67} 68 69inetroute_list_t * 70inetroute_list_init() 71{ 72 char * buf = NULL; 73 char * lim; 74 inetroute_list_t * list_p = NULL; 75 int list_size = 2; 76 int mib[6]; 77 size_t needed; 78 char * next; 79 struct rt_msghdr * rtm; 80 81 mib[0] = CTL_NET; 82 mib[1] = PF_ROUTE; 83 mib[2] = 0; 84 mib[3] = 0; 85 mib[4] = NET_RT_DUMP; 86 mib[5] = 0; 87 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 88 perror("route-sysctl-estimate"); 89 goto err; 90 } 91 if ((buf = malloc(needed)) == 0) { 92 goto err; 93 } 94 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 95 perror("sysctl of routing table"); 96 goto err; 97 } 98 list_p = (inetroute_list_t *)malloc(sizeof(*list_p)); 99 list_p->def_index = INDEX_NONE; 100 if (list_p == NULL) 101 goto err; 102 list_p->count = 0; 103 list_p->list = (inetroute_t *)malloc(sizeof(*(list_p->list)) * list_size); 104 if (list_p->list == NULL) 105 goto err; 106 lim = buf + needed; 107 for (next = buf; next < lim; next += rtm->rtm_msglen) { 108 void * addrs; 109 struct sockaddr * dst = NULL; 110 struct sockaddr * gateway = NULL; 111 struct sockaddr * mask = NULL; 112 113 /* ALIGN: kernel ensures that next will be aligned, cast ok */ 114 rtm = (struct rt_msghdr *)(void *)next; 115 addrs = (void *)(&rtm[1]); 116 if (rtm->rtm_addrs & RTA_DST) { 117 dst = (struct sockaddr *)addrs; 118 addrs = next_sockaddr(dst); 119 } 120 if (rtm->rtm_addrs & RTA_GATEWAY) { 121 gateway = (struct sockaddr *)addrs; 122 addrs = next_sockaddr(gateway); 123 } 124 if (rtm->rtm_addrs & RTA_NETMASK) { 125 mask = (struct sockaddr *)addrs; 126 } 127 128 if (dst && dst->sa_family == AF_INET 129 && gateway 130 && mask 131 && !(rtm->rtm_flags & RTF_HOST)) { 132 /* ALIGN: dst aligned, after cast 133 * dst_p is aligned to fields of dst. */ 134 struct sockaddr_in * dst_p = (struct sockaddr_in *)(void *)dst; 135 136 /* ALIGN: mask_p aligned, after cast, mask_p aligned to fields of 137 * mask. */ 138 struct sockaddr_in * mask_p = (struct sockaddr_in *)(void *)mask; 139 140 inetroute_t * entry; 141 if (list_p->count == list_size) { 142 list_size *= 2; 143 list_p->list = (inetroute_t *) 144 realloc(list_p->list, sizeof(*(list_p->list)) * list_size); 145 if (list_p->list == NULL) 146 goto err; 147 } 148 entry = list_p->list + list_p->count; 149 bzero(entry, sizeof(*entry)); 150 entry->dest = dst_p->sin_addr; 151 if (mask_p->sin_len != 0) { 152 entry->mask = mask_p->sin_addr; 153 } 154 /* remember the non-interface-scoped default route */ 155 if ((rtm->rtm_flags & RTF_IFSCOPE) == 0 156 && dst_p->sin_addr.s_addr == INADDR_ANY) { 157 list_p->def_index = list_p->count; 158 } 159 if (gateway->sa_family == AF_LINK) { 160 /* ALIGN: gateway aligned. After cast, 161 * sdl fields should be aligned */ 162 struct sockaddr_dl * sdl = (struct sockaddr_dl *)(void *)gateway; 163 entry->gateway.link = *sdl; 164 } 165 else { 166 struct sockaddr_in * in_p = (struct sockaddr_in *)(void *)gateway; 167 entry->gateway.inet = *in_p; 168 } 169 list_p->count++; 170 } 171 } 172 free(buf); 173 return (list_p); 174 err: 175 if (buf) 176 free(buf); 177 inetroute_list_free(&list_p); 178 return (NULL); 179} 180 181void 182inetroute_list_free(inetroute_list_t * * list) 183{ 184 if (list != NULL && *list != NULL) { 185 if ((*list)->list) 186 free((*list)->list); 187 (*list)->list = NULL; 188 free(*list); 189 *list = NULL; 190 } 191} 192 193struct in_addr * 194inetroute_default(inetroute_list_t * list_p) 195{ 196 inetroute_t * entry; 197 198 if (list_p->def_index == INDEX_NONE) { 199 return (NULL); 200 } 201 entry = list_p->list + list_p->def_index; 202 if (entry->gateway.inet.sin_family == AF_INET) { 203 return (&(entry->gateway.inet.sin_addr)); 204 } 205 return (NULL); 206} 207 208void 209inetroute_list_print(inetroute_list_t * list_p) 210{ 211 int i; 212 213 for (i = 0; i < list_p->count; i++) { 214 inetroute_t * entry = list_p->list + i; 215 216 if (entry->gateway.link.sdl_family == AF_LINK) { 217 printf("%s ==> link %d\n", 218 inet_nettoa(entry->dest, entry->mask), 219 entry->gateway.link.sdl_index); 220 } 221 else { 222 printf("%s ==> %s\n", 223 inet_nettoa(entry->dest, entry->mask), 224 inet_ntoa(entry->gateway.inet.sin_addr)); 225 } 226 } 227} 228 229#ifdef TEST_INETROUTE 230int 231main() 232{ 233 inetroute_list_t * list_p; 234 struct in_addr * def; 235 236 list_p = inetroute_list_init(); 237 if (list_p == NULL) 238 exit(0); 239 inetroute_list_print(list_p); 240 def = inetroute_default(list_p); 241 if (def) { 242 printf("default route: %s\n", inet_ntoa(*def)); 243 } 244 inetroute_list_free(&list_p); 245 exit(0); 246} 247#endif /* TEST_INETROUTE */ 248