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

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

ROUTE(8): Fix memory leak

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