source: rtems-libbsd/freebsd/sbin/route/route.c @ 2017a6d

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 2017a6d was 7eeb079, checked in by Sebastian Huber <sebastian.huber@…>, on 02/02/15 at 13:27:13

Update to FreeBSD 9.3

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