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 #include "opt_inet.h"
30fc88ecd3SAlexander V. Chernikov #include "opt_inet6.h"
31fc88ecd3SAlexander V. Chernikov
324f08f052SAlexander V. Chernikov #include <sys/ctype.h>
33fc88ecd3SAlexander V. Chernikov #include <sys/param.h>
34fc88ecd3SAlexander V. Chernikov #include <sys/systm.h>
35fc88ecd3SAlexander V. Chernikov #include <sys/malloc.h>
36fc88ecd3SAlexander V. Chernikov #include <sys/mbuf.h>
37fc88ecd3SAlexander V. Chernikov #include <sys/socket.h>
38fc88ecd3SAlexander V. Chernikov #include <sys/sysctl.h>
39fc88ecd3SAlexander V. Chernikov #include <sys/syslog.h>
40fc88ecd3SAlexander V. Chernikov #include <sys/kernel.h>
41fc88ecd3SAlexander V. Chernikov #include <sys/lock.h>
42fc88ecd3SAlexander V. Chernikov #include <sys/rmlock.h>
43fc88ecd3SAlexander V. Chernikov
44fc88ecd3SAlexander V. Chernikov #include <ddb/ddb.h>
45fc88ecd3SAlexander V. Chernikov #include <ddb/db_lex.h>
46fc88ecd3SAlexander V. Chernikov
47fc88ecd3SAlexander V. Chernikov #include <net/if.h>
48fc88ecd3SAlexander V. Chernikov #include <net/if_var.h>
492c2b37adSJustin Hibbits #include <net/if_private.h>
50fc88ecd3SAlexander V. Chernikov #include <net/if_dl.h>
51fc88ecd3SAlexander V. Chernikov #include <net/route.h>
52fc88ecd3SAlexander V. Chernikov #include <net/route/nhop.h>
53da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h>
54656442a7SAlexander V. Chernikov #include <net/route/route_var.h>
55fc88ecd3SAlexander V. Chernikov
56fc88ecd3SAlexander V. Chernikov /*
57fc88ecd3SAlexander V. Chernikov * Unfortunately, RTF_ values are expressed as raw masks rather than powers of
58fc88ecd3SAlexander V. Chernikov * 2, so we cannot use them as nice C99 initializer indices below.
59fc88ecd3SAlexander V. Chernikov */
60fc88ecd3SAlexander V. Chernikov static const char * const rtf_flag_strings[] = {
61fc88ecd3SAlexander V. Chernikov "UP",
62fc88ecd3SAlexander V. Chernikov "GATEWAY",
63fc88ecd3SAlexander V. Chernikov "HOST",
64fc88ecd3SAlexander V. Chernikov "REJECT",
65fc88ecd3SAlexander V. Chernikov "DYNAMIC",
66fc88ecd3SAlexander V. Chernikov "MODIFIED",
67fc88ecd3SAlexander V. Chernikov "DONE",
68fc88ecd3SAlexander V. Chernikov "UNUSED_0x80",
69fc88ecd3SAlexander V. Chernikov "UNUSED_0x100",
70fc88ecd3SAlexander V. Chernikov "XRESOLVE",
71fc88ecd3SAlexander V. Chernikov "LLDATA",
72fc88ecd3SAlexander V. Chernikov "STATIC",
73fc88ecd3SAlexander V. Chernikov "BLACKHOLE",
74fc88ecd3SAlexander V. Chernikov "UNUSED_0x2000",
75fc88ecd3SAlexander V. Chernikov "PROTO2",
76fc88ecd3SAlexander V. Chernikov "PROTO1",
77fc88ecd3SAlexander V. Chernikov "UNUSED_0x10000",
78fc88ecd3SAlexander V. Chernikov "UNUSED_0x20000",
79fc88ecd3SAlexander V. Chernikov "PROTO3",
80fc88ecd3SAlexander V. Chernikov "FIXEDMTU",
81fc88ecd3SAlexander V. Chernikov "PINNED",
82fc88ecd3SAlexander V. Chernikov "LOCAL",
83fc88ecd3SAlexander V. Chernikov "BROADCAST",
84fc88ecd3SAlexander V. Chernikov "MULTICAST",
85fc88ecd3SAlexander V. Chernikov /* Big gap. */
86fc88ecd3SAlexander V. Chernikov [28] = "STICKY",
87fc88ecd3SAlexander V. Chernikov [30] = "RNH_LOCKED",
88fc88ecd3SAlexander V. Chernikov [31] = "GWFLAG_COMPAT",
89fc88ecd3SAlexander V. Chernikov };
90fc88ecd3SAlexander V. Chernikov
91fc88ecd3SAlexander V. Chernikov static const char * __pure
rt_flag_name(unsigned idx)92fc88ecd3SAlexander V. Chernikov rt_flag_name(unsigned idx)
93fc88ecd3SAlexander V. Chernikov {
94fc88ecd3SAlexander V. Chernikov if (idx >= nitems(rtf_flag_strings))
95fc88ecd3SAlexander V. Chernikov return ("INVALID_FLAG");
96fc88ecd3SAlexander V. Chernikov if (rtf_flag_strings[idx] == NULL)
97fc88ecd3SAlexander V. Chernikov return ("UNKNOWN");
98fc88ecd3SAlexander V. Chernikov return (rtf_flag_strings[idx]);
99fc88ecd3SAlexander V. Chernikov }
100fc88ecd3SAlexander V. Chernikov
101fc88ecd3SAlexander V. Chernikov static void
rt_dumpaddr_ddb(const char * name,const struct sockaddr * sa)102fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb(const char *name, const struct sockaddr *sa)
103fc88ecd3SAlexander V. Chernikov {
104fc88ecd3SAlexander V. Chernikov char buf[INET6_ADDRSTRLEN], *res;
105fc88ecd3SAlexander V. Chernikov
106fc88ecd3SAlexander V. Chernikov res = NULL;
107fc88ecd3SAlexander V. Chernikov if (sa == NULL)
108fc88ecd3SAlexander V. Chernikov res = "NULL";
109fc88ecd3SAlexander V. Chernikov else if (sa->sa_family == AF_INET) {
110fc88ecd3SAlexander V. Chernikov res = inet_ntop(AF_INET,
111fc88ecd3SAlexander V. Chernikov &((const struct sockaddr_in *)sa)->sin_addr,
112fc88ecd3SAlexander V. Chernikov buf, sizeof(buf));
113fc88ecd3SAlexander V. Chernikov } else if (sa->sa_family == AF_INET6) {
114fc88ecd3SAlexander V. Chernikov res = inet_ntop(AF_INET6,
115fc88ecd3SAlexander V. Chernikov &((const struct sockaddr_in6 *)sa)->sin6_addr,
116fc88ecd3SAlexander V. Chernikov buf, sizeof(buf));
117fc88ecd3SAlexander V. Chernikov } else if (sa->sa_family == AF_LINK) {
118fc88ecd3SAlexander V. Chernikov res = "on link";
119fc88ecd3SAlexander V. Chernikov }
120fc88ecd3SAlexander V. Chernikov
121fc88ecd3SAlexander V. Chernikov if (res != NULL) {
122fc88ecd3SAlexander V. Chernikov db_printf("%s <%s> ", name, res);
123fc88ecd3SAlexander V. Chernikov return;
124fc88ecd3SAlexander V. Chernikov }
125fc88ecd3SAlexander V. Chernikov
126fc88ecd3SAlexander V. Chernikov db_printf("%s <af:%d> ", name, sa->sa_family);
127fc88ecd3SAlexander V. Chernikov }
128fc88ecd3SAlexander V. Chernikov
129fc88ecd3SAlexander V. Chernikov static int
rt_dumpentry_ddb(struct radix_node * rn,void * arg __unused)130fc88ecd3SAlexander V. Chernikov rt_dumpentry_ddb(struct radix_node *rn, void *arg __unused)
131fc88ecd3SAlexander V. Chernikov {
132fc88ecd3SAlexander V. Chernikov struct sockaddr_storage ss;
133fc88ecd3SAlexander V. Chernikov struct rtentry *rt;
1348c61eb21SAlexander V. Chernikov struct nhop_object *nh;
135fc88ecd3SAlexander V. Chernikov int flags, idx;
136fc88ecd3SAlexander V. Chernikov
137fc88ecd3SAlexander V. Chernikov /* If RNTORT is important, put it in a header. */
138fc88ecd3SAlexander V. Chernikov rt = (void *)rn;
1398c61eb21SAlexander V. Chernikov nh = (struct nhop_object *)rt->rt_nhop;
140fc88ecd3SAlexander V. Chernikov
141fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb("dst", rt_key(rt));
142fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb("gateway", &rt->rt_nhop->gw_sa);
143fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb("netmask", rtsock_fix_netmask(rt_key(rt), rt_mask(rt),
144fc88ecd3SAlexander V. Chernikov &ss));
1458c61eb21SAlexander V. Chernikov if ((nh->nh_ifp->if_flags & IFF_DYING) == 0) {
1468c61eb21SAlexander V. Chernikov rt_dumpaddr_ddb("ifp", nh->nh_ifp->if_addr->ifa_addr);
1478c61eb21SAlexander V. Chernikov rt_dumpaddr_ddb("ifa", nh->nh_ifa->ifa_addr);
148fc88ecd3SAlexander V. Chernikov }
149fc88ecd3SAlexander V. Chernikov
150fc88ecd3SAlexander V. Chernikov db_printf("flags ");
15193bfd365SAlexander V. Chernikov flags = rt->rte_flags | nhop_get_rtflags(nh);
152fc88ecd3SAlexander V. Chernikov if (flags == 0)
153fc88ecd3SAlexander V. Chernikov db_printf("none");
154fc88ecd3SAlexander V. Chernikov
155fc88ecd3SAlexander V. Chernikov while ((idx = ffs(flags)) > 0) {
156fc88ecd3SAlexander V. Chernikov idx--;
157fc88ecd3SAlexander V. Chernikov
158fc88ecd3SAlexander V. Chernikov db_printf("%s", rt_flag_name(idx));
159fc88ecd3SAlexander V. Chernikov flags &= ~(1ul << idx);
16093bfd365SAlexander V. Chernikov if (flags != 0)
16193bfd365SAlexander V. Chernikov db_printf(",");
162fc88ecd3SAlexander V. Chernikov }
163fc88ecd3SAlexander V. Chernikov
164fc88ecd3SAlexander V. Chernikov db_printf("\n");
165fc88ecd3SAlexander V. Chernikov return (0);
166fc88ecd3SAlexander V. Chernikov }
167fc88ecd3SAlexander V. Chernikov
DB_SHOW_COMMAND(routetable,db_show_routetable)168884eaacdSJohn Baldwin DB_SHOW_COMMAND(routetable, db_show_routetable)
169fc88ecd3SAlexander V. Chernikov {
170fc88ecd3SAlexander V. Chernikov struct rib_head *rnh;
171fc88ecd3SAlexander V. Chernikov int error, i, lim;
172fc88ecd3SAlexander V. Chernikov
173fc88ecd3SAlexander V. Chernikov if (have_addr)
174fc88ecd3SAlexander V. Chernikov i = lim = addr;
175fc88ecd3SAlexander V. Chernikov else {
176fc88ecd3SAlexander V. Chernikov i = 1;
177fc88ecd3SAlexander V. Chernikov lim = AF_MAX;
178fc88ecd3SAlexander V. Chernikov }
179fc88ecd3SAlexander V. Chernikov
180fc88ecd3SAlexander V. Chernikov for (; i <= lim; i++) {
181fc88ecd3SAlexander V. Chernikov rnh = rt_tables_get_rnh(0, i);
182fc88ecd3SAlexander V. Chernikov if (rnh == NULL) {
183fc88ecd3SAlexander V. Chernikov if (have_addr) {
184fc88ecd3SAlexander V. Chernikov db_printf("%s: AF %d not supported?\n",
185fc88ecd3SAlexander V. Chernikov __func__, i);
186fc88ecd3SAlexander V. Chernikov break;
187fc88ecd3SAlexander V. Chernikov }
188fc88ecd3SAlexander V. Chernikov continue;
189fc88ecd3SAlexander V. Chernikov }
190fc88ecd3SAlexander V. Chernikov
191fc88ecd3SAlexander V. Chernikov if (!have_addr && i > 1)
192fc88ecd3SAlexander V. Chernikov db_printf("\n");
193fc88ecd3SAlexander V. Chernikov
194fc88ecd3SAlexander V. Chernikov db_printf("Route table for AF %d%s%s%s:\n", i,
195fc88ecd3SAlexander V. Chernikov (i == AF_INET || i == AF_INET6) ? " (" : "",
196fc88ecd3SAlexander V. Chernikov (i == AF_INET) ? "INET" : (i == AF_INET6) ? "INET6" : "",
197fc88ecd3SAlexander V. Chernikov (i == AF_INET || i == AF_INET6) ? ")" : "");
198fc88ecd3SAlexander V. Chernikov
199fc88ecd3SAlexander V. Chernikov error = rnh->rnh_walktree(&rnh->head, rt_dumpentry_ddb, NULL);
200fc88ecd3SAlexander V. Chernikov if (error != 0)
201fc88ecd3SAlexander V. Chernikov db_printf("%s: walktree(%d): %d\n", __func__, i,
202fc88ecd3SAlexander V. Chernikov error);
203fc88ecd3SAlexander V. Chernikov }
204fc88ecd3SAlexander V. Chernikov }
205fc88ecd3SAlexander V. Chernikov
DB_SHOW_COMMAND_FLAGS(route,db_show_route,CS_OWN)206884eaacdSJohn Baldwin DB_SHOW_COMMAND_FLAGS(route, db_show_route, CS_OWN)
207fc88ecd3SAlexander V. Chernikov {
2084f08f052SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN], *buf, *end;
209d94be4ccSAlexander V. Chernikov struct rib_head *rh;
210d94be4ccSAlexander V. Chernikov struct radix_node *rn;
2114f08f052SAlexander V. Chernikov void *dst_addrp;
212fc88ecd3SAlexander V. Chernikov struct rtentry *rt;
213fc88ecd3SAlexander V. Chernikov union {
214fc88ecd3SAlexander V. Chernikov struct sockaddr_in dest_sin;
215fc88ecd3SAlexander V. Chernikov struct sockaddr_in6 dest_sin6;
216fc88ecd3SAlexander V. Chernikov } u;
2174f08f052SAlexander V. Chernikov int af;
218fc88ecd3SAlexander V. Chernikov
2194f08f052SAlexander V. Chernikov buf = db_get_line();
220fc88ecd3SAlexander V. Chernikov
2214f08f052SAlexander V. Chernikov /* Remove whitespaces from both ends */
2224f08f052SAlexander V. Chernikov end = buf + strlen(buf) - 1;
2234f08f052SAlexander V. Chernikov for (; (end >= buf) && (*end=='\n' || isspace(*end)); end--)
2244f08f052SAlexander V. Chernikov *end = '\0';
2254f08f052SAlexander V. Chernikov while (isspace(*buf))
2264f08f052SAlexander V. Chernikov buf++;
227fc88ecd3SAlexander V. Chernikov
2284f08f052SAlexander V. Chernikov /* Determine AF */
2294f08f052SAlexander V. Chernikov if (strchr(buf, ':') != NULL) {
230fc88ecd3SAlexander V. Chernikov af = AF_INET6;
2314f08f052SAlexander V. Chernikov u.dest_sin6.sin6_family = af;
2324f08f052SAlexander V. Chernikov u.dest_sin6.sin6_len = sizeof(struct sockaddr_in6);
233fc88ecd3SAlexander V. Chernikov dst_addrp = &u.dest_sin6.sin6_addr;
234fc88ecd3SAlexander V. Chernikov } else {
2354f08f052SAlexander V. Chernikov af = AF_INET;
2364f08f052SAlexander V. Chernikov u.dest_sin.sin_family = af;
2374f08f052SAlexander V. Chernikov u.dest_sin.sin_len = sizeof(struct sockaddr_in);
2384f08f052SAlexander V. Chernikov dst_addrp = &u.dest_sin.sin_addr;
239fc88ecd3SAlexander V. Chernikov }
240fc88ecd3SAlexander V. Chernikov
2414f08f052SAlexander V. Chernikov if (inet_pton(af, buf, dst_addrp) != 1)
2424f08f052SAlexander V. Chernikov goto usage;
2434f08f052SAlexander V. Chernikov
2444f08f052SAlexander V. Chernikov if (inet_ntop(af, dst_addrp, abuf, sizeof(abuf)) != NULL)
2454f08f052SAlexander V. Chernikov db_printf("Looking up route to destination '%s'\n", abuf);
246fc88ecd3SAlexander V. Chernikov
247d94be4ccSAlexander V. Chernikov rt = NULL;
248fc88ecd3SAlexander V. Chernikov CURVNET_SET(vnet0);
249d94be4ccSAlexander V. Chernikov
250d94be4ccSAlexander V. Chernikov rh = rt_tables_get_rnh(RT_DEFAULT_FIB, af);
251d94be4ccSAlexander V. Chernikov
252d94be4ccSAlexander V. Chernikov rn = rh->rnh_matchaddr(&u, &rh->head);
253d94be4ccSAlexander V. Chernikov if (rn && ((rn->rn_flags & RNF_ROOT) == 0))
254d94be4ccSAlexander V. Chernikov rt = (struct rtentry *)rn;
255d94be4ccSAlexander V. Chernikov
256fc88ecd3SAlexander V. Chernikov CURVNET_RESTORE();
257fc88ecd3SAlexander V. Chernikov
258fc88ecd3SAlexander V. Chernikov if (rt == NULL) {
259fc88ecd3SAlexander V. Chernikov db_printf("Could not get route for that server.\n");
260fc88ecd3SAlexander V. Chernikov return;
261fc88ecd3SAlexander V. Chernikov }
262fc88ecd3SAlexander V. Chernikov
263fc88ecd3SAlexander V. Chernikov rt_dumpentry_ddb((void *)rt, NULL);
264fc88ecd3SAlexander V. Chernikov
265fc88ecd3SAlexander V. Chernikov return;
266fc88ecd3SAlexander V. Chernikov usage:
267fc88ecd3SAlexander V. Chernikov db_printf("Usage: 'show route <address>'\n"
2684f08f052SAlexander V. Chernikov " Currently accepts only IPv4 and IPv6 addresses\n");
269fc88ecd3SAlexander V. Chernikov db_skip_to_eol();
270fc88ecd3SAlexander V. Chernikov }
271