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