1 /* $OpenBSD: route.c,v 1.109 2022/06/28 15:17:23 bluhm 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/socket.h> 36 37 #include <net/if.h> 38 #include <net/if_types.h> 39 #define _KERNEL 40 #include <net/route.h> 41 #undef _KERNEL 42 #include <netinet/ip_ipsp.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 46 #include <sys/sysctl.h> 47 48 #include <err.h> 49 #include <limits.h> 50 #include <netdb.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <ifaddrs.h> 56 57 #include "netstat.h" 58 59 static union { 60 struct sockaddr u_sa; 61 u_int32_t u_data[64]; 62 int u_dummy; /* force word-alignment */ 63 } pt_u; 64 65 struct rtentry rtentry; 66 67 static struct sockaddr *kgetsa(struct sockaddr *); 68 static struct sockaddr *plentosa(sa_family_t, int, struct sockaddr *); 69 static struct art_node *getdefault(struct art_table *); 70 static void p_table(struct art_table *); 71 static void p_artnode(struct art_node *); 72 static void p_krtentry(struct rtentry *); 73 74 /* 75 * Print routing tables. 76 */ 77 void 78 routepr(u_long afmap, u_long af2idx, u_long af2idx_max, u_int tableid) 79 { 80 struct art_root ar; 81 struct art_node *node; 82 struct srp *afm_head, *afm; 83 struct { 84 unsigned int limit; 85 void **tbl; 86 } map; 87 void **tbl; 88 int i; 89 uint8_t af2i[AF_MAX+1]; 90 uint8_t af2i_max; 91 92 printf("Routing tables\n"); 93 94 if (afmap == 0 || af2idx == 0 || af2idx_max == 0) { 95 printf("symbol not in namelist\n"); 96 return; 97 } 98 99 kread(afmap, &afm_head, sizeof(afm_head)); 100 kread(af2idx, af2i, sizeof(af2i)); 101 kread(af2idx_max, &af2i_max, sizeof(af2i_max)); 102 103 if ((afm = calloc(af2i_max + 1, sizeof(*afm))) == NULL) 104 err(1, NULL); 105 106 kread((u_long)afm_head, afm, (af2i_max + 1) * sizeof(*afm)); 107 108 for (i = 1; i <= AF_MAX; i++) { 109 if (af != AF_UNSPEC && af != i) 110 continue; 111 if (af2i[i] == 0 || afm[af2i[i]].ref == NULL) 112 continue; 113 114 kread((u_long)afm[af2i[i]].ref, &map, sizeof(map)); 115 if (tableid >= map.limit) 116 continue; 117 118 if ((tbl = calloc(map.limit, sizeof(*tbl))) == NULL) 119 err(1, NULL); 120 121 kread((u_long)map.tbl, tbl, map.limit * sizeof(*tbl)); 122 if (tbl[tableid] == NULL) 123 continue; 124 125 kread((u_long)tbl[tableid], &ar, sizeof(ar)); 126 127 free(tbl); 128 129 if (ar.ar_root.ref == NULL) 130 continue; 131 132 pr_family(i); 133 pr_rthdr(i, Aflag); 134 135 node = getdefault(ar.ar_root.ref); 136 if (node != NULL) 137 p_artnode(node); 138 139 p_table(ar.ar_root.ref); 140 } 141 142 free(afm); 143 } 144 145 static struct sockaddr * 146 kgetsa(struct sockaddr *dst) 147 { 148 149 kread((u_long)dst, &pt_u.u_sa, sizeof(pt_u.u_sa)); 150 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 151 kread((u_long)dst, pt_u.u_data, pt_u.u_sa.sa_len); 152 return (&pt_u.u_sa); 153 } 154 155 static struct sockaddr * 156 plentosa(sa_family_t af, int plen, struct sockaddr *sa_mask) 157 { 158 struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; 159 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; 160 uint8_t *p; 161 int i; 162 163 if (plen < 0) 164 return (NULL); 165 166 memset(sa_mask, 0, sizeof(struct sockaddr_storage)); 167 168 switch (af) { 169 case AF_INET: 170 if (plen > 32) 171 return (NULL); 172 sin->sin_family = AF_INET; 173 sin->sin_len = sizeof(struct sockaddr_in); 174 memset(&sin->sin_addr, 0, sizeof(sin->sin_addr)); 175 p = (uint8_t *)&sin->sin_addr; 176 break; 177 case AF_INET6: 178 if (plen > 128) 179 return (NULL); 180 sin6->sin6_family = AF_INET6; 181 sin6->sin6_len = sizeof(struct sockaddr_in6); 182 memset(&sin6->sin6_addr.s6_addr, 0, sizeof(sin6->sin6_addr.s6_addr)); 183 p = sin6->sin6_addr.s6_addr; 184 break; 185 default: 186 return (NULL); 187 } 188 189 for (i = 0; i < plen / 8; i++) 190 p[i] = 0xff; 191 if (plen % 8) 192 p[i] = (0xff00 >> (plen % 8)) & 0xff; 193 194 return (sa_mask); 195 } 196 197 static struct art_node * 198 getdefault(struct art_table *at) 199 { 200 struct art_node *node; 201 struct art_table table; 202 union { 203 struct srp node; 204 unsigned long count; 205 } *heap; 206 207 kread((u_long)at, &table, sizeof(table)); 208 heap = calloc(1, AT_HEAPSIZE(table.at_bits)); 209 kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); 210 211 node = heap[1].node.ref; 212 213 free(heap); 214 215 return (node); 216 } 217 218 static void 219 p_table(struct art_table *at) 220 { 221 struct art_node *next, *node; 222 struct art_table *nat, table; 223 union { 224 struct srp node; 225 unsigned long count; 226 } *heap; 227 int i, j; 228 229 kread((u_long)at, &table, sizeof(table)); 230 heap = calloc(1, AT_HEAPSIZE(table.at_bits)); 231 kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); 232 233 for (j = 1; j < table.at_minfringe; j += 2) { 234 for (i = (j > 2) ? j : 2; i < table.at_minfringe; i <<= 1) { 235 next = heap[i >> 1].node.ref; 236 node = heap[i].node.ref; 237 if (node != NULL && node != next) 238 p_artnode(node); 239 } 240 } 241 242 for (i = table.at_minfringe; i < table.at_minfringe << 1; i++) { 243 next = heap[i >> 1].node.ref; 244 node = heap[i].node.ref; 245 if (!ISLEAF(node)) { 246 nat = SUBTABLE(node); 247 node = getdefault(nat); 248 } else 249 nat = NULL; 250 251 if (node != NULL && node != next) 252 p_artnode(node); 253 254 if (nat != NULL) 255 p_table(nat); 256 } 257 258 free(heap); 259 } 260 261 static void 262 p_artnode(struct art_node *an) 263 { 264 struct art_node node; 265 struct rtentry *rt; 266 267 kread((u_long)an, &node, sizeof(node)); 268 rt = node.an_rtlist.sl_head.ref; 269 270 while (rt != NULL) { 271 kread((u_long)rt, &rtentry, sizeof(rtentry)); 272 if (Aflag) 273 printf("%-16p ", rt); 274 p_krtentry(&rtentry); 275 rt = rtentry.rt_next.se_next.ref; 276 } 277 } 278 279 static void 280 p_krtentry(struct rtentry *rt) 281 { 282 struct sockaddr_storage sock1, sock2; 283 struct sockaddr *sa = (struct sockaddr *)&sock1; 284 struct sockaddr *mask = (struct sockaddr *)&sock2; 285 286 bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr)); 287 if (sa->sa_len > sizeof(struct sockaddr)) 288 bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len); 289 290 if (sa->sa_family == PF_KEY) { 291 /* Ignore PF_KEY entries */ 292 return; 293 } 294 295 mask = plentosa(sa->sa_family, rt_plen(rt), mask); 296 297 p_addr(sa, mask, rt->rt_flags); 298 p_gwaddr(kgetsa(rt->rt_gateway), sa->sa_family); 299 p_flags(rt->rt_flags, "%-6.6s "); 300 printf("%5u %8lld ", rt->rt_refcnt.r_refs - 1, rt->rt_use); 301 if (rt->rt_rmx.rmx_mtu) 302 printf("%5u ", rt->rt_rmx.rmx_mtu); 303 else 304 printf("%5s ", "-"); 305 putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); 306 printf(" %2d", rt->rt_priority & RTP_MASK); 307 308 if (rt->rt_ifidx != 0) 309 printf(" if%d", rt->rt_ifidx); 310 putchar('\n'); 311 if (vflag) 312 printf("\texpire %10lld%c\n", 313 (long long)rt->rt_rmx.rmx_expire, 314 (rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' '); 315 } 316 317 /* 318 * Print routing statistics 319 */ 320 void 321 rt_stats(void) 322 { 323 struct rtstat rtstat; 324 int mib[6]; 325 size_t size; 326 327 mib[0] = CTL_NET; 328 mib[1] = PF_ROUTE; 329 mib[2] = 0; 330 mib[3] = 0; 331 mib[4] = NET_RT_STATS; 332 mib[5] = 0; 333 size = sizeof (rtstat); 334 335 if (sysctl(mib, 6, &rtstat, &size, NULL, 0) == -1) { 336 perror("sysctl of routing table statistics"); 337 exit(1); 338 } 339 340 printf("routing:\n"); 341 printf("\t%u bad routing redirect%s\n", 342 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 343 printf("\t%u dynamically created route%s\n", 344 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 345 printf("\t%u new gateway%s due to redirects\n", 346 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 347 printf("\t%u destination%s found unreachable\n", 348 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 349 printf("\t%u use%s of a wildcard route\n", 350 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 351 } 352 353 /* 354 * Print rdomain and rtable summary 355 */ 356 357 void 358 rdomainpr(void) 359 { 360 struct if_data *ifd; 361 struct ifaddrs *ifap, *ifa; 362 struct rt_tableinfo info; 363 364 int rtt_dom[RT_TABLEID_MAX+1]; 365 int rdom_rttcnt[RT_TABLEID_MAX+1] = { }; 366 int mib[6], rdom, rtt; 367 size_t len; 368 char *old, *rdom_if[RT_TABLEID_MAX+1] = { }; 369 370 getifaddrs(&ifap); 371 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 372 if (ifa->ifa_addr == NULL || 373 ifa->ifa_addr->sa_family != AF_LINK) 374 continue; 375 ifd = ifa->ifa_data; 376 if (rdom_if[ifd->ifi_rdomain] == NULL) { 377 if (asprintf(&rdom_if[ifd->ifi_rdomain], "%s", 378 ifa->ifa_name) == -1) 379 exit(1); 380 } else { 381 old = rdom_if[ifd->ifi_rdomain]; 382 if (asprintf(&rdom_if[ifd->ifi_rdomain], "%s %s", 383 old, ifa->ifa_name) == -1) 384 exit(1); 385 free(old); 386 } 387 } 388 freeifaddrs(ifap); 389 390 mib[0] = CTL_NET; 391 mib[1] = PF_ROUTE; 392 mib[2] = 0; 393 mib[3] = 0; 394 mib[4] = NET_RT_TABLE; 395 396 len = sizeof(info); 397 for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) { 398 mib[5] = rtt; 399 if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) 400 rtt_dom[rtt] = -1; 401 else { 402 rtt_dom[rtt] = info.rti_domainid; 403 rdom_rttcnt[info.rti_domainid]++; 404 } 405 } 406 407 for (rdom = 0; rdom <= RT_TABLEID_MAX; rdom++) { 408 if (rdom_if[rdom] == NULL) 409 continue; 410 printf("Rdomain %i\n", rdom); 411 printf(" Interface%s %s\n", 412 (strchr(rdom_if[rdom], ' ') == NULL) ? ":" : "s:", 413 rdom_if[rdom]); 414 printf(" Routing table%s", 415 (rdom_rttcnt[rdom] == 1) ? ":" : "s:"); 416 for (rtt = 0; rtt <= RT_TABLEID_MAX; rtt++) { 417 if (rtt_dom[rtt] == rdom) 418 printf(" %i", rtt); 419 } 420 printf("\n\n"); 421 free(rdom_if[rdom]); 422 } 423 } 424