1 /* $OpenBSD: route.c,v 1.106 2020/12/29 19:51:52 benno Exp $ */ 2 /* $NetBSD: route.c,v 1.15 1996/05/07 02:55:06 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/protosw.h> 35 #include <sys/select.h> 36 #include <sys/socket.h> 37 38 #include <net/if.h> 39 #include <net/if_types.h> 40 #include <net/route.h> 41 #include <netinet/ip_ipsp.h> 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 45 #include <sys/sysctl.h> 46 47 #include <err.h> 48 #include <limits.h> 49 #include <netdb.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <ifaddrs.h> 55 56 #include "netstat.h" 57 58 static union { 59 struct sockaddr u_sa; 60 u_int32_t u_data[64]; 61 int u_dummy; /* force word-alignment */ 62 } pt_u; 63 64 struct rtentry rtentry; 65 66 static struct sockaddr *kgetsa(struct sockaddr *); 67 static struct sockaddr *plentosa(sa_family_t, int, struct sockaddr *); 68 static struct art_node *getdefault(struct art_table *); 69 static void p_table(struct art_table *); 70 static void p_artnode(struct art_node *); 71 static void p_krtentry(struct rtentry *); 72 73 /* 74 * Print routing tables. 75 */ 76 void 77 routepr(u_long afmap, u_long af2idx, u_long af2idx_max, u_int tableid) 78 { 79 struct art_root ar; 80 struct art_node *node; 81 struct srp *afm_head, *afm; 82 struct { 83 unsigned int limit; 84 void **tbl; 85 } map; 86 void **tbl; 87 int i; 88 uint8_t af2i[AF_MAX+1]; 89 uint8_t af2i_max; 90 91 printf("Routing tables\n"); 92 93 if (afmap == 0 || af2idx == 0 || af2idx_max == 0) { 94 printf("symbol not in namelist\n"); 95 return; 96 } 97 98 kread(afmap, &afm_head, sizeof(afm_head)); 99 kread(af2idx, af2i, sizeof(af2i)); 100 kread(af2idx_max, &af2i_max, sizeof(af2i_max)); 101 102 if ((afm = calloc(af2i_max + 1, sizeof(*afm))) == NULL) 103 err(1, NULL); 104 105 kread((u_long)afm_head, afm, (af2i_max + 1) * sizeof(*afm)); 106 107 for (i = 1; i <= AF_MAX; i++) { 108 if (af != AF_UNSPEC && af != i) 109 continue; 110 if (af2i[i] == 0 || afm[af2i[i]].ref == NULL) 111 continue; 112 113 kread((u_long)afm[af2i[i]].ref, &map, sizeof(map)); 114 if (tableid >= map.limit) 115 continue; 116 117 if ((tbl = calloc(map.limit, sizeof(*tbl))) == NULL) 118 err(1, NULL); 119 120 kread((u_long)map.tbl, tbl, map.limit * sizeof(*tbl)); 121 if (tbl[tableid] == NULL) 122 continue; 123 124 kread((u_long)tbl[tableid], &ar, sizeof(ar)); 125 126 free(tbl); 127 128 if (ar.ar_root.ref == NULL) 129 continue; 130 131 pr_family(i); 132 pr_rthdr(i, Aflag); 133 134 node = getdefault(ar.ar_root.ref); 135 if (node != NULL) 136 p_artnode(node); 137 138 p_table(ar.ar_root.ref); 139 } 140 141 free(afm); 142 } 143 144 static struct sockaddr * 145 kgetsa(struct sockaddr *dst) 146 { 147 148 kread((u_long)dst, &pt_u.u_sa, sizeof(pt_u.u_sa)); 149 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 150 kread((u_long)dst, pt_u.u_data, pt_u.u_sa.sa_len); 151 return (&pt_u.u_sa); 152 } 153 154 static struct sockaddr * 155 plentosa(sa_family_t af, int plen, struct sockaddr *sa_mask) 156 { 157 struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; 158 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; 159 uint8_t *p; 160 int i; 161 162 if (plen < 0) 163 return (NULL); 164 165 memset(sa_mask, 0, sizeof(struct sockaddr_storage)); 166 167 switch (af) { 168 case AF_INET: 169 if (plen > 32) 170 return (NULL); 171 sin->sin_family = AF_INET; 172 sin->sin_len = sizeof(struct sockaddr_in); 173 memset(&sin->sin_addr, 0, sizeof(sin->sin_addr)); 174 p = (uint8_t *)&sin->sin_addr; 175 break; 176 case AF_INET6: 177 if (plen > 128) 178 return (NULL); 179 sin6->sin6_family = AF_INET6; 180 sin6->sin6_len = sizeof(struct sockaddr_in6); 181 memset(&sin6->sin6_addr.s6_addr, 0, sizeof(sin6->sin6_addr.s6_addr)); 182 p = sin6->sin6_addr.s6_addr; 183 break; 184 default: 185 return (NULL); 186 } 187 188 for (i = 0; i < plen / 8; i++) 189 p[i] = 0xff; 190 if (plen % 8) 191 p[i] = (0xff00 >> (plen % 8)) & 0xff; 192 193 return (sa_mask); 194 } 195 196 static struct art_node * 197 getdefault(struct art_table *at) 198 { 199 struct art_node *node; 200 struct art_table table; 201 union { 202 struct srp node; 203 unsigned long count; 204 } *heap; 205 206 kread((u_long)at, &table, sizeof(table)); 207 heap = calloc(1, AT_HEAPSIZE(table.at_bits)); 208 kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); 209 210 node = heap[1].node.ref; 211 212 free(heap); 213 214 return (node); 215 } 216 217 static void 218 p_table(struct art_table *at) 219 { 220 struct art_node *next, *node; 221 struct art_table *nat, table; 222 union { 223 struct srp node; 224 unsigned long count; 225 } *heap; 226 int i, j; 227 228 kread((u_long)at, &table, sizeof(table)); 229 heap = calloc(1, AT_HEAPSIZE(table.at_bits)); 230 kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); 231 232 for (j = 1; j < table.at_minfringe; j += 2) { 233 for (i = (j > 2) ? j : 2; i < table.at_minfringe; i <<= 1) { 234 next = heap[i >> 1].node.ref; 235 node = heap[i].node.ref; 236 if (node != NULL && node != next) 237 p_artnode(node); 238 } 239 } 240 241 for (i = table.at_minfringe; i < table.at_minfringe << 1; i++) { 242 next = heap[i >> 1].node.ref; 243 node = heap[i].node.ref; 244 if (!ISLEAF(node)) { 245 nat = SUBTABLE(node); 246 node = getdefault(nat); 247 } else 248 nat = NULL; 249 250 if (node != NULL && node != next) 251 p_artnode(node); 252 253 if (nat != NULL) 254 p_table(nat); 255 } 256 257 free(heap); 258 } 259 260 static void 261 p_artnode(struct art_node *an) 262 { 263 struct art_node node; 264 struct rtentry *rt; 265 266 kread((u_long)an, &node, sizeof(node)); 267 rt = node.an_rtlist.sl_head.ref; 268 269 while (rt != NULL) { 270 kread((u_long)rt, &rtentry, sizeof(rtentry)); 271 if (Aflag) 272 printf("%-16p ", rt); 273 p_krtentry(&rtentry); 274 rt = rtentry.rt_next.se_next.ref; 275 } 276 } 277 278 static void 279 p_krtentry(struct rtentry *rt) 280 { 281 struct sockaddr_storage sock1, sock2; 282 struct sockaddr *sa = (struct sockaddr *)&sock1; 283 struct sockaddr *mask = (struct sockaddr *)&sock2; 284 285 bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr)); 286 if (sa->sa_len > sizeof(struct sockaddr)) 287 bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len); 288 289 if (sa->sa_family == PF_KEY) { 290 /* Ignore PF_KEY entries */ 291 return; 292 } 293 294 mask = plentosa(sa->sa_family, rt_plen(rt), mask); 295 296 p_addr(sa, mask, rt->rt_flags); 297 p_gwaddr(kgetsa(rt->rt_gateway), sa->sa_family); 298 p_flags(rt->rt_flags, "%-6.6s "); 299 printf("%5u %8lld ", rt->rt_refcnt - 1, rt->rt_use); 300 if (rt->rt_rmx.rmx_mtu) 301 printf("%5u ", rt->rt_rmx.rmx_mtu); 302 else 303 printf("%5s ", "-"); 304 putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); 305 printf(" %2d", rt->rt_priority & RTP_MASK); 306 307 if (rt->rt_ifidx != 0) 308 printf(" if%d", rt->rt_ifidx); 309 putchar('\n'); 310 if (vflag) 311 printf("\texpire %10lld%c\n", 312 (long long)rt->rt_rmx.rmx_expire, 313 (rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' '); 314 } 315 316 /* 317 * Print routing statistics 318 */ 319 void 320 rt_stats(void) 321 { 322 struct rtstat rtstat; 323 int mib[6]; 324 size_t size; 325 326 mib[0] = CTL_NET; 327 mib[1] = PF_ROUTE; 328 mib[2] = 0; 329 mib[3] = 0; 330 mib[4] = NET_RT_STATS; 331 mib[5] = 0; 332 size = sizeof (rtstat); 333 334 if (sysctl(mib, 6, &rtstat, &size, NULL, 0) == -1) { 335 perror("sysctl of routing table statistics"); 336 exit(1); 337 } 338 339 printf("routing:\n"); 340 printf("\t%u bad routing redirect%s\n", 341 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 342 printf("\t%u dynamically created route%s\n", 343 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 344 printf("\t%u new gateway%s due to redirects\n", 345 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 346 printf("\t%u destination%s found unreachable\n", 347 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 348 printf("\t%u use%s of a wildcard route\n", 349 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 350 } 351 352 /* 353 * Print rdomain and rtable summary 354 */ 355 356 void 357 rdomainpr(void) 358 { 359 struct if_data *ifd; 360 struct ifaddrs *ifap, *ifa; 361 struct rt_tableinfo info; 362 363 int rtt_dom[RT_TABLEID_MAX+1]; 364 int rdom_rttcnt[RT_TABLEID_MAX+1] = { }; 365 int mib[6], rdom, rtt; 366 size_t len; 367 char *old, *rdom_if[RT_TABLEID_MAX+1] = { }; 368 369 getifaddrs(&ifap); 370 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 371 if (ifa->ifa_addr == NULL || 372 ifa->ifa_addr->sa_family != AF_LINK) 373 continue; 374 ifd = ifa->ifa_data; 375 if (rdom_if[ifd->ifi_rdomain] == NULL) { 376 if (asprintf(&rdom_if[ifd->ifi_rdomain], "%s", 377 ifa->ifa_name) == -1) 378 exit(1); 379 } else { 380 old = rdom_if[ifd->ifi_rdomain]; 381 if (asprintf(&rdom_if[ifd->ifi_rdomain], "%s %s", 382 old, ifa->ifa_name) == -1) 383 exit(1); 384 free(old); 385 } 386 } 387 freeifaddrs(ifap); 388 389 mib[0] = CTL_NET; 390 mib[1] = PF_ROUTE; 391 mib[2] = 0; 392 mib[3] = 0; 393 mib[4] = NET_RT_TABLE; 394 395 len = sizeof(info); 396 for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) { 397 mib[5] = rtt; 398 if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) 399 rtt_dom[rtt] = -1; 400 else { 401 rtt_dom[rtt] = info.rti_domainid; 402 rdom_rttcnt[info.rti_domainid]++; 403 } 404 } 405 406 for (rdom = 0; rdom <= RT_TABLEID_MAX; rdom++) { 407 if (rdom_if[rdom] == NULL) 408 continue; 409 printf("Rdomain %i\n", rdom); 410 printf(" Interface%s %s\n", 411 (strchr(rdom_if[rdom], ' ') == NULL) ? ":" : "s:", 412 rdom_if[rdom]); 413 printf(" Routing table%s", 414 (rdom_rttcnt[rdom] == 1) ? ":" : "s:"); 415 for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) { 416 if (rtt_dom[rtt] == rdom) 417 printf(" %i", rtt); 418 } 419 printf("\n\n"); 420 free(rdom_if[rdom]); 421 } 422 } 423