mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-24 11:29:10 +00:00
94fafad064
IPv6 scoped addr display is not yet supported by ifconfig and route. Now almost of IPv6 apps support it, so its support in ifconfig and route is important to keep consisetncy, and to avoid user confusion. Approved by: jkh
1547 lines
36 KiB
C
1547 lines
36 KiB
C
/*
|
|
* Copyright (c) 1983, 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
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char copyright[] =
|
|
"@(#) Copyright (c) 1983, 1993\n\
|
|
The Regents of the University of California. All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
#if 0
|
|
static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
|
|
#endif
|
|
static const char rcsid[] =
|
|
"$FreeBSD$";
|
|
#endif /* not lint */
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/module.h>
|
|
#include <sys/linker.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_var.h>
|
|
#include <net/if_dl.h>
|
|
#include <net/if_types.h>
|
|
#include <net/route.h>
|
|
|
|
/* IP */
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_var.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
/* IPX */
|
|
#define IPXIP
|
|
#define IPTUNNEL
|
|
#include <netipx/ipx.h>
|
|
#include <netipx/ipx_if.h>
|
|
|
|
/* Appletalk */
|
|
#include <netatalk/at.h>
|
|
|
|
/* XNS */
|
|
#ifdef NS
|
|
#define NSIP
|
|
#include <netns/ns.h>
|
|
#include <netns/ns_if.h>
|
|
#endif
|
|
|
|
/* OSI */
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "ifconfig.h"
|
|
|
|
/* wrapper for KAME-special getnameinfo() */
|
|
#ifndef NI_WITHSCOPEID
|
|
#define NI_WITHSCOPEID 0
|
|
#endif
|
|
|
|
struct ifreq ifr, ridreq;
|
|
struct ifaliasreq addreq;
|
|
#ifdef INET6
|
|
struct in6_ifreq in6_ridreq;
|
|
struct in6_aliasreq in6_addreq;
|
|
#endif
|
|
struct sockaddr_in netmask;
|
|
struct netrange at_nr; /* AppleTalk net range */
|
|
|
|
char name[32];
|
|
int flags;
|
|
int metric;
|
|
int mtu;
|
|
int setaddr;
|
|
int setipdst;
|
|
int doalias;
|
|
int clearaddr;
|
|
int newaddr = 1;
|
|
#ifdef INET6
|
|
static int ip6lifetime;
|
|
#endif
|
|
|
|
struct afswtch;
|
|
|
|
#ifdef INET6
|
|
char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
|
|
#endif
|
|
|
|
void Perror __P((const char *cmd));
|
|
void checkatrange __P((struct sockaddr_at *));
|
|
int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp));
|
|
void notealias __P((const char *, int, int, const struct afswtch *afp));
|
|
void printb __P((const char *s, unsigned value, const char *bits));
|
|
void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
|
|
void status __P((const struct afswtch *afp, int addrcount,
|
|
struct sockaddr_dl *sdl, struct if_msghdr *ifm,
|
|
struct ifa_msghdr *ifam));
|
|
void usage __P((void));
|
|
void ifmaybeload __P((char *name));
|
|
|
|
#ifdef INET6
|
|
int prefix __P((void *, int));
|
|
static char *sec2str __P((time_t));
|
|
int explicit_prefix = 0;
|
|
#endif
|
|
|
|
typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp));
|
|
c_func setatphase, setatrange;
|
|
c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask;
|
|
#ifdef INET6
|
|
c_func setifprefixlen;
|
|
c_func setip6flags;
|
|
#endif
|
|
c_func setifipdst;
|
|
c_func setifflags, setifmetric, setifmtu;
|
|
|
|
|
|
#define NEXTARG 0xffffff
|
|
|
|
const
|
|
struct cmd {
|
|
const char *c_name;
|
|
int c_parameter; /* NEXTARG means next argv */
|
|
void (*c_func) __P((const char *, int, int, const struct afswtch *afp));
|
|
} cmds[] = {
|
|
{ "up", IFF_UP, setifflags } ,
|
|
{ "down", -IFF_UP, setifflags },
|
|
{ "arp", -IFF_NOARP, setifflags },
|
|
{ "-arp", IFF_NOARP, setifflags },
|
|
{ "debug", IFF_DEBUG, setifflags },
|
|
{ "-debug", -IFF_DEBUG, setifflags },
|
|
{ "alias", IFF_UP, notealias },
|
|
{ "-alias", -IFF_UP, notealias },
|
|
{ "delete", -IFF_UP, notealias },
|
|
#ifdef notdef
|
|
#define EN_SWABIPS 0x1000
|
|
{ "swabips", EN_SWABIPS, setifflags },
|
|
{ "-swabips", -EN_SWABIPS, setifflags },
|
|
#endif
|
|
{ "netmask", NEXTARG, setifnetmask },
|
|
#ifdef INET6
|
|
{ "prefixlen", NEXTARG, setifprefixlen },
|
|
{ "anycast", IN6_IFF_ANYCAST, setip6flags },
|
|
{ "tentative", IN6_IFF_TENTATIVE, setip6flags },
|
|
{ "-tentative", -IN6_IFF_TENTATIVE, setip6flags },
|
|
#endif
|
|
{ "range", NEXTARG, setatrange },
|
|
{ "phase", NEXTARG, setatphase },
|
|
{ "metric", NEXTARG, setifmetric },
|
|
{ "broadcast", NEXTARG, setifbroadaddr },
|
|
{ "ipdst", NEXTARG, setifipdst },
|
|
{ "link0", IFF_LINK0, setifflags },
|
|
{ "-link0", -IFF_LINK0, setifflags },
|
|
{ "link1", IFF_LINK1, setifflags },
|
|
{ "-link1", -IFF_LINK1, setifflags },
|
|
{ "link2", IFF_LINK2, setifflags },
|
|
{ "-link2", -IFF_LINK2, setifflags },
|
|
#ifdef USE_IF_MEDIA
|
|
{ "media", NEXTARG, setmedia },
|
|
{ "mediaopt", NEXTARG, setmediaopt },
|
|
{ "-mediaopt", NEXTARG, unsetmediaopt },
|
|
#endif
|
|
#ifdef USE_VLANS
|
|
{ "vlan", NEXTARG, setvlantag },
|
|
{ "vlandev", NEXTARG, setvlandev },
|
|
{ "-vlandev", NEXTARG, unsetvlandev },
|
|
#endif
|
|
{ "normal", -IFF_LINK0, setifflags },
|
|
{ "compress", IFF_LINK0, setifflags },
|
|
{ "noicmp", IFF_LINK1, setifflags },
|
|
{ "mtu", NEXTARG, setifmtu },
|
|
{ 0, 0, setifaddr },
|
|
{ 0, 0, setifdstaddr },
|
|
};
|
|
|
|
/*
|
|
* XNS support liberally adapted from code written at the University of
|
|
* Maryland principally by James O'Toole and Chris Torek.
|
|
*/
|
|
typedef void af_status __P((int, struct rt_addrinfo *));
|
|
typedef void af_getaddr __P((const char *, int));
|
|
typedef void af_getprefix __P((const char *, int));
|
|
|
|
af_status in_status, ipx_status, at_status, ether_status;
|
|
af_getaddr in_getaddr, ipx_getaddr, at_getaddr;
|
|
|
|
#ifdef INET6
|
|
af_status in6_status;
|
|
af_getaddr in6_getaddr;
|
|
af_getprefix in6_getprefix;
|
|
#endif /*INET6*/
|
|
#ifdef NS
|
|
af_status xns_status;
|
|
af_getaddr xns_getaddr;
|
|
#endif
|
|
|
|
/* Known address families */
|
|
const
|
|
struct afswtch {
|
|
const char *af_name;
|
|
short af_af;
|
|
af_status *af_status;
|
|
af_getaddr *af_getaddr;
|
|
af_getprefix *af_getprefix;
|
|
u_long af_difaddr;
|
|
u_long af_aifaddr;
|
|
caddr_t af_ridreq;
|
|
caddr_t af_addreq;
|
|
} afs[] = {
|
|
#define C(x) ((caddr_t) &x)
|
|
{ "inet", AF_INET, in_status, in_getaddr, NULL,
|
|
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
|
|
#ifdef INET6
|
|
{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
|
|
SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
|
|
C(in6_ridreq), C(in6_addreq) },
|
|
#endif /*INET6*/
|
|
{ "ipx", AF_IPX, ipx_status, ipx_getaddr, NULL,
|
|
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
|
|
{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
|
|
SIOCDIFADDR, SIOCAIFADDR, C(addreq), C(addreq) },
|
|
#ifdef NS
|
|
{ "ns", AF_NS, xns_status, xns_getaddr, NULL,
|
|
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
|
|
#endif
|
|
{ "ether", AF_INET, ether_status, NULL, NULL }, /* XXX not real!! */
|
|
#if 0 /* XXX conflicts with the media command */
|
|
#ifdef USE_IF_MEDIA
|
|
{ "media", AF_INET, media_status, NULL, NULL, }, /* XXX not real!! */
|
|
#endif
|
|
#ifdef USE_VLANS
|
|
{ "vlan", AF_INET, media_status, NULL, NULL, }, /* XXX not real!! */
|
|
#endif
|
|
#endif
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
/*
|
|
* Expand the compacted form of addresses as returned via the
|
|
* configuration read via sysctl().
|
|
*/
|
|
|
|
#define ROUNDUP(a) \
|
|
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
|
|
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
|
|
|
|
void
|
|
rt_xaddrs(cp, cplim, rtinfo)
|
|
caddr_t cp, cplim;
|
|
struct rt_addrinfo *rtinfo;
|
|
{
|
|
struct sockaddr *sa;
|
|
int i;
|
|
|
|
memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
|
|
for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
|
|
if ((rtinfo->rti_addrs & (1 << i)) == 0)
|
|
continue;
|
|
rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
|
|
ADVANCE(cp, sa);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
usage()
|
|
{
|
|
#ifndef INET6
|
|
fprintf(stderr, "%s\n%s\n%s\n%s\n",
|
|
"usage: ifconfig interface address_family [address [dest_address]]",
|
|
" [parameters]",
|
|
" ifconfig -a [-d] [-u] [address_family]",
|
|
" ifconfig -l [-d] [-u] [address_family]");
|
|
#else
|
|
fprintf(stderr, "%s\n%s\n%s\n%s\n",
|
|
"usage: ifconfig [-L] interface address_family [address [dest_address]]",
|
|
" [parameters]",
|
|
" ifconfig -a [-L] [-d] [-u] [address_family]",
|
|
" ifconfig -l [-d] [-u] [address_family]");
|
|
#endif
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *const *argv;
|
|
{
|
|
int c;
|
|
int all, namesonly, downonly, uponly;
|
|
int foundit = 0, need_nl = 0;
|
|
const struct afswtch *afp = 0;
|
|
int addrcount;
|
|
struct if_msghdr *ifm, *nextifm;
|
|
struct ifa_msghdr *ifam;
|
|
struct sockaddr_dl *sdl;
|
|
char *buf, *lim, *next;
|
|
|
|
|
|
size_t needed;
|
|
int mib[6];
|
|
|
|
/* Parse leading line options */
|
|
all = downonly = uponly = namesonly = 0;
|
|
while ((c = getopt(argc, argv, "adlmu"
|
|
#ifdef INET6
|
|
"L"
|
|
#endif
|
|
)) != -1) {
|
|
switch (c) {
|
|
case 'a': /* scan all interfaces */
|
|
all++;
|
|
break;
|
|
#ifdef INET6
|
|
case 'L':
|
|
ip6lifetime++; /* print IPv6 address lifetime */
|
|
break;
|
|
#endif
|
|
case 'l': /* scan interface names only */
|
|
namesonly++;
|
|
break;
|
|
case 'd': /* restrict scan to "down" interfaces */
|
|
downonly++;
|
|
break;
|
|
case 'u': /* restrict scan to "up" interfaces */
|
|
uponly++;
|
|
break;
|
|
case 'm': /* show media choices in status */
|
|
/* ignored for compatibility */
|
|
break;
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
/* -l cannot be used with -a or -m */
|
|
if (namesonly && all)
|
|
usage();
|
|
|
|
/* nonsense.. */
|
|
if (uponly && downonly)
|
|
usage();
|
|
|
|
/* -a and -l allow an address family arg to limit the output */
|
|
if (all || namesonly) {
|
|
if (argc > 1)
|
|
usage();
|
|
|
|
if (argc == 1) {
|
|
for (afp = afs; afp->af_name; afp++)
|
|
if (strcmp(afp->af_name, *argv) == 0) {
|
|
argc--, argv++;
|
|
break;
|
|
}
|
|
if (afp->af_name == NULL)
|
|
usage();
|
|
/* leave with afp non-zero */
|
|
}
|
|
} else {
|
|
/* not listing, need an argument */
|
|
if (argc < 1)
|
|
usage();
|
|
|
|
strncpy(name, *argv, sizeof(name));
|
|
argc--, argv++;
|
|
|
|
/* check and maybe load support for this interface */
|
|
ifmaybeload(name);
|
|
}
|
|
|
|
/* Check for address family */
|
|
if (argc > 0) {
|
|
for (afp = afs; afp->af_name; afp++)
|
|
if (strcmp(afp->af_name, *argv) == 0) {
|
|
argc--, argv++;
|
|
break;
|
|
}
|
|
if (afp->af_name == NULL)
|
|
afp = NULL; /* not a family, NULL */
|
|
}
|
|
|
|
mib[0] = CTL_NET;
|
|
mib[1] = PF_ROUTE;
|
|
mib[2] = 0;
|
|
mib[3] = 0; /* address family */
|
|
mib[4] = NET_RT_IFLIST;
|
|
mib[5] = 0;
|
|
|
|
/* if particular family specified, only ask about it */
|
|
if (afp)
|
|
mib[3] = afp->af_af;
|
|
|
|
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
|
|
errx(1, "iflist-sysctl-estimate");
|
|
if ((buf = malloc(needed)) == NULL)
|
|
errx(1, "malloc");
|
|
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
|
|
errx(1, "actual retrieval of interface table");
|
|
lim = buf + needed;
|
|
|
|
next = buf;
|
|
while (next < lim) {
|
|
|
|
ifm = (struct if_msghdr *)next;
|
|
|
|
if (ifm->ifm_type == RTM_IFINFO) {
|
|
sdl = (struct sockaddr_dl *)(ifm + 1);
|
|
flags = ifm->ifm_flags;
|
|
} else {
|
|
fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
|
|
fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO,
|
|
ifm->ifm_type);
|
|
fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
|
|
fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next,
|
|
lim);
|
|
exit (1);
|
|
}
|
|
|
|
next += ifm->ifm_msglen;
|
|
ifam = NULL;
|
|
addrcount = 0;
|
|
while (next < lim) {
|
|
|
|
nextifm = (struct if_msghdr *)next;
|
|
|
|
if (nextifm->ifm_type != RTM_NEWADDR)
|
|
break;
|
|
|
|
if (ifam == NULL)
|
|
ifam = (struct ifa_msghdr *)nextifm;
|
|
|
|
addrcount++;
|
|
next += nextifm->ifm_msglen;
|
|
}
|
|
|
|
if (all || namesonly) {
|
|
if (uponly)
|
|
if ((flags & IFF_UP) == 0)
|
|
continue; /* not up */
|
|
if (downonly)
|
|
if (flags & IFF_UP)
|
|
continue; /* not down */
|
|
strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
|
|
name[sdl->sdl_nlen] = '\0';
|
|
if (namesonly) {
|
|
if (afp == NULL ||
|
|
afp->af_status != ether_status ||
|
|
sdl->sdl_type == IFT_ETHER) {
|
|
if (need_nl)
|
|
putchar(' ');
|
|
fputs(name, stdout);
|
|
need_nl++;
|
|
}
|
|
continue;
|
|
}
|
|
} else {
|
|
if (strlen(name) != sdl->sdl_nlen)
|
|
continue; /* not same len */
|
|
if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0)
|
|
continue; /* not same name */
|
|
}
|
|
|
|
if (argc > 0)
|
|
ifconfig(argc, argv, afp);
|
|
else
|
|
status(afp, addrcount, sdl, ifm, ifam);
|
|
|
|
if (all == 0 && namesonly == 0) {
|
|
foundit++; /* flag it as 'done' */
|
|
break;
|
|
}
|
|
}
|
|
free(buf);
|
|
|
|
if (namesonly && need_nl > 0)
|
|
putchar('\n');
|
|
|
|
if (all == 0 && namesonly == 0 && foundit == 0)
|
|
errx(1, "interface %s does not exist", name);
|
|
|
|
|
|
exit (0);
|
|
}
|
|
|
|
|
|
int
|
|
ifconfig(argc, argv, afp)
|
|
int argc;
|
|
char *const *argv;
|
|
const struct afswtch *afp;
|
|
{
|
|
int s;
|
|
|
|
if (afp == NULL)
|
|
afp = &afs[0];
|
|
ifr.ifr_addr.sa_family = afp->af_af;
|
|
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
|
|
|
|
if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
|
|
err(1, "socket");
|
|
|
|
while (argc > 0) {
|
|
register const struct cmd *p;
|
|
|
|
for (p = cmds; p->c_name; p++)
|
|
if (strcmp(*argv, p->c_name) == 0)
|
|
break;
|
|
if (p->c_name == 0 && setaddr)
|
|
p++; /* got src, do dst */
|
|
if (p->c_func) {
|
|
if (p->c_parameter == NEXTARG) {
|
|
if (argv[1] == NULL)
|
|
errx(1, "'%s' requires argument",
|
|
p->c_name);
|
|
(*p->c_func)(argv[1], 0, s, afp);
|
|
argc--, argv++;
|
|
} else
|
|
(*p->c_func)(*argv, p->c_parameter, s, afp);
|
|
}
|
|
argc--, argv++;
|
|
}
|
|
#ifdef INET6
|
|
if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) {
|
|
/* Aggregatable address architecture defines all prefixes
|
|
are 64. So, it is convenient to set prefixlen to 64 if
|
|
it is not specified. */
|
|
setifprefixlen("64", 0, s, afp);
|
|
/* in6_getprefix("64", MASK) if MASK is available here... */
|
|
}
|
|
#endif
|
|
if (setipdst && ifr.ifr_addr.sa_family == AF_IPX) {
|
|
struct ipxip_req rq;
|
|
int size = sizeof(rq);
|
|
|
|
rq.rq_ipx = addreq.ifra_addr;
|
|
rq.rq_ip = addreq.ifra_dstaddr;
|
|
|
|
if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
|
|
Perror("Encapsulation Routing");
|
|
}
|
|
if (ifr.ifr_addr.sa_family == AF_APPLETALK)
|
|
checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
|
|
#ifdef NS
|
|
if (setipdst && ifr.ifr_addr.sa_family == AF_NS) {
|
|
struct nsip_req rq;
|
|
int size = sizeof(rq);
|
|
|
|
rq.rq_ns = addreq.ifra_addr;
|
|
rq.rq_ip = addreq.ifra_dstaddr;
|
|
|
|
if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
|
|
Perror("Encapsulation Routing");
|
|
}
|
|
#endif
|
|
if (clearaddr) {
|
|
if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
|
|
warnx("interface %s cannot change %s addresses!",
|
|
name, afp->af_name);
|
|
clearaddr = NULL;
|
|
}
|
|
}
|
|
if (clearaddr) {
|
|
int ret;
|
|
strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
|
|
if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
|
|
if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
|
|
/* means no previous address for interface */
|
|
} else
|
|
Perror("ioctl (SIOCDIFADDR)");
|
|
}
|
|
}
|
|
if (newaddr) {
|
|
if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
|
|
warnx("interface %s cannot change %s addresses!",
|
|
name, afp->af_name);
|
|
newaddr = 0;
|
|
}
|
|
}
|
|
if (newaddr) {
|
|
strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
|
|
if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
|
|
Perror("ioctl (SIOCAIFADDR)");
|
|
}
|
|
close(s);
|
|
return(0);
|
|
}
|
|
#define RIDADDR 0
|
|
#define ADDR 1
|
|
#define MASK 2
|
|
#define DSTADDR 3
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
setifaddr(addr, param, s, afp)
|
|
const char *addr;
|
|
int param;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (*afp->af_getaddr == NULL)
|
|
return;
|
|
/*
|
|
* Delay the ioctl to set the interface addr until flags are all set.
|
|
* The address interpretation may depend on the flags,
|
|
* and the flags may change when the address is set.
|
|
*/
|
|
setaddr++;
|
|
if (doalias == 0)
|
|
clearaddr = 1;
|
|
(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
|
|
}
|
|
|
|
void
|
|
setifnetmask(addr, dummy, s, afp)
|
|
const char *addr;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (*afp->af_getaddr == NULL)
|
|
return;
|
|
(*afp->af_getaddr)(addr, MASK);
|
|
}
|
|
|
|
#ifdef INET6
|
|
void
|
|
setifprefixlen(addr, dummy, s, afp)
|
|
const char *addr;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (*afp->af_getprefix)
|
|
(*afp->af_getprefix)(addr, MASK);
|
|
explicit_prefix = 1;
|
|
}
|
|
|
|
void
|
|
setip6flags(dummyaddr, flag, dummysoc, afp)
|
|
const char *dummyaddr __unused;
|
|
int flag;
|
|
int dummysoc __unused;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (afp->af_af != AF_INET6)
|
|
err(1, "address flags can be set only for inet6 addresses");
|
|
|
|
if (flag < 0)
|
|
in6_addreq.ifra_flags &= ~(-flag);
|
|
else
|
|
in6_addreq.ifra_flags |= flag;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
setifbroadaddr(addr, dummy, s, afp)
|
|
const char *addr;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (*afp->af_getaddr == NULL)
|
|
return;
|
|
(*afp->af_getaddr)(addr, DSTADDR);
|
|
}
|
|
|
|
void
|
|
setifipdst(addr, dummy, s, afp)
|
|
const char *addr;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
in_getaddr(addr, DSTADDR);
|
|
setipdst++;
|
|
clearaddr = 0;
|
|
newaddr = 0;
|
|
}
|
|
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
|
|
|
|
void
|
|
notealias(addr, param, s, afp)
|
|
const char *addr;
|
|
int param;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (setaddr && doalias == 0 && param < 0)
|
|
bcopy((caddr_t)rqtosa(af_addreq),
|
|
(caddr_t)rqtosa(af_ridreq),
|
|
rqtosa(af_addreq)->sa_len);
|
|
doalias = param;
|
|
if (param < 0) {
|
|
clearaddr = 1;
|
|
newaddr = 0;
|
|
} else
|
|
clearaddr = 0;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
setifdstaddr(addr, param, s, afp)
|
|
const char *addr;
|
|
int param __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (*afp->af_getaddr == NULL)
|
|
return;
|
|
(*afp->af_getaddr)(addr, DSTADDR);
|
|
}
|
|
|
|
/*
|
|
* Note: doing an SIOCIGIFFLAGS scribbles on the union portion
|
|
* of the ifreq structure, which may confuse other parts of ifconfig.
|
|
* Make a private copy so we can avoid that.
|
|
*/
|
|
void
|
|
setifflags(vname, value, s, afp)
|
|
const char *vname;
|
|
int value;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
struct ifreq my_ifr;
|
|
|
|
bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
|
|
|
|
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
|
|
Perror("ioctl (SIOCGIFFLAGS)");
|
|
exit(1);
|
|
}
|
|
strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name));
|
|
flags = my_ifr.ifr_flags;
|
|
|
|
if (value < 0) {
|
|
value = -value;
|
|
flags &= ~value;
|
|
} else
|
|
flags |= value;
|
|
my_ifr.ifr_flags = flags;
|
|
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
|
|
Perror(vname);
|
|
}
|
|
|
|
void
|
|
setifmetric(val, dummy, s, afp)
|
|
const char *val;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
|
|
ifr.ifr_metric = atoi(val);
|
|
if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
|
|
warn("ioctl (set metric)");
|
|
}
|
|
|
|
void
|
|
setifmtu(val, dummy, s, afp)
|
|
const char *val;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
|
|
ifr.ifr_mtu = atoi(val);
|
|
if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
|
|
warn("ioctl (set mtu)");
|
|
}
|
|
|
|
|
|
#define IFFBITS \
|
|
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
|
|
"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
|
|
"\20MULTICAST"
|
|
|
|
/*
|
|
* Print the status of the interface. If an address family was
|
|
* specified, show it and it only; otherwise, show them all.
|
|
*/
|
|
void
|
|
status(afp, addrcount, sdl, ifm, ifam)
|
|
const struct afswtch *afp;
|
|
int addrcount;
|
|
struct sockaddr_dl *sdl;
|
|
struct if_msghdr *ifm;
|
|
struct ifa_msghdr *ifam;
|
|
{
|
|
const struct afswtch *p = NULL;
|
|
struct rt_addrinfo info;
|
|
int allfamilies, s;
|
|
struct ifstat ifs;
|
|
|
|
if (afp == NULL) {
|
|
allfamilies = 1;
|
|
afp = &afs[0];
|
|
} else
|
|
allfamilies = 0;
|
|
|
|
ifr.ifr_addr.sa_family = afp->af_af;
|
|
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
|
|
|
|
if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
|
|
err(1, "socket");
|
|
|
|
/*
|
|
* XXX is it we are doing a SIOCGIFMETRIC etc for one family.
|
|
* is it possible that the metric and mtu can be different for
|
|
* each family? If so, we have a format problem, because the
|
|
* metric and mtu is printed on the global the flags line.
|
|
*/
|
|
if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
|
|
warn("ioctl (SIOCGIFMETRIC)");
|
|
else
|
|
metric = ifr.ifr_metric;
|
|
|
|
if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
|
|
warn("ioctl (SIOCGIFMTU)");
|
|
else
|
|
mtu = ifr.ifr_mtu;
|
|
|
|
printf("%s: ", name);
|
|
printb("flags", flags, IFFBITS);
|
|
if (metric)
|
|
printf(" metric %d", metric);
|
|
if (mtu)
|
|
printf(" mtu %d", mtu);
|
|
putchar('\n');
|
|
|
|
while (addrcount > 0) {
|
|
|
|
info.rti_addrs = ifam->ifam_addrs;
|
|
|
|
/* Expand the compacted addresses */
|
|
rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
|
|
&info);
|
|
|
|
if (!allfamilies) {
|
|
if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family &&
|
|
#ifdef USE_IF_MEDIA
|
|
afp->af_status != media_status &&
|
|
#endif
|
|
#ifdef USE_VLANS
|
|
afp->af_status != vlan_status &&
|
|
#endif
|
|
afp->af_status != ether_status) {
|
|
p = afp;
|
|
(*p->af_status)(s, &info);
|
|
}
|
|
} else for (p = afs; p->af_name; p++) {
|
|
if (p->af_af == info.rti_info[RTAX_IFA]->sa_family &&
|
|
#ifdef USE_IF_MEDIA
|
|
p->af_status != media_status &&
|
|
#endif
|
|
#ifdef USE_VLANS
|
|
p->af_status != vlan_status &&
|
|
#endif
|
|
p->af_status != ether_status)
|
|
(*p->af_status)(s, &info);
|
|
}
|
|
addrcount--;
|
|
ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
|
|
}
|
|
if (allfamilies || afp->af_status == ether_status)
|
|
ether_status(s, (struct rt_addrinfo *)sdl);
|
|
#ifdef USE_IF_MEDIA
|
|
if (allfamilies || afp->af_status == media_status)
|
|
media_status(s, NULL);
|
|
#endif
|
|
#ifdef USE_VLANS
|
|
if (allfamilies || afp->af_status == vlan_status)
|
|
vlan_status(s, NULL);
|
|
#endif
|
|
strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
|
|
if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
|
|
printf("%s", ifs.ascii);
|
|
|
|
if (!allfamilies && !p && afp->af_status != media_status &&
|
|
afp->af_status != ether_status && afp->af_status != vlan_status)
|
|
warnx("%s has no %s interface address!", name, afp->af_name);
|
|
|
|
close(s);
|
|
return;
|
|
}
|
|
|
|
void
|
|
in_status(s, info)
|
|
int s __unused;
|
|
struct rt_addrinfo * info;
|
|
{
|
|
struct sockaddr_in *sin, null_sin;
|
|
|
|
memset(&null_sin, 0, sizeof(null_sin));
|
|
|
|
sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
|
|
printf("\tinet %s ", inet_ntoa(sin->sin_addr));
|
|
|
|
if (flags & IFF_POINTOPOINT) {
|
|
/* note RTAX_BRD overlap with IFF_BROADCAST */
|
|
sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
|
|
if (!sin)
|
|
sin = &null_sin;
|
|
printf("--> %s ", inet_ntoa(sin->sin_addr));
|
|
}
|
|
|
|
sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
|
|
if (!sin)
|
|
sin = &null_sin;
|
|
printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
|
|
|
|
if (flags & IFF_BROADCAST) {
|
|
/* note RTAX_BRD overlap with IFF_POINTOPOINT */
|
|
sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
|
|
if (sin && sin->sin_addr.s_addr != 0)
|
|
printf("broadcast %s", inet_ntoa(sin->sin_addr));
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
#ifdef INET6
|
|
void
|
|
in6_status(s, info)
|
|
int s __unused;
|
|
struct rt_addrinfo * info;
|
|
{
|
|
struct sockaddr_in6 *sin, null_sin;
|
|
struct in6_ifreq ifr6;
|
|
int s6;
|
|
u_int32_t flags6;
|
|
struct in6_addrlifetime lifetime;
|
|
time_t t = time(NULL);
|
|
int error;
|
|
|
|
memset(&null_sin, 0, sizeof(null_sin));
|
|
|
|
sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
|
|
strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
|
|
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
|
perror("ifconfig: socket");
|
|
return;
|
|
}
|
|
ifr6.ifr_addr = *sin;
|
|
if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
|
|
perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)");
|
|
close(s6);
|
|
return;
|
|
}
|
|
flags6 = ifr6.ifr_ifru.ifru_flags6;
|
|
memset(&lifetime, 0, sizeof(lifetime));
|
|
ifr6.ifr_addr = *sin;
|
|
if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
|
|
perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)");
|
|
close(s6);
|
|
return;
|
|
}
|
|
lifetime = ifr6.ifr_ifru.ifru_lifetime;
|
|
close(s6);
|
|
|
|
/* XXX: embedded link local addr check */
|
|
if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
|
|
*(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
|
|
u_short index;
|
|
|
|
index = *(u_short *)&sin->sin6_addr.s6_addr[2];
|
|
*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
|
|
if (sin->sin6_scope_id == 0)
|
|
sin->sin6_scope_id = ntohs(index);
|
|
}
|
|
|
|
error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
|
|
sizeof(addr_buf), NULL, 0,
|
|
NI_NUMERICHOST|NI_WITHSCOPEID);
|
|
if (error != 0)
|
|
inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
|
|
sizeof(addr_buf));
|
|
printf("\tinet6 %s ", addr_buf);
|
|
|
|
if (flags & IFF_POINTOPOINT) {
|
|
/* note RTAX_BRD overlap with IFF_BROADCAST */
|
|
sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
|
|
/*
|
|
* some of the interfaces do not have valid destination
|
|
* address.
|
|
*/
|
|
if (sin && sin->sin6_family == AF_INET6) {
|
|
int error;
|
|
|
|
/* XXX: embedded link local addr check */
|
|
if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
|
|
*(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
|
|
u_short index;
|
|
|
|
index = *(u_short *)&sin->sin6_addr.s6_addr[2];
|
|
*(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
|
|
if (sin->sin6_scope_id == 0)
|
|
sin->sin6_scope_id = ntohs(index);
|
|
}
|
|
|
|
error = getnameinfo((struct sockaddr *)sin,
|
|
sin->sin6_len, addr_buf,
|
|
sizeof(addr_buf), NULL, 0,
|
|
NI_NUMERICHOST|NI_WITHSCOPEID);
|
|
if (error != 0)
|
|
inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
|
|
sizeof(addr_buf));
|
|
printf("--> %s ", addr_buf);
|
|
}
|
|
}
|
|
|
|
sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
|
|
if (!sin)
|
|
sin = &null_sin;
|
|
printf("prefixlen %d ", prefix(&sin->sin6_addr,
|
|
sizeof(struct in6_addr)));
|
|
|
|
if (flags6 & IN6_IFF_ANYCAST)
|
|
printf("anycast ");
|
|
if (flags6 & IN6_IFF_TENTATIVE)
|
|
printf("tentative ");
|
|
if (flags6 & IN6_IFF_DUPLICATED)
|
|
printf("duplicated ");
|
|
if (flags6 & IN6_IFF_DETACHED)
|
|
printf("detached ");
|
|
if (flags6 & IN6_IFF_DEPRECATED)
|
|
printf("deprecated ");
|
|
|
|
|
|
if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
|
|
printf("pltime ");
|
|
if (lifetime.ia6t_preferred) {
|
|
printf("%s ", lifetime.ia6t_preferred < t
|
|
? "0" : sec2str(lifetime.ia6t_preferred - t));
|
|
} else
|
|
printf("infty ");
|
|
|
|
printf("vltime ");
|
|
if (lifetime.ia6t_expire) {
|
|
printf("%s ", lifetime.ia6t_expire < t
|
|
? "0" : sec2str(lifetime.ia6t_expire - t));
|
|
} else
|
|
printf("infty ");
|
|
}
|
|
|
|
putchar('\n');
|
|
}
|
|
#endif /*INET6*/
|
|
|
|
void
|
|
ipx_status(s, info)
|
|
int s __unused;
|
|
struct rt_addrinfo * info;
|
|
{
|
|
struct sockaddr_ipx *sipx, null_sipx;
|
|
|
|
memset(&null_sipx, 0, sizeof(null_sipx));
|
|
|
|
sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
|
|
printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
|
|
|
|
if (flags & IFF_POINTOPOINT) {
|
|
sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
|
|
if (!sipx)
|
|
sipx = &null_sipx;
|
|
printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
void
|
|
at_status(s, info)
|
|
int s __unused;
|
|
struct rt_addrinfo * info;
|
|
{
|
|
struct sockaddr_at *sat, null_sat;
|
|
struct netrange *nr;
|
|
|
|
memset(&null_sat, 0, sizeof(null_sat));
|
|
|
|
sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
|
|
nr = &sat->sat_range.r_netrange;
|
|
printf("\tatalk %d.%d range %d-%d phase %d",
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
|
|
ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
|
|
if (flags & IFF_POINTOPOINT) {
|
|
/* note RTAX_BRD overlap with IFF_BROADCAST */
|
|
sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
|
|
if (!sat)
|
|
sat = &null_sat;
|
|
printf("--> %d.%d",
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
|
|
}
|
|
if (flags & IFF_BROADCAST) {
|
|
/* note RTAX_BRD overlap with IFF_POINTOPOINT */
|
|
sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
|
|
if (sat)
|
|
printf(" broadcast %d.%d",
|
|
ntohs(sat->sat_addr.s_net),
|
|
sat->sat_addr.s_node);
|
|
}
|
|
|
|
putchar('\n');
|
|
}
|
|
|
|
#ifdef NS
|
|
void
|
|
xns_status(s, info)
|
|
int s __unused;
|
|
struct rt_addrinfo * info;
|
|
{
|
|
struct sockaddr_ns *sns, null_sns;
|
|
|
|
memset(&null_sns, 0, sizeof(null_sns));
|
|
|
|
sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA];
|
|
printf("\tns %s ", ns_ntoa(sns->sns_addr));
|
|
|
|
if (flags & IFF_POINTOPOINT) {
|
|
sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD];
|
|
if (!sns)
|
|
sns = &null_sns;
|
|
printf("--> %s ", ns_ntoa(sns->sns_addr));
|
|
}
|
|
|
|
putchar('\n');
|
|
close(s);
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
ether_status(s, info)
|
|
int s __unused;
|
|
struct rt_addrinfo *info;
|
|
{
|
|
char *cp;
|
|
int n;
|
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *)info;
|
|
|
|
cp = (char *)LLADDR(sdl);
|
|
if ((n = sdl->sdl_alen) > 0) {
|
|
if (sdl->sdl_type == IFT_ETHER)
|
|
printf ("\tether ");
|
|
else
|
|
printf ("\tlladdr ");
|
|
while (--n >= 0)
|
|
printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
|
|
putchar('\n');
|
|
}
|
|
}
|
|
|
|
void
|
|
Perror(cmd)
|
|
const char *cmd;
|
|
{
|
|
switch (errno) {
|
|
|
|
case ENXIO:
|
|
errx(1, "%s: no such interface", cmd);
|
|
break;
|
|
|
|
case EPERM:
|
|
errx(1, "%s: permission denied", cmd);
|
|
break;
|
|
|
|
default:
|
|
err(1, "%s", cmd);
|
|
}
|
|
}
|
|
|
|
#define SIN(x) ((struct sockaddr_in *) &(x))
|
|
struct sockaddr_in *sintab[] = {
|
|
SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
|
|
SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
|
|
|
|
void
|
|
in_getaddr(s, which)
|
|
const char *s;
|
|
int which;
|
|
{
|
|
register struct sockaddr_in *sin = sintab[which];
|
|
struct hostent *hp;
|
|
struct netent *np;
|
|
|
|
sin->sin_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin_family = AF_INET;
|
|
|
|
if (inet_aton(s, &sin->sin_addr))
|
|
return;
|
|
if ((hp = gethostbyname(s)) != 0)
|
|
bcopy(hp->h_addr, (char *)&sin->sin_addr,
|
|
MIN(hp->h_length, sizeof(sin->sin_addr)));
|
|
else if ((np = getnetbyname(s)) != 0)
|
|
sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
|
|
else
|
|
errx(1, "%s: bad value", s);
|
|
}
|
|
|
|
#ifdef INET6
|
|
#define SIN6(x) ((struct sockaddr_in6 *) &(x))
|
|
struct sockaddr_in6 *sin6tab[] = {
|
|
SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
|
|
SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
|
|
|
|
void
|
|
in6_getaddr(s, which)
|
|
const char *s;
|
|
int which;
|
|
{
|
|
register struct sockaddr_in6 *sin = sin6tab[which];
|
|
struct addrinfo hints, *res;
|
|
int error = -1;
|
|
|
|
newaddr &= 1;
|
|
|
|
sin->sin6_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin6_family = AF_INET6;
|
|
|
|
if (sin->sin6_family == AF_INET6) {
|
|
bzero(&hints, sizeof(struct addrinfo));
|
|
hints.ai_family = AF_INET6;
|
|
error = getaddrinfo(s, NULL, &hints, &res);
|
|
}
|
|
if (error != 0) {
|
|
if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
|
|
errx(1, "%s: bad value", s);
|
|
} else
|
|
bcopy(res->ai_addr, sin, res->ai_addrlen);
|
|
}
|
|
|
|
void
|
|
in6_getprefix(plen, which)
|
|
const char *plen;
|
|
int which;
|
|
{
|
|
register struct sockaddr_in6 *sin = sin6tab[which];
|
|
register u_char *cp;
|
|
int len = atoi(plen);
|
|
|
|
if ((len < 0) || (len > 128))
|
|
errx(1, "%s: bad value", plen);
|
|
sin->sin6_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin6_family = AF_INET6;
|
|
if ((len == 0) || (len == 128)) {
|
|
memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
|
|
return;
|
|
}
|
|
memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
|
|
for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
|
|
*cp++ = 0xff;
|
|
*cp = 0xff << (8 - len);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Print a value a la the %b format of the kernel's printf
|
|
*/
|
|
void
|
|
printb(s, v, bits)
|
|
const char *s;
|
|
register unsigned v;
|
|
register const char *bits;
|
|
{
|
|
register int i, any = 0;
|
|
register char c;
|
|
|
|
if (bits && *bits == 8)
|
|
printf("%s=%o", s, v);
|
|
else
|
|
printf("%s=%x", s, v);
|
|
bits++;
|
|
if (bits) {
|
|
putchar('<');
|
|
while ((i = *bits++) != '\0') {
|
|
if (v & (1 << (i-1))) {
|
|
if (any)
|
|
putchar(',');
|
|
any = 1;
|
|
for (; (c = *bits) > 32; bits++)
|
|
putchar(c);
|
|
} else
|
|
for (; *bits > 32; bits++)
|
|
;
|
|
}
|
|
putchar('>');
|
|
}
|
|
}
|
|
|
|
#define SIPX(x) ((struct sockaddr_ipx *) &(x))
|
|
struct sockaddr_ipx *sipxtab[] = {
|
|
SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
|
|
SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
|
|
|
|
void
|
|
ipx_getaddr(addr, which)
|
|
const char *addr;
|
|
int which;
|
|
{
|
|
struct sockaddr_ipx *sipx = sipxtab[which];
|
|
|
|
sipx->sipx_family = AF_IPX;
|
|
sipx->sipx_len = sizeof(*sipx);
|
|
sipx->sipx_addr = ipx_addr(addr);
|
|
if (which == MASK)
|
|
printf("Attempt to set IPX netmask will be ineffectual\n");
|
|
}
|
|
|
|
void
|
|
at_getaddr(addr, which)
|
|
const char *addr;
|
|
int which;
|
|
{
|
|
struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
|
|
u_int net, node;
|
|
|
|
sat->sat_family = AF_APPLETALK;
|
|
sat->sat_len = sizeof(*sat);
|
|
if (which == MASK)
|
|
errx(1, "AppleTalk does not use netmasks");
|
|
if (sscanf(addr, "%u.%u", &net, &node) != 2
|
|
|| net > 0xffff || node > 0xfe)
|
|
errx(1, "%s: illegal address", addr);
|
|
sat->sat_addr.s_net = htons(net);
|
|
sat->sat_addr.s_node = node;
|
|
}
|
|
|
|
/* XXX FIXME -- should use strtoul for better parsing. */
|
|
void
|
|
setatrange(range, dummy, s, afp)
|
|
const char *range;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
u_short first = 123, last = 123;
|
|
|
|
if (sscanf(range, "%hu-%hu", &first, &last) != 2
|
|
|| first == 0 || first > 0xffff
|
|
|| last == 0 || last > 0xffff || first > last)
|
|
errx(1, "%s: illegal net range: %u-%u", range, first, last);
|
|
at_nr.nr_firstnet = htons(first);
|
|
at_nr.nr_lastnet = htons(last);
|
|
}
|
|
|
|
void
|
|
setatphase(phase, dummy, s, afp)
|
|
const char *phase;
|
|
int dummy __unused;
|
|
int s;
|
|
const struct afswtch *afp;
|
|
{
|
|
if (!strcmp(phase, "1"))
|
|
at_nr.nr_phase = 1;
|
|
else if (!strcmp(phase, "2"))
|
|
at_nr.nr_phase = 2;
|
|
else
|
|
errx(1, "%s: illegal phase", phase);
|
|
}
|
|
|
|
void
|
|
checkatrange(struct sockaddr_at *sat)
|
|
{
|
|
if (at_nr.nr_phase == 0)
|
|
at_nr.nr_phase = 2; /* Default phase 2 */
|
|
if (at_nr.nr_firstnet == 0)
|
|
at_nr.nr_firstnet = /* Default range of one */
|
|
at_nr.nr_lastnet = sat->sat_addr.s_net;
|
|
printf("\tatalk %d.%d range %d-%d phase %d\n",
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
|
|
ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
|
|
if ((u_short) ntohs(at_nr.nr_firstnet) >
|
|
(u_short) ntohs(sat->sat_addr.s_net)
|
|
|| (u_short) ntohs(at_nr.nr_lastnet) <
|
|
(u_short) ntohs(sat->sat_addr.s_net))
|
|
errx(1, "AppleTalk address is not in range");
|
|
sat->sat_range.r_netrange = at_nr;
|
|
}
|
|
|
|
#ifdef NS
|
|
#define SNS(x) ((struct sockaddr_ns *) &(x))
|
|
struct sockaddr_ns *snstab[] = {
|
|
SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
|
|
SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
|
|
|
|
void
|
|
xns_getaddr(addr, which)
|
|
const char *addr;
|
|
int which;
|
|
{
|
|
struct sockaddr_ns *sns = snstab[which];
|
|
|
|
sns->sns_family = AF_NS;
|
|
sns->sns_len = sizeof(*sns);
|
|
sns->sns_addr = ns_addr(addr);
|
|
if (which == MASK)
|
|
printf("Attempt to set XNS netmask will be ineffectual\n");
|
|
}
|
|
#endif
|
|
|
|
#ifdef INET6
|
|
int
|
|
prefix(val, size)
|
|
void *val;
|
|
int size;
|
|
{
|
|
register u_char *name = (u_char *)val;
|
|
register int byte, bit, plen = 0;
|
|
|
|
for (byte = 0; byte < size; byte++, plen += 8)
|
|
if (name[byte] != 0xff)
|
|
break;
|
|
if (byte == size)
|
|
return (plen);
|
|
for (bit = 7; bit != 0; bit--, plen++)
|
|
if (!(name[byte] & (1 << bit)))
|
|
break;
|
|
for (; bit != 0; bit--)
|
|
if (name[byte] & (1 << bit))
|
|
return(0);
|
|
byte++;
|
|
for (; byte < size; byte++)
|
|
if (name[byte])
|
|
return(0);
|
|
return (plen);
|
|
}
|
|
|
|
static char *
|
|
sec2str(total)
|
|
time_t total;
|
|
{
|
|
static char result[256];
|
|
int days, hours, mins, secs;
|
|
int first = 1;
|
|
char *p = result;
|
|
|
|
if (0) {
|
|
days = total / 3600 / 24;
|
|
hours = (total / 3600) % 24;
|
|
mins = (total / 60) % 60;
|
|
secs = total % 60;
|
|
|
|
if (days) {
|
|
first = 0;
|
|
p += sprintf(p, "%dd", days);
|
|
}
|
|
if (!first || hours) {
|
|
first = 0;
|
|
p += sprintf(p, "%dh", hours);
|
|
}
|
|
if (!first || mins) {
|
|
first = 0;
|
|
p += sprintf(p, "%dm", mins);
|
|
}
|
|
sprintf(p, "%ds", secs);
|
|
} else
|
|
sprintf(result, "%lu", (unsigned long)total);
|
|
|
|
return(result);
|
|
}
|
|
#endif /*INET6*/
|
|
|
|
void
|
|
ifmaybeload(name)
|
|
char *name;
|
|
{
|
|
struct module_stat mstat;
|
|
int fileid, modid;
|
|
char ifkind[35], *cp, *dp;
|
|
|
|
|
|
/* turn interface and unit into module name */
|
|
strcpy(ifkind, "if_");
|
|
for (cp = name, dp = ifkind + 3; (*cp != 0) && !isdigit(*cp); cp++, dp++)
|
|
*dp = *cp;
|
|
*dp = 0;
|
|
|
|
/* scan files in kernel */
|
|
mstat.version = sizeof(struct module_stat);
|
|
for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
|
|
/* scan modules in file */
|
|
for (modid = kldfirstmod(fileid); modid > 0;
|
|
modid = modfnext(modid)) {
|
|
if (modstat(modid, &mstat) < 0)
|
|
continue;
|
|
/* strip bus name if present */
|
|
if ((cp = strchr(mstat.name, '/')) != NULL) {
|
|
cp++;
|
|
} else {
|
|
cp = mstat.name;
|
|
}
|
|
/* already loaded? */
|
|
if (!strcmp(ifkind, cp))
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* not present, we should try to load it */
|
|
kldload(ifkind);
|
|
}
|