route.c revision 1.86 1 1.86 yamaguch /* $NetBSD: route.c,v 1.86 2020/05/27 05:59:16 yamaguchi 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.86 yamaguch __RCSID("$NetBSD: route.c,v 1.86 2020/05/27 05:59:16 yamaguchi 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.81 christos 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.81 christos p_sockaddr(kgetsa((const struct sockaddr *)rnode.rn_key),
163 1.83 christos NULL, 0, 44, nflag);
164 1.81 christos putchar('\n');
165 1.81 christos }
166 1.81 christos if ((rn = rnode.rn_dupedkey) != NULL)
167 1.81 christos goto again;
168 1.81 christos } else {
169 1.81 christos if (Aflag && do_rtent) {
170 1.81 christos printf("%-8.8lx ", (u_long) rn);
171 1.81 christos p_rtnode();
172 1.81 christos }
173 1.81 christos rn = rnode.rn_r;
174 1.81 christos p_tree(rnode.rn_l);
175 1.81 christos p_tree(rn);
176 1.81 christos }
177 1.81 christos }
178 1.81 christos
179 1.81 christos static void
180 1.81 christos p_rtnode(void)
181 1.81 christos {
182 1.81 christos struct radix_mask *rm = rnode.rn_mklist;
183 1.81 christos char nbuf[20];
184 1.81 christos
185 1.81 christos if (rnode.rn_b < 0) {
186 1.81 christos if (rnode.rn_mask) {
187 1.81 christos printf("\t mask ");
188 1.81 christos p_sockaddr(kgetsa((const struct sockaddr *)rnode.rn_mask),
189 1.83 christos NULL, 0, -1, nflag);
190 1.81 christos } else if (rm == 0)
191 1.81 christos return;
192 1.81 christos } else {
193 1.81 christos (void)snprintf(nbuf, sizeof nbuf, "(%d)", rnode.rn_b);
194 1.81 christos printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long) rnode.rn_l,
195 1.81 christos (u_long) rnode.rn_r);
196 1.81 christos }
197 1.81 christos while (rm) {
198 1.81 christos kget(rm, rmask);
199 1.81 christos (void)snprintf(nbuf, sizeof nbuf, " %d refs, ", rmask.rm_refs);
200 1.81 christos printf(" mk = %8.8lx {(%d),%s", (u_long) rm,
201 1.81 christos -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
202 1.81 christos if (rmask.rm_flags & RNF_NORMAL) {
203 1.81 christos struct radix_node rnode_aux;
204 1.81 christos printf(" <normal>, ");
205 1.81 christos kget(rmask.rm_leaf, rnode_aux);
206 1.81 christos p_sockaddr(kgetsa((const struct sockaddr *)rnode_aux.rn_mask),
207 1.83 christos NULL, 0, -1, nflag);
208 1.81 christos } else
209 1.81 christos p_sockaddr(kgetsa((const struct sockaddr *)rmask.rm_mask),
210 1.83 christos NULL, 0, -1, nflag);
211 1.81 christos putchar('}');
212 1.81 christos if ((rm = rmask.rm_mklist) != NULL)
213 1.81 christos printf(" ->");
214 1.81 christos }
215 1.81 christos putchar('\n');
216 1.81 christos }
217 1.81 christos
218 1.81 christos static struct sockaddr *sockcopy(struct sockaddr *, union sockaddr_union *);
219 1.81 christos
220 1.81 christos /*
221 1.81 christos * copy a sockaddr into an allocated region, allocate at least sockaddr
222 1.81 christos * bytes and zero unused
223 1.81 christos */
224 1.81 christos static struct sockaddr *
225 1.81 christos sockcopy(struct sockaddr *sp, union sockaddr_union *dp)
226 1.81 christos {
227 1.81 christos int len;
228 1.81 christos
229 1.81 christos if (sp == 0 || sp->sa_len == 0)
230 1.81 christos (void)memset(dp, 0, sizeof (*sp));
231 1.81 christos else {
232 1.81 christos len = (sp->sa_len >= sizeof (*sp)) ? sp->sa_len : sizeof (*sp);
233 1.81 christos (void)memcpy(dp, sp, len);
234 1.81 christos }
235 1.81 christos return ((struct sockaddr *)dp);
236 1.81 christos }
237 1.81 christos
238 1.81 christos static void
239 1.81 christos p_krtentry(struct rtentry *rt)
240 1.81 christos {
241 1.81 christos static struct ifnet ifnet, *lastif;
242 1.81 christos union sockaddr_union addr_un, mask_un;
243 1.81 christos struct sockaddr *addr, *mask;
244 1.81 christos
245 1.81 christos memset(&addr_un, 0, sizeof(addr_un));
246 1.81 christos memset(&mask_un, 0, sizeof(mask_un));
247 1.81 christos addr = sockcopy(kgetsa(rt_getkey(rt)), &addr_un);
248 1.81 christos if (rt_mask(rt))
249 1.81 christos mask = sockcopy(kgetsa(rt_mask(rt)), &mask_un);
250 1.81 christos else
251 1.81 christos mask = sockcopy(NULL, &mask_un);
252 1.83 christos p_addr(addr, mask, rt->rt_flags, nflag);
253 1.83 christos p_gwaddr(kgetsa(rt->rt_gateway), kgetsa(rt->rt_gateway)->sa_family, nflag);
254 1.83 christos p_flags(rt->rt_flags);
255 1.81 christos printf("%6d %8"PRIu64" ", rt->rt_refcnt, rt->rt_use);
256 1.81 christos if (rt->rt_rmx.rmx_mtu)
257 1.81 christos printf("%6"PRIu64, rt->rt_rmx.rmx_mtu);
258 1.81 christos else
259 1.81 christos printf("%6s", "-");
260 1.81 christos putchar((rt->rt_rmx.rmx_locks & RTV_MTU) ? 'L' : ' ');
261 1.81 christos if (tagflag == 1) {
262 1.84 manu #ifndef SMALL
263 1.81 christos if (rt->rt_tag != NULL) {
264 1.81 christos const struct sockaddr *tagsa = kgetsa(rt->rt_tag);
265 1.81 christos char *tagstr;
266 1.81 christos
267 1.81 christos if (tagsa->sa_family == AF_MPLS) {
268 1.81 christos tagstr = mpls_ntoa(tagsa);
269 1.81 christos if (strlen(tagstr) < 7)
270 1.81 christos printf("%7s", tagstr);
271 1.81 christos else
272 1.81 christos printf("%s", tagstr);
273 1.81 christos }
274 1.81 christos else
275 1.81 christos printf("%7s", "-");
276 1.81 christos } else
277 1.84 manu #endif
278 1.81 christos printf("%7s", "-");
279 1.81 christos }
280 1.81 christos if (rt->rt_ifp) {
281 1.81 christos if (rt->rt_ifp != lastif) {
282 1.81 christos kget(rt->rt_ifp, ifnet);
283 1.81 christos lastif = rt->rt_ifp;
284 1.81 christos }
285 1.81 christos printf(" %.16s%s", ifnet.if_xname,
286 1.81 christos rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
287 1.81 christos }
288 1.81 christos putchar('\n');
289 1.84 manu #ifndef SMALL
290 1.82 christos if (vflag)
291 1.83 christos p_rtrmx(&rt->rt_rmx);
292 1.84 manu #endif
293 1.81 christos }
294 1.81 christos
295 1.1 cgd /*
296 1.1 cgd * Print routing statistics
297 1.1 cgd */
298 1.10 mycroft void
299 1.79 matt rt_stats(u_long off)
300 1.1 cgd {
301 1.73 lukem struct rtstat rtstats;
302 1.1 cgd
303 1.67 elad if (use_sysctl) {
304 1.73 lukem size_t rtsize = sizeof(rtstats);
305 1.67 elad
306 1.86 yamaguch if (sysctlbyname("net.rtable.stats", &rtstats, &rtsize,
307 1.67 elad NULL, 0) == -1)
308 1.67 elad err(1, "rt_stats: sysctl");
309 1.67 elad } else if (off == 0) {
310 1.1 cgd printf("rtstat: symbol not in namelist\n");
311 1.1 cgd return;
312 1.67 elad } else
313 1.73 lukem kread(off, (char *)&rtstats, sizeof(rtstats));
314 1.67 elad
315 1.1 cgd printf("routing:\n");
316 1.53 itojun printf("\t%llu bad routing redirect%s\n",
317 1.73 lukem (unsigned long long)rtstats.rts_badredirect,
318 1.73 lukem plural(rtstats.rts_badredirect));
319 1.53 itojun printf("\t%llu dynamically created route%s\n",
320 1.73 lukem (unsigned long long)rtstats.rts_dynamic,
321 1.73 lukem plural(rtstats.rts_dynamic));
322 1.53 itojun printf("\t%llu new gateway%s due to redirects\n",
323 1.73 lukem (unsigned long long)rtstats.rts_newgateway,
324 1.73 lukem plural(rtstats.rts_newgateway));
325 1.53 itojun printf("\t%llu destination%s found unreachable\n",
326 1.73 lukem (unsigned long long)rtstats.rts_unreach,
327 1.73 lukem plural(rtstats.rts_unreach));
328 1.53 itojun printf("\t%llu use%s of a wildcard route\n",
329 1.73 lukem (unsigned long long)rtstats.rts_wildcard,
330 1.73 lukem plural(rtstats.rts_wildcard));
331 1.1 cgd }
332