route.c revision 1.89 1 /* $NetBSD: route.c,v 1.89 2005/08/12 16:29:06 ginsbach Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
41 #else
42 __RCSID("$NetBSD: route.c,v 1.89 2005/08/12 16:29:06 ginsbach Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/file.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
50 #include <sys/mbuf.h>
51 #include <sys/sysctl.h>
52
53 #include <net/if.h>
54 #include <net/route.h>
55 #include <net/if_dl.h>
56 #include <net80211/ieee80211_netbsd.h>
57 #include <netinet/in.h>
58 #include <netatalk/at.h>
59 #include <netns/ns.h>
60 #include <netiso/iso.h>
61 #include <netccitt/x25.h>
62 #include <arpa/inet.h>
63 #include <netdb.h>
64
65 #include <errno.h>
66 #include <unistd.h>
67 #include <stdio.h>
68 #include <ctype.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <time.h>
72 #include <paths.h>
73 #include <err.h>
74
75 #include "keywords.h"
76 #include "extern.h"
77
78 typedef union sockunion *sup;
79
80 static char *any_ntoa(const struct sockaddr *);
81 static void set_metric(char *, int);
82 static int newroute(int, char **);
83 static void inet_makenetandmask(u_int32_t, struct sockaddr_in *);
84 #ifdef INET6
85 static int inet6_makenetandmask(struct sockaddr_in6 *);
86 #endif
87 static int getaddr(int, char *, struct hostent **);
88 static int flushroutes(int, char *[], int);
89 #ifndef SMALL
90 static int prefixlen(const char *);
91 static int x25_makemask(void);
92 static void interfaces(void);
93 static void monitor(void);
94 static void print_getmsg(struct rt_msghdr *, int);
95 static const char *linkstate(struct if_msghdr *);
96 #endif /* SMALL */
97 static int rtmsg(int, int );
98 static void mask_addr(void);
99 static void print_rtmsg(struct rt_msghdr *, int);
100 static void pmsg_common(struct rt_msghdr *);
101 static void pmsg_addrs(char *, int);
102 static void bprintf(FILE *, int, u_char *);
103 static void sodump(sup, const char *);
104 static void sockaddr(char *, struct sockaddr *);
105
106 union sockunion {
107 struct sockaddr sa;
108 struct sockaddr_in sin;
109 #ifdef INET6
110 struct sockaddr_in6 sin6;
111 #endif
112 struct sockaddr_at sat;
113 struct sockaddr_dl sdl;
114 #ifndef SMALL
115 struct sockaddr_ns sns;
116 struct sockaddr_iso siso;
117 struct sockaddr_x25 sx25;
118 #endif /* SMALL */
119 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
120
121 int pid, rtm_addrs;
122 int sock;
123 int forcehost, forcenet, doflush, nflag, af, qflag, tflag;
124 int iflag, verbose, aflen = sizeof(struct sockaddr_in);
125 int locking, lockrest, debugonly, shortoutput, rv;
126 struct rt_metrics rt_metrics;
127 u_int32_t rtm_inits;
128 short ns_nullh[] = {0,0,0};
129 short ns_bh[] = {-1,-1,-1};
130
131
132 void
133 usage(const char *cp)
134 {
135
136 if (cp)
137 warnx("botched keyword: %s", cp);
138 (void)fprintf(stderr,
139 "Usage: %s [ -fnqvs ] cmd [[ -<qualifers> ] args ]\n",
140 getprogname());
141 exit(1);
142 /* NOTREACHED */
143 }
144
145 #define PRIETHER "02x:%02x:%02x:%02x:%02x:%02x"
146 #define PRIETHER_ARGS(__enaddr) (__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \
147 (__enaddr)[3], (__enaddr)[4], (__enaddr)[5]
148 #define ROUNDUP(a) \
149 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
150 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
151
152 int
153 main(int argc, char **argv)
154 {
155 int ch;
156
157 if (argc < 2)
158 usage(NULL);
159
160 while ((ch = getopt(argc, argv, "dfnqstv")) != -1)
161 switch (ch) {
162 case 'd':
163 debugonly = 1;
164 break;
165 case 'f':
166 doflush = 1;
167 break;
168 case 'n':
169 nflag = 1;
170 break;
171 case 'q':
172 qflag = 1;
173 break;
174 case 's':
175 shortoutput = 1;
176 break;
177 case 't':
178 tflag = 1;
179 break;
180 case 'v':
181 verbose = 1;
182 break;
183 case '?':
184 default:
185 usage(NULL);
186 /*NOTREACHED*/
187 }
188 argc -= optind;
189 argv += optind;
190
191 pid = getpid();
192 if (tflag)
193 sock = open("/dev/null", O_WRONLY, 0);
194 else
195 sock = socket(PF_ROUTE, SOCK_RAW, 0);
196 if (sock < 0)
197 err(1, "socket");
198
199 if (*argv == NULL) {
200 if (doflush)
201 ch = K_FLUSH;
202 else
203 goto no_cmd;
204 } else
205 ch = keyword(*argv);
206
207 switch (ch) {
208 #ifndef SMALL
209 case K_GET:
210 #endif /* SMALL */
211 case K_CHANGE:
212 case K_ADD:
213 case K_DELETE:
214 if (doflush)
215 (void)flushroutes(1, argv, 0);
216 return newroute(argc, argv);
217
218 case K_SHOW:
219 show(argc, argv);
220 return 0;
221
222 #ifndef SMALL
223 case K_MONITOR:
224 monitor();
225 return 0;
226
227 #endif /* SMALL */
228 case K_FLUSH:
229 return flushroutes(argc, argv, 0);
230
231 case K_FLUSHALL:
232 return flushroutes(argc, argv, 1);
233 no_cmd:
234 default:
235 usage(*argv);
236 /*NOTREACHED*/
237 }
238 }
239
240 /*
241 * Purge all entries in the routing tables not
242 * associated with network interfaces.
243 */
244 static int
245 flushroutes(int argc, char *argv[], int doall)
246 {
247 size_t needed;
248 int mib[6], rlen, seqno;
249 char *buf, *next, *lim;
250 struct rt_msghdr *rtm;
251
252 af = 0;
253 shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
254 if (argc > 1) {
255 argv++;
256 if (argc == 2 && **argv == '-')
257 switch (keyword(*argv + 1)) {
258 case K_INET:
259 af = AF_INET;
260 break;
261 #ifdef INET6
262 case K_INET6:
263 af = AF_INET6;
264 break;
265 #endif
266 #ifndef SMALL
267 case K_ATALK:
268 af = AF_APPLETALK;
269 break;
270 case K_XNS:
271 af = AF_NS;
272 break;
273 #endif /* SMALL */
274 case K_LINK:
275 af = AF_LINK;
276 break;
277 #ifndef SMALL
278 case K_ISO:
279 case K_OSI:
280 af = AF_ISO;
281 break;
282 case K_X25:
283 af = AF_CCITT;
284 #endif /* SMALL */
285 default:
286 goto bad;
287 } else
288 bad: usage(*argv);
289 }
290 mib[0] = CTL_NET;
291 mib[1] = PF_ROUTE;
292 mib[2] = 0; /* protocol */
293 mib[3] = 0; /* wildcard address family */
294 mib[4] = NET_RT_DUMP;
295 mib[5] = 0; /* no flags */
296 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
297 err(1, "route-sysctl-estimate");
298 if (needed == 0)
299 return 0;
300 if ((buf = malloc(needed)) == NULL)
301 err(1, "malloc");
302 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
303 err(1, "actual retrieval of routing table");
304 lim = buf + needed;
305 if (verbose) {
306 (void)printf("Examining routing table from sysctl\n");
307 if (af)
308 printf("(address family %s)\n", (*argv + 1));
309 }
310 seqno = 0; /* ??? */
311 for (next = buf; next < lim; next += rtm->rtm_msglen) {
312 rtm = (struct rt_msghdr *)next;
313 if (verbose)
314 print_rtmsg(rtm, rtm->rtm_msglen);
315 if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC |
316 RTF_LLINFO)) && !doall)
317 continue;
318 if (af) {
319 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
320
321 if (sa->sa_family != af)
322 continue;
323 }
324 if (debugonly)
325 continue;
326 rtm->rtm_type = RTM_DELETE;
327 rtm->rtm_seq = seqno;
328 rlen = write(sock, next, rtm->rtm_msglen);
329 if (rlen < (int)rtm->rtm_msglen) {
330 warn("write to routing socket, got %d for rlen", rlen);
331 return 1;
332 }
333 seqno++;
334 if (qflag)
335 continue;
336 if (verbose)
337 print_rtmsg(rtm, rlen);
338 else {
339 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
340 (void)printf("%-20.20s ",
341 routename(sa, NULL, rtm->rtm_flags));
342 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
343 (void)printf("%-20.20s ",
344 routename(sa, NULL, RTF_HOST));
345 (void)printf("done\n");
346 }
347 }
348 return 0;
349 }
350
351
352 static char hexlist[] = "0123456789abcdef";
353
354 static char *
355 any_ntoa(const struct sockaddr *sa)
356 {
357 static char obuf[3 * 256];
358 const char *in;
359 char *out;
360 int len;
361
362 #if __GNUC__ > 2
363 len = sa->sa_len - offsetof(struct sockaddr, sa_data);
364 #else
365 len = sa->sa_len - ((struct sockaddr*)&sa->sa_data - sa);
366 #endif
367 in = sa->sa_data;
368 out = obuf;
369
370 do {
371 *out++ = hexlist[(*in >> 4) & 15];
372 *out++ = hexlist[(*in++) & 15];
373 *out++ = '.';
374 } while (--len > 0);
375 out[-1] = '\0';
376 return obuf;
377 }
378
379
380 int
381 netmask_length(struct sockaddr *nm, int family)
382 {
383 static int
384 /* number of bits in a nibble */
385 _t[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 },
386 /* good nibbles are 1111, 1110, 1100, 1000, 0000 */
387 _g[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 };
388 int mask, good, zeroes, maskbytes, bit, i;
389 unsigned char *maskdata;
390
391 if (nm == NULL)
392 return 0;
393
394 mask = 0;
395 good = 1;
396 zeroes = 0;
397
398 switch (family) {
399 case AF_INET: {
400 struct sockaddr_in *nsin = (struct sockaddr_in *)nm;
401 maskdata = (unsigned char *)&nsin->sin_addr;
402 maskbytes = nsin->sin_len -
403 ((caddr_t)&nsin->sin_addr - (caddr_t)nsin);
404 break;
405 }
406 case AF_INET6: {
407 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nm;
408 maskdata = (unsigned char *)&sin6->sin6_addr;
409 maskbytes = sin6->sin6_len -
410 ((caddr_t)&sin6->sin6_addr - (caddr_t)sin6);
411 break;
412 }
413 default:
414 return 0;
415 }
416
417 /*
418 * Count the bits in the nibbles of the mask, and marking the
419 * netmask as not good (or at best, non-standard and very
420 * discouraged, in the case of AF_INET) if we find either of
421 * a nibble with non-contiguous bits, or a non-zero nibble
422 * after we've found a zero nibble.
423 */
424 for (i = 0; i < maskbytes; i++) {
425 /* high nibble */
426 mask += bit = _t[maskdata[i] >> 4];
427 good &= _g[maskdata[i] >> 4];
428 if (zeroes && bit)
429 good = 0;
430 if (bit == 0)
431 zeroes = 1;
432 /* low nibble */
433 mask += bit = _t[maskdata[i] & 0xf];
434 good &= _g[maskdata[i] & 0xf];
435 if (zeroes && bit)
436 good = 0;
437 if (bit == 0)
438 zeroes = 1;
439 }
440
441 /*
442 * Always return the number of bits found, but as a negative
443 * if the mask wasn't one we like.
444 */
445 return good ? mask : -mask;
446 }
447
448 char *
449 netmask_string(struct sockaddr *mask, int len)
450 {
451 static char smask[16];
452
453 if (len >= 0)
454 snprintf(smask, sizeof(smask), "%d", len);
455 else {
456 /* XXX AF_INET only?! */
457 struct sockaddr_in nsin;
458
459 memset(&nsin, 0, sizeof(nsin));
460 memcpy(&nsin, mask, mask->sa_len);
461 snprintf(smask, sizeof(smask), "%s", inet_ntoa(nsin.sin_addr));
462 }
463
464 return smask;
465 }
466
467
468 const char *
469 routename(struct sockaddr *sa, struct sockaddr *nm, int flags)
470 {
471 const char *cp;
472 static char line[50];
473 struct hostent *hp;
474 static char domain[MAXHOSTNAMELEN + 1];
475 static int first = 1;
476 struct in_addr in;
477 int nml;
478
479 if ((flags & RTF_HOST) == 0)
480 return netname(sa, nm);
481
482 if (first) {
483 first = 0;
484 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
485 (cp = strchr(domain, '.')))
486 (void)strlcpy(domain, cp + 1, sizeof(domain));
487 else
488 domain[0] = 0;
489 }
490
491 if (sa->sa_len == 0)
492 strlcpy(line, "default", sizeof(line));
493 else switch (sa->sa_family) {
494
495 case AF_INET:
496 in = ((struct sockaddr_in *)sa)->sin_addr;
497 nml = netmask_length(nm, AF_INET);
498
499 cp = 0;
500 if (in.s_addr == INADDR_ANY || sa->sa_len < 4) {
501 if (nml == 0)
502 cp = "default";
503 else {
504 static char notdefault[sizeof(NOTDEFSTRING)];
505
506 snprintf(notdefault, sizeof(notdefault),
507 "0.0.0.0/%s", netmask_string(nm, nml));
508 cp = notdefault;
509 }
510 }
511 if (cp == 0 && !nflag) {
512 hp = gethostbyaddr((char *)&in, sizeof(struct in_addr),
513 AF_INET);
514 if (hp) {
515 char *ccp;
516 if ((ccp = strchr(hp->h_name, '.')) &&
517 !strcmp(ccp + 1, domain))
518 *ccp = 0;
519 cp = hp->h_name;
520 }
521 }
522 if (cp)
523 (void)strlcpy(line, cp, sizeof(line));
524 else
525 (void)strlcpy(line, inet_ntoa(in), sizeof(line));
526 break;
527
528 case AF_LINK:
529 return (link_ntoa((struct sockaddr_dl *)sa));
530
531 #ifndef SMALL
532 #ifdef INET6
533 case AF_INET6:
534 {
535 struct sockaddr_in6 sin6;
536 int niflags;
537 char nihost[NI_MAXHOST];
538
539 niflags = 0;
540 if (nflag)
541 niflags |= NI_NUMERICHOST;
542 memset(&sin6, 0, sizeof(sin6));
543 memcpy(&sin6, sa, sa->sa_len);
544 sin6.sin6_len = sizeof(struct sockaddr_in6);
545 sin6.sin6_family = AF_INET6;
546 #ifdef __KAME__
547 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
548 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
549 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
550 sin6.sin6_scope_id == 0) {
551 sin6.sin6_scope_id =
552 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
553 sin6.sin6_addr.s6_addr[2] = 0;
554 sin6.sin6_addr.s6_addr[3] = 0;
555 }
556 #endif
557 nml = netmask_length(nm, AF_INET6);
558 if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
559 if (nml == 0)
560 strlcpy(line, "::", sizeof(line));
561 else
562 /* noncontiguous never happens in ipv6 */
563 snprintf(line, sizeof(line), "::/%d", nml);
564 }
565 else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
566 nihost, sizeof(nihost), NULL, 0, niflags) != 0)
567 strlcpy(line, "invalid", sizeof(line));
568 else {
569 char *ccp;
570 if (!nflag && (ccp = strchr(nihost, '.')) &&
571 strcmp(ccp + 1, domain) == 0)
572 *ccp = 0;
573 strlcpy(line, nihost, sizeof(line));
574 }
575 break;
576 }
577 #endif
578
579 case AF_NS:
580 return (ns_print((struct sockaddr_ns *)sa));
581
582 case AF_ISO:
583 (void)snprintf(line, sizeof line, "iso %s",
584 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
585 break;
586
587 case AF_APPLETALK:
588 (void)snprintf(line, sizeof(line), "atalk %d.%d",
589 ((struct sockaddr_at *)sa)->sat_addr.s_net,
590 ((struct sockaddr_at *)sa)->sat_addr.s_node);
591 break;
592 #endif /* SMALL */
593
594 default:
595 (void)snprintf(line, sizeof line, "(%d) %s",
596 sa->sa_family, any_ntoa(sa));
597 break;
598
599 }
600 return (line);
601 }
602
603 /*
604 * Return the name of the network whose address is given.
605 * The address is assumed to be that of a net or subnet, not a host.
606 */
607 const char *
608 netname(struct sockaddr *sa, struct sockaddr *nm)
609 {
610 const char *cp = 0;
611 static char line[50];
612 struct netent *np = 0;
613 u_int32_t net, mask;
614 u_int32_t i;
615 int subnetshift, nml;
616 struct in_addr in;
617
618 switch (sa->sa_family) {
619
620 case AF_INET:
621 in = ((struct sockaddr_in *)sa)->sin_addr;
622 i = ntohl(in.s_addr);
623 nml = netmask_length(nm, AF_INET);
624 if (i == 0) {
625 if (nml == 0)
626 cp = "default";
627 else {
628 static char notdefault[sizeof(NOTDEFSTRING)];
629
630 snprintf(notdefault, sizeof(notdefault),
631 "0.0.0.0/%s", netmask_string(nm, nml));
632 cp = notdefault;
633 }
634 }
635 else if (!nflag) {
636 if (IN_CLASSA(i)) {
637 mask = IN_CLASSA_NET;
638 subnetshift = 8;
639 } else if (IN_CLASSB(i)) {
640 mask = IN_CLASSB_NET;
641 subnetshift = 8;
642 } else {
643 mask = IN_CLASSC_NET;
644 subnetshift = 4;
645 }
646 /*
647 * If there are more bits than the standard mask
648 * would suggest, subnets must be in use.
649 * Guess at the subnet mask, assuming reasonable
650 * width subnet fields.
651 */
652 while (i &~ mask)
653 mask = (int32_t)mask >> subnetshift;
654 net = i & mask;
655 while ((mask & 1) == 0)
656 mask >>= 1, net >>= 1;
657 np = getnetbyaddr(net, AF_INET);
658 if (np)
659 cp = np->n_name;
660 }
661 if (cp)
662 (void)strlcpy(line, cp, sizeof(line));
663 else {
664 #if 0 /* XXX - This is silly... */
665 #define C(x) ((x) & 0xff)
666 if ((i & 0xffffff) == 0)
667 (void)snprintf(line, sizeof line, "%u",
668 C(i >> 24));
669 else if ((i & 0xffff) == 0)
670 (void)snprintf(line, sizeof line, "%u.%u",
671 C(i >> 24), C(i >> 16));
672 else if ((i & 0xff) == 0)
673 (void)snprintf(line, sizeof line, "%u.%u.%u",
674 C(i >> 24), C(i >> 16), C(i >> 8));
675 else
676 (void)snprintf(line, sizeof line, "%u.%u.%u.%u",
677 C(i >> 24), C(i >> 16), C(i >> 8), C(i));
678 #undef C
679 #else /* XXX */
680 if (nml == 0)
681 strlcpy(line, inet_ntoa(in), sizeof(line));
682 else
683 snprintf(line, sizeof(line), "%s/%d", inet_ntoa(in), nml);
684 #endif /* XXX */
685 }
686 break;
687
688 case AF_LINK:
689 return (link_ntoa((struct sockaddr_dl *)sa));
690
691 #ifndef SMALL
692 #ifdef INET6
693 case AF_INET6:
694 {
695 struct sockaddr_in6 sin6;
696 int niflags;
697
698 niflags = 0;
699 if (nflag)
700 niflags |= NI_NUMERICHOST;
701 memset(&sin6, 0, sizeof(sin6));
702 memcpy(&sin6, sa, sa->sa_len);
703 sin6.sin6_len = sizeof(struct sockaddr_in6);
704 sin6.sin6_family = AF_INET6;
705 #ifdef __KAME__
706 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
707 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
708 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
709 sin6.sin6_scope_id == 0) {
710 sin6.sin6_scope_id =
711 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
712 sin6.sin6_addr.s6_addr[2] = 0;
713 sin6.sin6_addr.s6_addr[3] = 0;
714 }
715 #endif
716 nml = netmask_length(nm, AF_INET6);
717 if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
718 if (nml == 0)
719 strlcpy(line, "::", sizeof(line));
720 else
721 /* noncontiguous never happens in ipv6 */
722 snprintf(line, sizeof(line), "::/%d", nml);
723 }
724
725 else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
726 line, sizeof(line), NULL, 0, niflags) != 0)
727 strlcpy(line, "invalid", sizeof(line));
728 break;
729 }
730 #endif
731
732 case AF_NS:
733 return (ns_print((struct sockaddr_ns *)sa));
734
735 case AF_ISO:
736 (void)snprintf(line, sizeof line, "iso %s",
737 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
738 break;
739
740 case AF_APPLETALK:
741 (void)snprintf(line, sizeof(line), "atalk %d.%d",
742 ((struct sockaddr_at *)sa)->sat_addr.s_net,
743 ((struct sockaddr_at *)sa)->sat_addr.s_node);
744 break;
745 #endif /* SMALL */
746
747 default:
748 (void)snprintf(line, sizeof line, "af %d: %s",
749 sa->sa_family, any_ntoa(sa));
750 break;
751 }
752 return (line);
753 }
754
755 static void
756 set_metric(char *value, int key)
757 {
758 int flag = 0;
759 u_long noval, *valp = &noval;
760
761 switch (key) {
762 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
763 caseof(K_MTU, RTV_MTU, rmx_mtu);
764 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
765 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
766 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
767 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
768 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
769 caseof(K_RTT, RTV_RTT, rmx_rtt);
770 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
771 }
772 rtm_inits |= flag;
773 if (lockrest || locking)
774 rt_metrics.rmx_locks |= flag;
775 if (locking)
776 locking = 0;
777 *valp = atoi(value);
778 }
779
780 static int
781 newroute(int argc, char **argv)
782 {
783 const char *cmd, *dest = "", *gateway = "";
784 const char *error;
785 int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
786 int key;
787 struct hostent *hp = 0;
788
789 cmd = argv[0];
790 af = 0;
791 if (*cmd != 'g')
792 shutdown(sock, SHUT_RD); /* Don't want to read back our messages */
793 while (--argc > 0) {
794 if (**(++argv)== '-') {
795 switch (key = keyword(1 + *argv)) {
796
797 case K_SA:
798 af = PF_ROUTE;
799 aflen = sizeof(union sockunion);
800 break;
801
802 #ifndef SMALL
803 case K_ATALK:
804 af = AF_APPLETALK;
805 aflen = sizeof(struct sockaddr_at);
806 break;
807 #endif
808
809 case K_INET:
810 af = AF_INET;
811 aflen = sizeof(struct sockaddr_in);
812 break;
813
814 #ifdef INET6
815 case K_INET6:
816 af = AF_INET6;
817 aflen = sizeof(struct sockaddr_in6);
818 break;
819 #endif
820
821 case K_LINK:
822 af = AF_LINK;
823 aflen = sizeof(struct sockaddr_dl);
824 break;
825
826 #ifndef SMALL
827 case K_OSI:
828 case K_ISO:
829 af = AF_ISO;
830 aflen = sizeof(struct sockaddr_iso);
831 break;
832
833 case K_X25:
834 af = AF_CCITT;
835 aflen = sizeof(struct sockaddr_x25);
836 break;
837
838 case K_XNS:
839 af = AF_NS;
840 aflen = sizeof(struct sockaddr_ns);
841 break;
842 #endif /* SMALL */
843
844 case K_IFACE:
845 case K_INTERFACE:
846 iflag++;
847 break;
848 case K_NOSTATIC:
849 flags &= ~RTF_STATIC;
850 break;
851 case K_LLINFO:
852 flags |= RTF_LLINFO;
853 break;
854 case K_LOCK:
855 locking = 1;
856 break;
857 case K_LOCKREST:
858 lockrest = 1;
859 break;
860 case K_HOST:
861 forcehost++;
862 break;
863 case K_REJECT:
864 flags |= RTF_REJECT;
865 break;
866 case K_BLACKHOLE:
867 flags |= RTF_BLACKHOLE;
868 break;
869 case K_CLONED:
870 flags |= RTF_CLONED;
871 break;
872 case K_PROTO1:
873 flags |= RTF_PROTO1;
874 break;
875 case K_PROTO2:
876 flags |= RTF_PROTO2;
877 break;
878 case K_CLONING:
879 flags |= RTF_CLONING;
880 break;
881 case K_XRESOLVE:
882 flags |= RTF_XRESOLVE;
883 break;
884 case K_STATIC:
885 flags |= RTF_STATIC;
886 break;
887 case K_IFA:
888 if (!--argc)
889 usage(1+*argv);
890 (void)getaddr(RTA_IFA, *++argv, 0);
891 break;
892 case K_IFP:
893 if (!--argc)
894 usage(1+*argv);
895 (void)getaddr(RTA_IFP, *++argv, 0);
896 break;
897 case K_GENMASK:
898 if (!--argc)
899 usage(1+*argv);
900 (void)getaddr(RTA_GENMASK, *++argv, 0);
901 break;
902 case K_GATEWAY:
903 if (!--argc)
904 usage(1+*argv);
905 (void)getaddr(RTA_GATEWAY, *++argv, 0);
906 break;
907 case K_DST:
908 if (!--argc)
909 usage(1+*argv);
910 ishost = getaddr(RTA_DST, *++argv, &hp);
911 dest = *argv;
912 break;
913 case K_NETMASK:
914 if (!--argc)
915 usage(1+*argv);
916 (void)getaddr(RTA_NETMASK, *++argv, 0);
917 /* FALLTHROUGH */
918 case K_NET:
919 forcenet++;
920 break;
921 case K_PREFIXLEN:
922 if (!--argc)
923 usage(1+*argv);
924 ishost = prefixlen(*++argv);
925 break;
926 case K_MTU:
927 case K_HOPCOUNT:
928 case K_EXPIRE:
929 case K_RECVPIPE:
930 case K_SENDPIPE:
931 case K_SSTHRESH:
932 case K_RTT:
933 case K_RTTVAR:
934 if (!--argc)
935 usage(1+*argv);
936 set_metric(*++argv, key);
937 break;
938 default:
939 usage(1+*argv);
940 }
941 } else {
942 if ((rtm_addrs & RTA_DST) == 0) {
943 dest = *argv;
944 ishost = getaddr(RTA_DST, *argv, &hp);
945 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
946 gateway = *argv;
947 (void)getaddr(RTA_GATEWAY, *argv, &hp);
948 } else {
949 ret = atoi(*argv);
950
951 if (ret == 0) {
952 if (strcmp(*argv, "0") == 0) {
953 if (!qflag) {
954 warnx("%s, %s",
955 "old usage of trailing 0",
956 "assuming route to if");
957 }
958 } else
959 usage((char *)NULL);
960 iflag = 1;
961 continue;
962 } else if (ret > 0 && ret < 10) {
963 if (!qflag) {
964 warnx("%s, %s",
965 "old usage of trailing digit",
966 "assuming route via gateway");
967 }
968 iflag = 0;
969 continue;
970 }
971 (void)getaddr(RTA_NETMASK, *argv, 0);
972 }
973 }
974 }
975 if (forcehost && forcenet)
976 errx(1, "-host and -net conflict");
977 else if (forcehost)
978 ishost = 1;
979 else if (forcenet)
980 ishost = 0;
981 flags |= RTF_UP;
982 if (ishost)
983 flags |= RTF_HOST;
984 if (iflag == 0)
985 flags |= RTF_GATEWAY;
986 for (attempts = 1; ; attempts++) {
987 errno = 0;
988 if ((ret = rtmsg(*cmd, flags)) == 0)
989 break;
990 if (errno != ENETUNREACH && errno != ESRCH)
991 break;
992 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
993 hp->h_addr_list++;
994 memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
995 hp->h_length);
996 } else
997 break;
998 }
999 if (*cmd == 'g')
1000 return rv;
1001 if (!qflag) {
1002 oerrno = errno;
1003 (void)printf("%s %s %s", cmd, ishost? "host" : "net", dest);
1004 if (*gateway) {
1005 (void)printf(": gateway %s", gateway);
1006 if (attempts > 1 && ret == 0 && af == AF_INET)
1007 (void)printf(" (%s)",
1008 inet_ntoa(so_gate.sin.sin_addr));
1009 }
1010 if (ret == 0)
1011 (void)printf("\n");
1012 else {
1013 switch (oerrno) {
1014 case ESRCH:
1015 error = "not in table";
1016 break;
1017 case EBUSY:
1018 error = "entry in use";
1019 break;
1020 case ENOBUFS:
1021 error = "routing table overflow";
1022 break;
1023 default:
1024 error = strerror(oerrno);
1025 break;
1026 }
1027 (void)printf(": %s\n", error);
1028 }
1029 }
1030 return (ret != 0);
1031 }
1032
1033 static void
1034 inet_makenetandmask(u_int32_t net, struct sockaddr_in *isin)
1035 {
1036 u_int32_t addr, mask = 0;
1037 char *cp;
1038
1039 rtm_addrs |= RTA_NETMASK;
1040 if (net == 0)
1041 mask = addr = 0;
1042 else if (net < 128) {
1043 addr = net << IN_CLASSA_NSHIFT;
1044 mask = IN_CLASSA_NET;
1045 } else if (net < 192) {
1046 addr = net << IN_CLASSA_NSHIFT;
1047 mask = IN_CLASSB_NET;
1048 } else if (net < 224) {
1049 addr = net << IN_CLASSA_NSHIFT;
1050 mask = IN_CLASSC_NET;
1051 } else if (net < 256) {
1052 addr = net << IN_CLASSA_NSHIFT;
1053 mask = IN_CLASSD_NET;
1054 } else if (net < 49152) { /* 192 * 256 */
1055 addr = net << IN_CLASSB_NSHIFT;
1056 mask = IN_CLASSB_NET;
1057 } else if (net < 57344) { /* 224 * 256 */
1058 addr = net << IN_CLASSB_NSHIFT;
1059 mask = IN_CLASSC_NET;
1060 } else if (net < 65536) {
1061 addr = net << IN_CLASSB_NSHIFT;
1062 mask = IN_CLASSB_NET;
1063 } else if (net < 14680064L) { /* 224 * 65536 */
1064 addr = net << IN_CLASSC_NSHIFT;
1065 mask = IN_CLASSC_NET;
1066 } else if (net < 16777216L) {
1067 addr = net << IN_CLASSC_NSHIFT;
1068 mask = IN_CLASSD_NET;
1069 } else {
1070 addr = net;
1071 if ((addr & IN_CLASSA_HOST) == 0)
1072 mask = IN_CLASSA_NET;
1073 else if ((addr & IN_CLASSB_HOST) == 0)
1074 mask = IN_CLASSB_NET;
1075 else if ((addr & IN_CLASSC_HOST) == 0)
1076 mask = IN_CLASSC_NET;
1077 else
1078 mask = -1;
1079 }
1080 isin->sin_addr.s_addr = htonl(addr);
1081 isin = &so_mask.sin;
1082 isin->sin_addr.s_addr = htonl(mask);
1083 isin->sin_len = 0;
1084 isin->sin_family = 0;
1085 cp = (char *)(&isin->sin_addr + 1);
1086 while (*--cp == 0 && cp > (char *)isin)
1087 ;
1088 isin->sin_len = 1 + cp - (char *)isin;
1089 }
1090
1091 #ifdef INET6
1092 /*
1093 * XXX the function may need more improvement...
1094 */
1095 static int
1096 inet6_makenetandmask(struct sockaddr_in6 *sin6)
1097 {
1098 const char *plen;
1099 struct in6_addr in6;
1100
1101 plen = NULL;
1102 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
1103 sin6->sin6_scope_id == 0) {
1104 plen = "0";
1105 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
1106 /* aggregatable global unicast - RFC2374 */
1107 memset(&in6, 0, sizeof(in6));
1108 if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8))
1109 plen = "64";
1110 }
1111
1112 if (!plen || strcmp(plen, "128") == 0)
1113 return 1;
1114 else {
1115 rtm_addrs |= RTA_NETMASK;
1116 (void)prefixlen(plen);
1117 return 0;
1118 }
1119 }
1120 #endif
1121
1122 /*
1123 * Interpret an argument as a network address of some kind,
1124 * returning 1 if a host address, 0 if a network address.
1125 */
1126 static int
1127 getaddr(int which, char *s, struct hostent **hpp)
1128 {
1129 sup su;
1130 struct hostent *hp;
1131 struct netent *np;
1132 u_int32_t val;
1133 char *t;
1134 int afamily; /* local copy of af so we can change it */
1135
1136 if (af == 0) {
1137 af = AF_INET;
1138 aflen = sizeof(struct sockaddr_in);
1139 }
1140 afamily = af;
1141 rtm_addrs |= which;
1142 switch (which) {
1143 case RTA_DST:
1144 su = &so_dst;
1145 break;
1146 case RTA_GATEWAY:
1147 su = &so_gate;
1148 break;
1149 case RTA_NETMASK:
1150 su = &so_mask;
1151 break;
1152 case RTA_GENMASK:
1153 su = &so_genmask;
1154 break;
1155 case RTA_IFP:
1156 su = &so_ifp;
1157 afamily = AF_LINK;
1158 break;
1159 case RTA_IFA:
1160 su = &so_ifa;
1161 su->sa.sa_family = af;
1162 break;
1163 default:
1164 su = NULL;
1165 usage("Internal Error");
1166 /*NOTREACHED*/
1167 }
1168 su->sa.sa_len = aflen;
1169 su->sa.sa_family = afamily; /* cases that don't want it have left already */
1170 if (strcmp(s, "default") == 0) {
1171 switch (which) {
1172 case RTA_DST:
1173 forcenet++;
1174 (void)getaddr(RTA_NETMASK, s, 0);
1175 break;
1176 case RTA_NETMASK:
1177 case RTA_GENMASK:
1178 su->sa.sa_len = 0;
1179 }
1180 return (0);
1181 }
1182 switch (afamily) {
1183 #ifndef SMALL
1184 #ifdef INET6
1185 case AF_INET6:
1186 {
1187 struct addrinfo hints, *res;
1188 char *slash = 0;
1189
1190 if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0)
1191 *slash = '\0';
1192 memset(&hints, 0, sizeof(hints));
1193 hints.ai_family = afamily; /*AF_INET6*/
1194 hints.ai_flags = AI_NUMERICHOST;
1195 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
1196 if (getaddrinfo(s, "0", &hints, &res) != 0) {
1197 hints.ai_flags = 0;
1198 if (slash) {
1199 *slash = '/';
1200 slash = 0;
1201 }
1202 if (getaddrinfo(s, "0", &hints, &res) != 0)
1203 errx(1, "bad value: %s", s);
1204 }
1205 if (slash)
1206 *slash = '/';
1207 if (sizeof(su->sin6) != res->ai_addrlen)
1208 errx(1, "%s: bad value", s);
1209 if (res->ai_next)
1210 errx(1, "address resolved to multiple values: %s", s);
1211 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1212 freeaddrinfo(res);
1213 #ifdef __KAME__
1214 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1215 IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
1216 su->sin6.sin6_scope_id) {
1217 *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1218 htons(su->sin6.sin6_scope_id);
1219 su->sin6.sin6_scope_id = 0;
1220 }
1221 #endif
1222 if (hints.ai_flags == AI_NUMERICHOST) {
1223 if (slash)
1224 return (prefixlen(slash + 1));
1225 if (which == RTA_DST)
1226 return (inet6_makenetandmask(&su->sin6));
1227 return (0);
1228 } else
1229 return (1);
1230 }
1231 #endif
1232
1233 case AF_NS:
1234 if (which == RTA_DST) {
1235 struct sockaddr_ns *sms = &(so_mask.sns);
1236 memset(sms, 0, sizeof(*sms));
1237 sms->sns_family = 0;
1238 sms->sns_len = 6;
1239 sms->sns_addr.x_net = *(union ns_net *)ns_bh;
1240 rtm_addrs |= RTA_NETMASK;
1241 }
1242 su->sns.sns_addr = ns_addr(s);
1243 return (!ns_nullhost(su->sns.sns_addr));
1244
1245 case AF_OSI:
1246 su->siso.siso_addr = *iso_addr(s);
1247 if (which == RTA_NETMASK || which == RTA_GENMASK) {
1248 char *cp = (char *)TSEL(&su->siso);
1249 su->siso.siso_nlen = 0;
1250 do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
1251 su->siso.siso_len = 1 + cp - (char *)su;
1252 }
1253 return (1);
1254
1255 case AF_CCITT:
1256 ccitt_addr(s, &su->sx25);
1257 return (which == RTA_DST ? x25_makemask() : 1);
1258 #endif /* SMALL */
1259
1260 case PF_ROUTE:
1261 su->sa.sa_len = sizeof(*su);
1262 sockaddr(s, &su->sa);
1263 return (1);
1264
1265 #ifndef SMALL
1266 case AF_APPLETALK:
1267 t = strchr (s, '.');
1268 if (!t) {
1269 badataddr:
1270 errx(1, "bad address: %s", s);
1271 }
1272 val = atoi (s);
1273 if (val > 65535)
1274 goto badataddr;
1275 su->sat.sat_addr.s_net = val;
1276 val = atoi (t);
1277 if (val > 256)
1278 goto badataddr;
1279 su->sat.sat_addr.s_node = val;
1280 rtm_addrs |= RTA_NETMASK;
1281 return(forcehost || su->sat.sat_addr.s_node != 0);
1282 #endif
1283
1284 case AF_LINK:
1285 link_addr(s, &su->sdl);
1286 return (1);
1287
1288 case AF_INET:
1289 default:
1290 break;
1291 }
1292
1293 if (hpp == NULL)
1294 hpp = &hp;
1295 *hpp = NULL;
1296
1297 if ((t = strchr(s, '/')) != NULL && which == RTA_DST) {
1298 *t = '\0';
1299 if (forcenet == 0) {
1300 if ((val = inet_addr(s)) != INADDR_NONE) {
1301 inet_makenetandmask(htonl(val), &su->sin);
1302 return prefixlen(&t[1]);
1303 }
1304 } else {
1305 if ((val = inet_network(s)) != INADDR_NONE) {
1306 inet_makenetandmask(val, &su->sin);
1307 return prefixlen(&t[1]);
1308 }
1309 }
1310 *t = '/';
1311 }
1312 if (inet_aton(s, &su->sin.sin_addr) &&
1313 (which != RTA_DST || forcenet == 0)) {
1314 val = su->sin.sin_addr.s_addr;
1315 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1316 return (1);
1317 else {
1318 val = ntohl(val);
1319 goto netdone;
1320 }
1321 }
1322 if ((val = inet_network(s)) != INADDR_NONE ||
1323 ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
1324 netdone:
1325 if (which == RTA_DST)
1326 inet_makenetandmask(val, &su->sin);
1327 return (0);
1328 }
1329 hp = gethostbyname(s);
1330 if (hp) {
1331 *hpp = hp;
1332 su->sin.sin_family = hp->h_addrtype;
1333 memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length);
1334 return (1);
1335 }
1336 errx(1, "bad value: %s", s);
1337 }
1338
1339 int
1340 prefixlen(const char *s)
1341 {
1342 int len = atoi(s), q, r;
1343 int max;
1344
1345 switch (af) {
1346 case AF_INET:
1347 max = sizeof(struct in_addr) * 8;
1348 break;
1349 #ifdef INET6
1350 case AF_INET6:
1351 max = sizeof(struct in6_addr) * 8;
1352 break;
1353 #endif
1354 default:
1355 errx(1, "prefixlen is not supported with af %d", af);
1356 }
1357
1358 rtm_addrs |= RTA_NETMASK;
1359 if (len < -1 || len > max)
1360 errx(1, "bad value: %s", s);
1361
1362 q = len >> 3;
1363 r = len & 7;
1364 switch (af) {
1365 case AF_INET:
1366 memset(&so_mask, 0, sizeof(so_mask));
1367 so_mask.sin.sin_family = AF_INET;
1368 so_mask.sin.sin_len = sizeof(struct sockaddr_in);
1369 so_mask.sin.sin_addr.s_addr = htonl(0xffffffff << (32 - len));
1370 break;
1371 #ifdef INET6
1372 case AF_INET6:
1373 so_mask.sin6.sin6_family = AF_INET6;
1374 so_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
1375 memset((void *)&so_mask.sin6.sin6_addr, 0,
1376 sizeof(so_mask.sin6.sin6_addr));
1377 if (q > 0)
1378 memset((void *)&so_mask.sin6.sin6_addr, 0xff, q);
1379 if (r > 0)
1380 *((u_char *)&so_mask.sin6.sin6_addr + q) =
1381 (0xff00 >> r) & 0xff;
1382 break;
1383 #endif
1384 }
1385 return (len == max);
1386 }
1387
1388 #ifndef SMALL
1389 int
1390 x25_makemask(void)
1391 {
1392 char *cp;
1393
1394 if ((rtm_addrs & RTA_NETMASK) == 0) {
1395 rtm_addrs |= RTA_NETMASK;
1396 for (cp = (char *)&so_mask.sx25.x25_net;
1397 cp < &so_mask.sx25.x25_opts.op_flags; cp++)
1398 *cp = -1;
1399 so_mask.sx25.x25_len = (u_char)&(((sup)0)->sx25.x25_opts);
1400 }
1401 return 0;
1402 }
1403
1404
1405 const char *
1406 ns_print(struct sockaddr_ns *sns)
1407 {
1408 struct ns_addr work;
1409 union { union ns_net net_e; u_int32_t int32_t_e; } net;
1410 u_short port;
1411 static char mybuf[50], cport[10], chost[25];
1412 const char *host = "";
1413 char *p;
1414 u_char *q;
1415
1416 work = sns->sns_addr;
1417 port = ntohs(work.x_port);
1418 work.x_port = 0;
1419 net.net_e = work.x_net;
1420 if (ns_nullhost(work) && net.int32_t_e == 0) {
1421 if (!port)
1422 return ("*.*");
1423 (void)snprintf(mybuf, sizeof mybuf, "*.%XH", port);
1424 return (mybuf);
1425 }
1426
1427 if (memcmp(ns_bh, work.x_host.c_host, 6) == 0)
1428 host = "any";
1429 else if (memcmp(ns_nullh, work.x_host.c_host, 6) == 0)
1430 host = "*";
1431 else {
1432 q = work.x_host.c_host;
1433 (void)snprintf(chost, sizeof chost, "%02X%02X%02X%02X%02X%02XH",
1434 q[0], q[1], q[2], q[3], q[4], q[5]);
1435 for (p = chost; *p == '0' && p < chost + 12; p++)
1436 /* void */;
1437 host = p;
1438 }
1439 if (port)
1440 (void)snprintf(cport, sizeof cport, ".%XH", htons(port));
1441 else
1442 *cport = 0;
1443
1444 (void)snprintf(mybuf, sizeof mybuf, "%XH.%s%s",
1445 (u_int32_t)ntohl(net.int32_t_e), host, cport);
1446 return (mybuf);
1447 }
1448
1449 static void
1450 interfaces(void)
1451 {
1452 size_t needed;
1453 int mib[6];
1454 char *buf, *lim, *next;
1455 struct rt_msghdr *rtm;
1456
1457 mib[0] = CTL_NET;
1458 mib[1] = PF_ROUTE;
1459 mib[2] = 0; /* protocol */
1460 mib[3] = 0; /* wildcard address family */
1461 mib[4] = NET_RT_IFLIST;
1462 mib[5] = 0; /* no flags */
1463 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1464 err(1, "route-sysctl-estimate");
1465 if ((buf = malloc(needed)) == NULL)
1466 err(1, "malloc");
1467 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1468 err(1, "actual retrieval of interface table");
1469 lim = buf + needed;
1470 for (next = buf; next < lim; next += rtm->rtm_msglen) {
1471 rtm = (struct rt_msghdr *)next;
1472 print_rtmsg(rtm, rtm->rtm_msglen);
1473 }
1474 }
1475
1476 static void
1477 monitor(void)
1478 {
1479 int n;
1480 char msg[2048];
1481
1482 verbose = 1;
1483 if (debugonly) {
1484 interfaces();
1485 exit(0);
1486 }
1487 for(;;) {
1488 time_t now;
1489 n = read(sock, msg, 2048);
1490 now = time(NULL);
1491 (void)printf("got message of size %d on %s", n, ctime(&now));
1492 print_rtmsg((struct rt_msghdr *)msg, n);
1493 }
1494 }
1495
1496 #endif /* SMALL */
1497
1498
1499 struct {
1500 struct rt_msghdr m_rtm;
1501 char m_space[512];
1502 } m_rtmsg;
1503
1504 static int
1505 rtmsg(int cmd, int flags)
1506 {
1507 static int seq;
1508 int rlen;
1509 char *cp = m_rtmsg.m_space;
1510 int l;
1511
1512 #define NEXTADDR(w, u) \
1513 if (rtm_addrs & (w)) {\
1514 l = ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1515 if (verbose && ! shortoutput) sodump(&(u),#u);\
1516 }
1517
1518 errno = 0;
1519 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1520 if (cmd == 'a')
1521 cmd = RTM_ADD;
1522 else if (cmd == 'c')
1523 cmd = RTM_CHANGE;
1524 else if (cmd == 'g') {
1525 #ifdef SMALL
1526 return (-1);
1527 #else /* SMALL */
1528 cmd = RTM_GET;
1529 if (so_ifp.sa.sa_family == 0) {
1530 so_ifp.sa.sa_family = AF_LINK;
1531 so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1532 rtm_addrs |= RTA_IFP;
1533 }
1534 #endif /* SMALL */
1535 } else
1536 cmd = RTM_DELETE;
1537 #define rtm m_rtmsg.m_rtm
1538 rtm.rtm_type = cmd;
1539 rtm.rtm_flags = flags;
1540 rtm.rtm_version = RTM_VERSION;
1541 rtm.rtm_seq = ++seq;
1542 rtm.rtm_addrs = rtm_addrs;
1543 rtm.rtm_rmx = rt_metrics;
1544 rtm.rtm_inits = rtm_inits;
1545
1546 if (rtm_addrs & RTA_NETMASK)
1547 mask_addr();
1548 NEXTADDR(RTA_DST, so_dst);
1549 NEXTADDR(RTA_GATEWAY, so_gate);
1550 NEXTADDR(RTA_NETMASK, so_mask);
1551 NEXTADDR(RTA_GENMASK, so_genmask);
1552 NEXTADDR(RTA_IFP, so_ifp);
1553 NEXTADDR(RTA_IFA, so_ifa);
1554 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1555 if (verbose && ! shortoutput)
1556 print_rtmsg(&rtm, l);
1557 if (debugonly)
1558 return (0);
1559 if ((rlen = write(sock, (char *)&m_rtmsg, l)) < 0) {
1560 warn("writing to routing socket");
1561 return (-1);
1562 }
1563 #ifndef SMALL
1564 if (cmd == RTM_GET) {
1565 do {
1566 l = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
1567 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1568 if (l < 0)
1569 err(1, "read from routing socket");
1570 else
1571 print_getmsg(&rtm, l);
1572 }
1573 #endif /* SMALL */
1574 #undef rtm
1575 return (0);
1576 }
1577
1578 static void
1579 mask_addr(void)
1580 {
1581 int olen = so_mask.sa.sa_len;
1582 char *cp1 = olen + (char *)&so_mask, *cp2;
1583
1584 for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1585 if (*--cp1 != 0) {
1586 so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1587 break;
1588 }
1589 if ((rtm_addrs & RTA_DST) == 0)
1590 return;
1591 switch (so_dst.sa.sa_family) {
1592 case AF_INET:
1593 #ifdef INET6
1594 case AF_INET6:
1595 #endif
1596 #ifndef SMALL
1597 case AF_APPLETALK:
1598 case AF_NS:
1599 case AF_CCITT:
1600 #endif /* SMALL */
1601 case 0:
1602 return;
1603 #ifndef SMALL
1604 case AF_ISO:
1605 olen = MIN(so_dst.siso.siso_nlen,
1606 MAX(so_mask.sa.sa_len - 6, 0));
1607 break;
1608 #endif /* SMALL */
1609 }
1610 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1611 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1612 while (cp2 > cp1)
1613 *--cp2 = 0;
1614 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1615 while (cp1 > so_dst.sa.sa_data)
1616 *--cp1 &= *--cp2;
1617 #ifndef SMALL
1618 switch (so_dst.sa.sa_family) {
1619 case AF_ISO:
1620 so_dst.siso.siso_nlen = olen;
1621 break;
1622 }
1623 #endif /* SMALL */
1624 }
1625
1626 const char *msgtypes[] = {
1627 "",
1628 "RTM_ADD: Add Route",
1629 "RTM_DELETE: Delete Route",
1630 "RTM_CHANGE: Change Metrics or flags",
1631 "RTM_GET: Report Metrics",
1632 "RTM_LOSING: Kernel Suspects Partitioning",
1633 "RTM_REDIRECT: Told to use different route",
1634 "RTM_MISS: Lookup failed on this address",
1635 "RTM_LOCK: fix specified metrics",
1636 "RTM_OLDADD: caused by SIOCADDRT",
1637 "RTM_OLDDEL: caused by SIOCDELRT",
1638 "RTM_RESOLVE: Route created by cloning",
1639 "RTM_NEWADDR: address being added to iface",
1640 "RTM_DELADDR: address being removed from iface",
1641 "RTM_OIFINFO: iface status change (pre-1.5)",
1642 "RTM_IFINFO: iface status change",
1643 "RTM_IFANNOUNCE: iface arrival/departure",
1644 "RTM_IEEE80211: IEEE80211 wireless event",
1645 0,
1646 };
1647
1648 char metricnames[] =
1649 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1650 char routeflags[] =
1651 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1";
1652 char ifnetflags[] =
1653 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1654 char addrnames[] =
1655 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1656
1657
1658 #ifndef SMALL
1659 static const char *
1660 linkstate(struct if_msghdr *ifm)
1661 {
1662 static char buf[64];
1663
1664 switch (ifm->ifm_data.ifi_link_state) {
1665 case LINK_STATE_UNKNOWN:
1666 return "carrier: unknown";
1667 case LINK_STATE_DOWN:
1668 return "carrier: no carrier";
1669 case LINK_STATE_UP:
1670 return "carrier: active";
1671 default:
1672 (void)snprintf(buf, sizeof(buf), "carrier: 0x%x",
1673 ifm->ifm_data.ifi_link_state);
1674 return buf;
1675 }
1676 }
1677 #endif /* SMALL */
1678
1679 static void
1680 print_rtmsg(struct rt_msghdr *rtm, int msglen)
1681 {
1682 struct if_msghdr *ifm;
1683 struct ifa_msghdr *ifam;
1684 struct if_announcemsghdr *ifan;
1685 union {
1686 struct ieee80211_join_event join;
1687 struct ieee80211_leave_event leave;
1688 struct ieee80211_replay_event replay;
1689 struct ieee80211_michael_event michael;
1690 } ev;
1691 size_t evlen = 0;
1692
1693 if (verbose == 0)
1694 return;
1695 if (rtm->rtm_version != RTM_VERSION) {
1696 (void)printf("routing message version %d not understood\n",
1697 rtm->rtm_version);
1698 return;
1699 }
1700 if (msgtypes[rtm->rtm_type])
1701 (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1702 else
1703 (void)printf("#%d: ", rtm->rtm_type);
1704 (void)printf("len %d, ", rtm->rtm_msglen);
1705 switch (rtm->rtm_type) {
1706 case RTM_IFINFO:
1707 ifm = (struct if_msghdr *)rtm;
1708 (void)printf("if# %d, %s, flags:", ifm->ifm_index,
1709 #ifdef SMALL
1710 ""
1711 #else
1712 linkstate(ifm)
1713 #endif /* SMALL */
1714 );
1715 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1716 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1717 break;
1718 case RTM_NEWADDR:
1719 case RTM_DELADDR:
1720 ifam = (struct ifa_msghdr *)rtm;
1721 (void)printf("metric %d, flags:", ifam->ifam_metric);
1722 bprintf(stdout, ifam->ifam_flags, routeflags);
1723 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1724 break;
1725 case RTM_IEEE80211:
1726 ifan = (struct if_announcemsghdr *)rtm;
1727 (void)printf("if# %d, what: ", ifan->ifan_index);
1728 switch (ifan->ifan_what) {
1729 case RTM_IEEE80211_ASSOC:
1730 printf("associate");
1731 break;
1732 case RTM_IEEE80211_REASSOC:
1733 printf("re-associate");
1734 break;
1735 case RTM_IEEE80211_DISASSOC:
1736 printf("disassociate");
1737 break;
1738 case RTM_IEEE80211_SCAN:
1739 printf("scan complete");
1740 break;
1741 case RTM_IEEE80211_JOIN:
1742 evlen = sizeof(ev.join);
1743 printf("join");
1744 break;
1745 case RTM_IEEE80211_LEAVE:
1746 evlen = sizeof(ev.leave);
1747 printf("leave");
1748 break;
1749 case RTM_IEEE80211_MICHAEL:
1750 evlen = sizeof(ev.michael);
1751 printf("michael");
1752 break;
1753 case RTM_IEEE80211_REPLAY:
1754 evlen = sizeof(ev.replay);
1755 printf("replay");
1756 break;
1757 default:
1758 evlen = 0;
1759 printf("#%d", ifan->ifan_what);
1760 break;
1761 }
1762 if (sizeof(*ifan) + evlen > ifan->ifan_msglen) {
1763 printf(" (truncated)\n");
1764 break;
1765 }
1766 (void)memcpy(&ev, (ifan + 1), evlen);
1767 switch (ifan->ifan_what) {
1768 case RTM_IEEE80211_JOIN:
1769 case RTM_IEEE80211_LEAVE:
1770 printf(" mac %" PRIETHER,
1771 PRIETHER_ARGS(ev.join.iev_addr));
1772 break;
1773 case RTM_IEEE80211_REPLAY:
1774 case RTM_IEEE80211_MICHAEL:
1775 printf(" src %" PRIETHER " dst %" PRIETHER
1776 " cipher %" PRIu8 " keyix %" PRIu8,
1777 PRIETHER_ARGS(ev.replay.iev_src),
1778 PRIETHER_ARGS(ev.replay.iev_dst),
1779 ev.replay.iev_cipher,
1780 ev.replay.iev_keyix);
1781 if (ifan->ifan_what == RTM_IEEE80211_REPLAY) {
1782 printf(" key rsc %#" PRIx64
1783 " frame rsc %#" PRIx64,
1784 ev.replay.iev_keyrsc, ev.replay.iev_rsc);
1785 }
1786 break;
1787 default:
1788 break;
1789 }
1790 printf("\n");
1791 break;
1792 case RTM_IFANNOUNCE:
1793 ifan = (struct if_announcemsghdr *)rtm;
1794 (void)printf("if# %d, what: ", ifan->ifan_index);
1795 switch (ifan->ifan_what) {
1796 case IFAN_ARRIVAL:
1797 printf("arrival");
1798 break;
1799 case IFAN_DEPARTURE:
1800 printf("departure");
1801 break;
1802 default:
1803 printf("#%d", ifan->ifan_what);
1804 break;
1805 }
1806 printf("\n");
1807 break;
1808 default:
1809 (void)printf("pid: %d, seq %d, errno %d, flags:",
1810 rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1811 bprintf(stdout, rtm->rtm_flags, routeflags);
1812 pmsg_common(rtm);
1813 }
1814 }
1815
1816 #ifndef SMALL
1817 static void
1818 print_getmsg(struct rt_msghdr *rtm, int msglen)
1819 {
1820 struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL;
1821 struct sockaddr_dl *ifp = NULL;
1822 struct sockaddr *sa;
1823 char *cp;
1824 int i;
1825
1826 if (! shortoutput)
1827 (void)printf(" route to: %s\n",
1828 routename((struct sockaddr *) &so_dst, NULL, RTF_HOST));
1829 if (rtm->rtm_version != RTM_VERSION) {
1830 warnx("routing message version %d not understood",
1831 rtm->rtm_version);
1832 return;
1833 }
1834 if (rtm->rtm_msglen > msglen) {
1835 warnx("message length mismatch, in packet %d, returned %d",
1836 rtm->rtm_msglen, msglen);
1837 }
1838 if (rtm->rtm_errno) {
1839 warn("RTM_GET");
1840 return;
1841 }
1842 cp = ((char *)(rtm + 1));
1843 if (rtm->rtm_addrs)
1844 for (i = 1; i; i <<= 1)
1845 if (i & rtm->rtm_addrs) {
1846 sa = (struct sockaddr *)cp;
1847 switch (i) {
1848 case RTA_DST:
1849 dst = sa;
1850 break;
1851 case RTA_GATEWAY:
1852 gate = sa;
1853 break;
1854 case RTA_NETMASK:
1855 mask = sa;
1856 break;
1857 case RTA_IFP:
1858 if (sa->sa_family == AF_LINK &&
1859 ((struct sockaddr_dl *)sa)->sdl_nlen)
1860 ifp = (struct sockaddr_dl *)sa;
1861 break;
1862 case RTA_IFA:
1863 ifa = sa;
1864 break;
1865 }
1866 ADVANCE(cp, sa);
1867 }
1868 if (dst && mask)
1869 mask->sa_family = dst->sa_family; /* XXX */
1870 if (dst && ! shortoutput)
1871 (void)printf("destination: %s\n",
1872 routename(dst, mask, RTF_HOST));
1873 if (mask && ! shortoutput) {
1874 int savenflag = nflag;
1875
1876 nflag = 1;
1877 (void)printf(" mask: %s\n",
1878 routename(mask, NULL, RTF_HOST));
1879 nflag = savenflag;
1880 }
1881 if (gate && rtm->rtm_flags & RTF_GATEWAY && ! shortoutput)
1882 (void)printf(" gateway: %s\n",
1883 routename(gate, NULL, RTF_HOST));
1884 if (ifa && ! shortoutput)
1885 (void)printf(" local addr: %s\n",
1886 routename(ifa, NULL, RTF_HOST));
1887 if (ifp && ! shortoutput)
1888 (void)printf(" interface: %.*s\n",
1889 ifp->sdl_nlen, ifp->sdl_data);
1890 if (! shortoutput) {
1891 (void)printf(" flags: ");
1892 bprintf(stdout, rtm->rtm_flags, routeflags);
1893 }
1894
1895 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1896 #define msec(u) (((u) + 500) / 1000) /* usec to msec */
1897
1898 if (! shortoutput) {
1899 (void)printf("\n%s\n", "\
1900 recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
1901 printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1902 printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1903 printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1904 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1905 printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1906 printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1907 printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1908 if (rtm->rtm_rmx.rmx_expire)
1909 rtm->rtm_rmx.rmx_expire -= time(0);
1910 printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1911 }
1912 #undef lock
1913 #undef msec
1914 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1915
1916 if ((rtm->rtm_addrs & RTF_GATEWAY) == 0)
1917 rv = 1;
1918 else {
1919 const char *name;
1920 int addrs;
1921
1922 cp = (char *)(rtm + 1);
1923 addrs = rtm->rtm_addrs;
1924
1925 for (i = 1; i; i <<= 1) {
1926 sa = (struct sockaddr *)cp;
1927 if (i == RTF_GATEWAY) {
1928 name = routename(sa, NULL, RTF_HOST);
1929 if (name[0] == '\0')
1930 rv = 1;
1931 else if (shortoutput)
1932 printf("%s\n", name);
1933 }
1934 if (i & addrs)
1935 ADVANCE(cp, sa);
1936 }
1937 }
1938
1939 if (shortoutput)
1940 return;
1941 else if (verbose)
1942 pmsg_common(rtm);
1943 else if (rtm->rtm_addrs &~ RTA_IGN) {
1944 (void)printf("sockaddrs: ");
1945 bprintf(stdout, rtm->rtm_addrs, addrnames);
1946 putchar('\n');
1947 }
1948 #undef RTA_IGN
1949 }
1950 #endif /* SMALL */
1951
1952 void
1953 pmsg_common(struct rt_msghdr *rtm)
1954 {
1955 (void)printf("\nlocks: ");
1956 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1957 (void)printf(" inits: ");
1958 bprintf(stdout, rtm->rtm_inits, metricnames);
1959 pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1960 }
1961
1962 static void
1963 pmsg_addrs(char *cp, int addrs)
1964 {
1965 struct sockaddr *sa;
1966 int i;
1967
1968 if (addrs != 0) {
1969 (void)printf("\nsockaddrs: ");
1970 bprintf(stdout, addrs, addrnames);
1971 (void)putchar('\n');
1972 for (i = 1; i; i <<= 1)
1973 if (i & addrs) {
1974 sa = (struct sockaddr *)cp;
1975 (void)printf(" %s",
1976 routename(sa, NULL, RTF_HOST));
1977 ADVANCE(cp, sa);
1978 }
1979 }
1980 (void)putchar('\n');
1981 (void)fflush(stdout);
1982 }
1983
1984 static void
1985 bprintf(FILE *fp, int b, u_char *s)
1986 {
1987 int i;
1988 int gotsome = 0;
1989
1990 if (b == 0)
1991 return;
1992 while ((i = *s++) != 0) {
1993 if (b & (1 << (i-1))) {
1994 if (gotsome == 0)
1995 i = '<';
1996 else
1997 i = ',';
1998 (void)putc(i, fp);
1999 gotsome = 1;
2000 for (; (i = *s) > 32; s++)
2001 (void)putc(i, fp);
2002 } else
2003 while (*s > 32)
2004 s++;
2005 }
2006 if (gotsome)
2007 (void)putc('>', fp);
2008 }
2009
2010 int
2011 keyword(char *cp)
2012 {
2013 struct keytab *kt = keywords;
2014
2015 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
2016 kt++;
2017 return kt->kt_i;
2018 }
2019
2020 static void
2021 sodump(sup su, const char *which)
2022 {
2023 #ifdef INET6
2024 char ntop_buf[NI_MAXHOST];
2025 #endif
2026
2027 switch (su->sa.sa_family) {
2028 case AF_INET:
2029 (void)printf("%s: inet %s; ",
2030 which, inet_ntoa(su->sin.sin_addr));
2031 break;
2032 #ifndef SMALL
2033 case AF_APPLETALK:
2034 (void)printf("%s: atalk %d.%d; ",
2035 which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node);
2036 break;
2037 #endif
2038 case AF_LINK:
2039 (void)printf("%s: link %s; ",
2040 which, link_ntoa(&su->sdl));
2041 break;
2042 #ifndef SMALL
2043 #ifdef INET6
2044 case AF_INET6:
2045 (void)printf("%s: inet6 %s; ",
2046 which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
2047 ntop_buf, sizeof(ntop_buf)));
2048 break;
2049 #endif
2050 case AF_ISO:
2051 (void)printf("%s: iso %s; ",
2052 which, iso_ntoa(&su->siso.siso_addr));
2053 break;
2054 case AF_NS:
2055 (void)printf("%s: xns %s; ",
2056 which, ns_ntoa(su->sns.sns_addr));
2057 break;
2058 #endif /* SMALL */
2059 default:
2060 (void)printf("%s: (%d) %s; ",
2061 which, su->sa.sa_family, any_ntoa(&su->sa));
2062 }
2063 (void)fflush(stdout);
2064 }
2065
2066 /* States*/
2067 #define VIRGIN 0
2068 #define GOTONE 1
2069 #define GOTTWO 2
2070 /* Inputs */
2071 #define DIGIT (4*0)
2072 #define END (4*1)
2073 #define DELIM (4*2)
2074
2075 static void
2076 sockaddr(char *addr, struct sockaddr *sa)
2077 {
2078 char *cp = (char *)sa;
2079 int size = sa->sa_len;
2080 char *cplim = cp + size;
2081 int byte = 0, state = VIRGIN, new = 0;
2082
2083 (void)memset(cp, 0, size);
2084 cp++;
2085 do {
2086 if ((*addr >= '0') && (*addr <= '9')) {
2087 new = *addr - '0';
2088 } else if ((*addr >= 'a') && (*addr <= 'f')) {
2089 new = *addr - 'a' + 10;
2090 } else if ((*addr >= 'A') && (*addr <= 'F')) {
2091 new = *addr - 'A' + 10;
2092 } else if (*addr == 0)
2093 state |= END;
2094 else
2095 state |= DELIM;
2096 addr++;
2097 switch (state /* | INPUT */) {
2098 case GOTTWO | DIGIT:
2099 *cp++ = byte; /*FALLTHROUGH*/
2100 case VIRGIN | DIGIT:
2101 state = GOTONE; byte = new; continue;
2102 case GOTONE | DIGIT:
2103 state = GOTTWO; byte = new + (byte << 4); continue;
2104 default: /* | DELIM */
2105 state = VIRGIN; *cp++ = byte; byte = 0; continue;
2106 case GOTONE | END:
2107 case GOTTWO | END:
2108 *cp++ = byte; /* FALLTHROUGH */
2109 case VIRGIN | END:
2110 break;
2111 }
2112 break;
2113 } while (cp < cplim);
2114 sa->sa_len = cp - (char *)sa;
2115 }
2116