1 /* $OpenBSD: route.c,v 1.104 2019/06/28 13:35:02 deraadt 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 55 #include "netstat.h" 56 57 static union { 58 struct sockaddr u_sa; 59 u_int32_t u_data[64]; 60 int u_dummy; /* force word-alignment */ 61 } pt_u; 62 63 struct rtentry rtentry; 64 65 static struct sockaddr *kgetsa(struct sockaddr *); 66 static struct sockaddr *plentosa(sa_family_t, int, struct sockaddr *); 67 static struct art_node *getdefault(struct art_table *); 68 static void p_table(struct art_table *); 69 static void p_artnode(struct art_node *); 70 static void p_krtentry(struct rtentry *); 71 72 /* 73 * Print routing tables. 74 */ 75 void 76 routepr(u_long afmap, u_long af2idx, u_long af2idx_max, u_int tableid) 77 { 78 struct art_root ar; 79 struct art_node *node; 80 struct srp *afm_head, *afm; 81 struct { 82 unsigned int limit; 83 void **tbl; 84 } map; 85 void **tbl; 86 int i; 87 uint8_t af2i[AF_MAX+1]; 88 uint8_t af2i_max; 89 90 printf("Routing tables\n"); 91 92 if (afmap == 0 || af2idx == 0 || af2idx_max == 0) { 93 printf("symbol not in namelist\n"); 94 return; 95 } 96 97 kread(afmap, &afm_head, sizeof(afm_head)); 98 kread(af2idx, af2i, sizeof(af2i)); 99 kread(af2idx_max, &af2i_max, sizeof(af2i_max)); 100 101 if ((afm = calloc(af2i_max + 1, sizeof(*afm))) == NULL) 102 err(1, NULL); 103 104 kread((u_long)afm_head, afm, (af2i_max + 1) * sizeof(*afm)); 105 106 for (i = 1; i <= AF_MAX; i++) { 107 if (af != AF_UNSPEC && af != i) 108 continue; 109 if (af2i[i] == 0 || afm[af2i[i]].ref == NULL) 110 continue; 111 112 kread((u_long)afm[af2i[i]].ref, &map, sizeof(map)); 113 if (tableid >= map.limit) 114 continue; 115 116 if ((tbl = calloc(map.limit, sizeof(*tbl))) == NULL) 117 err(1, NULL); 118 119 kread((u_long)map.tbl, tbl, map.limit * sizeof(*tbl)); 120 if (tbl[tableid] == NULL) 121 continue; 122 123 kread((u_long)tbl[tableid], &ar, sizeof(ar)); 124 125 free(tbl); 126 127 if (ar.ar_root.ref == NULL) 128 continue; 129 130 pr_family(i); 131 pr_rthdr(i, Aflag); 132 133 node = getdefault(ar.ar_root.ref); 134 if (node != NULL) 135 p_artnode(node); 136 137 p_table(ar.ar_root.ref); 138 } 139 140 free(afm); 141 } 142 143 static struct sockaddr * 144 kgetsa(struct sockaddr *dst) 145 { 146 147 kread((u_long)dst, &pt_u.u_sa, sizeof(pt_u.u_sa)); 148 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 149 kread((u_long)dst, pt_u.u_data, pt_u.u_sa.sa_len); 150 return (&pt_u.u_sa); 151 } 152 153 static struct sockaddr * 154 plentosa(sa_family_t af, int plen, struct sockaddr *sa_mask) 155 { 156 struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; 157 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; 158 uint8_t *p; 159 int i; 160 161 if (plen < 0) 162 return (NULL); 163 164 memset(sa_mask, 0, sizeof(struct sockaddr_storage)); 165 166 switch (af) { 167 case AF_INET: 168 if (plen > 32) 169 return (NULL); 170 sin->sin_family = AF_INET; 171 sin->sin_len = sizeof(struct sockaddr_in); 172 memset(&sin->sin_addr, 0, sizeof(sin->sin_addr)); 173 p = (uint8_t *)&sin->sin_addr; 174 break; 175 case AF_INET6: 176 if (plen > 128) 177 return (NULL); 178 sin6->sin6_family = AF_INET6; 179 sin6->sin6_len = sizeof(struct sockaddr_in6); 180 memset(&sin6->sin6_addr.s6_addr, 0, sizeof(sin6->sin6_addr.s6_addr)); 181 p = sin6->sin6_addr.s6_addr; 182 break; 183 default: 184 return (NULL); 185 } 186 187 for (i = 0; i < plen / 8; i++) 188 p[i] = 0xff; 189 if (plen % 8) 190 p[i] = (0xff00 >> (plen % 8)) & 0xff; 191 192 return (sa_mask); 193 } 194 195 static struct art_node * 196 getdefault(struct art_table *at) 197 { 198 struct art_node *node; 199 struct art_table table; 200 union { 201 struct srp node; 202 unsigned long count; 203 } *heap; 204 205 kread((u_long)at, &table, sizeof(table)); 206 heap = calloc(1, AT_HEAPSIZE(table.at_bits)); 207 kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); 208 209 node = heap[1].node.ref; 210 211 free(heap); 212 213 return (node); 214 } 215 216 static void 217 p_table(struct art_table *at) 218 { 219 struct art_node *next, *node; 220 struct art_table *nat, table; 221 union { 222 struct srp node; 223 unsigned long count; 224 } *heap; 225 int i, j; 226 227 kread((u_long)at, &table, sizeof(table)); 228 heap = calloc(1, AT_HEAPSIZE(table.at_bits)); 229 kread((u_long)table.at_heap, heap, AT_HEAPSIZE(table.at_bits)); 230 231 for (j = 1; j < table.at_minfringe; j += 2) { 232 for (i = (j > 2) ? j : 2; i < table.at_minfringe; i <<= 1) { 233 next = heap[i >> 1].node.ref; 234 node = heap[i].node.ref; 235 if (node != NULL && node != next) 236 p_artnode(node); 237 } 238 } 239 240 for (i = table.at_minfringe; i < table.at_minfringe << 1; i++) { 241 next = heap[i >> 1].node.ref; 242 node = heap[i].node.ref; 243 if (!ISLEAF(node)) { 244 nat = SUBTABLE(node); 245 node = getdefault(nat); 246 } else 247 nat = NULL; 248 249 if (node != NULL && node != next) 250 p_artnode(node); 251 252 if (nat != NULL) 253 p_table(nat); 254 } 255 256 free(heap); 257 } 258 259 static void 260 p_artnode(struct art_node *an) 261 { 262 struct art_node node; 263 struct rtentry *rt; 264 265 kread((u_long)an, &node, sizeof(node)); 266 rt = node.an_rtlist.sl_head.ref; 267 268 while (rt != NULL) { 269 kread((u_long)rt, &rtentry, sizeof(rtentry)); 270 if (Aflag) 271 printf("%-16p ", rt); 272 p_krtentry(&rtentry); 273 rt = rtentry.rt_next.se_next.ref; 274 } 275 } 276 277 static void 278 p_krtentry(struct rtentry *rt) 279 { 280 struct sockaddr_storage sock1, sock2; 281 struct sockaddr *sa = (struct sockaddr *)&sock1; 282 struct sockaddr *mask = (struct sockaddr *)&sock2; 283 284 bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr)); 285 if (sa->sa_len > sizeof(struct sockaddr)) 286 bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len); 287 288 if (sa->sa_family == PF_KEY) { 289 /* Ignore PF_KEY entries */ 290 return; 291 } 292 293 mask = plentosa(sa->sa_family, rt_plen(rt), mask); 294 295 p_addr(sa, mask, rt->rt_flags); 296 p_gwaddr(kgetsa(rt->rt_gateway), sa->sa_family); 297 p_flags(rt->rt_flags, "%-6.6s "); 298 printf("%5u %8lld ", rt->rt_refcnt - 1, rt->rt_use); 299 if (rt->rt_rmx.rmx_mtu) 300 printf("%5u ", rt->rt_rmx.rmx_mtu); 301 else 302 printf("%5s ", "-"); 303 putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); 304 printf(" %2d", rt->rt_priority & RTP_MASK); 305 306 if (rt->rt_ifidx != 0) 307 printf(" if%d", rt->rt_ifidx); 308 putchar('\n'); 309 if (vflag) 310 printf("\texpire %10lld%c\n", 311 (long long)rt->rt_rmx.rmx_expire, 312 (rt->rt_rmx.rmx_locks & RTV_EXPIRE) ? 'L' : ' '); 313 } 314 315 /* 316 * Print routing statistics 317 */ 318 void 319 rt_stats(void) 320 { 321 struct rtstat rtstat; 322 int mib[6]; 323 size_t size; 324 325 mib[0] = CTL_NET; 326 mib[1] = PF_ROUTE; 327 mib[2] = 0; 328 mib[3] = 0; 329 mib[4] = NET_RT_STATS; 330 mib[5] = 0; 331 size = sizeof (rtstat); 332 333 if (sysctl(mib, 6, &rtstat, &size, NULL, 0) == -1) { 334 perror("sysctl of routing table statistics"); 335 exit(1); 336 } 337 338 printf("routing:\n"); 339 printf("\t%u bad routing redirect%s\n", 340 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 341 printf("\t%u dynamically created route%s\n", 342 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 343 printf("\t%u new gateway%s due to redirects\n", 344 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 345 printf("\t%u destination%s found unreachable\n", 346 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 347 printf("\t%u use%s of a wildcard route\n", 348 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 349 } 350