source: rtems-libbsd/freebsd-userspace/commands/sbin/route/route.c @ 3ac9bb1

4.115-freebsd-12freebsd-9.3
Last change on this file since 3ac9bb1 was 3ac9bb1, checked in by Jennifer Averett <jennifer.averett@…>, on Oct 5, 2012 at 6:41:20 PM

route.c and ifconfig.c: Added rtems style mains.

Fixed route.c to match freebsd version with only rtems additions.

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