1 1.88 msaitoh /* $NetBSD: route.c,v 1.88 2022/09/02 06:25:43 msaitoh Exp $ */ 2 1.14 thorpej 3 1.1 cgd /* 4 1.10 mycroft * Copyright (c) 1983, 1988, 1993 5 1.10 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.63 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.23 lukem #include <sys/cdefs.h> 33 1.81 christos #ifndef lint 34 1.81 christos #if 0 35 1.81 christos static char sccsid[] = "from: @(#)route.c 8.3 (Berkeley) 3/9/94"; 36 1.81 christos #else 37 1.88 msaitoh __RCSID("$NetBSD: route.c,v 1.88 2022/09/02 06:25:43 msaitoh Exp $"); 38 1.81 christos #endif 39 1.81 christos #endif /* not lint */ 40 1.81 christos 41 1.81 christos #include <stdbool.h> 42 1.81 christos #include <sys/param.h> 43 1.81 christos #include <sys/protosw.h> 44 1.81 christos #include <sys/socket.h> 45 1.81 christos #include <sys/mbuf.h> 46 1.81 christos #include <sys/un.h> 47 1.1 cgd 48 1.81 christos #include <net/if.h> 49 1.81 christos #include <net/if_dl.h> 50 1.81 christos #include <net/if_types.h> 51 1.81 christos #include <net/route.h> 52 1.81 christos #include <netinet/in.h> 53 1.81 christos #include <netatalk/at.h> 54 1.81 christos #include <netmpls/mpls.h> 55 1.1 cgd 56 1.80 joerg #include <sys/sysctl.h> 57 1.81 christos 58 1.81 christos #include <arpa/inet.h> 59 1.81 christos 60 1.29 mrg #include <err.h> 61 1.81 christos #include <kvm.h> 62 1.81 christos #include <netdb.h> 63 1.81 christos #include <stdio.h> 64 1.81 christos #include <stdlib.h> 65 1.81 christos #include <string.h> 66 1.81 christos #include <unistd.h> 67 1.29 mrg 68 1.10 mycroft #include "netstat.h" 69 1.83 christos #include "rtutil.h" 70 1.1 cgd 71 1.81 christos #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) 72 1.81 christos 73 1.81 christos /* 74 1.81 christos * XXX we put all of the sockaddr types in here to force the alignment 75 1.81 christos * to be correct. 76 1.81 christos */ 77 1.81 christos static union sockaddr_union { 78 1.81 christos struct sockaddr u_sa; 79 1.81 christos struct sockaddr_in u_in; 80 1.81 christos struct sockaddr_un u_un; 81 1.81 christos struct sockaddr_at u_at; 82 1.81 christos struct sockaddr_dl u_dl; 83 1.81 christos u_short u_data[128]; 84 1.81 christos int u_dummy; /* force word-alignment */ 85 1.81 christos } pt_u; 86 1.81 christos 87 1.81 christos int do_rtent = 0; 88 1.81 christos struct rtentry rtentry; 89 1.81 christos struct radix_node rnode; 90 1.81 christos struct radix_mask rmask; 91 1.81 christos 92 1.81 christos static struct sockaddr *kgetsa(const struct sockaddr *); 93 1.81 christos static void p_tree(struct radix_node *); 94 1.81 christos static void p_rtnode(void); 95 1.81 christos static void p_krtentry(struct rtentry *); 96 1.81 christos 97 1.81 christos /* 98 1.81 christos * Print routing tables. 99 1.81 christos */ 100 1.81 christos void 101 1.81 christos routepr(u_long rtree) 102 1.81 christos { 103 1.81 christos struct radix_node_head *rnh, head; 104 1.87 msaitoh struct radix_node_head *rt_nodes[AF_MAX + 1]; 105 1.81 christos int i; 106 1.81 christos 107 1.81 christos printf("Routing tables\n"); 108 1.81 christos 109 1.81 christos if (rtree == 0) { 110 1.81 christos printf("rt_tables: symbol not in namelist\n"); 111 1.81 christos return; 112 1.81 christos } 113 1.81 christos 114 1.81 christos kget(rtree, rt_nodes); 115 1.81 christos for (i = 0; i <= AF_MAX; i++) { 116 1.81 christos if ((rnh = rt_nodes[i]) == 0) 117 1.81 christos continue; 118 1.81 christos kget(rnh, head); 119 1.81 christos if (i == AF_UNSPEC) { 120 1.81 christos if (Aflag && (af == 0 || af == 0xff)) { 121 1.81 christos printf("Netmasks:\n"); 122 1.81 christos p_tree(head.rnh_treetop); 123 1.81 christos } 124 1.81 christos } else if (af == AF_UNSPEC || af == i) { 125 1.83 christos p_family(i); 126 1.81 christos do_rtent = 1; 127 1.83 christos p_rthdr(i, Aflag); 128 1.81 christos p_tree(head.rnh_treetop); 129 1.81 christos } 130 1.81 christos } 131 1.81 christos } 132 1.81 christos 133 1.81 christos static struct sockaddr * 134 1.81 christos kgetsa(const struct sockaddr *dst) 135 1.81 christos { 136 1.81 christos 137 1.81 christos kget(dst, pt_u.u_sa); 138 1.81 christos if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 139 1.81 christos kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); 140 1.81 christos return (&pt_u.u_sa); 141 1.81 christos } 142 1.81 christos 143 1.81 christos static void 144 1.81 christos p_tree(struct radix_node *rn) 145 1.81 christos { 146 1.81 christos 147 1.81 christos again: 148 1.81 christos kget(rn, rnode); 149 1.81 christos if (rnode.rn_b < 0) { 150 1.81 christos if (Aflag) 151 1.81 christos printf("%-8.8lx ", (u_long) rn); 152 1.81 christos if (rnode.rn_flags & RNF_ROOT) { 153 1.81 christos if (Aflag) 154 1.81 christos printf("(root node)%s", 155 1.81 christos rnode.rn_dupedkey ? " =>\n" : "\n"); 156 1.81 christos } else if (do_rtent) { 157 1.81 christos kget(rn, rtentry); 158 1.81 christos p_krtentry(&rtentry); 159 1.81 christos if (Aflag) 160 1.81 christos p_rtnode(); 161 1.81 christos } else { 162 1.87 msaitoh p_sockaddr( 163 1.87 msaitoh kgetsa((const struct sockaddr *)rnode.rn_key), 164 1.87 msaitoh NULL, 0, 44, nflag); 165 1.81 christos putchar('\n'); 166 1.81 christos } 167 1.81 christos if ((rn = rnode.rn_dupedkey) != NULL) 168 1.81 christos goto again; 169 1.81 christos } else { 170 1.81 christos if (Aflag && do_rtent) { 171 1.81 christos printf("%-8.8lx ", (u_long) rn); 172 1.81 christos p_rtnode(); 173 1.81 christos } 174 1.81 christos rn = rnode.rn_r; 175 1.81 christos p_tree(rnode.rn_l); 176 1.81 christos p_tree(rn); 177 1.81 christos } 178 1.81 christos } 179 1.81 christos 180 1.81 christos static void 181 1.81 christos p_rtnode(void) 182 1.81 christos { 183 1.81 christos struct radix_mask *rm = rnode.rn_mklist; 184 1.81 christos char nbuf[20]; 185 1.81 christos 186 1.81 christos if (rnode.rn_b < 0) { 187 1.81 christos if (rnode.rn_mask) { 188 1.81 christos printf("\t mask "); 189 1.87 msaitoh p_sockaddr( 190 1.87 msaitoh kgetsa((const struct sockaddr *)rnode.rn_mask), 191 1.87 msaitoh NULL, 0, -1, nflag); 192 1.81 christos } else if (rm == 0) 193 1.81 christos return; 194 1.81 christos } else { 195 1.81 christos (void)snprintf(nbuf, sizeof nbuf, "(%d)", rnode.rn_b); 196 1.81 christos printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long) rnode.rn_l, 197 1.81 christos (u_long) rnode.rn_r); 198 1.81 christos } 199 1.81 christos while (rm) { 200 1.81 christos kget(rm, rmask); 201 1.81 christos (void)snprintf(nbuf, sizeof nbuf, " %d refs, ", rmask.rm_refs); 202 1.81 christos printf(" mk = %8.8lx {(%d),%s", (u_long) rm, 203 1.81 christos -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); 204 1.81 christos if (rmask.rm_flags & RNF_NORMAL) { 205 1.81 christos struct radix_node rnode_aux; 206 1.81 christos printf(" <normal>, "); 207 1.81 christos kget(rmask.rm_leaf, rnode_aux); 208 1.81 christos p_sockaddr(kgetsa((const struct sockaddr *)rnode_aux.rn_mask), 209 1.87 msaitoh NULL, 0, -1, nflag); 210 1.81 christos } else 211 1.87 msaitoh p_sockaddr( 212 1.87 msaitoh kgetsa((const struct sockaddr *)rmask.rm_mask), 213 1.87 msaitoh NULL, 0, -1, nflag); 214 1.81 christos putchar('}'); 215 1.81 christos if ((rm = rmask.rm_mklist) != NULL) 216 1.81 christos printf(" ->"); 217 1.81 christos } 218 1.81 christos putchar('\n'); 219 1.81 christos } 220 1.81 christos 221 1.81 christos static struct sockaddr *sockcopy(struct sockaddr *, union sockaddr_union *); 222 1.81 christos 223 1.81 christos /* 224 1.81 christos * copy a sockaddr into an allocated region, allocate at least sockaddr 225 1.81 christos * bytes and zero unused 226 1.81 christos */ 227 1.81 christos static struct sockaddr * 228 1.81 christos sockcopy(struct sockaddr *sp, union sockaddr_union *dp) 229 1.81 christos { 230 1.81 christos int len; 231 1.81 christos 232 1.81 christos if (sp == 0 || sp->sa_len == 0) 233 1.81 christos (void)memset(dp, 0, sizeof (*sp)); 234 1.81 christos else { 235 1.81 christos len = (sp->sa_len >= sizeof (*sp)) ? sp->sa_len : sizeof (*sp); 236 1.81 christos (void)memcpy(dp, sp, len); 237 1.81 christos } 238 1.81 christos return ((struct sockaddr *)dp); 239 1.81 christos } 240 1.81 christos 241 1.81 christos static void 242 1.81 christos p_krtentry(struct rtentry *rt) 243 1.81 christos { 244 1.81 christos static struct ifnet ifnet, *lastif; 245 1.81 christos union sockaddr_union addr_un, mask_un; 246 1.81 christos struct sockaddr *addr, *mask; 247 1.81 christos 248 1.81 christos memset(&addr_un, 0, sizeof(addr_un)); 249 1.81 christos memset(&mask_un, 0, sizeof(mask_un)); 250 1.81 christos addr = sockcopy(kgetsa(rt_getkey(rt)), &addr_un); 251 1.81 christos if (rt_mask(rt)) 252 1.81 christos mask = sockcopy(kgetsa(rt_mask(rt)), &mask_un); 253 1.81 christos else 254 1.81 christos mask = sockcopy(NULL, &mask_un); 255 1.83 christos p_addr(addr, mask, rt->rt_flags, nflag); 256 1.87 msaitoh p_gwaddr(kgetsa(rt->rt_gateway), kgetsa(rt->rt_gateway)->sa_family, 257 1.87 msaitoh nflag); 258 1.83 christos p_flags(rt->rt_flags); 259 1.81 christos printf("%6d %8"PRIu64" ", rt->rt_refcnt, rt->rt_use); 260 1.81 christos if (rt->rt_rmx.rmx_mtu) 261 1.87 msaitoh printf("%6"PRIu64, rt->rt_rmx.rmx_mtu); 262 1.81 christos else 263 1.81 christos printf("%6s", "-"); 264 1.81 christos putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' '); 265 1.81 christos if (tagflag == 1) { 266 1.84 manu #ifndef SMALL 267 1.81 christos if (rt->rt_tag != NULL) { 268 1.81 christos const struct sockaddr *tagsa = kgetsa(rt->rt_tag); 269 1.81 christos char *tagstr; 270 1.81 christos 271 1.81 christos if (tagsa->sa_family == AF_MPLS) { 272 1.81 christos tagstr = mpls_ntoa(tagsa); 273 1.81 christos if (strlen(tagstr) < 7) 274 1.81 christos printf("%7s", tagstr); 275 1.81 christos else 276 1.81 christos printf("%s", tagstr); 277 1.87 msaitoh } else 278 1.81 christos printf("%7s", "-"); 279 1.81 christos } else 280 1.84 manu #endif 281 1.81 christos printf("%7s", "-"); 282 1.81 christos } 283 1.81 christos if (rt->rt_ifp) { 284 1.81 christos if (rt->rt_ifp != lastif) { 285 1.81 christos kget(rt->rt_ifp, ifnet); 286 1.81 christos lastif = rt->rt_ifp; 287 1.81 christos } 288 1.81 christos printf(" %.16s%s", ifnet.if_xname, 289 1.81 christos rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 290 1.81 christos } 291 1.81 christos putchar('\n'); 292 1.84 manu #ifndef SMALL 293 1.82 christos if (vflag) 294 1.83 christos p_rtrmx(&rt->rt_rmx); 295 1.84 manu #endif 296 1.81 christos } 297 1.81 christos 298 1.1 cgd /* 299 1.1 cgd * Print routing statistics 300 1.1 cgd */ 301 1.10 mycroft void 302 1.79 matt rt_stats(u_long off) 303 1.1 cgd { 304 1.73 lukem struct rtstat rtstats; 305 1.1 cgd 306 1.67 elad if (use_sysctl) { 307 1.73 lukem size_t rtsize = sizeof(rtstats); 308 1.67 elad 309 1.86 yamaguch if (sysctlbyname("net.rtable.stats", &rtstats, &rtsize, 310 1.67 elad NULL, 0) == -1) 311 1.67 elad err(1, "rt_stats: sysctl"); 312 1.87 msaitoh } else if (off == 0) { 313 1.1 cgd printf("rtstat: symbol not in namelist\n"); 314 1.1 cgd return; 315 1.67 elad } else 316 1.73 lukem kread(off, (char *)&rtstats, sizeof(rtstats)); 317 1.67 elad 318 1.1 cgd printf("routing:\n"); 319 1.53 itojun printf("\t%llu bad routing redirect%s\n", 320 1.88 msaitoh (unsigned long long)rtstats.rts_badredirect, 321 1.88 msaitoh plural(rtstats.rts_badredirect)); 322 1.53 itojun printf("\t%llu dynamically created route%s\n", 323 1.88 msaitoh (unsigned long long)rtstats.rts_dynamic, 324 1.88 msaitoh plural(rtstats.rts_dynamic)); 325 1.53 itojun printf("\t%llu new gateway%s due to redirects\n", 326 1.88 msaitoh (unsigned long long)rtstats.rts_newgateway, 327 1.88 msaitoh plural(rtstats.rts_newgateway)); 328 1.53 itojun printf("\t%llu destination%s found unreachable\n", 329 1.88 msaitoh (unsigned long long)rtstats.rts_unreach, 330 1.88 msaitoh plural(rtstats.rts_unreach)); 331 1.53 itojun printf("\t%llu use%s of a wildcard route\n", 332 1.88 msaitoh (unsigned long long)rtstats.rts_wildcard, 333 1.88 msaitoh plural(rtstats.rts_wildcard)); 334 1.1 cgd } 335