Deleted Added
full compact
route.c (146079) route.c (146187)
1/*
2 * Copyright (c) 1983, 1989, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
33 The Regents of the University of California. All rights reserved.\n";
34#endif /* not lint */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
39#endif
40static const char rcsid[] =
1/*
2 * Copyright (c) 1983, 1989, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
33 The Regents of the University of California. All rights reserved.\n";
34#endif /* not lint */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
39#endif
40static const char rcsid[] =
41 "$FreeBSD: head/sbin/route/route.c 146079 2005-05-11 02:50:41Z jmallett $";
41 "$FreeBSD: head/sbin/route/route.c 146187 2005-05-13 16:31:11Z ume $";
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/file.h>
46#include <sys/socket.h>
47#include <sys/ioctl.h>
48#include <sys/sysctl.h>
49#include <sys/types.h>
50
51#include <net/if.h>
52#include <net/route.h>
53#include <net/if_dl.h>
54#include <netinet/in.h>
55#include <netinet/if_ether.h>
56#include <netatalk/at.h>
57#include <arpa/inet.h>
58#include <netdb.h>
59
60#include <ctype.h>
61#include <err.h>
62#include <errno.h>
63#include <paths.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <sysexits.h>
68#include <unistd.h>
69#include <ifaddrs.h>
70
71struct keytab {
72 char *kt_cp;
73 int kt_i;
74} keywords[] = {
75#include "keywords.h"
76 {0, 0}
77};
78
79struct ortentry route;
80union sockunion {
81 struct sockaddr sa;
82 struct sockaddr_in sin;
83#ifdef INET6
84 struct sockaddr_in6 sin6;
85#endif
86 struct sockaddr_at sat;
87 struct sockaddr_dl sdl;
88 struct sockaddr_inarp sinarp;
89 struct sockaddr_storage ss; /* added to avoid memory overrun */
90} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
91
92typedef union sockunion *sup;
93int pid, rtm_addrs;
94int s;
95int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
96int iflag, verbose, aflen = sizeof (struct sockaddr_in);
97int locking, lockrest, debugonly;
98struct rt_metrics rt_metrics;
99u_long rtm_inits;
100uid_t uid;
101int atalk_aton(const char *, struct at_addr *);
102char *atalk_ntoa(struct at_addr);
103const char *routename(), *netname();
104void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
105void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
106#ifdef INET6
107static int inet6_makenetandmask(struct sockaddr_in6 *, char *);
108#endif
109int getaddr(), rtmsg(), x25_makemask();
110int prefixlen();
111extern char *iso_ntoa();
112
113void usage(const char *) __dead2;
114
115void
116usage(cp)
117 const char *cp;
118{
119 if (cp)
120 warnx("bad keyword: %s", cp);
121 (void) fprintf(stderr,
122 "usage: route [-dnqtv] command [[modifiers] args]\n");
123 exit(EX_USAGE);
124 /* NOTREACHED */
125}
126
127int
128main(argc, argv)
129 int argc;
130 char **argv;
131{
132 int ch;
133
134 if (argc < 2)
135 usage((char *)NULL);
136
137 while ((ch = getopt(argc, argv, "nqdtv")) != -1)
138 switch(ch) {
139 case 'n':
140 nflag = 1;
141 break;
142 case 'q':
143 qflag = 1;
144 break;
145 case 'v':
146 verbose = 1;
147 break;
148 case 't':
149 tflag = 1;
150 break;
151 case 'd':
152 debugonly = 1;
153 break;
154 case '?':
155 default:
156 usage((char *)NULL);
157 }
158 argc -= optind;
159 argv += optind;
160
161 pid = getpid();
162 uid = geteuid();
163 if (tflag)
164 s = open(_PATH_DEVNULL, O_WRONLY, 0);
165 else
166 s = socket(PF_ROUTE, SOCK_RAW, 0);
167 if (s < 0)
168 err(EX_OSERR, "socket");
169 if (*argv)
170 switch (keyword(*argv)) {
171 case K_GET:
172 uid = 0;
173 /* FALLTHROUGH */
174
175 case K_CHANGE:
176 case K_ADD:
177 case K_DELETE:
178 newroute(argc, argv);
179 /* NOTREACHED */
180
181 case K_MONITOR:
182 monitor();
183 /* NOTREACHED */
184
185 case K_FLUSH:
186 flushroutes(argc, argv);
187 exit(0);
188 /* NOTREACHED */
189 }
190 usage(*argv);
191 /* NOTREACHED */
192}
193
194/*
195 * Purge all entries in the routing tables not
196 * associated with network interfaces.
197 */
198void
199flushroutes(argc, argv)
200 int argc;
201 char *argv[];
202{
203 size_t needed;
204 int mib[6], rlen, seqno, count = 0;
205 char *buf, *next, *lim;
206 struct rt_msghdr *rtm;
207
208 if (uid && !debugonly) {
209 errx(EX_NOPERM, "must be root to alter routing table");
210 }
211 shutdown(s, SHUT_RD); /* Don't want to read back our messages */
212 if (argc > 1) {
213 argv++;
214 if (argc == 2 && **argv == '-')
215 switch (keyword(*argv + 1)) {
216 case K_INET:
217 af = AF_INET;
218 break;
219#ifdef INET6
220 case K_INET6:
221 af = AF_INET6;
222 break;
223#endif
224 case K_ATALK:
225 af = AF_APPLETALK;
226 break;
227 case K_LINK:
228 af = AF_LINK;
229 break;
230 default:
231 goto bad;
232 } else
233bad: usage(*argv);
234 }
235retry:
236 mib[0] = CTL_NET;
237 mib[1] = PF_ROUTE;
238 mib[2] = 0; /* protocol */
239 mib[3] = 0; /* wildcard address family */
240 mib[4] = NET_RT_DUMP;
241 mib[5] = 0; /* no flags */
242 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
243 err(EX_OSERR, "route-sysctl-estimate");
244 if ((buf = malloc(needed)) == NULL)
245 errx(EX_OSERR, "malloc failed");
246 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
247 if (errno == ENOMEM && count++ < 10) {
248 warnx("Routing table grew, retrying");
249 sleep(1);
250 free(buf);
251 goto retry;
252 }
253 err(EX_OSERR, "route-sysctl-get");
254 }
255 lim = buf + needed;
256 if (verbose)
257 (void) printf("Examining routing table from sysctl\n");
258 seqno = 0; /* ??? */
259 for (next = buf; next < lim; next += rtm->rtm_msglen) {
260 rtm = (struct rt_msghdr *)next;
261 if (verbose)
262 print_rtmsg(rtm, rtm->rtm_msglen);
263 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
264 continue;
265 if (af) {
266 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
267
268 if (sa->sa_family != af)
269 continue;
270 }
271 if (debugonly)
272 continue;
273 rtm->rtm_type = RTM_DELETE;
274 rtm->rtm_seq = seqno;
275 rlen = write(s, next, rtm->rtm_msglen);
276 if (rlen < 0 && errno == EPERM)
277 err(1, "write to routing socket");
278 if (rlen < (int)rtm->rtm_msglen) {
279 warn("write to routing socket");
280 (void) printf("got only %d for rlen\n", rlen);
281 free(buf);
282 goto retry;
283 break;
284 }
285 seqno++;
286 if (qflag)
287 continue;
288 if (verbose)
289 print_rtmsg(rtm, rlen);
290 else {
291 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
292 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
293 routename(sa) : netname(sa));
294 sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
295 (void) printf("%-20.20s ", routename(sa));
296 (void) printf("done\n");
297 }
298 }
299}
300
301const char *
302routename(sa)
303 struct sockaddr *sa;
304{
305 char *cp;
306 static char line[MAXHOSTNAMELEN + 1];
307 struct hostent *hp;
308 static char domain[MAXHOSTNAMELEN + 1];
309 static int first = 1, n;
310
311 if (first) {
312 first = 0;
313 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
314 (cp = strchr(domain, '.'))) {
315 domain[MAXHOSTNAMELEN] = '\0';
316 (void) strcpy(domain, cp + 1);
317 } else
318 domain[0] = 0;
319 }
320
321 if (sa->sa_len == 0)
322 strcpy(line, "default");
323 else switch (sa->sa_family) {
324
325 case AF_INET:
326 { struct in_addr in;
327 in = ((struct sockaddr_in *)sa)->sin_addr;
328
329 cp = 0;
330 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
331 cp = "default";
332 if (cp == 0 && !nflag) {
333 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
334 AF_INET);
335 if (hp) {
336 if ((cp = strchr(hp->h_name, '.')) &&
337 !strcmp(cp + 1, domain))
338 *cp = 0;
339 cp = hp->h_name;
340 }
341 }
342 if (cp) {
343 strncpy(line, cp, sizeof(line) - 1);
344 line[sizeof(line) - 1] = '\0';
345 } else
346 (void) sprintf(line, "%s", inet_ntoa(in));
347 break;
348 }
349
350#ifdef INET6
351 case AF_INET6:
352 {
353 struct sockaddr_in6 sin6; /* use static var for safety */
354 int niflags = 0;
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/file.h>
46#include <sys/socket.h>
47#include <sys/ioctl.h>
48#include <sys/sysctl.h>
49#include <sys/types.h>
50
51#include <net/if.h>
52#include <net/route.h>
53#include <net/if_dl.h>
54#include <netinet/in.h>
55#include <netinet/if_ether.h>
56#include <netatalk/at.h>
57#include <arpa/inet.h>
58#include <netdb.h>
59
60#include <ctype.h>
61#include <err.h>
62#include <errno.h>
63#include <paths.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <sysexits.h>
68#include <unistd.h>
69#include <ifaddrs.h>
70
71struct keytab {
72 char *kt_cp;
73 int kt_i;
74} keywords[] = {
75#include "keywords.h"
76 {0, 0}
77};
78
79struct ortentry route;
80union sockunion {
81 struct sockaddr sa;
82 struct sockaddr_in sin;
83#ifdef INET6
84 struct sockaddr_in6 sin6;
85#endif
86 struct sockaddr_at sat;
87 struct sockaddr_dl sdl;
88 struct sockaddr_inarp sinarp;
89 struct sockaddr_storage ss; /* added to avoid memory overrun */
90} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
91
92typedef union sockunion *sup;
93int pid, rtm_addrs;
94int s;
95int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
96int iflag, verbose, aflen = sizeof (struct sockaddr_in);
97int locking, lockrest, debugonly;
98struct rt_metrics rt_metrics;
99u_long rtm_inits;
100uid_t uid;
101int atalk_aton(const char *, struct at_addr *);
102char *atalk_ntoa(struct at_addr);
103const char *routename(), *netname();
104void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
105void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
106#ifdef INET6
107static int inet6_makenetandmask(struct sockaddr_in6 *, char *);
108#endif
109int getaddr(), rtmsg(), x25_makemask();
110int prefixlen();
111extern char *iso_ntoa();
112
113void usage(const char *) __dead2;
114
115void
116usage(cp)
117 const char *cp;
118{
119 if (cp)
120 warnx("bad keyword: %s", cp);
121 (void) fprintf(stderr,
122 "usage: route [-dnqtv] command [[modifiers] args]\n");
123 exit(EX_USAGE);
124 /* NOTREACHED */
125}
126
127int
128main(argc, argv)
129 int argc;
130 char **argv;
131{
132 int ch;
133
134 if (argc < 2)
135 usage((char *)NULL);
136
137 while ((ch = getopt(argc, argv, "nqdtv")) != -1)
138 switch(ch) {
139 case 'n':
140 nflag = 1;
141 break;
142 case 'q':
143 qflag = 1;
144 break;
145 case 'v':
146 verbose = 1;
147 break;
148 case 't':
149 tflag = 1;
150 break;
151 case 'd':
152 debugonly = 1;
153 break;
154 case '?':
155 default:
156 usage((char *)NULL);
157 }
158 argc -= optind;
159 argv += optind;
160
161 pid = getpid();
162 uid = geteuid();
163 if (tflag)
164 s = open(_PATH_DEVNULL, O_WRONLY, 0);
165 else
166 s = socket(PF_ROUTE, SOCK_RAW, 0);
167 if (s < 0)
168 err(EX_OSERR, "socket");
169 if (*argv)
170 switch (keyword(*argv)) {
171 case K_GET:
172 uid = 0;
173 /* FALLTHROUGH */
174
175 case K_CHANGE:
176 case K_ADD:
177 case K_DELETE:
178 newroute(argc, argv);
179 /* NOTREACHED */
180
181 case K_MONITOR:
182 monitor();
183 /* NOTREACHED */
184
185 case K_FLUSH:
186 flushroutes(argc, argv);
187 exit(0);
188 /* NOTREACHED */
189 }
190 usage(*argv);
191 /* NOTREACHED */
192}
193
194/*
195 * Purge all entries in the routing tables not
196 * associated with network interfaces.
197 */
198void
199flushroutes(argc, argv)
200 int argc;
201 char *argv[];
202{
203 size_t needed;
204 int mib[6], rlen, seqno, count = 0;
205 char *buf, *next, *lim;
206 struct rt_msghdr *rtm;
207
208 if (uid && !debugonly) {
209 errx(EX_NOPERM, "must be root to alter routing table");
210 }
211 shutdown(s, SHUT_RD); /* Don't want to read back our messages */
212 if (argc > 1) {
213 argv++;
214 if (argc == 2 && **argv == '-')
215 switch (keyword(*argv + 1)) {
216 case K_INET:
217 af = AF_INET;
218 break;
219#ifdef INET6
220 case K_INET6:
221 af = AF_INET6;
222 break;
223#endif
224 case K_ATALK:
225 af = AF_APPLETALK;
226 break;
227 case K_LINK:
228 af = AF_LINK;
229 break;
230 default:
231 goto bad;
232 } else
233bad: usage(*argv);
234 }
235retry:
236 mib[0] = CTL_NET;
237 mib[1] = PF_ROUTE;
238 mib[2] = 0; /* protocol */
239 mib[3] = 0; /* wildcard address family */
240 mib[4] = NET_RT_DUMP;
241 mib[5] = 0; /* no flags */
242 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
243 err(EX_OSERR, "route-sysctl-estimate");
244 if ((buf = malloc(needed)) == NULL)
245 errx(EX_OSERR, "malloc failed");
246 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
247 if (errno == ENOMEM && count++ < 10) {
248 warnx("Routing table grew, retrying");
249 sleep(1);
250 free(buf);
251 goto retry;
252 }
253 err(EX_OSERR, "route-sysctl-get");
254 }
255 lim = buf + needed;
256 if (verbose)
257 (void) printf("Examining routing table from sysctl\n");
258 seqno = 0; /* ??? */
259 for (next = buf; next < lim; next += rtm->rtm_msglen) {
260 rtm = (struct rt_msghdr *)next;
261 if (verbose)
262 print_rtmsg(rtm, rtm->rtm_msglen);
263 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
264 continue;
265 if (af) {
266 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
267
268 if (sa->sa_family != af)
269 continue;
270 }
271 if (debugonly)
272 continue;
273 rtm->rtm_type = RTM_DELETE;
274 rtm->rtm_seq = seqno;
275 rlen = write(s, next, rtm->rtm_msglen);
276 if (rlen < 0 && errno == EPERM)
277 err(1, "write to routing socket");
278 if (rlen < (int)rtm->rtm_msglen) {
279 warn("write to routing socket");
280 (void) printf("got only %d for rlen\n", rlen);
281 free(buf);
282 goto retry;
283 break;
284 }
285 seqno++;
286 if (qflag)
287 continue;
288 if (verbose)
289 print_rtmsg(rtm, rlen);
290 else {
291 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
292 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
293 routename(sa) : netname(sa));
294 sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
295 (void) printf("%-20.20s ", routename(sa));
296 (void) printf("done\n");
297 }
298 }
299}
300
301const char *
302routename(sa)
303 struct sockaddr *sa;
304{
305 char *cp;
306 static char line[MAXHOSTNAMELEN + 1];
307 struct hostent *hp;
308 static char domain[MAXHOSTNAMELEN + 1];
309 static int first = 1, n;
310
311 if (first) {
312 first = 0;
313 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
314 (cp = strchr(domain, '.'))) {
315 domain[MAXHOSTNAMELEN] = '\0';
316 (void) strcpy(domain, cp + 1);
317 } else
318 domain[0] = 0;
319 }
320
321 if (sa->sa_len == 0)
322 strcpy(line, "default");
323 else switch (sa->sa_family) {
324
325 case AF_INET:
326 { struct in_addr in;
327 in = ((struct sockaddr_in *)sa)->sin_addr;
328
329 cp = 0;
330 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
331 cp = "default";
332 if (cp == 0 && !nflag) {
333 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
334 AF_INET);
335 if (hp) {
336 if ((cp = strchr(hp->h_name, '.')) &&
337 !strcmp(cp + 1, domain))
338 *cp = 0;
339 cp = hp->h_name;
340 }
341 }
342 if (cp) {
343 strncpy(line, cp, sizeof(line) - 1);
344 line[sizeof(line) - 1] = '\0';
345 } else
346 (void) sprintf(line, "%s", inet_ntoa(in));
347 break;
348 }
349
350#ifdef INET6
351 case AF_INET6:
352 {
353 struct sockaddr_in6 sin6; /* use static var for safety */
354 int niflags = 0;
355#ifdef NI_WITHSCOPEID
356 niflags = NI_WITHSCOPEID;
357#endif
358
359 memset(&sin6, 0, sizeof(sin6));
360 memcpy(&sin6, sa, sa->sa_len);
361 sin6.sin6_len = sizeof(struct sockaddr_in6);
362 sin6.sin6_family = AF_INET6;
363#ifdef __KAME__
364 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
365 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
366 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
367 sin6.sin6_scope_id == 0) {
368 sin6.sin6_scope_id =
369 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
370 sin6.sin6_addr.s6_addr[2] = 0;
371 sin6.sin6_addr.s6_addr[3] = 0;
372 }
373#endif
374 if (nflag)
375 niflags |= NI_NUMERICHOST;
376 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
377 line, sizeof(line), NULL, 0, niflags) != 0)
378 strncpy(line, "invalid", sizeof(line));
379
380 return(line);
381 }
382#endif
383
384 case AF_APPLETALK:
385 (void) snprintf(line, sizeof(line), "atalk %s",
386 atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
387 break;
388
389 case AF_LINK:
390 return (link_ntoa((struct sockaddr_dl *)sa));
391
392 default:
393 { u_short *s = (u_short *)sa;
394 u_short *slim = s + ((sa->sa_len + 1) >> 1);
395 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
396 char *cpe = line + sizeof(line);
397
398 while (++s < slim && cp < cpe) /* start with sa->sa_data */
399 if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
400 cp += n;
401 else
402 *cp = '\0';
403 break;
404 }
405 }
406 return (line);
407}
408
409/*
410 * Return the name of the network whose address is given.
411 * The address is assumed to be that of a net or subnet, not a host.
412 */
413const char *
414netname(sa)
415 struct sockaddr *sa;
416{
417 char *cp = 0;
418 static char line[MAXHOSTNAMELEN + 1];
419 struct netent *np = 0;
420 u_long net, mask;
421 u_long i;
422 int n, subnetshift;
423
424 switch (sa->sa_family) {
425
426 case AF_INET:
427 { struct in_addr in;
428 in = ((struct sockaddr_in *)sa)->sin_addr;
429
430 i = in.s_addr = ntohl(in.s_addr);
431 if (in.s_addr == 0)
432 cp = "default";
433 else if (!nflag) {
434 if (IN_CLASSA(i)) {
435 mask = IN_CLASSA_NET;
436 subnetshift = 8;
437 } else if (IN_CLASSB(i)) {
438 mask = IN_CLASSB_NET;
439 subnetshift = 8;
440 } else {
441 mask = IN_CLASSC_NET;
442 subnetshift = 4;
443 }
444 /*
445 * If there are more bits than the standard mask
446 * would suggest, subnets must be in use.
447 * Guess at the subnet mask, assuming reasonable
448 * width subnet fields.
449 */
450 while (in.s_addr &~ mask)
451 mask = (long)mask >> subnetshift;
452 net = in.s_addr & mask;
453 while ((mask & 1) == 0)
454 mask >>= 1, net >>= 1;
455 np = getnetbyaddr(net, AF_INET);
456 if (np)
457 cp = np->n_name;
458 }
459#define C(x) (unsigned)((x) & 0xff)
460 if (cp)
461 strncpy(line, cp, sizeof(line));
462 else if ((in.s_addr & 0xffffff) == 0)
463 (void) sprintf(line, "%u", C(in.s_addr >> 24));
464 else if ((in.s_addr & 0xffff) == 0)
465 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
466 C(in.s_addr >> 16));
467 else if ((in.s_addr & 0xff) == 0)
468 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
469 C(in.s_addr >> 16), C(in.s_addr >> 8));
470 else
471 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
472 C(in.s_addr >> 16), C(in.s_addr >> 8),
473 C(in.s_addr));
474#undef C
475 break;
476 }
477
478#ifdef INET6
479 case AF_INET6:
480 {
481 struct sockaddr_in6 sin6; /* use static var for safety */
482 int niflags = 0;
355
356 memset(&sin6, 0, sizeof(sin6));
357 memcpy(&sin6, sa, sa->sa_len);
358 sin6.sin6_len = sizeof(struct sockaddr_in6);
359 sin6.sin6_family = AF_INET6;
360#ifdef __KAME__
361 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
362 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
363 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
364 sin6.sin6_scope_id == 0) {
365 sin6.sin6_scope_id =
366 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
367 sin6.sin6_addr.s6_addr[2] = 0;
368 sin6.sin6_addr.s6_addr[3] = 0;
369 }
370#endif
371 if (nflag)
372 niflags |= NI_NUMERICHOST;
373 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
374 line, sizeof(line), NULL, 0, niflags) != 0)
375 strncpy(line, "invalid", sizeof(line));
376
377 return(line);
378 }
379#endif
380
381 case AF_APPLETALK:
382 (void) snprintf(line, sizeof(line), "atalk %s",
383 atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
384 break;
385
386 case AF_LINK:
387 return (link_ntoa((struct sockaddr_dl *)sa));
388
389 default:
390 { u_short *s = (u_short *)sa;
391 u_short *slim = s + ((sa->sa_len + 1) >> 1);
392 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
393 char *cpe = line + sizeof(line);
394
395 while (++s < slim && cp < cpe) /* start with sa->sa_data */
396 if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
397 cp += n;
398 else
399 *cp = '\0';
400 break;
401 }
402 }
403 return (line);
404}
405
406/*
407 * Return the name of the network whose address is given.
408 * The address is assumed to be that of a net or subnet, not a host.
409 */
410const char *
411netname(sa)
412 struct sockaddr *sa;
413{
414 char *cp = 0;
415 static char line[MAXHOSTNAMELEN + 1];
416 struct netent *np = 0;
417 u_long net, mask;
418 u_long i;
419 int n, subnetshift;
420
421 switch (sa->sa_family) {
422
423 case AF_INET:
424 { struct in_addr in;
425 in = ((struct sockaddr_in *)sa)->sin_addr;
426
427 i = in.s_addr = ntohl(in.s_addr);
428 if (in.s_addr == 0)
429 cp = "default";
430 else if (!nflag) {
431 if (IN_CLASSA(i)) {
432 mask = IN_CLASSA_NET;
433 subnetshift = 8;
434 } else if (IN_CLASSB(i)) {
435 mask = IN_CLASSB_NET;
436 subnetshift = 8;
437 } else {
438 mask = IN_CLASSC_NET;
439 subnetshift = 4;
440 }
441 /*
442 * If there are more bits than the standard mask
443 * would suggest, subnets must be in use.
444 * Guess at the subnet mask, assuming reasonable
445 * width subnet fields.
446 */
447 while (in.s_addr &~ mask)
448 mask = (long)mask >> subnetshift;
449 net = in.s_addr & mask;
450 while ((mask & 1) == 0)
451 mask >>= 1, net >>= 1;
452 np = getnetbyaddr(net, AF_INET);
453 if (np)
454 cp = np->n_name;
455 }
456#define C(x) (unsigned)((x) & 0xff)
457 if (cp)
458 strncpy(line, cp, sizeof(line));
459 else if ((in.s_addr & 0xffffff) == 0)
460 (void) sprintf(line, "%u", C(in.s_addr >> 24));
461 else if ((in.s_addr & 0xffff) == 0)
462 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
463 C(in.s_addr >> 16));
464 else if ((in.s_addr & 0xff) == 0)
465 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
466 C(in.s_addr >> 16), C(in.s_addr >> 8));
467 else
468 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
469 C(in.s_addr >> 16), C(in.s_addr >> 8),
470 C(in.s_addr));
471#undef C
472 break;
473 }
474
475#ifdef INET6
476 case AF_INET6:
477 {
478 struct sockaddr_in6 sin6; /* use static var for safety */
479 int niflags = 0;
483#ifdef NI_WITHSCOPEID
484 niflags = NI_WITHSCOPEID;
485#endif
486
487 memset(&sin6, 0, sizeof(sin6));
488 memcpy(&sin6, sa, sa->sa_len);
489 sin6.sin6_len = sizeof(struct sockaddr_in6);
490 sin6.sin6_family = AF_INET6;
491#ifdef __KAME__
492 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
493 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
494 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
495 sin6.sin6_scope_id == 0) {
496 sin6.sin6_scope_id =
497 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
498 sin6.sin6_addr.s6_addr[2] = 0;
499 sin6.sin6_addr.s6_addr[3] = 0;
500 }
501#endif
502 if (nflag)
503 niflags |= NI_NUMERICHOST;
504 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
505 line, sizeof(line), NULL, 0, niflags) != 0)
506 strncpy(line, "invalid", sizeof(line));
507
508 return(line);
509 }
510#endif
511
512 case AF_APPLETALK:
513 (void) snprintf(line, sizeof(line), "atalk %s",
514 atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
515 break;
516
517 case AF_LINK:
518 return (link_ntoa((struct sockaddr_dl *)sa));
519
520
521 default:
522 { u_short *s = (u_short *)sa->sa_data;
523 u_short *slim = s + ((sa->sa_len + 1)>>1);
524 char *cp = line + sprintf(line, "af %d:", sa->sa_family);
525 char *cpe = line + sizeof(line);
526
527 while (s < slim && cp < cpe)
528 if ((n = snprintf(cp, cpe - cp, " %x", *s++)) > 0)
529 cp += n;
530 else
531 *cp = '\0';
532 break;
533 }
534 }
535 return (line);
536}
537
538void
539set_metric(value, key)
540 char *value;
541 int key;
542{
543 int flag = 0;
544 u_long noval, *valp = &noval;
545
546 switch (key) {
547#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
548 caseof(K_MTU, RTV_MTU, rmx_mtu);
549 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
550 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
551 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
552 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
553 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
554 caseof(K_RTT, RTV_RTT, rmx_rtt);
555 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
556 }
557 rtm_inits |= flag;
558 if (lockrest || locking)
559 rt_metrics.rmx_locks |= flag;
560 if (locking)
561 locking = 0;
562 *valp = atoi(value);
563}
564
565void
566newroute(argc, argv)
567 int argc;
568 char **argv;
569{
570 char *cmd, *dest = "", *gateway = "", *err;
571 int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC;
572 int key;
573 struct hostent *hp = 0;
574
575 if (uid) {
576 errx(EX_NOPERM, "must be root to alter routing table");
577 }
578 cmd = argv[0];
579 if (*cmd != 'g')
580 shutdown(s, SHUT_RD); /* Don't want to read back our messages */
581 while (--argc > 0) {
582 if (**(++argv)== '-') {
583 switch (key = keyword(1 + *argv)) {
584 case K_LINK:
585 af = AF_LINK;
586 aflen = sizeof(struct sockaddr_dl);
587 break;
588 case K_INET:
589 af = AF_INET;
590 aflen = sizeof(struct sockaddr_in);
591 break;
592#ifdef INET6
593 case K_INET6:
594 af = AF_INET6;
595 aflen = sizeof(struct sockaddr_in6);
596 break;
597#endif
598 case K_ATALK:
599 af = AF_APPLETALK;
600 aflen = sizeof(struct sockaddr_at);
601 break;
602 case K_SA:
603 af = PF_ROUTE;
604 aflen = sizeof(union sockunion);
605 break;
606 case K_IFACE:
607 case K_INTERFACE:
608 iflag++;
609 break;
610 case K_NOSTATIC:
611 flags &= ~RTF_STATIC;
612 break;
613 case K_LLINFO:
614 flags |= RTF_LLINFO;
615 break;
616 case K_LOCK:
617 locking = 1;
618 break;
619 case K_LOCKREST:
620 lockrest = 1;
621 break;
622 case K_HOST:
623 forcehost++;
624 break;
625 case K_REJECT:
626 flags |= RTF_REJECT;
627 break;
628 case K_BLACKHOLE:
629 flags |= RTF_BLACKHOLE;
630 break;
631 case K_PROTO1:
632 flags |= RTF_PROTO1;
633 break;
634 case K_PROTO2:
635 flags |= RTF_PROTO2;
636 break;
637 case K_PROXY:
638 proxy = 1;
639 break;
640 case K_CLONING:
641 flags |= RTF_CLONING;
642 break;
643 case K_XRESOLVE:
644 flags |= RTF_XRESOLVE;
645 break;
646 case K_STATIC:
647 flags |= RTF_STATIC;
648 break;
649 case K_IFA:
650 if (!--argc)
651 usage((char *)NULL);
652 (void) getaddr(RTA_IFA, *++argv, 0);
653 break;
654 case K_IFP:
655 if (!--argc)
656 usage((char *)NULL);
657 (void) getaddr(RTA_IFP, *++argv, 0);
658 break;
659 case K_GENMASK:
660 if (!--argc)
661 usage((char *)NULL);
662 (void) getaddr(RTA_GENMASK, *++argv, 0);
663 break;
664 case K_GATEWAY:
665 if (!--argc)
666 usage((char *)NULL);
667 (void) getaddr(RTA_GATEWAY, *++argv, 0);
668 break;
669 case K_DST:
670 if (!--argc)
671 usage((char *)NULL);
672 ishost = getaddr(RTA_DST, *++argv, &hp);
673 dest = *argv;
674 break;
675 case K_NETMASK:
676 if (!--argc)
677 usage((char *)NULL);
678 (void) getaddr(RTA_NETMASK, *++argv, 0);
679 /* FALLTHROUGH */
680 case K_NET:
681 forcenet++;
682 break;
683 case K_PREFIXLEN:
684 if (!--argc)
685 usage((char *)NULL);
686 if (prefixlen(*++argv) == -1) {
687 forcenet = 0;
688 ishost = 1;
689 } else {
690 forcenet = 1;
691 ishost = 0;
692 }
693 break;
694 case K_MTU:
695 case K_HOPCOUNT:
696 case K_EXPIRE:
697 case K_RECVPIPE:
698 case K_SENDPIPE:
699 case K_SSTHRESH:
700 case K_RTT:
701 case K_RTTVAR:
702 if (!--argc)
703 usage((char *)NULL);
704 set_metric(*++argv, key);
705 break;
706 default:
707 usage(1+*argv);
708 }
709 } else {
710 if ((rtm_addrs & RTA_DST) == 0) {
711 dest = *argv;
712 ishost = getaddr(RTA_DST, *argv, &hp);
713 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
714 gateway = *argv;
715 (void) getaddr(RTA_GATEWAY, *argv, &hp);
716 } else {
717 (void) getaddr(RTA_NETMASK, *argv, 0);
718 forcenet = 1;
719 }
720 }
721 }
722 if (forcehost) {
723 ishost = 1;
724#ifdef INET6
725 if (af == AF_INET6) {
726 rtm_addrs &= ~RTA_NETMASK;
727 memset((void *)&so_mask, 0, sizeof(so_mask));
728 }
729#endif
730 }
731 if (forcenet)
732 ishost = 0;
733 flags |= RTF_UP;
734 if (ishost)
735 flags |= RTF_HOST;
736 if (iflag == 0)
737 flags |= RTF_GATEWAY;
738 if (proxy) {
739 so_dst.sinarp.sin_other = SIN_PROXY;
740 flags |= RTF_ANNOUNCE;
741 }
742 for (attempts = 1; ; attempts++) {
743 errno = 0;
744 if ((ret = rtmsg(*cmd, flags)) == 0)
745 break;
746 if (errno != ENETUNREACH && errno != ESRCH)
747 break;
748 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
749 hp->h_addr_list++;
750 memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
751 MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
752 } else
753 break;
754 }
755 if (*cmd == 'g')
756 exit(0);
757 if (!qflag) {
758 oerrno = errno;
759 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
760 if (*gateway) {
761 (void) printf(": gateway %s", gateway);
762 if (attempts > 1 && ret == 0 && af == AF_INET)
763 (void) printf(" (%s)",
764 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
765 }
766 if (ret == 0) {
767 (void) printf("\n");
768 } else {
769 switch (oerrno) {
770 case ESRCH:
771 err = "not in table";
772 break;
773 case EBUSY:
774 err = "entry in use";
775 break;
776 case ENOBUFS:
777 err = "routing table overflow";
778 break;
779 case EDQUOT: /* handle recursion avoidance in rt_setgate() */
780 err = "gateway uses the same route";
781 break;
782 default:
783 err = strerror(oerrno);
784 break;
785 }
786 (void) printf(": %s\n", err);
787 }
788 }
789 exit(ret != 0);
790}
791
792void
793inet_makenetandmask(net, sin, bits)
794 u_long net, bits;
795 struct sockaddr_in *sin;
796{
797 u_long addr, mask = 0;
798 char *cp;
799
800 rtm_addrs |= RTA_NETMASK;
801 if (net == 0)
802 mask = addr = 0;
803 else if (net < 128) {
804 addr = net << IN_CLASSA_NSHIFT;
805 mask = IN_CLASSA_NET;
806 } else if (net < 65536) {
807 addr = net << IN_CLASSB_NSHIFT;
808 mask = IN_CLASSB_NET;
809 } else if (net < 16777216L) {
810 addr = net << IN_CLASSC_NSHIFT;
811 mask = IN_CLASSC_NET;
812 } else {
813 addr = net;
814 if ((addr & IN_CLASSA_HOST) == 0)
815 mask = IN_CLASSA_NET;
816 else if ((addr & IN_CLASSB_HOST) == 0)
817 mask = IN_CLASSB_NET;
818 else if ((addr & IN_CLASSC_HOST) == 0)
819 mask = IN_CLASSC_NET;
820 else
821 mask = -1;
822 }
823 if (bits)
824 mask = 0xffffffff << (32 - bits);
825 sin->sin_addr.s_addr = htonl(addr);
826 sin = &so_mask.sin;
827 sin->sin_addr.s_addr = htonl(mask);
828 sin->sin_len = 0;
829 sin->sin_family = 0;
830 cp = (char *)(&sin->sin_addr + 1);
831 while (*--cp == 0 && cp > (char *)sin)
832 ;
833 sin->sin_len = 1 + cp - (char *)sin;
834}
835
836#ifdef INET6
837/*
838 * XXX the function may need more improvement...
839 */
840static int
841inet6_makenetandmask(sin6, plen)
842 struct sockaddr_in6 *sin6;
843 char *plen;
844{
845 struct in6_addr in6;
846
847 if (!plen) {
848 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
849 sin6->sin6_scope_id == 0) {
850 plen = "0";
851 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
852 /* aggregatable global unicast - RFC2374 */
853 memset(&in6, 0, sizeof(in6));
854 if (!memcmp(&sin6->sin6_addr.s6_addr[8],
855 &in6.s6_addr[8], 8))
856 plen = "64";
857 }
858 }
859
860 if (!plen || strcmp(plen, "128") == 0)
861 return 1;
862 rtm_addrs |= RTA_NETMASK;
863 (void)prefixlen(plen);
864 return 0;
865}
866#endif
867
868/*
869 * Interpret an argument as a network address of some kind,
870 * returning 1 if a host address, 0 if a network address.
871 */
872int
873getaddr(which, s, hpp)
874 int which;
875 char *s;
876 struct hostent **hpp;
877{
878 sup su;
879 struct hostent *hp;
880 struct netent *np;
881 u_long val;
882 char *q;
883 int afamily; /* local copy of af so we can change it */
884
885 if (af == 0) {
886 af = AF_INET;
887 aflen = sizeof(struct sockaddr_in);
888 }
889 afamily = af;
890 rtm_addrs |= which;
891 switch (which) {
892 case RTA_DST:
893 su = &so_dst;
894 break;
895 case RTA_GATEWAY:
896 su = &so_gate;
897 if (iflag) {
898 struct ifaddrs *ifap, *ifa;
899 struct sockaddr_dl *sdl = NULL;
900
901 if (getifaddrs(&ifap))
902 err(1, "getifaddrs");
903
904 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
905 if (ifa->ifa_addr->sa_family != AF_LINK)
906 continue;
907
908 if (strcmp(s, ifa->ifa_name))
909 continue;
910
911 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
912 }
913 /* If we found it, then use it */
914 if (sdl) {
915 /*
916 * Copy is safe since we have a
917 * sockaddr_storage member in sockunion{}.
918 * Note that we need to copy before calling
919 * freeifaddrs().
920 */
921 memcpy(&su->sdl, sdl, sdl->sdl_len);
922 }
923 freeifaddrs(ifap);
924 if (sdl)
925 return(1);
926 }
927 break;
928 case RTA_NETMASK:
929 su = &so_mask;
930 break;
931 case RTA_GENMASK:
932 su = &so_genmask;
933 break;
934 case RTA_IFP:
935 su = &so_ifp;
936 afamily = AF_LINK;
937 break;
938 case RTA_IFA:
939 su = &so_ifa;
940 break;
941 default:
942 usage("internal error");
943 /*NOTREACHED*/
944 }
945 su->sa.sa_len = aflen;
946 su->sa.sa_family = afamily; /* cases that don't want it have left already */
947 if (strcmp(s, "default") == 0) {
948 /*
949 * Default is net 0.0.0.0/0
950 */
951 switch (which) {
952 case RTA_DST:
953 forcenet++;
954#if 0
955 bzero(su, sizeof(*su)); /* for readability */
956#endif
957 (void) getaddr(RTA_NETMASK, s, 0);
958 break;
959#if 0
960 case RTA_NETMASK:
961 case RTA_GENMASK:
962 bzero(su, sizeof(*su)); /* for readability */
963#endif
964 }
965 return (0);
966 }
967 switch (afamily) {
968#ifdef INET6
969 case AF_INET6:
970 {
971 struct addrinfo hints, *res;
972
973 q = NULL;
974 if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
975 *q = '\0';
976 memset(&hints, 0, sizeof(hints));
977 hints.ai_family = afamily; /*AF_INET6*/
978 hints.ai_flags = AI_NUMERICHOST;
979 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
980 if (getaddrinfo(s, "0", &hints, &res) != 0 ||
981 res->ai_family != AF_INET6 ||
982 res->ai_addrlen != sizeof(su->sin6)) {
983 (void) fprintf(stderr, "%s: bad value\n", s);
984 exit(1);
985 }
986 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
987#ifdef __KAME__
988 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
989 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
990 su->sin6.sin6_scope_id) {
991 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
992 htons(su->sin6.sin6_scope_id);
993 su->sin6.sin6_scope_id = 0;
994 }
995#endif
996 freeaddrinfo(res);
997 if (q != NULL)
998 *q++ = '/';
999 if (which == RTA_DST)
1000 return (inet6_makenetandmask(&su->sin6, q));
1001 return (0);
1002 }
1003#endif /* INET6 */
1004
1005 case AF_APPLETALK:
1006 if (!atalk_aton(s, &su->sat.sat_addr))
1007 errx(EX_NOHOST, "bad address: %s", s);
1008 rtm_addrs |= RTA_NETMASK;
1009 return(forcehost || su->sat.sat_addr.s_node != 0);
1010
1011 case AF_LINK:
1012 link_addr(s, &su->sdl);
1013 return (1);
1014
1015
1016 case PF_ROUTE:
1017 su->sa.sa_len = sizeof(*su);
1018 sockaddr(s, &su->sa);
1019 return (1);
1020
1021 case AF_INET:
1022 default:
1023 break;
1024 }
1025
1026 if (hpp == NULL)
1027 hpp = &hp;
1028 *hpp = NULL;
1029
1030 q = strchr(s,'/');
1031 if (q && which == RTA_DST) {
1032 *q = '\0';
1033 if ((val = inet_network(s)) != INADDR_NONE) {
1034 inet_makenetandmask(
1035 val, &su->sin, strtoul(q+1, 0, 0));
1036 return (0);
1037 }
1038 *q = '/';
1039 }
1040 if ((which != RTA_DST || forcenet == 0) &&
1041 inet_aton(s, &su->sin.sin_addr)) {
1042 val = su->sin.sin_addr.s_addr;
1043 if (which != RTA_DST || forcehost ||
1044 inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1045 return (1);
1046 else {
1047 val = ntohl(val);
1048 goto netdone;
1049 }
1050 }
1051 if (which == RTA_DST && forcehost == 0 &&
1052 ((val = inet_network(s)) != INADDR_NONE ||
1053 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
1054netdone:
1055 inet_makenetandmask(val, &su->sin, 0);
1056 return (0);
1057 }
1058 hp = gethostbyname(s);
1059 if (hp) {
1060 *hpp = hp;
1061 su->sin.sin_family = hp->h_addrtype;
1062 memmove((char *)&su->sin.sin_addr, hp->h_addr,
1063 MIN(hp->h_length, sizeof(su->sin.sin_addr)));
1064 return (1);
1065 }
1066 errx(EX_NOHOST, "bad address: %s", s);
1067}
1068
1069int
1070prefixlen(s)
1071 char *s;
1072{
1073 int len = atoi(s), q, r;
1074 int max;
1075 char *p;
1076
1077 rtm_addrs |= RTA_NETMASK;
1078 switch (af) {
1079#ifdef INET6
1080 case AF_INET6:
1081 max = 128;
1082 p = (char *)&so_mask.sin6.sin6_addr;
1083 break;
1084#endif
1085 case AF_INET:
1086 max = 32;
1087 p = (char *)&so_mask.sin.sin_addr;
1088 break;
1089 default:
1090 (void) fprintf(stderr, "prefixlen not supported in this af\n");
1091 exit(1);
1092 /*NOTREACHED*/
1093 }
1094
1095 if (len < 0 || max < len) {
1096 (void) fprintf(stderr, "%s: bad value\n", s);
1097 exit(1);
1098 }
1099
1100 q = len >> 3;
1101 r = len & 7;
1102 so_mask.sa.sa_family = af;
1103 so_mask.sa.sa_len = aflen;
1104 memset((void *)p, 0, max / 8);
1105 if (q > 0)
1106 memset((void *)p, 0xff, q);
1107 if (r > 0)
1108 *((u_char *)p + q) = (0xff00 >> r) & 0xff;
1109 if (len == max)
1110 return -1;
1111 else
1112 return len;
1113}
1114
1115void
1116interfaces()
1117{
1118 size_t needed;
1119 int mib[6];
1120 char *buf, *lim, *next, count = 0;
1121 struct rt_msghdr *rtm;
1122
1123retry2:
1124 mib[0] = CTL_NET;
1125 mib[1] = PF_ROUTE;
1126 mib[2] = 0; /* protocol */
1127 mib[3] = 0; /* wildcard address family */
1128 mib[4] = NET_RT_IFLIST;
1129 mib[5] = 0; /* no flags */
1130 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1131 err(EX_OSERR, "route-sysctl-estimate");
1132 if ((buf = malloc(needed)) == NULL)
1133 errx(EX_OSERR, "malloc failed");
1134 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1135 if (errno == ENOMEM && count++ < 10) {
1136 warnx("Routing table grew, retrying");
1137 sleep(1);
1138 free(buf);
1139 goto retry2;
1140 }
1141 err(EX_OSERR, "actual retrieval of interface table");
1142 }
1143 lim = buf + needed;
1144 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1145 rtm = (struct rt_msghdr *)next;
1146 print_rtmsg(rtm, rtm->rtm_msglen);
1147 }
1148}
1149
1150void
1151monitor()
1152{
1153 int n;
1154 char msg[2048];
1155
1156 verbose = 1;
1157 if (debugonly) {
1158 interfaces();
1159 exit(0);
1160 }
1161 for(;;) {
1162 time_t now;
1163 n = read(s, msg, 2048);
1164 now = time(NULL);
1165 (void) printf("\ngot message of size %d on %s", n, ctime(&now));
1166 print_rtmsg((struct rt_msghdr *)msg, n);
1167 }
1168}
1169
1170struct {
1171 struct rt_msghdr m_rtm;
1172 char m_space[512];
1173} m_rtmsg;
1174
1175int
1176rtmsg(cmd, flags)
1177 int cmd, flags;
1178{
1179 static int seq;
1180 int rlen;
1181 char *cp = m_rtmsg.m_space;
1182 int l;
1183
1184#define NEXTADDR(w, u) \
1185 if (rtm_addrs & (w)) {\
1186 l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\
1187 if (verbose) sodump(&(u),"u");\
1188 }
1189
1190 errno = 0;
1191 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1192 if (cmd == 'a')
1193 cmd = RTM_ADD;
1194 else if (cmd == 'c')
1195 cmd = RTM_CHANGE;
1196 else if (cmd == 'g') {
1197 cmd = RTM_GET;
1198 if (so_ifp.sa.sa_family == 0) {
1199 so_ifp.sa.sa_family = AF_LINK;
1200 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1201 rtm_addrs |= RTA_IFP;
1202 }
1203 } else
1204 cmd = RTM_DELETE;
1205#define rtm m_rtmsg.m_rtm
1206 rtm.rtm_type = cmd;
1207 rtm.rtm_flags = flags;
1208 rtm.rtm_version = RTM_VERSION;
1209 rtm.rtm_seq = ++seq;
1210 rtm.rtm_addrs = rtm_addrs;
1211 rtm.rtm_rmx = rt_metrics;
1212 rtm.rtm_inits = rtm_inits;
1213
1214 if (rtm_addrs & RTA_NETMASK)
1215 mask_addr();
1216 NEXTADDR(RTA_DST, so_dst);
1217 NEXTADDR(RTA_GATEWAY, so_gate);
1218 NEXTADDR(RTA_NETMASK, so_mask);
1219 NEXTADDR(RTA_GENMASK, so_genmask);
1220 NEXTADDR(RTA_IFP, so_ifp);
1221 NEXTADDR(RTA_IFA, so_ifa);
1222 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1223 if (verbose)
1224 print_rtmsg(&rtm, l);
1225 if (debugonly)
1226 return (0);
1227 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1228 if (errno == EPERM)
1229 err(1, "writing to routing socket");
1230 warn("writing to routing socket");
1231 return (-1);
1232 }
1233 if (cmd == RTM_GET) {
1234 do {
1235 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1236 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1237 if (l < 0)
1238 warn("read from routing socket");
1239 else
1240 print_getmsg(&rtm, l);
1241 }
1242#undef rtm
1243 return (0);
1244}
1245
1246void
1247mask_addr()
1248{
1249 int olen = so_mask.sa.sa_len;
1250 char *cp1 = olen + (char *)&so_mask, *cp2;
1251
1252 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1253 if (*--cp1 != 0) {
1254 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1255 break;
1256 }
1257 if ((rtm_addrs & RTA_DST) == 0)
1258 return;
1259 switch (so_dst.sa.sa_family) {
1260 case AF_INET:
1261#ifdef INET6
1262 case AF_INET6:
1263#endif
1264 case AF_APPLETALK:
1265 case 0:
1266 return;
1267 }
1268 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1269 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1270 while (cp2 > cp1)
1271 *--cp2 = 0;
1272 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1273 while (cp1 > so_dst.sa.sa_data)
1274 *--cp1 &= *--cp2;
1275}
1276
1277char *msgtypes[] = {
1278 "",
1279 "RTM_ADD: Add Route",
1280 "RTM_DELETE: Delete Route",
1281 "RTM_CHANGE: Change Metrics or flags",
1282 "RTM_GET: Report Metrics",
1283 "RTM_LOSING: Kernel Suspects Partitioning",
1284 "RTM_REDIRECT: Told to use different route",
1285 "RTM_MISS: Lookup failed on this address",
1286 "RTM_LOCK: fix specified metrics",
1287 "RTM_OLDADD: caused by SIOCADDRT",
1288 "RTM_OLDDEL: caused by SIOCDELRT",
1289 "RTM_RESOLVE: Route created by cloning",
1290 "RTM_NEWADDR: address being added to iface",
1291 "RTM_DELADDR: address being removed from iface",
1292 "RTM_IFINFO: iface status change",
1293 "RTM_NEWMADDR: new multicast group membership on iface",
1294 "RTM_DELMADDR: multicast group membership removed from iface",
1295 "RTM_IFANNOUNCE: interface arrival/departure",
1296 0,
1297};
1298
1299char metricnames[] =
1300"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1301"\1mtu";
1302char routeflags[] =
1303"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1304"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1305"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
1306"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
1307char ifnetflags[] =
1308"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1309"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1310"\017LINK2\020MULTICAST";
1311char addrnames[] =
1312"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1313
1314void
1315print_rtmsg(rtm, msglen)
1316 struct rt_msghdr *rtm;
1317 int msglen;
1318{
1319 struct if_msghdr *ifm;
1320 struct ifa_msghdr *ifam;
1321#ifdef RTM_NEWMADDR
1322 struct ifma_msghdr *ifmam;
1323#endif
1324 struct if_announcemsghdr *ifan;
1325 char *state;
1326
1327 if (verbose == 0)
1328 return;
1329 if (rtm->rtm_version != RTM_VERSION) {
1330 (void) printf("routing message version %d not understood\n",
1331 rtm->rtm_version);
1332 return;
1333 }
1334 if (msgtypes[rtm->rtm_type] != NULL)
1335 (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1336 else
1337 (void)printf("#%d: ", rtm->rtm_type);
1338 (void)printf("len %d, ", rtm->rtm_msglen);
1339 switch (rtm->rtm_type) {
1340 case RTM_IFINFO:
1341 ifm = (struct if_msghdr *)rtm;
1342 (void) printf("if# %d, ", ifm->ifm_index);
1343 switch (ifm->ifm_data.ifi_link_state) {
1344 case LINK_STATE_DOWN:
1345 state = "down";
1346 break;
1347 case LINK_STATE_UP:
1348 state = "up";
1349 break;
1350 default:
1351 state = "unknown";
1352 break;
1353 }
1354 (void) printf("link: %s, flags:", state);
1355 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1356 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1357 break;
1358 case RTM_NEWADDR:
1359 case RTM_DELADDR:
1360 ifam = (struct ifa_msghdr *)rtm;
1361 (void) printf("metric %d, flags:", ifam->ifam_metric);
1362 bprintf(stdout, ifam->ifam_flags, routeflags);
1363 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1364 break;
1365#ifdef RTM_NEWMADDR
1366 case RTM_NEWMADDR:
1367 case RTM_DELMADDR:
1368 ifmam = (struct ifma_msghdr *)rtm;
1369 pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
1370 break;
1371#endif
1372 case RTM_IFANNOUNCE:
1373 ifan = (struct if_announcemsghdr *)rtm;
1374 (void) printf("if# %d, what: ", ifan->ifan_index);
1375 switch (ifan->ifan_what) {
1376 case IFAN_ARRIVAL:
1377 printf("arrival");
1378 break;
1379 case IFAN_DEPARTURE:
1380 printf("departure");
1381 break;
1382 default:
1383 printf("#%d", ifan->ifan_what);
1384 break;
1385 }
1386 printf("\n");
1387 break;
1388
1389 default:
1390 (void) printf("pid: %ld, seq %d, errno %d, flags:",
1391 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1392 bprintf(stdout, rtm->rtm_flags, routeflags);
1393 pmsg_common(rtm);
1394 }
1395}
1396
1397void
1398print_getmsg(rtm, msglen)
1399 struct rt_msghdr *rtm;
1400 int msglen;
1401{
1402 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1403 struct sockaddr_dl *ifp = NULL;
1404 struct sockaddr *sa;
1405 char *cp;
1406 int i;
1407
1408 (void) printf(" route to: %s\n", routename(&so_dst));
1409 if (rtm->rtm_version != RTM_VERSION) {
1410 warnx("routing message version %d not understood",
1411 rtm->rtm_version);
1412 return;
1413 }
1414 if (rtm->rtm_msglen > msglen) {
1415 warnx("message length mismatch, in packet %d, returned %d",
1416 rtm->rtm_msglen, msglen);
1417 }
1418 if (rtm->rtm_errno) {
1419 errno = rtm->rtm_errno;
1420 warn("message indicates error %d", errno);
1421 return;
1422 }
1423 cp = ((char *)(rtm + 1));
1424 if (rtm->rtm_addrs)
1425 for (i = 1; i; i <<= 1)
1426 if (i & rtm->rtm_addrs) {
1427 sa = (struct sockaddr *)cp;
1428 switch (i) {
1429 case RTA_DST:
1430 dst = sa;
1431 break;
1432 case RTA_GATEWAY:
1433 gate = sa;
1434 break;
1435 case RTA_NETMASK:
1436 mask = sa;
1437 break;
1438 case RTA_IFP:
1439 if (sa->sa_family == AF_LINK &&
1440 ((struct sockaddr_dl *)sa)->sdl_nlen)
1441 ifp = (struct sockaddr_dl *)sa;
1442 break;
1443 }
1444 cp += SA_SIZE(sa);
1445 }
1446 if (dst && mask)
1447 mask->sa_family = dst->sa_family; /* XXX */
1448 if (dst)
1449 (void)printf("destination: %s\n", routename(dst));
1450 if (mask) {
1451 int savenflag = nflag;
1452
1453 nflag = 1;
1454 (void)printf(" mask: %s\n", routename(mask));
1455 nflag = savenflag;
1456 }
1457 if (gate && rtm->rtm_flags & RTF_GATEWAY)
1458 (void)printf(" gateway: %s\n", routename(gate));
1459 if (ifp)
1460 (void)printf(" interface: %.*s\n",
1461 ifp->sdl_nlen, ifp->sdl_data);
1462 (void)printf(" flags: ");
1463 bprintf(stdout, rtm->rtm_flags, routeflags);
1464
1465#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1466#define msec(u) (((u) + 500) / 1000) /* usec to msec */
1467
1468 (void) printf("\n%s\n", "\
1469 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1470 printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1471 printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1472 printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1473 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1474 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1475 printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1476 printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1477 if (rtm->rtm_rmx.rmx_expire)
1478 rtm->rtm_rmx.rmx_expire -= time(0);
1479 printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1480#undef lock
1481#undef msec
1482#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1483 if (verbose)
1484 pmsg_common(rtm);
1485 else if (rtm->rtm_addrs &~ RTA_IGN) {
1486 (void) printf("sockaddrs: ");
1487 bprintf(stdout, rtm->rtm_addrs, addrnames);
1488 putchar('\n');
1489 }
1490#undef RTA_IGN
1491}
1492
1493void
1494pmsg_common(rtm)
1495 struct rt_msghdr *rtm;
1496{
1497 (void) printf("\nlocks: ");
1498 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1499 (void) printf(" inits: ");
1500 bprintf(stdout, rtm->rtm_inits, metricnames);
1501 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1502}
1503
1504void
1505pmsg_addrs(cp, addrs)
1506 char *cp;
1507 int addrs;
1508{
1509 struct sockaddr *sa;
1510 int i;
1511
1512 if (addrs == 0) {
1513 (void) putchar('\n');
1514 return;
1515 }
1516 (void) printf("\nsockaddrs: ");
1517 bprintf(stdout, addrs, addrnames);
1518 (void) putchar('\n');
1519 for (i = 1; i; i <<= 1)
1520 if (i & addrs) {
1521 sa = (struct sockaddr *)cp;
1522 (void) printf(" %s", routename(sa));
1523 cp += SA_SIZE(sa);
1524 }
1525 (void) putchar('\n');
1526 (void) fflush(stdout);
1527}
1528
1529void
1530bprintf(fp, b, s)
1531 FILE *fp;
1532 int b;
1533 u_char *s;
1534{
1535 int i;
1536 int gotsome = 0;
1537
1538 if (b == 0)
1539 return;
1540 while ((i = *s++) != 0) {
1541 if (b & (1 << (i-1))) {
1542 if (gotsome == 0)
1543 i = '<';
1544 else
1545 i = ',';
1546 (void) putc(i, fp);
1547 gotsome = 1;
1548 for (; (i = *s) > 32; s++)
1549 (void) putc(i, fp);
1550 } else
1551 while (*s > 32)
1552 s++;
1553 }
1554 if (gotsome)
1555 (void) putc('>', fp);
1556}
1557
1558int
1559keyword(cp)
1560 char *cp;
1561{
1562 struct keytab *kt = keywords;
1563
1564 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1565 kt++;
1566 return kt->kt_i;
1567}
1568
1569void
1570sodump(su, which)
1571 sup su;
1572 char *which;
1573{
1574 switch (su->sa.sa_family) {
1575 case AF_LINK:
1576 (void) printf("%s: link %s; ",
1577 which, link_ntoa(&su->sdl));
1578 break;
1579 case AF_INET:
1580 (void) printf("%s: inet %s; ",
1581 which, inet_ntoa(su->sin.sin_addr));
1582 break;
1583 case AF_APPLETALK:
1584 (void) printf("%s: atalk %s; ",
1585 which, atalk_ntoa(su->sat.sat_addr));
1586 break;
1587 }
1588 (void) fflush(stdout);
1589}
1590
1591/* States*/
1592#define VIRGIN 0
1593#define GOTONE 1
1594#define GOTTWO 2
1595/* Inputs */
1596#define DIGIT (4*0)
1597#define END (4*1)
1598#define DELIM (4*2)
1599
1600void
1601sockaddr(addr, sa)
1602 char *addr;
1603 struct sockaddr *sa;
1604{
1605 char *cp = (char *)sa;
1606 int size = sa->sa_len;
1607 char *cplim = cp + size;
1608 int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
1609
1610 memset(cp, 0, size);
1611 cp++;
1612 do {
1613 if ((*addr >= '0') && (*addr <= '9')) {
1614 new = *addr - '0';
1615 } else if ((*addr >= 'a') && (*addr <= 'f')) {
1616 new = *addr - 'a' + 10;
1617 } else if ((*addr >= 'A') && (*addr <= 'F')) {
1618 new = *addr - 'A' + 10;
1619 } else if (*addr == 0)
1620 state |= END;
1621 else
1622 state |= DELIM;
1623 addr++;
1624 switch (state /* | INPUT */) {
1625 case GOTTWO | DIGIT:
1626 *cp++ = byte; /*FALLTHROUGH*/
1627 case VIRGIN | DIGIT:
1628 state = GOTONE; byte = new; continue;
1629 case GOTONE | DIGIT:
1630 state = GOTTWO; byte = new + (byte << 4); continue;
1631 default: /* | DELIM */
1632 state = VIRGIN; *cp++ = byte; byte = 0; continue;
1633 case GOTONE | END:
1634 case GOTTWO | END:
1635 *cp++ = byte; /* FALLTHROUGH */
1636 case VIRGIN | END:
1637 break;
1638 }
1639 break;
1640 } while (cp < cplim);
1641 sa->sa_len = cp - (char *)sa;
1642}
1643
1644int
1645atalk_aton(const char *text, struct at_addr *addr)
1646{
1647 u_int net, node;
1648
1649 if (sscanf(text, "%u.%u", &net, &node) != 2
1650 || net > 0xffff || node > 0xff)
1651 return(0);
1652 addr->s_net = htons(net);
1653 addr->s_node = node;
1654 return(1);
1655}
1656
1657char *
1658atalk_ntoa(struct at_addr at)
1659{
1660 static char buf[20];
1661
1662 (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
1663 return(buf);
1664}
480
481 memset(&sin6, 0, sizeof(sin6));
482 memcpy(&sin6, sa, sa->sa_len);
483 sin6.sin6_len = sizeof(struct sockaddr_in6);
484 sin6.sin6_family = AF_INET6;
485#ifdef __KAME__
486 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
487 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
488 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
489 sin6.sin6_scope_id == 0) {
490 sin6.sin6_scope_id =
491 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
492 sin6.sin6_addr.s6_addr[2] = 0;
493 sin6.sin6_addr.s6_addr[3] = 0;
494 }
495#endif
496 if (nflag)
497 niflags |= NI_NUMERICHOST;
498 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
499 line, sizeof(line), NULL, 0, niflags) != 0)
500 strncpy(line, "invalid", sizeof(line));
501
502 return(line);
503 }
504#endif
505
506 case AF_APPLETALK:
507 (void) snprintf(line, sizeof(line), "atalk %s",
508 atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
509 break;
510
511 case AF_LINK:
512 return (link_ntoa((struct sockaddr_dl *)sa));
513
514
515 default:
516 { u_short *s = (u_short *)sa->sa_data;
517 u_short *slim = s + ((sa->sa_len + 1)>>1);
518 char *cp = line + sprintf(line, "af %d:", sa->sa_family);
519 char *cpe = line + sizeof(line);
520
521 while (s < slim && cp < cpe)
522 if ((n = snprintf(cp, cpe - cp, " %x", *s++)) > 0)
523 cp += n;
524 else
525 *cp = '\0';
526 break;
527 }
528 }
529 return (line);
530}
531
532void
533set_metric(value, key)
534 char *value;
535 int key;
536{
537 int flag = 0;
538 u_long noval, *valp = &noval;
539
540 switch (key) {
541#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
542 caseof(K_MTU, RTV_MTU, rmx_mtu);
543 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
544 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
545 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
546 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
547 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
548 caseof(K_RTT, RTV_RTT, rmx_rtt);
549 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
550 }
551 rtm_inits |= flag;
552 if (lockrest || locking)
553 rt_metrics.rmx_locks |= flag;
554 if (locking)
555 locking = 0;
556 *valp = atoi(value);
557}
558
559void
560newroute(argc, argv)
561 int argc;
562 char **argv;
563{
564 char *cmd, *dest = "", *gateway = "", *err;
565 int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC;
566 int key;
567 struct hostent *hp = 0;
568
569 if (uid) {
570 errx(EX_NOPERM, "must be root to alter routing table");
571 }
572 cmd = argv[0];
573 if (*cmd != 'g')
574 shutdown(s, SHUT_RD); /* Don't want to read back our messages */
575 while (--argc > 0) {
576 if (**(++argv)== '-') {
577 switch (key = keyword(1 + *argv)) {
578 case K_LINK:
579 af = AF_LINK;
580 aflen = sizeof(struct sockaddr_dl);
581 break;
582 case K_INET:
583 af = AF_INET;
584 aflen = sizeof(struct sockaddr_in);
585 break;
586#ifdef INET6
587 case K_INET6:
588 af = AF_INET6;
589 aflen = sizeof(struct sockaddr_in6);
590 break;
591#endif
592 case K_ATALK:
593 af = AF_APPLETALK;
594 aflen = sizeof(struct sockaddr_at);
595 break;
596 case K_SA:
597 af = PF_ROUTE;
598 aflen = sizeof(union sockunion);
599 break;
600 case K_IFACE:
601 case K_INTERFACE:
602 iflag++;
603 break;
604 case K_NOSTATIC:
605 flags &= ~RTF_STATIC;
606 break;
607 case K_LLINFO:
608 flags |= RTF_LLINFO;
609 break;
610 case K_LOCK:
611 locking = 1;
612 break;
613 case K_LOCKREST:
614 lockrest = 1;
615 break;
616 case K_HOST:
617 forcehost++;
618 break;
619 case K_REJECT:
620 flags |= RTF_REJECT;
621 break;
622 case K_BLACKHOLE:
623 flags |= RTF_BLACKHOLE;
624 break;
625 case K_PROTO1:
626 flags |= RTF_PROTO1;
627 break;
628 case K_PROTO2:
629 flags |= RTF_PROTO2;
630 break;
631 case K_PROXY:
632 proxy = 1;
633 break;
634 case K_CLONING:
635 flags |= RTF_CLONING;
636 break;
637 case K_XRESOLVE:
638 flags |= RTF_XRESOLVE;
639 break;
640 case K_STATIC:
641 flags |= RTF_STATIC;
642 break;
643 case K_IFA:
644 if (!--argc)
645 usage((char *)NULL);
646 (void) getaddr(RTA_IFA, *++argv, 0);
647 break;
648 case K_IFP:
649 if (!--argc)
650 usage((char *)NULL);
651 (void) getaddr(RTA_IFP, *++argv, 0);
652 break;
653 case K_GENMASK:
654 if (!--argc)
655 usage((char *)NULL);
656 (void) getaddr(RTA_GENMASK, *++argv, 0);
657 break;
658 case K_GATEWAY:
659 if (!--argc)
660 usage((char *)NULL);
661 (void) getaddr(RTA_GATEWAY, *++argv, 0);
662 break;
663 case K_DST:
664 if (!--argc)
665 usage((char *)NULL);
666 ishost = getaddr(RTA_DST, *++argv, &hp);
667 dest = *argv;
668 break;
669 case K_NETMASK:
670 if (!--argc)
671 usage((char *)NULL);
672 (void) getaddr(RTA_NETMASK, *++argv, 0);
673 /* FALLTHROUGH */
674 case K_NET:
675 forcenet++;
676 break;
677 case K_PREFIXLEN:
678 if (!--argc)
679 usage((char *)NULL);
680 if (prefixlen(*++argv) == -1) {
681 forcenet = 0;
682 ishost = 1;
683 } else {
684 forcenet = 1;
685 ishost = 0;
686 }
687 break;
688 case K_MTU:
689 case K_HOPCOUNT:
690 case K_EXPIRE:
691 case K_RECVPIPE:
692 case K_SENDPIPE:
693 case K_SSTHRESH:
694 case K_RTT:
695 case K_RTTVAR:
696 if (!--argc)
697 usage((char *)NULL);
698 set_metric(*++argv, key);
699 break;
700 default:
701 usage(1+*argv);
702 }
703 } else {
704 if ((rtm_addrs & RTA_DST) == 0) {
705 dest = *argv;
706 ishost = getaddr(RTA_DST, *argv, &hp);
707 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
708 gateway = *argv;
709 (void) getaddr(RTA_GATEWAY, *argv, &hp);
710 } else {
711 (void) getaddr(RTA_NETMASK, *argv, 0);
712 forcenet = 1;
713 }
714 }
715 }
716 if (forcehost) {
717 ishost = 1;
718#ifdef INET6
719 if (af == AF_INET6) {
720 rtm_addrs &= ~RTA_NETMASK;
721 memset((void *)&so_mask, 0, sizeof(so_mask));
722 }
723#endif
724 }
725 if (forcenet)
726 ishost = 0;
727 flags |= RTF_UP;
728 if (ishost)
729 flags |= RTF_HOST;
730 if (iflag == 0)
731 flags |= RTF_GATEWAY;
732 if (proxy) {
733 so_dst.sinarp.sin_other = SIN_PROXY;
734 flags |= RTF_ANNOUNCE;
735 }
736 for (attempts = 1; ; attempts++) {
737 errno = 0;
738 if ((ret = rtmsg(*cmd, flags)) == 0)
739 break;
740 if (errno != ENETUNREACH && errno != ESRCH)
741 break;
742 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
743 hp->h_addr_list++;
744 memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
745 MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
746 } else
747 break;
748 }
749 if (*cmd == 'g')
750 exit(0);
751 if (!qflag) {
752 oerrno = errno;
753 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
754 if (*gateway) {
755 (void) printf(": gateway %s", gateway);
756 if (attempts > 1 && ret == 0 && af == AF_INET)
757 (void) printf(" (%s)",
758 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
759 }
760 if (ret == 0) {
761 (void) printf("\n");
762 } else {
763 switch (oerrno) {
764 case ESRCH:
765 err = "not in table";
766 break;
767 case EBUSY:
768 err = "entry in use";
769 break;
770 case ENOBUFS:
771 err = "routing table overflow";
772 break;
773 case EDQUOT: /* handle recursion avoidance in rt_setgate() */
774 err = "gateway uses the same route";
775 break;
776 default:
777 err = strerror(oerrno);
778 break;
779 }
780 (void) printf(": %s\n", err);
781 }
782 }
783 exit(ret != 0);
784}
785
786void
787inet_makenetandmask(net, sin, bits)
788 u_long net, bits;
789 struct sockaddr_in *sin;
790{
791 u_long addr, mask = 0;
792 char *cp;
793
794 rtm_addrs |= RTA_NETMASK;
795 if (net == 0)
796 mask = addr = 0;
797 else if (net < 128) {
798 addr = net << IN_CLASSA_NSHIFT;
799 mask = IN_CLASSA_NET;
800 } else if (net < 65536) {
801 addr = net << IN_CLASSB_NSHIFT;
802 mask = IN_CLASSB_NET;
803 } else if (net < 16777216L) {
804 addr = net << IN_CLASSC_NSHIFT;
805 mask = IN_CLASSC_NET;
806 } else {
807 addr = net;
808 if ((addr & IN_CLASSA_HOST) == 0)
809 mask = IN_CLASSA_NET;
810 else if ((addr & IN_CLASSB_HOST) == 0)
811 mask = IN_CLASSB_NET;
812 else if ((addr & IN_CLASSC_HOST) == 0)
813 mask = IN_CLASSC_NET;
814 else
815 mask = -1;
816 }
817 if (bits)
818 mask = 0xffffffff << (32 - bits);
819 sin->sin_addr.s_addr = htonl(addr);
820 sin = &so_mask.sin;
821 sin->sin_addr.s_addr = htonl(mask);
822 sin->sin_len = 0;
823 sin->sin_family = 0;
824 cp = (char *)(&sin->sin_addr + 1);
825 while (*--cp == 0 && cp > (char *)sin)
826 ;
827 sin->sin_len = 1 + cp - (char *)sin;
828}
829
830#ifdef INET6
831/*
832 * XXX the function may need more improvement...
833 */
834static int
835inet6_makenetandmask(sin6, plen)
836 struct sockaddr_in6 *sin6;
837 char *plen;
838{
839 struct in6_addr in6;
840
841 if (!plen) {
842 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
843 sin6->sin6_scope_id == 0) {
844 plen = "0";
845 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
846 /* aggregatable global unicast - RFC2374 */
847 memset(&in6, 0, sizeof(in6));
848 if (!memcmp(&sin6->sin6_addr.s6_addr[8],
849 &in6.s6_addr[8], 8))
850 plen = "64";
851 }
852 }
853
854 if (!plen || strcmp(plen, "128") == 0)
855 return 1;
856 rtm_addrs |= RTA_NETMASK;
857 (void)prefixlen(plen);
858 return 0;
859}
860#endif
861
862/*
863 * Interpret an argument as a network address of some kind,
864 * returning 1 if a host address, 0 if a network address.
865 */
866int
867getaddr(which, s, hpp)
868 int which;
869 char *s;
870 struct hostent **hpp;
871{
872 sup su;
873 struct hostent *hp;
874 struct netent *np;
875 u_long val;
876 char *q;
877 int afamily; /* local copy of af so we can change it */
878
879 if (af == 0) {
880 af = AF_INET;
881 aflen = sizeof(struct sockaddr_in);
882 }
883 afamily = af;
884 rtm_addrs |= which;
885 switch (which) {
886 case RTA_DST:
887 su = &so_dst;
888 break;
889 case RTA_GATEWAY:
890 su = &so_gate;
891 if (iflag) {
892 struct ifaddrs *ifap, *ifa;
893 struct sockaddr_dl *sdl = NULL;
894
895 if (getifaddrs(&ifap))
896 err(1, "getifaddrs");
897
898 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
899 if (ifa->ifa_addr->sa_family != AF_LINK)
900 continue;
901
902 if (strcmp(s, ifa->ifa_name))
903 continue;
904
905 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
906 }
907 /* If we found it, then use it */
908 if (sdl) {
909 /*
910 * Copy is safe since we have a
911 * sockaddr_storage member in sockunion{}.
912 * Note that we need to copy before calling
913 * freeifaddrs().
914 */
915 memcpy(&su->sdl, sdl, sdl->sdl_len);
916 }
917 freeifaddrs(ifap);
918 if (sdl)
919 return(1);
920 }
921 break;
922 case RTA_NETMASK:
923 su = &so_mask;
924 break;
925 case RTA_GENMASK:
926 su = &so_genmask;
927 break;
928 case RTA_IFP:
929 su = &so_ifp;
930 afamily = AF_LINK;
931 break;
932 case RTA_IFA:
933 su = &so_ifa;
934 break;
935 default:
936 usage("internal error");
937 /*NOTREACHED*/
938 }
939 su->sa.sa_len = aflen;
940 su->sa.sa_family = afamily; /* cases that don't want it have left already */
941 if (strcmp(s, "default") == 0) {
942 /*
943 * Default is net 0.0.0.0/0
944 */
945 switch (which) {
946 case RTA_DST:
947 forcenet++;
948#if 0
949 bzero(su, sizeof(*su)); /* for readability */
950#endif
951 (void) getaddr(RTA_NETMASK, s, 0);
952 break;
953#if 0
954 case RTA_NETMASK:
955 case RTA_GENMASK:
956 bzero(su, sizeof(*su)); /* for readability */
957#endif
958 }
959 return (0);
960 }
961 switch (afamily) {
962#ifdef INET6
963 case AF_INET6:
964 {
965 struct addrinfo hints, *res;
966
967 q = NULL;
968 if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
969 *q = '\0';
970 memset(&hints, 0, sizeof(hints));
971 hints.ai_family = afamily; /*AF_INET6*/
972 hints.ai_flags = AI_NUMERICHOST;
973 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
974 if (getaddrinfo(s, "0", &hints, &res) != 0 ||
975 res->ai_family != AF_INET6 ||
976 res->ai_addrlen != sizeof(su->sin6)) {
977 (void) fprintf(stderr, "%s: bad value\n", s);
978 exit(1);
979 }
980 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
981#ifdef __KAME__
982 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
983 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
984 su->sin6.sin6_scope_id) {
985 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
986 htons(su->sin6.sin6_scope_id);
987 su->sin6.sin6_scope_id = 0;
988 }
989#endif
990 freeaddrinfo(res);
991 if (q != NULL)
992 *q++ = '/';
993 if (which == RTA_DST)
994 return (inet6_makenetandmask(&su->sin6, q));
995 return (0);
996 }
997#endif /* INET6 */
998
999 case AF_APPLETALK:
1000 if (!atalk_aton(s, &su->sat.sat_addr))
1001 errx(EX_NOHOST, "bad address: %s", s);
1002 rtm_addrs |= RTA_NETMASK;
1003 return(forcehost || su->sat.sat_addr.s_node != 0);
1004
1005 case AF_LINK:
1006 link_addr(s, &su->sdl);
1007 return (1);
1008
1009
1010 case PF_ROUTE:
1011 su->sa.sa_len = sizeof(*su);
1012 sockaddr(s, &su->sa);
1013 return (1);
1014
1015 case AF_INET:
1016 default:
1017 break;
1018 }
1019
1020 if (hpp == NULL)
1021 hpp = &hp;
1022 *hpp = NULL;
1023
1024 q = strchr(s,'/');
1025 if (q && which == RTA_DST) {
1026 *q = '\0';
1027 if ((val = inet_network(s)) != INADDR_NONE) {
1028 inet_makenetandmask(
1029 val, &su->sin, strtoul(q+1, 0, 0));
1030 return (0);
1031 }
1032 *q = '/';
1033 }
1034 if ((which != RTA_DST || forcenet == 0) &&
1035 inet_aton(s, &su->sin.sin_addr)) {
1036 val = su->sin.sin_addr.s_addr;
1037 if (which != RTA_DST || forcehost ||
1038 inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1039 return (1);
1040 else {
1041 val = ntohl(val);
1042 goto netdone;
1043 }
1044 }
1045 if (which == RTA_DST && forcehost == 0 &&
1046 ((val = inet_network(s)) != INADDR_NONE ||
1047 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
1048netdone:
1049 inet_makenetandmask(val, &su->sin, 0);
1050 return (0);
1051 }
1052 hp = gethostbyname(s);
1053 if (hp) {
1054 *hpp = hp;
1055 su->sin.sin_family = hp->h_addrtype;
1056 memmove((char *)&su->sin.sin_addr, hp->h_addr,
1057 MIN(hp->h_length, sizeof(su->sin.sin_addr)));
1058 return (1);
1059 }
1060 errx(EX_NOHOST, "bad address: %s", s);
1061}
1062
1063int
1064prefixlen(s)
1065 char *s;
1066{
1067 int len = atoi(s), q, r;
1068 int max;
1069 char *p;
1070
1071 rtm_addrs |= RTA_NETMASK;
1072 switch (af) {
1073#ifdef INET6
1074 case AF_INET6:
1075 max = 128;
1076 p = (char *)&so_mask.sin6.sin6_addr;
1077 break;
1078#endif
1079 case AF_INET:
1080 max = 32;
1081 p = (char *)&so_mask.sin.sin_addr;
1082 break;
1083 default:
1084 (void) fprintf(stderr, "prefixlen not supported in this af\n");
1085 exit(1);
1086 /*NOTREACHED*/
1087 }
1088
1089 if (len < 0 || max < len) {
1090 (void) fprintf(stderr, "%s: bad value\n", s);
1091 exit(1);
1092 }
1093
1094 q = len >> 3;
1095 r = len & 7;
1096 so_mask.sa.sa_family = af;
1097 so_mask.sa.sa_len = aflen;
1098 memset((void *)p, 0, max / 8);
1099 if (q > 0)
1100 memset((void *)p, 0xff, q);
1101 if (r > 0)
1102 *((u_char *)p + q) = (0xff00 >> r) & 0xff;
1103 if (len == max)
1104 return -1;
1105 else
1106 return len;
1107}
1108
1109void
1110interfaces()
1111{
1112 size_t needed;
1113 int mib[6];
1114 char *buf, *lim, *next, count = 0;
1115 struct rt_msghdr *rtm;
1116
1117retry2:
1118 mib[0] = CTL_NET;
1119 mib[1] = PF_ROUTE;
1120 mib[2] = 0; /* protocol */
1121 mib[3] = 0; /* wildcard address family */
1122 mib[4] = NET_RT_IFLIST;
1123 mib[5] = 0; /* no flags */
1124 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1125 err(EX_OSERR, "route-sysctl-estimate");
1126 if ((buf = malloc(needed)) == NULL)
1127 errx(EX_OSERR, "malloc failed");
1128 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1129 if (errno == ENOMEM && count++ < 10) {
1130 warnx("Routing table grew, retrying");
1131 sleep(1);
1132 free(buf);
1133 goto retry2;
1134 }
1135 err(EX_OSERR, "actual retrieval of interface table");
1136 }
1137 lim = buf + needed;
1138 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1139 rtm = (struct rt_msghdr *)next;
1140 print_rtmsg(rtm, rtm->rtm_msglen);
1141 }
1142}
1143
1144void
1145monitor()
1146{
1147 int n;
1148 char msg[2048];
1149
1150 verbose = 1;
1151 if (debugonly) {
1152 interfaces();
1153 exit(0);
1154 }
1155 for(;;) {
1156 time_t now;
1157 n = read(s, msg, 2048);
1158 now = time(NULL);
1159 (void) printf("\ngot message of size %d on %s", n, ctime(&now));
1160 print_rtmsg((struct rt_msghdr *)msg, n);
1161 }
1162}
1163
1164struct {
1165 struct rt_msghdr m_rtm;
1166 char m_space[512];
1167} m_rtmsg;
1168
1169int
1170rtmsg(cmd, flags)
1171 int cmd, flags;
1172{
1173 static int seq;
1174 int rlen;
1175 char *cp = m_rtmsg.m_space;
1176 int l;
1177
1178#define NEXTADDR(w, u) \
1179 if (rtm_addrs & (w)) {\
1180 l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\
1181 if (verbose) sodump(&(u),"u");\
1182 }
1183
1184 errno = 0;
1185 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1186 if (cmd == 'a')
1187 cmd = RTM_ADD;
1188 else if (cmd == 'c')
1189 cmd = RTM_CHANGE;
1190 else if (cmd == 'g') {
1191 cmd = RTM_GET;
1192 if (so_ifp.sa.sa_family == 0) {
1193 so_ifp.sa.sa_family = AF_LINK;
1194 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1195 rtm_addrs |= RTA_IFP;
1196 }
1197 } else
1198 cmd = RTM_DELETE;
1199#define rtm m_rtmsg.m_rtm
1200 rtm.rtm_type = cmd;
1201 rtm.rtm_flags = flags;
1202 rtm.rtm_version = RTM_VERSION;
1203 rtm.rtm_seq = ++seq;
1204 rtm.rtm_addrs = rtm_addrs;
1205 rtm.rtm_rmx = rt_metrics;
1206 rtm.rtm_inits = rtm_inits;
1207
1208 if (rtm_addrs & RTA_NETMASK)
1209 mask_addr();
1210 NEXTADDR(RTA_DST, so_dst);
1211 NEXTADDR(RTA_GATEWAY, so_gate);
1212 NEXTADDR(RTA_NETMASK, so_mask);
1213 NEXTADDR(RTA_GENMASK, so_genmask);
1214 NEXTADDR(RTA_IFP, so_ifp);
1215 NEXTADDR(RTA_IFA, so_ifa);
1216 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1217 if (verbose)
1218 print_rtmsg(&rtm, l);
1219 if (debugonly)
1220 return (0);
1221 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1222 if (errno == EPERM)
1223 err(1, "writing to routing socket");
1224 warn("writing to routing socket");
1225 return (-1);
1226 }
1227 if (cmd == RTM_GET) {
1228 do {
1229 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1230 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1231 if (l < 0)
1232 warn("read from routing socket");
1233 else
1234 print_getmsg(&rtm, l);
1235 }
1236#undef rtm
1237 return (0);
1238}
1239
1240void
1241mask_addr()
1242{
1243 int olen = so_mask.sa.sa_len;
1244 char *cp1 = olen + (char *)&so_mask, *cp2;
1245
1246 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1247 if (*--cp1 != 0) {
1248 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1249 break;
1250 }
1251 if ((rtm_addrs & RTA_DST) == 0)
1252 return;
1253 switch (so_dst.sa.sa_family) {
1254 case AF_INET:
1255#ifdef INET6
1256 case AF_INET6:
1257#endif
1258 case AF_APPLETALK:
1259 case 0:
1260 return;
1261 }
1262 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1263 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1264 while (cp2 > cp1)
1265 *--cp2 = 0;
1266 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1267 while (cp1 > so_dst.sa.sa_data)
1268 *--cp1 &= *--cp2;
1269}
1270
1271char *msgtypes[] = {
1272 "",
1273 "RTM_ADD: Add Route",
1274 "RTM_DELETE: Delete Route",
1275 "RTM_CHANGE: Change Metrics or flags",
1276 "RTM_GET: Report Metrics",
1277 "RTM_LOSING: Kernel Suspects Partitioning",
1278 "RTM_REDIRECT: Told to use different route",
1279 "RTM_MISS: Lookup failed on this address",
1280 "RTM_LOCK: fix specified metrics",
1281 "RTM_OLDADD: caused by SIOCADDRT",
1282 "RTM_OLDDEL: caused by SIOCDELRT",
1283 "RTM_RESOLVE: Route created by cloning",
1284 "RTM_NEWADDR: address being added to iface",
1285 "RTM_DELADDR: address being removed from iface",
1286 "RTM_IFINFO: iface status change",
1287 "RTM_NEWMADDR: new multicast group membership on iface",
1288 "RTM_DELMADDR: multicast group membership removed from iface",
1289 "RTM_IFANNOUNCE: interface arrival/departure",
1290 0,
1291};
1292
1293char metricnames[] =
1294"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1295"\1mtu";
1296char routeflags[] =
1297"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1298"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1299"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
1300"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
1301char ifnetflags[] =
1302"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1303"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1304"\017LINK2\020MULTICAST";
1305char addrnames[] =
1306"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1307
1308void
1309print_rtmsg(rtm, msglen)
1310 struct rt_msghdr *rtm;
1311 int msglen;
1312{
1313 struct if_msghdr *ifm;
1314 struct ifa_msghdr *ifam;
1315#ifdef RTM_NEWMADDR
1316 struct ifma_msghdr *ifmam;
1317#endif
1318 struct if_announcemsghdr *ifan;
1319 char *state;
1320
1321 if (verbose == 0)
1322 return;
1323 if (rtm->rtm_version != RTM_VERSION) {
1324 (void) printf("routing message version %d not understood\n",
1325 rtm->rtm_version);
1326 return;
1327 }
1328 if (msgtypes[rtm->rtm_type] != NULL)
1329 (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1330 else
1331 (void)printf("#%d: ", rtm->rtm_type);
1332 (void)printf("len %d, ", rtm->rtm_msglen);
1333 switch (rtm->rtm_type) {
1334 case RTM_IFINFO:
1335 ifm = (struct if_msghdr *)rtm;
1336 (void) printf("if# %d, ", ifm->ifm_index);
1337 switch (ifm->ifm_data.ifi_link_state) {
1338 case LINK_STATE_DOWN:
1339 state = "down";
1340 break;
1341 case LINK_STATE_UP:
1342 state = "up";
1343 break;
1344 default:
1345 state = "unknown";
1346 break;
1347 }
1348 (void) printf("link: %s, flags:", state);
1349 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1350 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1351 break;
1352 case RTM_NEWADDR:
1353 case RTM_DELADDR:
1354 ifam = (struct ifa_msghdr *)rtm;
1355 (void) printf("metric %d, flags:", ifam->ifam_metric);
1356 bprintf(stdout, ifam->ifam_flags, routeflags);
1357 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1358 break;
1359#ifdef RTM_NEWMADDR
1360 case RTM_NEWMADDR:
1361 case RTM_DELMADDR:
1362 ifmam = (struct ifma_msghdr *)rtm;
1363 pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
1364 break;
1365#endif
1366 case RTM_IFANNOUNCE:
1367 ifan = (struct if_announcemsghdr *)rtm;
1368 (void) printf("if# %d, what: ", ifan->ifan_index);
1369 switch (ifan->ifan_what) {
1370 case IFAN_ARRIVAL:
1371 printf("arrival");
1372 break;
1373 case IFAN_DEPARTURE:
1374 printf("departure");
1375 break;
1376 default:
1377 printf("#%d", ifan->ifan_what);
1378 break;
1379 }
1380 printf("\n");
1381 break;
1382
1383 default:
1384 (void) printf("pid: %ld, seq %d, errno %d, flags:",
1385 (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1386 bprintf(stdout, rtm->rtm_flags, routeflags);
1387 pmsg_common(rtm);
1388 }
1389}
1390
1391void
1392print_getmsg(rtm, msglen)
1393 struct rt_msghdr *rtm;
1394 int msglen;
1395{
1396 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1397 struct sockaddr_dl *ifp = NULL;
1398 struct sockaddr *sa;
1399 char *cp;
1400 int i;
1401
1402 (void) printf(" route to: %s\n", routename(&so_dst));
1403 if (rtm->rtm_version != RTM_VERSION) {
1404 warnx("routing message version %d not understood",
1405 rtm->rtm_version);
1406 return;
1407 }
1408 if (rtm->rtm_msglen > msglen) {
1409 warnx("message length mismatch, in packet %d, returned %d",
1410 rtm->rtm_msglen, msglen);
1411 }
1412 if (rtm->rtm_errno) {
1413 errno = rtm->rtm_errno;
1414 warn("message indicates error %d", errno);
1415 return;
1416 }
1417 cp = ((char *)(rtm + 1));
1418 if (rtm->rtm_addrs)
1419 for (i = 1; i; i <<= 1)
1420 if (i & rtm->rtm_addrs) {
1421 sa = (struct sockaddr *)cp;
1422 switch (i) {
1423 case RTA_DST:
1424 dst = sa;
1425 break;
1426 case RTA_GATEWAY:
1427 gate = sa;
1428 break;
1429 case RTA_NETMASK:
1430 mask = sa;
1431 break;
1432 case RTA_IFP:
1433 if (sa->sa_family == AF_LINK &&
1434 ((struct sockaddr_dl *)sa)->sdl_nlen)
1435 ifp = (struct sockaddr_dl *)sa;
1436 break;
1437 }
1438 cp += SA_SIZE(sa);
1439 }
1440 if (dst && mask)
1441 mask->sa_family = dst->sa_family; /* XXX */
1442 if (dst)
1443 (void)printf("destination: %s\n", routename(dst));
1444 if (mask) {
1445 int savenflag = nflag;
1446
1447 nflag = 1;
1448 (void)printf(" mask: %s\n", routename(mask));
1449 nflag = savenflag;
1450 }
1451 if (gate && rtm->rtm_flags & RTF_GATEWAY)
1452 (void)printf(" gateway: %s\n", routename(gate));
1453 if (ifp)
1454 (void)printf(" interface: %.*s\n",
1455 ifp->sdl_nlen, ifp->sdl_data);
1456 (void)printf(" flags: ");
1457 bprintf(stdout, rtm->rtm_flags, routeflags);
1458
1459#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1460#define msec(u) (((u) + 500) / 1000) /* usec to msec */
1461
1462 (void) printf("\n%s\n", "\
1463 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1464 printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1465 printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1466 printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1467 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1468 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1469 printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1470 printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1471 if (rtm->rtm_rmx.rmx_expire)
1472 rtm->rtm_rmx.rmx_expire -= time(0);
1473 printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1474#undef lock
1475#undef msec
1476#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1477 if (verbose)
1478 pmsg_common(rtm);
1479 else if (rtm->rtm_addrs &~ RTA_IGN) {
1480 (void) printf("sockaddrs: ");
1481 bprintf(stdout, rtm->rtm_addrs, addrnames);
1482 putchar('\n');
1483 }
1484#undef RTA_IGN
1485}
1486
1487void
1488pmsg_common(rtm)
1489 struct rt_msghdr *rtm;
1490{
1491 (void) printf("\nlocks: ");
1492 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1493 (void) printf(" inits: ");
1494 bprintf(stdout, rtm->rtm_inits, metricnames);
1495 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1496}
1497
1498void
1499pmsg_addrs(cp, addrs)
1500 char *cp;
1501 int addrs;
1502{
1503 struct sockaddr *sa;
1504 int i;
1505
1506 if (addrs == 0) {
1507 (void) putchar('\n');
1508 return;
1509 }
1510 (void) printf("\nsockaddrs: ");
1511 bprintf(stdout, addrs, addrnames);
1512 (void) putchar('\n');
1513 for (i = 1; i; i <<= 1)
1514 if (i & addrs) {
1515 sa = (struct sockaddr *)cp;
1516 (void) printf(" %s", routename(sa));
1517 cp += SA_SIZE(sa);
1518 }
1519 (void) putchar('\n');
1520 (void) fflush(stdout);
1521}
1522
1523void
1524bprintf(fp, b, s)
1525 FILE *fp;
1526 int b;
1527 u_char *s;
1528{
1529 int i;
1530 int gotsome = 0;
1531
1532 if (b == 0)
1533 return;
1534 while ((i = *s++) != 0) {
1535 if (b & (1 << (i-1))) {
1536 if (gotsome == 0)
1537 i = '<';
1538 else
1539 i = ',';
1540 (void) putc(i, fp);
1541 gotsome = 1;
1542 for (; (i = *s) > 32; s++)
1543 (void) putc(i, fp);
1544 } else
1545 while (*s > 32)
1546 s++;
1547 }
1548 if (gotsome)
1549 (void) putc('>', fp);
1550}
1551
1552int
1553keyword(cp)
1554 char *cp;
1555{
1556 struct keytab *kt = keywords;
1557
1558 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1559 kt++;
1560 return kt->kt_i;
1561}
1562
1563void
1564sodump(su, which)
1565 sup su;
1566 char *which;
1567{
1568 switch (su->sa.sa_family) {
1569 case AF_LINK:
1570 (void) printf("%s: link %s; ",
1571 which, link_ntoa(&su->sdl));
1572 break;
1573 case AF_INET:
1574 (void) printf("%s: inet %s; ",
1575 which, inet_ntoa(su->sin.sin_addr));
1576 break;
1577 case AF_APPLETALK:
1578 (void) printf("%s: atalk %s; ",
1579 which, atalk_ntoa(su->sat.sat_addr));
1580 break;
1581 }
1582 (void) fflush(stdout);
1583}
1584
1585/* States*/
1586#define VIRGIN 0
1587#define GOTONE 1
1588#define GOTTWO 2
1589/* Inputs */
1590#define DIGIT (4*0)
1591#define END (4*1)
1592#define DELIM (4*2)
1593
1594void
1595sockaddr(addr, sa)
1596 char *addr;
1597 struct sockaddr *sa;
1598{
1599 char *cp = (char *)sa;
1600 int size = sa->sa_len;
1601 char *cplim = cp + size;
1602 int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
1603
1604 memset(cp, 0, size);
1605 cp++;
1606 do {
1607 if ((*addr >= '0') && (*addr <= '9')) {
1608 new = *addr - '0';
1609 } else if ((*addr >= 'a') && (*addr <= 'f')) {
1610 new = *addr - 'a' + 10;
1611 } else if ((*addr >= 'A') && (*addr <= 'F')) {
1612 new = *addr - 'A' + 10;
1613 } else if (*addr == 0)
1614 state |= END;
1615 else
1616 state |= DELIM;
1617 addr++;
1618 switch (state /* | INPUT */) {
1619 case GOTTWO | DIGIT:
1620 *cp++ = byte; /*FALLTHROUGH*/
1621 case VIRGIN | DIGIT:
1622 state = GOTONE; byte = new; continue;
1623 case GOTONE | DIGIT:
1624 state = GOTTWO; byte = new + (byte << 4); continue;
1625 default: /* | DELIM */
1626 state = VIRGIN; *cp++ = byte; byte = 0; continue;
1627 case GOTONE | END:
1628 case GOTTWO | END:
1629 *cp++ = byte; /* FALLTHROUGH */
1630 case VIRGIN | END:
1631 break;
1632 }
1633 break;
1634 } while (cp < cplim);
1635 sa->sa_len = cp - (char *)sa;
1636}
1637
1638int
1639atalk_aton(const char *text, struct at_addr *addr)
1640{
1641 u_int net, node;
1642
1643 if (sscanf(text, "%u.%u", &net, &node) != 2
1644 || net > 0xffff || node > 0xff)
1645 return(0);
1646 addr->s_net = htons(net);
1647 addr->s_node = node;
1648 return(1);
1649}
1650
1651char *
1652atalk_ntoa(struct at_addr at)
1653{
1654 static char buf[20];
1655
1656 (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
1657 return(buf);
1658}