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

55-freebsd-126-freebsd-12
Last change on this file since fb288fa was fb288fa, checked in by Sebastian Huber <sebastian.huber@…>, on 01/11/17 at 13:15:31

ROUTE(8): Disable routing socket timeout support

FIXME: This reverts the following change in FreeBSD.

commit 76a39ff8dc5e1f7bc8a065115ec3837761ed0600
Author: ae <ae@…>
Date: Wed Jul 27 08:26:34 2016 +0000

Due to dropped mbuf in netisr queue route(8) can fall into infinity
loop of reading the rtsock's feed. When it used by some scripts,
this leads to growing number of not finished route(8) instances and
thus growing number of rtsock consumers. Add SIGALRM handler to
prevent this.

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