source: rtems-libbsd/freebsd/sbin/route/route.c @ 21abaef

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 21abaef was 21abaef, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/15/16 at 05:32:56

freebsd: Don't use new wrappers for old ports.

Some of the commands have been adapted manually. So the wrapper
currently don't necessarily work as expected. For example ifconfig calls
malloc outside of the program call.

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