1fc88ecd3SAlexander V. Chernikov /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3fc88ecd3SAlexander V. Chernikov * 4fc88ecd3SAlexander V. Chernikov * Copyright 2019 Conrad Meyer <cem@FreeBSD.org> 5fc88ecd3SAlexander V. Chernikov * 6fc88ecd3SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 7fc88ecd3SAlexander V. Chernikov * modification, are permitted provided that the following conditions 8fc88ecd3SAlexander V. Chernikov * are met: 9fc88ecd3SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 10fc88ecd3SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 11fc88ecd3SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 12fc88ecd3SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 13fc88ecd3SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 14fc88ecd3SAlexander V. Chernikov * 15fc88ecd3SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16fc88ecd3SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17fc88ecd3SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18fc88ecd3SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19fc88ecd3SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20fc88ecd3SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21fc88ecd3SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22fc88ecd3SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23fc88ecd3SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24fc88ecd3SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25fc88ecd3SAlexander V. Chernikov * SUCH DAMAGE. 26fc88ecd3SAlexander V. Chernikov */ 27fc88ecd3SAlexander V. Chernikov 28fc88ecd3SAlexander V. Chernikov #include <sys/cdefs.h> 29fc88ecd3SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 30fc88ecd3SAlexander V. Chernikov #include "opt_inet.h" 31fc88ecd3SAlexander V. Chernikov #include "opt_inet6.h" 32fc88ecd3SAlexander V. Chernikov 334f08f052SAlexander V. Chernikov #include <sys/ctype.h> 34fc88ecd3SAlexander V. Chernikov #include <sys/param.h> 35fc88ecd3SAlexander V. Chernikov #include <sys/systm.h> 36fc88ecd3SAlexander V. Chernikov #include <sys/malloc.h> 37fc88ecd3SAlexander V. Chernikov #include <sys/mbuf.h> 38fc88ecd3SAlexander V. Chernikov #include <sys/socket.h> 39fc88ecd3SAlexander V. Chernikov #include <sys/sysctl.h> 40fc88ecd3SAlexander V. Chernikov #include <sys/syslog.h> 41fc88ecd3SAlexander V. Chernikov #include <sys/kernel.h> 42fc88ecd3SAlexander V. Chernikov #include <sys/lock.h> 43fc88ecd3SAlexander V. Chernikov #include <sys/rmlock.h> 44fc88ecd3SAlexander V. Chernikov 45fc88ecd3SAlexander V. Chernikov #include <ddb/ddb.h> 46fc88ecd3SAlexander V. Chernikov #include <ddb/db_lex.h> 47fc88ecd3SAlexander V. Chernikov 48fc88ecd3SAlexander V. Chernikov #include <net/if.h> 49fc88ecd3SAlexander V. Chernikov #include <net/if_var.h> 502c2b37adSJustin Hibbits #include <net/if_private.h> 51fc88ecd3SAlexander V. Chernikov #include <net/if_dl.h> 52fc88ecd3SAlexander V. Chernikov #include <net/route.h> 53fc88ecd3SAlexander V. Chernikov #include <net/route/nhop.h> 54da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h> 55656442a7SAlexander V. Chernikov #include <net/route/route_var.h> 56fc88ecd3SAlexander V. Chernikov 57fc88ecd3SAlexander V. Chernikov /* 58fc88ecd3SAlexander V. Chernikov * Unfortunately, RTF_ values are expressed as raw masks rather than powers of 59fc88ecd3SAlexander V. Chernikov * 2, so we cannot use them as nice C99 initializer indices below. 60fc88ecd3SAlexander V. Chernikov */ 61fc88ecd3SAlexander V. Chernikov static const char * const rtf_flag_strings[] = { 62fc88ecd3SAlexander V. Chernikov "UP", 63fc88ecd3SAlexander V. Chernikov "GATEWAY", 64fc88ecd3SAlexander V. Chernikov "HOST", 65fc88ecd3SAlexander V. Chernikov "REJECT", 66fc88ecd3SAlexander V. Chernikov "DYNAMIC", 67fc88ecd3SAlexander V. Chernikov "MODIFIED", 68fc88ecd3SAlexander V. Chernikov "DONE", 69fc88ecd3SAlexander V. Chernikov "UNUSED_0x80", 70fc88ecd3SAlexander V. Chernikov "UNUSED_0x100", 71fc88ecd3SAlexander V. Chernikov "XRESOLVE", 72fc88ecd3SAlexander V. Chernikov "LLDATA", 73fc88ecd3SAlexander V. Chernikov "STATIC", 74fc88ecd3SAlexander V. Chernikov "BLACKHOLE", 75fc88ecd3SAlexander V. Chernikov "UNUSED_0x2000", 76fc88ecd3SAlexander V. Chernikov "PROTO2", 77fc88ecd3SAlexander V. Chernikov "PROTO1", 78fc88ecd3SAlexander V. Chernikov "UNUSED_0x10000", 79fc88ecd3SAlexander V. Chernikov "UNUSED_0x20000", 80fc88ecd3SAlexander V. Chernikov "PROTO3", 81fc88ecd3SAlexander V. Chernikov "FIXEDMTU", 82fc88ecd3SAlexander V. Chernikov "PINNED", 83fc88ecd3SAlexander V. Chernikov "LOCAL", 84fc88ecd3SAlexander V. Chernikov "BROADCAST", 85fc88ecd3SAlexander V. Chernikov "MULTICAST", 86fc88ecd3SAlexander V. Chernikov /* Big gap. */ 87fc88ecd3SAlexander V. Chernikov [28] = "STICKY", 88fc88ecd3SAlexander V. Chernikov [30] = "RNH_LOCKED", 89fc88ecd3SAlexander V. Chernikov [31] = "GWFLAG_COMPAT", 90fc88ecd3SAlexander V. Chernikov }; 91fc88ecd3SAlexander V. Chernikov 92fc88ecd3SAlexander V. Chernikov static const char * __pure 93fc88ecd3SAlexander V. Chernikov rt_flag_name(unsigned idx) 94fc88ecd3SAlexander V. Chernikov { 95fc88ecd3SAlexander V. Chernikov if (idx >= nitems(rtf_flag_strings)) 96fc88ecd3SAlexander V. Chernikov return ("INVALID_FLAG"); 97fc88ecd3SAlexander V. Chernikov if (rtf_flag_strings[idx] == NULL) 98fc88ecd3SAlexander V. Chernikov return ("UNKNOWN"); 99fc88ecd3SAlexander V. Chernikov return (rtf_flag_strings[idx]); 100fc88ecd3SAlexander V. Chernikov } 101fc88ecd3SAlexander V. Chernikov 102fc88ecd3SAlexander V. Chernikov static void 103fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb(const char *name, const struct sockaddr *sa) 104fc88ecd3SAlexander V. Chernikov { 105fc88ecd3SAlexander V. Chernikov char buf[INET6_ADDRSTRLEN], *res; 106fc88ecd3SAlexander V. Chernikov 107fc88ecd3SAlexander V. Chernikov res = NULL; 108fc88ecd3SAlexander V. Chernikov if (sa == NULL) 109fc88ecd3SAlexander V. Chernikov res = "NULL"; 110fc88ecd3SAlexander V. Chernikov else if (sa->sa_family == AF_INET) { 111fc88ecd3SAlexander V. Chernikov res = inet_ntop(AF_INET, 112fc88ecd3SAlexander V. Chernikov &((const struct sockaddr_in *)sa)->sin_addr, 113fc88ecd3SAlexander V. Chernikov buf, sizeof(buf)); 114fc88ecd3SAlexander V. Chernikov } else if (sa->sa_family == AF_INET6) { 115fc88ecd3SAlexander V. Chernikov res = inet_ntop(AF_INET6, 116fc88ecd3SAlexander V. Chernikov &((const struct sockaddr_in6 *)sa)->sin6_addr, 117fc88ecd3SAlexander V. Chernikov buf, sizeof(buf)); 118fc88ecd3SAlexander V. Chernikov } else if (sa->sa_family == AF_LINK) { 119fc88ecd3SAlexander V. Chernikov res = "on link"; 120fc88ecd3SAlexander V. Chernikov } 121fc88ecd3SAlexander V. Chernikov 122fc88ecd3SAlexander V. Chernikov if (res != NULL) { 123fc88ecd3SAlexander V. Chernikov db_printf("%s <%s> ", name, res); 124fc88ecd3SAlexander V. Chernikov return; 125fc88ecd3SAlexander V. Chernikov } 126fc88ecd3SAlexander V. Chernikov 127fc88ecd3SAlexander V. Chernikov db_printf("%s <af:%d> ", name, sa->sa_family); 128fc88ecd3SAlexander V. Chernikov } 129fc88ecd3SAlexander V. Chernikov 130fc88ecd3SAlexander V. Chernikov static int 131fc88ecd3SAlexander V. Chernikov rt_dumpentry_ddb(struct radix_node *rn, void *arg __unused) 132fc88ecd3SAlexander V. Chernikov { 133fc88ecd3SAlexander V. Chernikov struct sockaddr_storage ss; 134fc88ecd3SAlexander V. Chernikov struct rtentry *rt; 1358c61eb21SAlexander V. Chernikov struct nhop_object *nh; 136fc88ecd3SAlexander V. Chernikov int flags, idx; 137fc88ecd3SAlexander V. Chernikov 138fc88ecd3SAlexander V. Chernikov /* If RNTORT is important, put it in a header. */ 139fc88ecd3SAlexander V. Chernikov rt = (void *)rn; 1408c61eb21SAlexander V. Chernikov nh = (struct nhop_object *)rt->rt_nhop; 141fc88ecd3SAlexander V. Chernikov 142fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb("dst", rt_key(rt)); 143fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb("gateway", &rt->rt_nhop->gw_sa); 144fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb("netmask", rtsock_fix_netmask(rt_key(rt), rt_mask(rt), 145fc88ecd3SAlexander V. Chernikov &ss)); 1468c61eb21SAlexander V. Chernikov if ((nh->nh_ifp->if_flags & IFF_DYING) == 0) { 1478c61eb21SAlexander V. Chernikov rt_dumpaddr_ddb("ifp", nh->nh_ifp->if_addr->ifa_addr); 1488c61eb21SAlexander V. Chernikov rt_dumpaddr_ddb("ifa", nh->nh_ifa->ifa_addr); 149fc88ecd3SAlexander V. Chernikov } 150fc88ecd3SAlexander V. Chernikov 151fc88ecd3SAlexander V. Chernikov db_printf("flags "); 15293bfd365SAlexander V. Chernikov flags = rt->rte_flags | nhop_get_rtflags(nh); 153fc88ecd3SAlexander V. Chernikov if (flags == 0) 154fc88ecd3SAlexander V. Chernikov db_printf("none"); 155fc88ecd3SAlexander V. Chernikov 156fc88ecd3SAlexander V. Chernikov while ((idx = ffs(flags)) > 0) { 157fc88ecd3SAlexander V. Chernikov idx--; 158fc88ecd3SAlexander V. Chernikov 159fc88ecd3SAlexander V. Chernikov db_printf("%s", rt_flag_name(idx)); 160fc88ecd3SAlexander V. Chernikov flags &= ~(1ul << idx); 16193bfd365SAlexander V. Chernikov if (flags != 0) 16293bfd365SAlexander V. Chernikov db_printf(","); 163fc88ecd3SAlexander V. Chernikov } 164fc88ecd3SAlexander V. Chernikov 165fc88ecd3SAlexander V. Chernikov db_printf("\n"); 166fc88ecd3SAlexander V. Chernikov return (0); 167fc88ecd3SAlexander V. Chernikov } 168fc88ecd3SAlexander V. Chernikov 169fc88ecd3SAlexander V. Chernikov DB_SHOW_COMMAND(routetable, db_show_routetable_cmd) 170fc88ecd3SAlexander V. Chernikov { 171fc88ecd3SAlexander V. Chernikov struct rib_head *rnh; 172fc88ecd3SAlexander V. Chernikov int error, i, lim; 173fc88ecd3SAlexander V. Chernikov 174fc88ecd3SAlexander V. Chernikov if (have_addr) 175fc88ecd3SAlexander V. Chernikov i = lim = addr; 176fc88ecd3SAlexander V. Chernikov else { 177fc88ecd3SAlexander V. Chernikov i = 1; 178fc88ecd3SAlexander V. Chernikov lim = AF_MAX; 179fc88ecd3SAlexander V. Chernikov } 180fc88ecd3SAlexander V. Chernikov 181fc88ecd3SAlexander V. Chernikov for (; i <= lim; i++) { 182fc88ecd3SAlexander V. Chernikov rnh = rt_tables_get_rnh(0, i); 183fc88ecd3SAlexander V. Chernikov if (rnh == NULL) { 184fc88ecd3SAlexander V. Chernikov if (have_addr) { 185fc88ecd3SAlexander V. Chernikov db_printf("%s: AF %d not supported?\n", 186fc88ecd3SAlexander V. Chernikov __func__, i); 187fc88ecd3SAlexander V. Chernikov break; 188fc88ecd3SAlexander V. Chernikov } 189fc88ecd3SAlexander V. Chernikov continue; 190fc88ecd3SAlexander V. Chernikov } 191fc88ecd3SAlexander V. Chernikov 192fc88ecd3SAlexander V. Chernikov if (!have_addr && i > 1) 193fc88ecd3SAlexander V. Chernikov db_printf("\n"); 194fc88ecd3SAlexander V. Chernikov 195fc88ecd3SAlexander V. Chernikov db_printf("Route table for AF %d%s%s%s:\n", i, 196fc88ecd3SAlexander V. Chernikov (i == AF_INET || i == AF_INET6) ? " (" : "", 197fc88ecd3SAlexander V. Chernikov (i == AF_INET) ? "INET" : (i == AF_INET6) ? "INET6" : "", 198fc88ecd3SAlexander V. Chernikov (i == AF_INET || i == AF_INET6) ? ")" : ""); 199fc88ecd3SAlexander V. Chernikov 200fc88ecd3SAlexander V. Chernikov error = rnh->rnh_walktree(&rnh->head, rt_dumpentry_ddb, NULL); 201fc88ecd3SAlexander V. Chernikov if (error != 0) 202fc88ecd3SAlexander V. Chernikov db_printf("%s: walktree(%d): %d\n", __func__, i, 203fc88ecd3SAlexander V. Chernikov error); 204fc88ecd3SAlexander V. Chernikov } 205fc88ecd3SAlexander V. Chernikov } 206fc88ecd3SAlexander V. Chernikov 207258958b3SMitchell Horne DB_SHOW_COMMAND_FLAGS(route, db_show_route_cmd, CS_OWN) 208fc88ecd3SAlexander V. Chernikov { 2094f08f052SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN], *buf, *end; 210d94be4ccSAlexander V. Chernikov struct rib_head *rh; 211d94be4ccSAlexander V. Chernikov struct radix_node *rn; 2124f08f052SAlexander V. Chernikov void *dst_addrp; 213fc88ecd3SAlexander V. Chernikov struct rtentry *rt; 214fc88ecd3SAlexander V. Chernikov union { 215fc88ecd3SAlexander V. Chernikov struct sockaddr_in dest_sin; 216fc88ecd3SAlexander V. Chernikov struct sockaddr_in6 dest_sin6; 217fc88ecd3SAlexander V. Chernikov } u; 2184f08f052SAlexander V. Chernikov int af; 219fc88ecd3SAlexander V. Chernikov 2204f08f052SAlexander V. Chernikov buf = db_get_line(); 221fc88ecd3SAlexander V. Chernikov 2224f08f052SAlexander V. Chernikov /* Remove whitespaces from both ends */ 2234f08f052SAlexander V. Chernikov end = buf + strlen(buf) - 1; 2244f08f052SAlexander V. Chernikov for (; (end >= buf) && (*end=='\n' || isspace(*end)); end--) 2254f08f052SAlexander V. Chernikov *end = '\0'; 2264f08f052SAlexander V. Chernikov while (isspace(*buf)) 2274f08f052SAlexander V. Chernikov buf++; 228fc88ecd3SAlexander V. Chernikov 2294f08f052SAlexander V. Chernikov /* Determine AF */ 2304f08f052SAlexander V. Chernikov if (strchr(buf, ':') != NULL) { 231fc88ecd3SAlexander V. Chernikov af = AF_INET6; 2324f08f052SAlexander V. Chernikov u.dest_sin6.sin6_family = af; 2334f08f052SAlexander V. Chernikov u.dest_sin6.sin6_len = sizeof(struct sockaddr_in6); 234fc88ecd3SAlexander V. Chernikov dst_addrp = &u.dest_sin6.sin6_addr; 235fc88ecd3SAlexander V. Chernikov } else { 2364f08f052SAlexander V. Chernikov af = AF_INET; 2374f08f052SAlexander V. Chernikov u.dest_sin.sin_family = af; 2384f08f052SAlexander V. Chernikov u.dest_sin.sin_len = sizeof(struct sockaddr_in); 2394f08f052SAlexander V. Chernikov dst_addrp = &u.dest_sin.sin_addr; 240fc88ecd3SAlexander V. Chernikov } 241fc88ecd3SAlexander V. Chernikov 2424f08f052SAlexander V. Chernikov if (inet_pton(af, buf, dst_addrp) != 1) 2434f08f052SAlexander V. Chernikov goto usage; 2444f08f052SAlexander V. Chernikov 2454f08f052SAlexander V. Chernikov if (inet_ntop(af, dst_addrp, abuf, sizeof(abuf)) != NULL) 2464f08f052SAlexander V. Chernikov db_printf("Looking up route to destination '%s'\n", abuf); 247fc88ecd3SAlexander V. Chernikov 248d94be4ccSAlexander V. Chernikov rt = NULL; 249fc88ecd3SAlexander V. Chernikov CURVNET_SET(vnet0); 250d94be4ccSAlexander V. Chernikov 251d94be4ccSAlexander V. Chernikov rh = rt_tables_get_rnh(RT_DEFAULT_FIB, af); 252d94be4ccSAlexander V. Chernikov 253d94be4ccSAlexander V. Chernikov rn = rh->rnh_matchaddr(&u, &rh->head); 254d94be4ccSAlexander V. Chernikov if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) 255d94be4ccSAlexander V. Chernikov rt = (struct rtentry *)rn; 256d94be4ccSAlexander V. Chernikov 257fc88ecd3SAlexander V. Chernikov CURVNET_RESTORE(); 258fc88ecd3SAlexander V. Chernikov 259fc88ecd3SAlexander V. Chernikov if (rt == NULL) { 260fc88ecd3SAlexander V. Chernikov db_printf("Could not get route for that server.\n"); 261fc88ecd3SAlexander V. Chernikov return; 262fc88ecd3SAlexander V. Chernikov } 263fc88ecd3SAlexander V. Chernikov 264fc88ecd3SAlexander V. Chernikov rt_dumpentry_ddb((void *)rt, NULL); 265fc88ecd3SAlexander V. Chernikov 266fc88ecd3SAlexander V. Chernikov return; 267fc88ecd3SAlexander V. Chernikov usage: 268fc88ecd3SAlexander V. Chernikov db_printf("Usage: 'show route <address>'\n" 2694f08f052SAlexander V. Chernikov " Currently accepts only IPv4 and IPv6 addresses\n"); 270fc88ecd3SAlexander V. Chernikov db_skip_to_eol(); 271fc88ecd3SAlexander V. Chernikov } 272