route.c revision 3f33f4f79cd49923b042b1d7c50a69056e05d3e6
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1990 Mentat Inc. */
/*
*
* Copyright (c) 1983, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)route.c 8.6 (Berkeley) 4/28/95
* @(#)linkaddr.c 8.1 (Berkeley) 6/4/93
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <netdb.h>
#include <limits.h>
#include <locale.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stropts.h>
#include <fcntl.h>
#include <setjmp.h>
#include <stdarg.h>
#include <assert.h>
static struct keytab {
char *kt_cp;
int kt_i;
} keywords[] = {
#define K_ADD 1
{"add", K_ADD},
#define K_BLACKHOLE 2
{"blackhole", K_BLACKHOLE},
#define K_CHANGE 3
{"change", K_CHANGE},
#define K_CLONING 4
{"cloning", K_CLONING},
#define K_DELETE 5
{"delete", K_DELETE},
#define K_DST 6
{"dst", K_DST},
#define K_EXPIRE 7
{"expire", K_EXPIRE},
#define K_FLUSH 8
{"flush", K_FLUSH},
#define K_GATEWAY 9
{"gateway", K_GATEWAY},
#define K_GET 11
{"get", K_GET},
#define K_HOPCOUNT 12
{"hopcount", K_HOPCOUNT},
#define K_HOST 13
{"host", K_HOST},
#define K_IFA 14
{"ifa", K_IFA},
#define K_IFACE 15
{"iface", K_IFACE},
#define K_IFP 16
{"ifp", K_IFP},
#define K_INET 17
{"inet", K_INET},
#define K_INET6 18
{"inet6", K_INET6},
#define K_INTERFACE 19
{"interface", K_INTERFACE},
#define K_LINK 20
{"link", K_LINK},
#define K_LOCK 21
{"lock", K_LOCK},
#define K_LOCKREST 22
{"lockrest", K_LOCKREST},
#define K_MASK 23
{"mask", K_MASK},
#define K_MONITOR 24
{"monitor", K_MONITOR},
#define K_MTU 25
{"mtu", K_MTU},
#define K_NET 26
{"net", K_NET},
#define K_NETMASK 27
{"netmask", K_NETMASK},
#define K_NOSTATIC 28
{"nostatic", K_NOSTATIC},
#define K_PRIVATE 29
{"private", K_PRIVATE},
#define K_PROTO1 30
{"proto1", K_PROTO1},
#define K_PROTO2 31
{"proto2", K_PROTO2},
#define K_RECVPIPE 32
{"recvpipe", K_RECVPIPE},
#define K_REJECT 33
{"reject", K_REJECT},
#define K_RTT 34
{"rtt", K_RTT},
#define K_RTTVAR 35
{"rttvar", K_RTTVAR},
#define K_SA 36
{"sa", K_SA},
#define K_SENDPIPE 37
{"sendpipe", K_SENDPIPE},
#define K_SSTHRESH 38
{"ssthresh", K_SSTHRESH},
#define K_STATIC 39
{"static", K_STATIC},
#define K_XRESOLVE 40
{"xresolve", K_XRESOLVE},
#define K_MULTIRT 41
{"multirt", K_MULTIRT},
#define K_SETSRC 42
{"setsrc", K_SETSRC},
#define K_SHOW 43
{"show", K_SHOW},
{0, 0}
};
/*
* Size of buffers used to hold command lines from the saved route file as
* well as error strings.
*/
#define BUF_SIZE 2048
typedef union sockunion {
struct sockaddr_in sin;
struct sockaddr_dl sdl;
struct sockaddr_in6 sin6;
} su_t;
/*
* This structure represents the digested information from parsing arguments
* to route add, change, delete, and get.
*
*/
typedef struct rtcmd_irep {
int ri_cmd;
int ri_flags;
int ri_af;
int ri_masklen;
struct rt_metrics ri_metrics;
int ri_addrs;
char *ri_dest_str;
struct hostent *ri_gate_hp;
char *ri_gate_str;
char *ri_ifp_str;
} rtcmd_irep_t;
typedef struct mib_item_s {
struct mib_item_s *next_item;
long group;
long mib_id;
long length;
} mib_item_t;
typedef enum {
} addr_type_t;
typedef enum {
char *cmd_string);
rtcmd_irep_t *rcip);
struct sockaddr_in *sin);
static rtcmd_irep_t *new_rtcmd_irep(void);
static int show_saved_routes(int argc);
static void syntax_arg_missing(char *keyword);
static void syntax_bad_keyword(char *keyword);
static void syntax_error(char *err, ...);
static int s;
static char perm_file_sfx[] = "/etc/inet/static_routes";
static char *perm_file;
static char *root_dir;
static char temp_file_sfx[] = "/etc/inet/static_routes.tmp";
static char *temp_file;
/*
* WARNING:
* This next variable indicates whether certain functions exit when an error
* is detected in the user input. Currently, exit_on_error is only set false
* in search_rtfile(), when argument are being parsed. Only those functions
* used by search_rtfile() to parse its arguments are designed to work in
* both modes. Take particular care in setting this false to ensure that any
* functions you call that might act on this flag properly return errors when
* exit_on_error is false.
*/
static int exit_on_error = B_TRUE;
static struct {
char m_space[512];
} m_rtmsg;
/*
* Sizes of data structures extracted from the base mib.
* This allows the size of the tables entries to grow while preserving
* binary compatibility.
*/
static int ipRouteEntrySize;
static int ipv6RouteEntrySize;
#define ROUNDUP_LONG(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
#define C(x) ((x) & 0xff)
/*
* return values from in_getprefixlen()
*/
void
{
cp);
}
"[ -R <root-dir> ] cmd [[ -<qualifers> ] args ]\n"));
exit(1);
/* NOTREACHED */
}
/*PRINTFLIKE1*/
void
syntax_error(char *err, ...)
{
if (exit_on_error) {
exit(1);
}
/* NOTREACHED */
}
void
syntax_bad_keyword(char *keyword)
{
}
void
syntax_arg_missing(char *keyword)
{
keyword);
}
void
{
if (s != NULL)
/* NOTREACHED */
}
int
{
extern int optind;
extern char *optarg;
int ch;
int key;
int rval;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (argc < 2)
switch (ch) {
case 'n':
break;
case 'q':
break;
case 'v':
break;
case 't':
break;
case 'd':
break;
case 'f':
break;
case 'p':
break;
case 'R':
break;
case '?':
default:
/* NOTREACHED */
}
}
if (tflag)
else
if (s < 0)
/*
* Handle the -p and -R flags. The -R flag only applies
* when the -p flag is set.
*/
} else {
}
if (fflag) {
/*
* Accept an address family keyword after the -f. Since the
* default address family is AF_INET, reassign af only for the
* other valid address families.
*/
case K_INET:
case K_INET6:
/* Skip over the address family parameter. */
argc--;
argv++;
break;
}
}
/*
* Act only on the file.
*/
} else {
flushroutes(0, NULL);
}
}
fflag = 0;
case K_GET:
case K_CHANGE:
case K_ADD:
case K_DELETE:
/*
* Act only on the file.
*/
rval = 0;
} else {
}
return (0);
}
return (rval);
case K_SHOW:
if (perm_flag) {
return (show_saved_routes(argc));
} else {
"route: show command requires -p"));
}
/* NOTREACHED */
case K_MONITOR:
/* NOTREACHED */
case K_FLUSH:
if (perm_flag) {
fflag = 1;
}
return (0);
}
}
if (!fflag)
return (0);
}
/*
* Purge all entries in the routing tables not
* associated with network interfaces.
*/
void
{
int seqno;
int sd; /* mib stream */
int oerrno;
int off = 0;
int on = 1;
sizeof (off)) < 0)
if (argc > 1) {
argv++;
/*
* The address family (preceded by a dash) may be used
* to flush the routes of that particular family.
*/
case K_INET:
break;
case K_LINK:
break;
case K_INET6:
break;
default:
/* NOTREACHED */
}
} else {
}
}
if (sd < 0) {
switch (errno) {
case EACCES:
gettext("route: flush: insufficient privileges\n"));
/* NOTREACHED */
default:
/* NOTREACHED */
}
}
if (verbose) {
(void) printf("Examining routing table from "
"T_SVR4_OPTMGMT_REQ\n");
}
seqno = 0; /* ??? */
switch (af) {
case AF_INET:
/* Extract ipRouteEntrySize */
continue;
sizeof (mib2_ipRouteEntry_t *)));
break;
}
}
if (ipRouteEntrySize == 0) {
gettext("ipRouteEntrySize can't be determined.\n"));
exit(1);
}
/*
* skip all the other trash that comes up the mib stream
*/
continue;
/* LINTED */
rp = (mib2_ipRouteEntry_t *)
((char *)rp + ipRouteEntrySize)) {
seqno++;
}
break;
}
break;
case AF_INET6:
/* Extract ipv6RouteEntrySize */
continue;
sizeof (mib2_ipv6RouteEntry_t *)));
break;
}
}
if (ipv6RouteEntrySize == 0) {
"ipv6RouteEntrySize cannot be determined.\n"));
exit(1);
}
/*
* skip all the other trash that comes up the mib stream
*/
continue;
/* LINTED */
rp6 = (mib2_ipv6RouteEntry_t *)
((char *)rp6 + ipv6RouteEntrySize)) {
seqno++;
}
break;
}
break;
}
sizeof (on)) < 0)
}
/*
* Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or
* MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in
* order to facilitate the flushing of RTF_GATEWAY routes.
*/
static void
{
char *cp;
int ire_type;
int rlen;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
int slen;
else
if (ire_type != IRE_DEFAULT &&
ire_type != IRE_PREFIX &&
return;
slen = sizeof (struct sockaddr_in);
} else {
slen = sizeof (struct sockaddr_in6);
}
if (debugonly) {
/*
* In debugonly mode, the routing socket message to delete the
* current entry is not actually sent. However if verbose is
* also set, the routing socket message that would have been
* is printed.
*/
if (verbose)
return;
}
if (rlen < 0) {
gettext("route: write to routing socket: %s\n"),
} else {
"routing socket got only %d for rlen\n"), rlen);
}
return;
}
if (qflag) {
/*
* In quiet mode, nothing is printed at all (unless the write()
* itself failed.
*/
return;
}
if (verbose) {
} else {
(void) printf("%-20.20s ",
/* LINTED */
(void) printf("done\n");
}
}
/*
* Return the name of the host whose address is given.
*/
char *
{
char *cp;
int error_num;
ushort_t *s;
if (first) {
else
domain[0] = 0;
}
return (line);
}
case AF_INET:
/* LINTED */
cp = "default";
AF_INET);
*cp = 0;
}
}
} else {
}
break;
case AF_LINK:
case AF_INET6:
/* LINTED */
if (IN6_IS_ADDR_UNSPECIFIED(&in6))
cp = "default";
*cp = 0;
}
}
} else {
}
break;
default:
while (++s < slim) /* start with sa->sa_data */
break;
}
return (line);
}
/*
* Return the name of the network whose address is given.
* The address is assumed to be that of a net or subnet, not a host.
*/
static char *
{
int subnetshift;
ushort_t *s;
case AF_INET:
/* LINTED */
cp = "default";
} else if (!nflag) {
subnetshift = 8;
subnetshift = 8;
} else {
subnetshift = 4;
}
/*
* If there are more bits than the standard mask
* would suggest, subnets must be in use.
* Guess at the subnet mask, assuming reasonable
* width subnet fields.
*/
while ((mask & 1) == 0)
}
} else {
}
break;
case AF_LINK:
case AF_INET6:
default:
/* LINTED */
while (s < slim)
break;
}
return (line);
}
/*
* Initialize a new structure. Keep in mind that ri_dst_str, ri_gate_str and
* ri_ifp_str will be freed by det_rtcmd_irep, so they should either be NULL
* or point to dynamically allocated memory.
*/
new_rtcmd_irep(void)
{
}
return (rcip);
}
void
{
}
}
void
{
}
}
/*
* Print the short form summary of a route command.
* Eg. "add net default: gateway 10.0.0.1"
* The final newline is not added, allowing the caller to append additional
* information.
*/
void
{
char *cmd;
char obuf[INET6_ADDRSTRLEN];
case RTM_ADD:
cmd = "add";
break;
case RTM_CHANGE:
cmd = "change";
break;
case RTM_DELETE:
cmd = "delete";
break;
case RTM_GET:
cmd = "get";
break;
default:
assert(0);
}
case AF_INET:
if (nflag) {
} else if (gw_good &&
/*
* Print the actual address used in the case
* where there was more than one address
* available for the name, and one was used
* successfully.
*/
} else {
rcip->ri_gate_str);
}
break;
case AF_INET6:
INET6_ADDRSTRLEN) != NULL) {
if (nflag) {
obuf);
break;
}
if (gw_good &&
break;
}
}
/* FALLTHROUGH */
default:
rcip->ri_gate_str);
break;
}
}
}
void
{
int flag = 0;
switch (key) {
#define caseof(x, y, z) \
}
if (lock)
}
/*
* Parse the options give in argv[], filling in rcip with the results.
* If cmd_string is non-null, argc and argv are ignored, and cmd_string is
* tokenized to produce the command line. Cmd_string is tokenized using
* strtok, which will overwrite whitespace in the string with nulls.
*
* Returns B_TRUE on success and B_FALSE on failure.
*/
{
const char *ws = "\f\n\r\t\v ";
char *tok = cmd_string;
char *keyword_str;
int key;
char *err;
if (cmd_string == NULL) {
} else {
}
/*
* The command keywords are already fully checked by main() or
* search_rtfile().
*/
switch (*tok) {
case 'a':
break;
case 'c':
break;
case 'd':
break;
case 'g':
break;
default:
/* NOTREACHED */
/* NOTREACHED */
}
#define NEXTTOKEN \
while (NEXTTOKEN) {
keyword_str = tok;
if (*tok == '-') {
} else {
/* All others must be preceded by '-' */
key = 0;
}
}
switch (key) {
case K_HOST:
if (atype == ADDR_TYPE_NET) {
"are mutually exclusive\n"));
return (B_FALSE);
}
break;
case K_NET:
if (atype == ADDR_TYPE_HOST) {
"are mutually exclusive\n"));
return (B_FALSE);
}
break;
case K_LINK:
break;
case K_INET:
break;
case K_SA:
break;
case K_INET6:
break;
case K_IFACE:
case K_INTERFACE:
break;
case K_NOSTATIC:
break;
case K_LOCK:
break;
case K_LOCKREST:
break;
case K_REJECT:
break;
case K_BLACKHOLE:
break;
case K_PROTO1:
break;
case K_PROTO2:
break;
case K_CLONING:
break;
case K_XRESOLVE:
break;
case K_STATIC:
break;
case K_IFA:
if (!NEXTTOKEN) {
return (B_FALSE);
}
return (B_FALSE);
}
break;
case K_IFP:
if (!NEXTTOKEN) {
return (B_FALSE);
}
return (B_FALSE);
}
break;
case K_GATEWAY:
if (!NEXTTOKEN) {
return (B_FALSE);
}
return (B_FALSE);
}
break;
case K_DST:
if (!NEXTTOKEN) {
return (B_FALSE);
}
return (B_FALSE);
}
break;
case K_NETMASK:
if (!NEXTTOKEN) {
return (B_FALSE);
}
return (B_FALSE);
}
break;
case K_MTU:
case K_HOPCOUNT:
case K_EXPIRE:
case K_RECVPIPE:
case K_SENDPIPE:
case K_SSTHRESH:
case K_RTT:
case K_RTTVAR:
if (!NEXTTOKEN) {
return (B_FALSE);
}
break;
case K_PRIVATE:
break;
case K_MULTIRT:
break;
case K_SETSRC:
if (!NEXTTOKEN) {
return (B_FALSE);
}
return (B_FALSE);
}
break;
default:
if (dash_keyword) {
return (B_FALSE);
}
return (B_FALSE);
}
/*
* For the gateway parameter, retrieve the
* pointer to the struct hostent so that all
* possible addresses can be tried until one
* is successful.
*/
return (B_FALSE);
}
} else {
/*
* Assume that a regular number is a metric.
* Needed for compatibility with old route
* command syntax.
*/
errno = 0;
metric < 0x80000000ul) {
if (verbose) {
(void) printf("old usage of "
"trailing number, assuming "
"route %s\n", iflag ?
"to if" : "via gateway");
}
continue;
}
return (B_FALSE);
}
}
}
}
return (B_FALSE);
"route: gateway required for add or delete command\n"));
return (B_FALSE);
}
if (!iflag) {
}
} else {
}
}
if (atype == ADDR_TYPE_HOST) {
}
return (B_TRUE);
}
/*
* This command always seeks to the end of the file prior to writing.
*/
void
{
int len;
int i;
len = 0;
argv[i]);
}
errno);
}
}
{
return (B_FALSE);
}
}
/*
* Search the route file for routes matching the supplied route. There are 3
* modes of operation:
* SEARCH_MODE_RET - no side effects.
* SEARCH_MODE_PRINT - prints each matching line.
* SEARCH_MODE_DEL - copies all valid, non-matching lines to tmp_fp.
*
* In all cases, the number of matches is returned. If rt is NULL, all routes
* matching the global af value are considered matching.
*/
int
{
char *tmp_buf;
int match_cnt;
match_cnt = 0;
/*
* Leave space at the beginning of file_line for "add ".
*/
/* Handle comments and blank lines */
if (mode == SEARCH_MODE_DEL &&
"route: failed to write to temp file"),
errno);
}
continue;
}
thisrt = new_rtcmd_irep();
/* args_to_rtcmd() will mangle the string passed. */
/* There was an error in args_to_rtcmd() or helpers */
continue;
}
continue;
}
}
(void) printf("\n");
}
errno);
}
}
return (match_cnt);
}
/*
* Perform the route operation given in argv on the persistent route file.
* If fflag is set, argc and argv are ignored, and the persisten route file
* is flushed of all routes matching the global family.
*/
void
{
int perm_fd;
const char commentstr[] =
"# File generated by route(1M) - do not edit.\n";
/* NOTREACHED */
}
sizeof (commentstr) - 1)
/* NOTREACHED */
}
if (!fflag) {
rt = new_rtcmd_irep();
}
/* NOTREACHED */
}
}
if (fflag) {
/* NOTREACHED */
}
return;
}
case RTM_ADD:
/* Route is already in the file */
exit(1);
}
(void) printf("\n");
break;
case RTM_CHANGE:
gettext("route: change command not supported with -p\n"));
/* NOTREACHED */
case RTM_DELETE:
/* Route not found */
exit(1);
}
/* NOTREACHED */
}
break;
case RTM_GET:
0) {
}
break;
default:
/* NOTREACHED */
}
/*
* Closing the file unlocks it.
*/
}
int
show_saved_routes(int argc)
{
int perm_fd;
int count = 0;
if (argc != 1) {
}
if (perm_fd == -1) {
(void) printf("No persistent routes are defined\n");
return (0);
} else {
}
}
errno);
/* NOTREACHED */
}
/* NOTREACHED */
}
if (count == 0)
(void) printf("No persistent routes are defined\n");
return (0);
}
int
{
char *err;
char obuf[INET6_ADDRSTRLEN];
newrt = new_rtcmd_irep();
/* Don't want to read back our messages */
(void) shutdown(s, 0);
}
} else {
gettext("route: %s: no such interface\n"),
newrt->ri_ifp_str);
exit(1);
}
}
}
errno = 0;
break;
break;
switch (af) {
case AF_INET:
continue;
case AF_INET6:
continue;
}
}
break;
}
if (ret == 0)
(void) printf("\n");
} else if (ret != 0) {
/*
* Note: there is nothing additional to print for get
* if ret == 0.
*/
if (nflag) {
case AF_INET:
(void) printf(" %s",
break;
case AF_INET6:
break;
}
/* FALLTHROUGH */
default:
break;
}
} else {
}
}
if (ret != 0) {
switch (oerrno) {
case ESRCH:
err = "not in table";
break;
case EBUSY:
err = "entry in use";
break;
case ENOBUFS:
err = "routing table overflow";
break;
case EEXIST:
err = "entry exists";
break;
case EPERM:
err = "insufficient privileges";
break;
default:
break;
}
}
return (oerrno);
}
/*
* Convert a network number to the corresponding IP address.
* If the RTA_NETMASK hasn't been specified yet set it based
* on the class of address.
*/
static void
{
if (net == 0) {
} else if (net < 128) {
} else if (net < 65536) {
} else if (net < 16777216L) {
} else {
if ((addr & IN_CLASSA_HOST) == 0)
else if ((addr & IN_CLASSB_HOST) == 0)
else if ((addr & IN_CLASSC_HOST) == 0)
else {
else
mask = IP_HOST_MASK;
}
}
}
}
static in_addr_t
{
int n;
struct sockaddr_in *sin;
char *buf;
int numifs;
int iosoc;
in_addr_t if_subnetmask = 0;
short if_flags;
if (mask == 0)
return (0);
/* Let's check to see if this is maybe a local subnet route. */
/* LINTED */
continue;
/* LINTED */
/*
* Don't trust pt-pt interfaces if there are
* other interfaces.
*/
if (if_flags & IFF_POINTOPOINT) {
continue;
}
/*
* Fine. Just assume the same net mask as the
* directly attached subnet interface is using.
*/
return (if_mask);
}
}
if (if_subnetmask != 0)
return (if_subnetmask);
return (mask);
}
/*
* Interpret an argument as a network address of some kind.
*
* If the address family is one looked up in getaddr() using one of the
* getipnodebyX() functions (currently only AF_INET6), then callers should
* freehostent() the returned "struct hostent" pointer if one was passed in.
*
* If exit_on_error is true, this function will cause route to exit on error by
* calling syntax_error(). Otherwise, it returns B_TRUE on success or B_FALSE
* on failure.
*/
static boolean_t
{
if (which == RTA_GATEWAY) {
} else {
}
switch (which) {
case RTA_DST:
break;
case RTA_GATEWAY:
break;
case RTA_NETMASK:
break;
case RTA_IFP:
return (B_TRUE);
/*
* RTA_SRC has overloaded meaning. It can represent the
* src address of incoming or outgoing packets.
*/
case RTA_IFA:
break;
case RTA_SRC:
break;
default:
/* NOTREACHED */
/* NOTREACHED */
}
if (strcmp(s, "default") == 0) {
}
return (B_TRUE);
}
return (B_TRUE);
}
case AF_LINK:
return (B_TRUE);
case PF_ROUTE:
return (B_TRUE);
case AF_INET6:
switch (which) {
case RTA_DST:
if (s[0] == '/') {
"route: %s: unexpected '/'\n"), s);
return (B_FALSE);
}
return (B_FALSE);
}
switch (rcip->ri_masklen) {
case NO_PREFIX:
/* Nothing there - ok */
return (B_TRUE);
case BAD_ADDR:
"route: bad prefix length in %s\n"), s);
return (B_FALSE);
default:
"route: bad prefix length: %d\n"),
rcip->ri_masklen);
return (B_FALSE);
}
break;
}
return (B_TRUE);
case RTA_GATEWAY:
case RTA_IFA:
case RTA_SRC:
case RTA_NETMASK:
gettext("route: -netmask not supported for IPv6: "
"use <prefix>/<prefix-length> instead\n"));
return (B_FALSE);
default:
/* NOTREACHED */
}
case AF_INET:
switch (which) {
case RTA_DST:
if (s[0] == '/') {
"route: %s: unexpected '/'\n"), s);
return (B_FALSE);
}
return (B_FALSE);
}
switch (rcip->ri_masklen) {
case NO_PREFIX:
/* Nothing there - ok */
return (B_TRUE);
case BAD_ADDR:
"route: bad prefix length in %s\n"), s);
return (B_FALSE);
default:
"route: bad prefix length: %d\n"),
rcip->ri_masklen);
return (B_FALSE);
}
break;
}
return (B_TRUE);
case RTA_GATEWAY:
case RTA_IFA:
case RTA_NETMASK:
case RTA_SRC:
rcip));
default:
/* NOTREACHED */
}
default:
/* NOTREACHED */
}
return (B_TRUE);
}
/*
* Interpret an argument as an IPv4 network address of some kind,
* returning B_TRUE on success or B_FALSE on failure.
* This function will cause an exit() on failure if exit_on_failure is set.
*
* Note that this *always* tries host interpretation before network
* interpretation.
*
* If the plenp argument is non-NULL, allow <addr>/<n> syntax and
* pass out <n> in *plenp.
* If <n> doesn't parse return BAD_ADDR as *plenp.
* If no /<n> is present return NO_PREFIX as *plenp.
*/
static boolean_t
{
/*
* Look for '/'<n> is plenp
*/
char *cp;
return (B_FALSE);
*cp = '\0';
return (B_FALSE);
}
/*
* Note: only the route destination can be a network, so we treat
* all other addresses as though "-net" was not specified.
*/
atype == ADDR_TYPE_HOST) {
}
return (B_TRUE);
}
return (B_TRUE);
}
(in_addr_t)-1) {
return (B_TRUE);
}
}
return (B_TRUE);
}
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Interpret an argument as an IPv6 network address of some kind,
* returning B_TRUE on success or B_FALSE on failure.
* This function will cause an exit() on failure if exit_on_failure is set.
*
* If the last argument is non-NULL allow a <addr>/<n> syntax and
* pass out <n> in *plenp.
* If <n> doesn't parse return BAD_ADDR as *plenp.
* If no /<n> is present return NO_PREFIX as *plenp.
*/
static boolean_t
{
int error_num;
/*
* Look for '/'<n> is plenp
*/
char *cp;
return (B_FALSE);
*cp = '\0';
return (B_FALSE);
}
return (B_TRUE);
}
/*
* This isn't a problem if we aren't going to use the address
* right away.
*/
if (!exit_on_error) {
return (B_TRUE);
}
"again later)\n"), s);
return (B_FALSE);
}
return (B_FALSE);
}
/*
* If "slash" is zero this parses the whole string as
* an integer. With "slash" non zero it parses the tail part as an integer.
*
* If it is not a valid integer this returns BAD_ADDR.
* If there is /<n> present this returns NO_PREFIX.
*/
int
{
int prefixlen;
return (NO_PREFIX);
str++;
if (prefixlen < 0)
return (BAD_ADDR);
return (BAD_ADDR);
return (BAD_ADDR);
else
return (prefixlen);
}
/*
* Convert a prefix length to a mask.
* Returns B_TRUE if ok. B_FALSE otherwise.
* Assumes the mask array is zeroed by the caller.
*/
{
return (B_FALSE);
while (prefixlen > 0) {
if (prefixlen >= 8) {
*mask++ = 0xFF;
prefixlen -= 8;
continue;
}
prefixlen--;
}
return (B_TRUE);
}
void
{
int n;
if (tflag)
exit(0);
if (argc > 1) {
argv++;
case K_INET:
break;
case K_LINK:
break;
case K_INET6:
break;
default:
/* NOTREACHED */
}
} else {
}
(void) close(s);
if (s < 0)
}
for (;;) {
if (n <= 0)
(void) printf("got message of size %d\n", n);
}
}
int
{
static int seq;
int rlen;
int l;
errno = 0;
}
#define NEXTADDR(w, u) \
cp += l; \
if (verbose) \
sodump(&(u), #u); \
}
/*
* RTA_SRC has overloaded meaning. It can represent the
* src address of incoming or outgoing packets.
*/
if (verbose)
print_rtmsg(&rtm, l);
if (debugonly)
return (0);
switch (errno) {
case ESRCH:
case EBUSY:
case ENOBUFS:
case EEXIST:
case ENETUNREACH:
case EHOSTUNREACH:
case EPERM:
break;
default:
break;
}
return (-1);
gettext("route: write to routing socket got only %d for "
"len\n"), rlen);
return (-1);
}
do {
if (l < 0) {
gettext("route: read from routing socket: %s\n"),
} else {
}
}
return (0);
}
static char *msgtypes[] = {
"",
"RTM_ADD: Add Route",
"RTM_DELETE: Delete Route",
"RTM_CHANGE: Change Metrics or flags",
"RTM_GET: Report Metrics",
"RTM_LOSING: Kernel Suspects Partitioning",
"RTM_REDIRECT: Told to use different route",
"RTM_MISS: Lookup failed on this address",
"RTM_LOCK: fix specified metrics",
"RTM_OLDADD: caused by SIOCADDRT",
"RTM_OLDDEL: caused by SIOCDELRT",
"RTM_RESOLVE: Route created by cloning",
"RTM_NEWADDR: address being added to iface",
"RTM_DELADDR: address being removed from iface",
"RTM_IFINFO: iface status change",
0,
};
static char metricnames[] =
"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
"\1mtu";
static char routeflags[] =
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
"\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC";
static char ifnetflags[] =
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP"
"\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST"
"\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE"
"\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF"
"\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6"
"\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE"
"\041XRESOLV\042COS\043PREFERRED\044TEMPORARY";
static char addrnames[] =
"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC";
void
{
struct ifa_msghdr *ifam;
if (!verbose)
return;
(void) printf("routing message version %d not understood\n",
rtm->rtm_version);
return;
}
(void) printf("message length mismatch, in packet %d, "
"returned %d\n",
}
/*
* Since rtm->rtm_type is unsigned, we'll just check the case of zero
* and the upper-bound of (NMSGTYPES - 1).
*/
(void) printf("routing message type %d not understood\n",
return;
}
case RTM_IFINFO:
break;
case RTM_NEWADDR:
case RTM_DELADDR:
break;
default:
(void) printf("pid: %ld, seq %d, errno %d, flags:",
}
}
void
{
char *cp;
int i;
gettext("routing message version %d not understood\n"),
rtm->rtm_version);
return;
}
gettext("message length mismatch, in packet %d, "
}
return;
}
for (i = 1; i != 0; i <<= 1) {
/* LINTED */
switch (i) {
case RTA_DST:
break;
case RTA_GATEWAY:
break;
case RTA_NETMASK:
break;
case RTA_IFP:
((struct sockaddr_dl *)sa)->
sdl_nlen != 0)
break;
case RTA_SRC:
break;
}
}
}
}
}
if (verbose) {
int i;
(void) printf(" interface: %.*s index %d address ",
i++) {
(void) printf("%02x ",
}
(void) printf("\n");
} else {
(void) printf(" interface: %.*s\n",
}
}
(void) printf(" flags: ");
"rttvar,ms hopcount mtu expire");
#define RTA_IGN \
if (verbose) {
(void) printf("sockaddrs: ");
(void) putchar('\n');
}
}
void
{
(void) printf("\nlocks: ");
(void) printf(" inits: ");
}
void
{
int i;
if (addrs == 0)
return;
(void) printf("\nsockaddrs: ");
(void) putchar('\n');
for (i = 1; i != 0; i <<= 1) {
if (i & addrs) {
/* LINTED */
}
}
(void) putchar('\n');
}
void
{
int i;
if (b == 0)
return;
while ((i = *s++) != 0) {
if (b & (1 << (i - 1))) {
if (!gotsome)
i = '<';
else
i = ',';
for (; (i = *s) > ' '; s++)
} else {
while (*s > ' ')
s++;
}
}
if (gotsome)
}
int
{
kt++;
}
void
{
static char obuf[INET6_ADDRSTRLEN];
case AF_LINK:
(void) printf("%s: link %s; ",
break;
case AF_INET:
(void) printf("%s: inet %s; ",
break;
case AF_INET6:
INET6_ADDRSTRLEN) != NULL) {
break;
}
/* FALLTHROUGH */
default:
/* NOTREACHED */
}
}
/* States */
#define VIRGIN 0
#define GOTONE 1
#define GOTTWO 2
#define RESET 3
/* Inputs */
#define DIGIT (4*0)
void
{
cp++;
do {
} else if (*addr == 0) {
} else {
}
addr++;
switch (state /* | INPUT */) {
/* FALLTHROUGH */
default: /* | DELIM */
/* FALLTHROUGH */
break;
}
break;
}
int
{
case AF_INET:
return (sizeof (struct sockaddr_in));
case AF_LINK:
return (sizeof (struct sockaddr_dl));
case AF_INET6:
return (sizeof (struct sockaddr_in6));
default:
return (sizeof (struct sockaddr));
}
}
void
{
do {
} else if (*addr == 0) {
} else {
}
addr++;
switch (state /* | INPUT */) {
continue;
continue;
/* FALLTHROUGH */
continue;
continue;
default: /* | DELIM */
byte = 0;
continue;
/* FALLTHROUGH */
break;
}
break;
}
static char hexlist[] = "0123456789abcdef";
char *
{
static char obuf[64];
int i;
*out++ = ':';
}
if (firsttime)
else
*out++ = '.';
i = *in++;
if (i > 0xf) {
i >>= 4;
out += 2;
} else {
}
}
*out = 0;
return (obuf);
}
static mib_item_t *
{
int flags;
int i, j, getcode;
flags = 0;
perror("mibget: putmsg (ctl)");
return (NULL);
}
/*
* each reply consists of a ctl part for one fixed structure
* or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK,
* len is the size of the data part of the message.
*/
for (j = 1; ; j++) {
flags = 0;
if (getcode < 0) {
perror("mibget: getmsg (ctl)");
if (verbose) {
"# level name len\n");
i = 0;
(void) printf("%d %4ld %5ld %ld\n",
}
}
break;
}
if (getcode == 0 &&
if (verbose) {
(void) printf("mibget getmsg() %d returned EOD "
}
return (first_item); /* this is EOD msg */
}
"T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = "
break;
}
(void) printf("mibget getmsg(ctl) %d returned %d, "
"ctlbuf.len = %d, PRIM_type = %ld\n",
(void) printf("T_OPTMGMT_ACK: "
"MGMT_flags = 0x%lx, req->len = %ld\n",
}
break;
}
perror("mibget: malloc");
break;
}
else
first_item = temp;
if (verbose) {
(void) printf("msg %d: group = %4ld mib_id = %5ld "
"length = %ld\n",
}
flags = 0;
if (getcode < 0) {
perror("mibget: getmsg (data)");
break;
} else if (getcode != 0) {
(void) printf("mibget getmsg(data) returned %d, "
"databuf.maxlen = %d, databuf.len = %d\n",
break;
}
}
/*
* On error, free all the allocated mib_item_t objects.
*/
while (first_item != NULL) {
}
return (NULL);
}