source: rtems-libbsd/freebsd/sbin/route/route.c @ 66659ff

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 66659ff was 66659ff, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 15:20:21

Update to FreeBSD 9.2

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