Add tool: arp.

The arp utility displays and modifies the Internet-to-Ethernet address translation tables used by the address resolution protocol.
dev
logwang 2017-12-13 16:59:59 +08:00
parent 4ca4a48737
commit df9cc249f2
17 changed files with 1915 additions and 99 deletions

View File

@ -1,4 +1,4 @@
SUBDIRS=compat libutil libmemstat libxo libnetgraph sysctl ifconfig route top netstat ngctl ipfw
SUBDIRS=compat libutil libmemstat libxo libnetgraph sysctl ifconfig route top netstat ngctl ipfw arp
all:
for d in $(SUBDIRS); do ( cd $$d; $(MAKE) all ) ; done

View File

@ -198,6 +198,20 @@ Note [dummynet](https://www.freebsd.org/cgi/man.cgi?query=dummynet) is not suppo
For more details, see [Manual page](https://www.freebsd.org/cgi/man.cgi?ipfw) or [handbook](https://www.freebsd.org/doc/handbook/firewalls-ipfw.html).
# arp
Usage
```
usage: arp -p <f-stack proc_id> [-n] [-i interface] hostname
arp -p <f-stack proc_id> [-n] [-i interface] -a
arp -p <f-stack proc_id> -d hostname [pub]
arp -p <f-stack proc_id> -d [-i interface] -a
arp -p <f-stack proc_id> -s hostname ether_addr [temp] [reject | blackhole] [pub [only]]
arp -p <f-stack proc_id> -S hostname ether_addr [temp] [reject | blackhole] [pub [only]]
arp -p <f-stack proc_id> -f filename
```
For more details, see [Manual page](https://www.freebsd.org/cgi/man.cgi?arp).
# how to implement a custom tool for communicating with F-Stack process
Add a new FF_MSG_TYPE in ff_msg.h:

9
tools/arp/Makefile Normal file
View File

@ -0,0 +1,9 @@
# @(#)Makefile 8.2 (Berkeley) 4/18/94
# $FreeBSD$
TOPDIR?=${CURDIR}/../..
PROG=arp
include ${TOPDIR}/tools/prog.mk

235
tools/arp/arp.4 Normal file
View File

@ -0,0 +1,235 @@
.\" Copyright (c) 1985, 1986, 1988, 1994
.\" 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.
.\" 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.
.\"
.\" @(#)arp4.4 6.5 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
.Dd November 5, 2013
.Dt ARP 4
.Os
.Sh NAME
.Nm arp
.Nd Address Resolution Protocol
.Sh SYNOPSIS
.Cd "device ether"
.Sh DESCRIPTION
The Address Resolution Protocol (ARP) is used to dynamically
map between Protocol Addresses (such as IP addresses) and
Local Network Addresses (such as Ethernet addresses).
This implementation maps IP addresses to Ethernet,
ARCnet,
or Token Ring addresses.
It is used by all the Ethernet interface drivers.
.Pp
ARP caches Internet-Ethernet address mappings.
When an interface requests a mapping for an address not in the cache,
ARP queues the message which requires the mapping and broadcasts
a message on the associated network requesting the address mapping.
If a response is provided, the new mapping is cached and any pending
message is transmitted.
ARP will queue at most one packet while waiting for a response to a
mapping request;
only the most recently ``transmitted'' packet is kept.
If the target host does not respond after several requests,
the host is considered to be down allowing an error to be returned to
transmission attempts.
Further demand for this mapping causes ARP request retransmissions, that
are ratelimited to one packet per second.
The error is
.Er EHOSTDOWN
for a non-responding destination host, and
.Er EHOSTUNREACH
for a non-responding router.
.Pp
The ARP cache is stored in the system routing table as
dynamically-created host routes.
The route to a directly-attached Ethernet network is installed as a
.Dq cloning
route (one with the
.Li RTF_CLONING
flag set),
causing routes to individual hosts on that network to be created on
demand.
These routes time out periodically (normally 20 minutes after validated;
entries are not validated when not in use).
.Pp
ARP entries may be added, deleted or changed with the
.Xr arp 8
utility.
Manually-added entries may be temporary or permanent,
and may be
.Dq published ,
in which case the system will respond to ARP requests for that host
as if it were the target of the request.
.Pp
In the past,
ARP was used to negotiate the use of a trailer encapsulation.
This is no longer supported.
.Pp
ARP watches passively for hosts impersonating the local host (i.e., a host
which responds to an ARP mapping request for the local host's address).
.Pp
Proxy ARP is a feature whereby the local host will respond to requests
for addresses other than itself, with its own address.
Normally, proxy ARP in
.Fx
is set up on a host-by-host basis using the
.Xr arp 8
utility, by adding an entry for each host inside a given subnet for
which proxying of ARP requests is desired.
However, the
.Dq "proxy all"
feature causes the local host to act as a proxy for
.Em all
hosts reachable through some other network interface,
different from the one the request came in from.
It may be enabled by setting the
.Xr sysctl 8
MIB variable
.Va net.link.ether.inet.proxyall
to 1.
.Sh MIB Variables
The ARP protocol implements a number of configurable variables in
.Va net.link.ether.inet
branch
of the
.Xr sysctl 3
MIB.
.Bl -tag -width "log_arp_permanent_modify"
.It Va allow_multicast
Should the kernel install ARP entries with multicast bit set in
the hardware address.
Installing such entries is RFC 1812 violation, but some prorietary
load balancing techniques require routers on network to do so.
Turned off by default.
.It Va log_arp_movements
Should the kernel log movements of IP addresses from one hardware
address to an other.
See
.Sx DIAGNOSTICS
below.
Turned on by default.
.It Va log_arp_permanent_modify
Should the kernel log attempts of remote host on network to modify a
permanent ARP entry.
See
.Sx DIAGNOSTICS
below.
Turned on by default.
.It Va log_arp_wrong_iface
Should the kernel log attempts to insert an ARP entry on an interface
when the IP network the address belongs to is connected to an other
interface.
See
.Sx DIAGNOSTICS
below.
Turned on by default.
.It Va max_log_per_second
Limit number of remotely triggered logging events to a configured value
per second.
Default is 1 log message per second.
.It Va max_age
How long an ARP entry is held in the cache until it needs to be refreshed.
Default is 1200 seconds.
.It Va maxhold
How many packets hold in the per-entry output queue while the entry
is being resolved.
Default is one packet.
.It Va maxtries
Number of retransmits before host is considered down and error is returned.
Default is 5 tries.
.It Va proxyall
Enables ARP proxying for all hosts on net.
Turned off by default.
.It Va wait
Lifetime of an incomplete ARP entry.
Default is 20 seconds.
.El
.Sh DIAGNOSTICS
.Bl -diag
.It "arp: %x:%x:%x:%x:%x:%x is using my IP address %d.%d.%d.%d on %s!"
ARP has discovered another host on the local network which responds to
mapping requests for its own Internet address with a different Ethernet
address, generally indicating that two hosts are attempting to use the
same Internet address.
.It "arp: link address is broadcast for IP address %d.%d.%d.%d!"
ARP requested information for a host, and received an answer indicating
that the host's ethernet address is the ethernet broadcast address.
This indicates a misconfigured or broken device.
.It "arp: %d.%d.%d.%d moved from %x:%x:%x:%x:%x:%x to %x:%x:%x:%x:%x:%x on %s"
ARP had a cached value for the ethernet address of the referenced host,
but received a reply indicating that the host is at a new address.
This can happen normally when host hardware addresses change,
or when a mobile node arrives or leaves the local subnet.
It can also indicate a problem with proxy ARP.
This message can only be issued if the sysctl
.Va net.link.ether.inet.log_arp_movements
is set to 1, which is the system's default behaviour.
.It "arpresolve: can't allocate llinfo for %d.%d.%d.%d"
The route for the referenced host points to a device upon which ARP is
required, but ARP was unable to allocate a routing table entry in which
to store the host's MAC address.
This usually points to a misconfigured routing table.
It can also occur if the kernel cannot allocate memory.
.It "arp: %d.%d.%d.%d is on if0 but got reply from %x:%x:%x:%x:%x:%x on if1"
Physical connections exist to the same logical IP network on both if0 and if1.
It can also occur if an entry already exists in the ARP cache for the IP
address above, and the cable has been disconnected from if0, then reconnected
to if1.
This message can only be issued if the sysctl
.Va net.link.ether.inet.log_arp_wrong_iface
is set to 1, which is the system's default behaviour.
.It "arp: %x:%x:%x:%x:%x:%x attempts to modify permanent entry for %d.%d.%d.%d on %s"
ARP has received an ARP reply that attempts to overwrite a permanent
entry in the local ARP table.
This error will only be logged if the sysctl
.Va net.link.ether.inet.log_arp_permanent_modify
is set to 1, which is the system's default behaviour.
.It "arp: %x:%x:%x:%x:%x:%x is multicast"
Kernel refused to install an entry with multicast hardware address.
If you really want such addresses being installed, set the sysctl
.Va net.link.ether.inet.allow_multicast
to a positive value.
.El
.Sh SEE ALSO
.Xr inet 4 ,
.Xr route 4 ,
.Xr arp 8 ,
.Xr ifconfig 8 ,
.Xr route 8 ,
.Xr sysctl 8
.Rs
.%A Plummer, D.
.%B "An Ethernet Address Resolution Protocol"
.%T RFC826
.Re
.Rs
.%A Leffler, S.J.
.%A Karels, M.J.
.%B "Trailer Encapsulations"
.%T RFC893
.Re

192
tools/arp/arp.8 Normal file
View File

@ -0,0 +1,192 @@
.\" Copyright (c) 1985, 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
.\" documentation and/or other materials provided with the distribution.
.\" 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.
.\"
.\" @(#)arp.8 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
.Dd January 31, 2013
.Dt ARP 8
.Os
.Sh NAME
.Nm arp
.Nd address resolution display and control
.Sh SYNOPSIS
.Nm
.Op Fl n
.Op Fl i Ar interface
.Ar hostname
.Nm
.Op Fl n
.Op Fl i Ar interface
.Fl a
.Nm
.Fl d Ar hostname
.Op Cm pub
.Nm
.Fl d
.Op Fl i Ar interface
.Fl a
.Nm
.Fl s Ar hostname ether_addr
.Op Cm temp
.Op Cm blackhole No \&| Cm reject
.Op Cm pub
.Nm
.Fl S Ar hostname ether_addr
.Op Cm temp
.Op Cm blackhole No \&| Cm reject
.Op Cm pub
.Nm
.Fl f Ar filename
.Sh DESCRIPTION
The
.Nm
utility displays and modifies the Internet-to-Ethernet address translation
tables used by the address resolution protocol
.Pq Xr arp 4 .
With no flags, the program displays the current
.Tn ARP
entry for
.Ar hostname .
The host may be specified by name or by number,
using Internet dot notation.
.Pp
Available options:
.Bl -tag -width indent
.It Fl a
The program displays or deletes all of the current
.Tn ARP
entries.
.It Fl d
A super-user may delete an entry for the host called
.Ar hostname
with the
.Fl d
flag.
If the
.Cm pub
keyword is specified, only the
.Dq published
.Tn ARP
entry
for this host will be deleted.
.Pp
Alternatively, the
.Fl d
flag may be combined with the
.Fl a
flag to delete all entries.
.It Fl i Ar interface
Limit the operation scope to the
.Tn ARP
entries on
.Ar interface .
Applicable only to the following operations:
display one, display all, delete all.
.It Fl n
Show network addresses as numbers (normally
.Nm
attempts to display addresses symbolically).
.It Fl s Ar hostname ether_addr
Create an
.Tn ARP
entry for the host called
.Ar hostname
with the Ethernet address
.Ar ether_addr .
The Ethernet address is given as six hex bytes separated by colons.
The entry will be permanent unless the word
.Cm temp
is given in the command.
If the word
.Cm pub
is given, the entry will be
.Dq published ;
i.e., this system will
act as an
.Tn ARP
server,
responding to requests for
.Ar hostname
even though the host address is not its own.
In this case the
.Ar ether_addr
can be given as
.Cm auto
in which case the interfaces on this host will be examined,
and if one of them is found to occupy the same subnet, its
Ethernet address will be used.
.Pp
If the
.Cm reject
keyword is specified the entry will be marked so that traffic to
the host will be discarded and the sender will be notified the
host is unreachable.
The
.Cm blackhole
keyword is similar in that traffic is discarded but the sender is
not notified.
These can be used to block external traffic to a host without
using a firewall.
.It Fl S Ar hostname ether_addr
Is just like
.Fl s
except any existing
.Tn ARP
entry for this host will be deleted first.
.It Fl f Ar filename
Cause the file
.Ar filename
to be read and multiple entries to be set in the
.Tn ARP
tables.
Entries
in the file should be of the form
.Pp
.Bd -ragged -offset indent -compact
.Ar hostname ether_addr
.Op Cm temp
.Op Cm blackhole No \&| Cm reject
.Op Cm pub
.Ed
.Pp
with argument meanings as given above.
Leading whitespace and empty lines are ignored.
A
.Ql #
character will mark the rest of the line as a comment.
.El
.Sh SEE ALSO
.Xr inet 3 ,
.Xr arp 4 ,
.Xr ifconfig 8 ,
.Xr ndp 8
.Sh HISTORY
The
.Nm
utility appeared in
.Bx 4.3 .

927
tools/arp/arp.c Normal file
View File

@ -0,0 +1,927 @@
/*
* Copyright (c) 1984, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Sun Microsystems, Inc.
*
* 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.
* 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.
*/
#if 0
#ifndef lint
static char const copyright[] =
"@(#) Copyright (c) 1984, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* arp - display, set, and delete arp table entries
*/
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/iso88025.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <nlist.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#ifdef FSTACK
#include <time.h>
#include "rtioctl.h"
#include "ff_ipc.h"
#ifndef __unused
#define __unused __attribute__((__unused__))
#define socket(a, b, c) rt_socket((a), (b), (c))
#define close(a) rt_close(a)
#endif
#endif
typedef void (action_fn)(struct sockaddr_dl *sdl,
struct sockaddr_in *s_in, struct rt_msghdr *rtm);
static int search(u_long addr, action_fn *action);
static action_fn print_entry;
static action_fn nuke_entry;
static int delete(char *host);
static void usage(void);
static int set(int argc, char **argv);
static int get(char *host);
static int file(char *name);
static struct rt_msghdr *rtmsg(int cmd,
struct sockaddr_in *dst, struct sockaddr_dl *sdl);
static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
static struct sockaddr_in *getaddr(char *host);
static int valid_type(int type);
static int nflag; /* no reverse dns lookups */
static char *rifname;
static time_t expire_time;
static int flags, doing_proxy;
struct if_nameindex *ifnameindex;
/* which function we're supposed to do */
#define F_GET 1
#define F_SET 2
#define F_FILESET 3
#define F_REPLACE 4
#define F_DELETE 5
#define SETFUNC(f) { if (func) usage(); func = (f); }
int
main(int argc, char *argv[])
{
int ch, func = 0;
int rtn = 0;
int aflag = 0; /* do it for all entries */
#ifndef FSTACK
while ((ch = getopt(argc, argv, "andfsSi:")) != -1)
#else
ff_ipc_init();
while ((ch = getopt(argc, argv, "andfsSi:p:")) != -1)
#endif
switch(ch) {
case 'a':
aflag = 1;
break;
case 'd':
SETFUNC(F_DELETE);
break;
case 'n':
nflag = 1;
break;
case 'S':
SETFUNC(F_REPLACE);
break;
case 's':
SETFUNC(F_SET);
break;
case 'f' :
SETFUNC(F_FILESET);
break;
case 'i':
rifname = optarg;
break;
#ifdef FSTACK
case 'p':
ff_set_proc_id(atoi(optarg));
break;
#endif
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (!func)
func = F_GET;
if (rifname) {
if (func != F_GET && !(func == F_DELETE && aflag))
errx(1, "-i not applicable to this operation");
if (if_nametoindex(rifname) == 0) {
if (errno == ENXIO)
errx(1, "interface %s does not exist", rifname);
else
err(1, "if_nametoindex(%s)", rifname);
}
}
switch (func) {
case F_GET:
if (aflag) {
if (argc != 0)
usage();
search(0, print_entry);
} else {
if (argc != 1)
usage();
rtn = get(argv[0]);
}
break;
case F_SET:
case F_REPLACE:
if (argc < 2 || argc > 6)
usage();
if (func == F_REPLACE)
(void)delete(argv[0]);
rtn = set(argc, argv) ? 1 : 0;
break;
case F_DELETE:
if (aflag) {
if (argc != 0)
usage();
search(0, nuke_entry);
} else {
if (argc != 1)
usage();
rtn = delete(argv[0]);
}
break;
case F_FILESET:
if (argc != 1)
usage();
rtn = file(argv[0]);
break;
}
if (ifnameindex != NULL)
if_freenameindex(ifnameindex);
return (rtn);
}
/*
* Process a file to set standard arp entries
*/
static int
file(char *name)
{
FILE *fp;
int i, retval;
char line[100], arg[5][50], *args[5], *p;
if ((fp = fopen(name, "r")) == NULL)
err(1, "cannot open %s", name);
args[0] = &arg[0][0];
args[1] = &arg[1][0];
args[2] = &arg[2][0];
args[3] = &arg[3][0];
args[4] = &arg[4][0];
retval = 0;
while(fgets(line, sizeof(line), fp) != NULL) {
if ((p = strchr(line, '#')) != NULL)
*p = '\0';
for (p = line; isblank(*p); p++);
if (*p == '\n' || *p == '\0')
continue;
i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1],
arg[2], arg[3], arg[4]);
if (i < 2) {
warnx("bad line: %s", line);
retval = 1;
continue;
}
if (set(i, args))
retval = 1;
}
fclose(fp);
return (retval);
}
/*
* Given a hostname, fills up a (static) struct sockaddr_in with
* the address of the host and returns a pointer to the
* structure.
*/
static struct sockaddr_in *
getaddr(char *host)
{
#ifndef FSTACK
struct hostent *hp;
#endif
static struct sockaddr_in reply;
bzero(&reply, sizeof(reply));
reply.sin_len = sizeof(reply);
reply.sin_family = AF_INET;
reply.sin_addr.s_addr = inet_addr(host);
if (reply.sin_addr.s_addr == INADDR_NONE) {
#ifndef FSTACK
if (!(hp = gethostbyname(host))) {
warnx("%s: %s", host, hstrerror(h_errno));
return (NULL);
}
bcopy((char *)hp->h_addr, (char *)&reply.sin_addr,
sizeof reply.sin_addr);
#else
warnx("reply.sin_addr.s_addr == INADDR_NONE");
#endif
}
return (&reply);
}
/*
* Returns true if the type is a valid one for ARP.
*/
static int
valid_type(int type)
{
switch (type) {
case IFT_ETHER:
case IFT_FDDI:
case IFT_INFINIBAND:
case IFT_ISO88023:
case IFT_ISO88024:
case IFT_ISO88025:
case IFT_L2VLAN:
case IFT_BRIDGE:
return (1);
default:
return (0);
}
}
/*
* Set an individual arp entry
*/
static int
set(int argc, char **argv)
{
struct sockaddr_in *addr;
struct sockaddr_in *dst; /* what are we looking for */
struct sockaddr_dl *sdl;
struct rt_msghdr *rtm;
struct ether_addr *ea;
char *host = argv[0], *eaddr = argv[1];
struct sockaddr_dl sdl_m;
argc -= 2;
argv += 2;
bzero(&sdl_m, sizeof(sdl_m));
sdl_m.sdl_len = sizeof(sdl_m);
sdl_m.sdl_family = AF_LINK;
dst = getaddr(host);
if (dst == NULL)
return (1);
doing_proxy = flags = expire_time = 0;
while (argc-- > 0) {
if (strncmp(argv[0], "temp", 4) == 0) {
struct timespec tp;
int max_age;
size_t len = sizeof(max_age);
clock_gettime(CLOCK_MONOTONIC, &tp);
if (sysctlbyname("net.link.ether.inet.max_age",
&max_age, &len, NULL, 0) != 0)
err(1, "sysctlbyname");
expire_time = tp.tv_sec + max_age;
} else if (strncmp(argv[0], "pub", 3) == 0) {
flags |= RTF_ANNOUNCE;
doing_proxy = 1;
if (argc && strncmp(argv[1], "only", 3) == 0) {
/*
* Compatibility: in pre FreeBSD 8 times
* the "only" keyword used to mean that
* an ARP entry should be announced, but
* not installed into routing table.
*/
argc--; argv++;
}
} else if (strncmp(argv[0], "blackhole", 9) == 0) {
if (flags & RTF_REJECT) {
printf("Choose one of blackhole or reject, not both.\n");
}
flags |= RTF_BLACKHOLE;
} else if (strncmp(argv[0], "reject", 6) == 0) {
if (flags & RTF_BLACKHOLE) {
printf("Choose one of blackhole or reject, not both.\n");
}
flags |= RTF_REJECT;
} else if (strncmp(argv[0], "trail", 5) == 0) {
/* XXX deprecated and undocumented feature */
printf("%s: Sending trailers is no longer supported\n",
host);
}
argv++;
}
ea = (struct ether_addr *)LLADDR(&sdl_m);
if (doing_proxy && !strcmp(eaddr, "auto")) {
if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
printf("no interface found for %s\n",
inet_ntoa(dst->sin_addr));
return (1);
}
sdl_m.sdl_alen = ETHER_ADDR_LEN;
} else {
struct ether_addr *ea1 = ether_aton(eaddr);
if (ea1 == NULL) {
warnx("invalid Ethernet address '%s'", eaddr);
return (1);
} else {
*ea = *ea1;
sdl_m.sdl_alen = ETHER_ADDR_LEN;
}
}
/*
* In the case a proxy-arp entry is being added for
* a remote end point, the RTF_ANNOUNCE flag in the
* RTM_GET command is an indication to the kernel
* routing code that the interface associated with
* the prefix route covering the local end of the
* PPP link should be returned, on which ARP applies.
*/
rtm = rtmsg(RTM_GET, dst, &sdl_m);
if (rtm == NULL) {
warn("%s", host);
return (1);
}
addr = (struct sockaddr_in *)(rtm + 1);
sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
if ((sdl->sdl_family != AF_LINK) ||
(rtm->rtm_flags & RTF_GATEWAY) ||
!valid_type(sdl->sdl_type)) {
printf("cannot intuit interface index and type for %s\n", host);
return (1);
}
sdl_m.sdl_type = sdl->sdl_type;
sdl_m.sdl_index = sdl->sdl_index;
return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL);
}
/*
* Display an individual arp entry
*/
static int
get(char *host)
{
struct sockaddr_in *addr;
addr = getaddr(host);
if (addr == NULL)
return (1);
if (0 == search(addr->sin_addr.s_addr, print_entry)) {
printf("%s (%s) -- no entry",
host, inet_ntoa(addr->sin_addr));
if (rifname)
printf(" on %s", rifname);
printf("\n");
return (1);
}
return (0);
}
/*
* Delete an arp entry
*/
static int
delete(char *host)
{
struct sockaddr_in *addr, *dst;
struct rt_msghdr *rtm;
struct sockaddr_dl *sdl;
struct sockaddr_dl sdl_m;
dst = getaddr(host);
if (dst == NULL)
return (1);
/*
* Perform a regular entry delete first.
*/
flags &= ~RTF_ANNOUNCE;
/*
* setup the data structure to notify the kernel
* it is the ARP entry the RTM_GET is interested
* in
*/
bzero(&sdl_m, sizeof(sdl_m));
sdl_m.sdl_len = sizeof(sdl_m);
sdl_m.sdl_family = AF_LINK;
for (;;) { /* try twice */
rtm = rtmsg(RTM_GET, dst, &sdl_m);
if (rtm == NULL) {
warn("%s", host);
return (1);
}
addr = (struct sockaddr_in *)(rtm + 1);
sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
/*
* With the new L2/L3 restructure, the route
* returned is a prefix route. The important
* piece of information from the previous
* RTM_GET is the interface index. In the
* case of ECMP, the kernel will traverse
* the route group for the given entry.
*/
if (sdl->sdl_family == AF_LINK &&
!(rtm->rtm_flags & RTF_GATEWAY) &&
valid_type(sdl->sdl_type) ) {
addr->sin_addr.s_addr = dst->sin_addr.s_addr;
break;
}
/*
* Regualar entry delete failed, now check if there
* is a proxy-arp entry to remove.
*/
if (flags & RTF_ANNOUNCE) {
fprintf(stderr, "delete: cannot locate %s\n",host);
return (1);
}
flags |= RTF_ANNOUNCE;
}
rtm->rtm_flags |= RTF_LLDATA;
if (rtmsg(RTM_DELETE, dst, NULL) != NULL) {
printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
return (0);
}
return (1);
}
/*
* Search the arp table and do some action on matching entries
*/
static int
search(u_long addr, action_fn *action)
{
int mib[6];
size_t needed;
char *lim, *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_in *sin2;
struct sockaddr_dl *sdl;
char ifname[IF_NAMESIZE];
int st, found_entry = 0;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
#ifdef RTF_LLINFO
mib[5] = RTF_LLINFO;
#else
mib[5] = 0;
#endif
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if (needed == 0) /* empty table */
return 0;
buf = NULL;
for (;;) {
buf = reallocf(buf, needed);
if (buf == NULL)
errx(1, "could not reallocate memory");
st = sysctl(mib, 6, buf, &needed, NULL, 0);
if (st == 0 || errno != ENOMEM)
break;
needed += needed / 8;
}
if (st == -1)
err(1, "actual retrieval of routing table");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin2 = (struct sockaddr_in *)(rtm + 1);
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
strcmp(ifname, rifname))
continue;
if (addr) {
if (addr != sin2->sin_addr.s_addr)
continue;
found_entry = 1;
}
(*action)(sdl, sin2, rtm);
}
free(buf);
return (found_entry);
}
/*
* Display an arp entry
*/
static void
print_entry(struct sockaddr_dl *sdl,
struct sockaddr_in *addr, struct rt_msghdr *rtm)
{
const char *host;
struct hostent *hp;
struct iso88025_sockaddr_dl_data *trld;
struct if_nameindex *p;
int seg;
if (ifnameindex == NULL)
if ((ifnameindex = if_nameindex()) == NULL)
err(1, "cannot retrieve interface names");
if (nflag == 0)
hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
sizeof addr->sin_addr, AF_INET);
else
hp = 0;
if (hp)
host = hp->h_name;
else {
host = "?";
if (h_errno == TRY_AGAIN)
nflag = 1;
}
printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr));
if (sdl->sdl_alen) {
if ((sdl->sdl_type == IFT_ETHER ||
sdl->sdl_type == IFT_L2VLAN ||
sdl->sdl_type == IFT_BRIDGE) &&
sdl->sdl_alen == ETHER_ADDR_LEN)
printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
else {
int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
printf("%s", link_ntoa(sdl) + n);
}
} else
printf("(incomplete)");
for (p = ifnameindex; p && ifnameindex->if_index &&
ifnameindex->if_name; p++) {
if (p->if_index == sdl->sdl_index) {
printf(" on %s", p->if_name);
break;
}
}
if (rtm->rtm_rmx.rmx_expire == 0)
printf(" permanent");
else {
static struct timespec tp;
if (tp.tv_sec == 0)
clock_gettime(CLOCK_MONOTONIC, &tp);
if ((expire_time = rtm->rtm_rmx.rmx_expire - tp.tv_sec) > 0)
printf(" expires in %d seconds", (int)expire_time);
else
printf(" expired");
}
if (rtm->rtm_flags & RTF_ANNOUNCE)
printf(" published");
switch(sdl->sdl_type) {
case IFT_ETHER:
printf(" [ethernet]");
break;
case IFT_ISO88025:
printf(" [token-ring]");
trld = SDL_ISO88025(sdl);
if (trld->trld_rcf != 0) {
printf(" rt=%x", ntohs(trld->trld_rcf));
for (seg = 0;
seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2);
seg++)
printf(":%x", ntohs(*(trld->trld_route[seg])));
}
break;
case IFT_FDDI:
printf(" [fddi]");
break;
case IFT_ATM:
printf(" [atm]");
break;
case IFT_L2VLAN:
printf(" [vlan]");
break;
case IFT_IEEE1394:
printf(" [firewire]");
break;
case IFT_BRIDGE:
printf(" [bridge]");
break;
case IFT_INFINIBAND:
printf(" [infiniband]");
break;
default:
break;
}
printf("\n");
}
/*
* Nuke an arp entry
*/
static void
nuke_entry(struct sockaddr_dl *sdl __unused,
struct sockaddr_in *addr, struct rt_msghdr *rtm)
{
char ip[20];
if (rtm->rtm_flags & RTF_PINNED)
return;
snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
delete(ip);
}
static void
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
#ifndef FSTACK
"usage: arp [-n] [-i interface] hostname",
" arp [-n] [-i interface] -a",
" arp -d hostname [pub]",
" arp -d [-i interface] -a",
" arp -s hostname ether_addr [temp] [reject | blackhole] [pub [only]]",
" arp -S hostname ether_addr [temp] [reject | blackhole] [pub [only]]",
" arp -f filename");
#else
"usage: arp -p <f-stack proc_id> [-n] [-i interface] hostname",
" arp -p <f-stack proc_id> [-n] [-i interface] -a",
" arp -p <f-stack proc_id> -d hostname [pub]",
" arp -p <f-stack proc_id> -d [-i interface] -a",
" arp -p <f-stack proc_id> -s hostname ether_addr [temp] [reject | blackhole] [pub [only]]",
" arp -p <f-stack proc_id> -S hostname ether_addr [temp] [reject | blackhole] [pub [only]]",
" arp -p <f-stack proc_id> -f filename");
#endif
exit(1);
}
static struct rt_msghdr *
rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl)
{
static int seq;
int rlen;
int l;
struct sockaddr_in so_mask, *som = &so_mask;
static int s = -1;
static pid_t pid;
static struct {
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
char *cp = m_rtmsg.m_space;
if (s < 0) { /* first time: open socket, get pid */
s = socket(PF_ROUTE, SOCK_RAW, 0);
if (s < 0)
err(1, "socket");
pid = getpid();
}
bzero(&so_mask, sizeof(so_mask));
so_mask.sin_len = 8;
so_mask.sin_addr.s_addr = 0xffffffff;
errno = 0;
/*
* XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
* appropriately.
*/
if (cmd == RTM_DELETE)
goto doit;
bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
rtm->rtm_flags = flags;
rtm->rtm_version = RTM_VERSION;
switch (cmd) {
default:
errx(1, "internal wrong cmd");
case RTM_ADD:
rtm->rtm_addrs |= RTA_GATEWAY;
rtm->rtm_rmx.rmx_expire = expire_time;
rtm->rtm_inits = RTV_EXPIRE;
rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
if (doing_proxy) {
rtm->rtm_addrs |= RTA_NETMASK;
rtm->rtm_flags &= ~RTF_HOST;
}
/* FALLTHROUGH */
case RTM_GET:
rtm->rtm_addrs |= RTA_DST;
}
#define NEXTADDR(w, s) \
do { \
if ((s) != NULL && rtm->rtm_addrs & (w)) { \
bcopy((s), cp, sizeof(*(s))); \
cp += SA_SIZE(s); \
} \
} while (0)
NEXTADDR(RTA_DST, dst);
NEXTADDR(RTA_GATEWAY, sdl);
NEXTADDR(RTA_NETMASK, som);
rtm->rtm_msglen = cp - (char *)&m_rtmsg;
doit:
l = rtm->rtm_msglen;
rtm->rtm_seq = ++seq;
rtm->rtm_type = cmd;
#ifndef FSTACK
if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
if (errno != ESRCH || cmd != RTM_DELETE) {
warn("writing to routing socket");
return (NULL);
}
}
do {
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
#else
l = rtioctl((char *)&m_rtmsg, l, sizeof(m_rtmsg));
#endif
if (l < 0)
warn("read from routing socket");
return (rtm);
}
/*
* get_ether_addr - get the hardware address of an interface on the
* the same subnet as ipaddr.
*/
#define MAX_IFS 32
static int
get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
{
struct ifreq *ifr, *ifend, *ifp;
in_addr_t ina, mask;
struct sockaddr_dl *dla;
struct ifreq ifreq;
struct ifconf ifc;
struct ifreq ifs[MAX_IFS];
int sock;
int retval = 0;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
err(1, "socket");
ifc.ifc_len = sizeof(ifs);
ifc.ifc_req = ifs;
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
warnx("ioctl(SIOCGIFCONF)");
goto done;
}
#define NEXTIFR(i) \
((struct ifreq *)((char *)&(i)->ifr_addr \
+ MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
/*
* Scan through looking for an interface with an Internet
* address on the same subnet as `ipaddr'.
*/
ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) {
if (ifr->ifr_addr.sa_family != AF_INET)
continue;
strncpy(ifreq.ifr_name, ifr->ifr_name,
sizeof(ifreq.ifr_name));
ifreq.ifr_addr = ifr->ifr_addr;
/*
* Check that the interface is up,
* and not point-to-point or loopback.
*/
if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0)
continue;
if ((ifreq.ifr_flags &
(IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
IFF_LOOPBACK|IFF_NOARP))
!= (IFF_UP|IFF_BROADCAST))
continue;
/*
* Get its netmask and check that it's on
* the right subnet.
*/
if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0)
continue;
mask = ((struct sockaddr_in *)
&ifreq.ifr_addr)->sin_addr.s_addr;
ina = ((struct sockaddr_in *)
&ifr->ifr_addr)->sin_addr.s_addr;
if ((ipaddr & mask) == (ina & mask))
break; /* ok, we got it! */
}
if (ifr >= ifend)
goto done;
/*
* Now scan through again looking for a link-level address
* for this interface.
*/
ifp = ifr;
for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr))
if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 &&
ifr->ifr_addr.sa_family == AF_LINK)
break;
if (ifr >= ifend)
goto done;
/*
* Found the link-level address - copy it out
*/
dla = (struct sockaddr_dl *) &ifr->ifr_addr;
memcpy(hwaddr, LLADDR(dla), dla->sdl_alen);
printf("using interface %s for proxy with address ",
ifp->ifr_name);
printf("%s\n", ether_ntoa(hwaddr));
retval = dla->sdl_alen;
done:
close(sock);
return (retval);
}

149
tools/compat/if_nameindex.c Normal file
View File

@ -0,0 +1,149 @@
/* $KAME: if_nameindex.c,v 1.8 2000/11/24 08:20:01 itojun Exp $ */
/*-
* Copyright (c) 1997, 2000
* Berkeley Software Design, Inc. 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.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
*
* BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
*/
#include <sys/cdefs.h>
#ifndef FSTACK
__FBSDID("$FreeBSD$");
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
/*
* From RFC 2553:
*
* 4.3 Return All Interface Names and Indexes
*
* The if_nameindex structure holds the information about a single
* interface and is defined as a result of including the <net/if.h>
* header.
*
* struct if_nameindex {
* unsigned int if_index;
* char *if_name;
* };
*
* The final function returns an array of if_nameindex structures, one
* structure per interface.
*
* struct if_nameindex *if_nameindex(void);
*
* The end of the array of structures is indicated by a structure with
* an if_index of 0 and an if_name of NULL. The function returns a NULL
* pointer upon an error, and would set errno to the appropriate value.
*
* The memory used for this array of structures along with the interface
* names pointed to by the if_name members is obtained dynamically.
* This memory is freed by the next function.
*
* 4.4. Free Memory
*
* The following function frees the dynamic memory that was allocated by
* if_nameindex().
*
* #include <net/if.h>
*
* void if_freenameindex(struct if_nameindex *ptr);
*
* The argument to this function must be a pointer that was returned by
* if_nameindex().
*/
struct if_nameindex *
if_nameindex(void)
{
struct ifaddrs *ifaddrs, *ifa;
unsigned int ni;
int nbytes;
struct if_nameindex *ifni, *ifni2;
char *cp;
if (getifaddrs(&ifaddrs) < 0)
return(NULL);
/*
* First, find out how many interfaces there are, and how
* much space we need for the string names.
*/
ni = 0;
nbytes = 0;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK) {
nbytes += strlen(ifa->ifa_name) + 1;
ni++;
}
}
/*
* Next, allocate a chunk of memory, use the first part
* for the array of structures, and the last part for
* the strings.
*/
cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes);
ifni = (struct if_nameindex *)cp;
if (ifni == NULL)
goto out;
cp += (ni + 1) * sizeof(struct if_nameindex);
/*
* Now just loop through the list of interfaces again,
* filling in the if_nameindex array and making copies
* of all the strings.
*/
ifni2 = ifni;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK) {
ifni2->if_index =
LLINDEX((struct sockaddr_dl*)ifa->ifa_addr);
ifni2->if_name = cp;
strcpy(cp, ifa->ifa_name);
ifni2++;
cp += strlen(cp) + 1;
}
}
/*
* Finally, don't forget to terminate the array.
*/
ifni2->if_index = 0;
ifni2->if_name = NULL;
out:
freeifaddrs(ifaddrs);
return(ifni);
}
void
if_freenameindex(struct if_nameindex *ptr)
{
free(ptr);
}

View File

@ -0,0 +1,180 @@
/*-
* Copyright (c) 1998, Larry Lile
* All rights reserved.
*
* For latest sources and information on this driver, please
* go to http://anarchy.stdio.com.
*
* Questions, comments or suggestions should be directed to
* Larry Lile <lile@stdio.com>.
*
* 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 unmodified, 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*
* Information gathered from tokenring@freebsd, /sys/net/ethernet.h and
* the Mach token ring driver.
*/
/*
* Fundamental constants relating to iso 802.5
*/
#ifndef _NET_ISO88025_H_
#define _NET_ISO88025_H_
#ifdef FSTACK
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif
#endif
/*
* General ISO 802.5 definitions
*/
#define ISO88025_ADDR_LEN 6
#define ISO88025_CF_LEN 2
#define ISO88025_HDR_LEN (ISO88025_CF_LEN + (ISO88025_ADDR_LEN * 2))
#define RCF_LEN 2
#define RIF_MAX_RD 14
#define RIF_MAX_LEN 16
#define TR_AC 0x10
#define TR_LLC_FRAME 0x40
#define TR_4MBPS 4000000
#define TR_16MBPS 16000000
#define TR_100MBPS 100000000
/*
* Source routing
*/
#define TR_RII 0x80
#define TR_RCF_BCST_MASK 0xe000
#define TR_RCF_LEN_MASK 0x1f00
#define TR_RCF_DIR 0x0080
#define TR_RCF_LF_MASK 0x0070
#define TR_RCF_RIFLEN(x) ((ntohs(x) & TR_RCF_LEN_MASK) >> 8)
/*
* Minimum and maximum packet payload lengths.
*/
#define ISO88025_MIN_LEN 0
#define ISO88025_MAX_LEN_4 4464
#define ISO88025_MAX_LEN_16 17960
#define ISO88025_MAX_LEN ISO88025_MAX_LEN_16
/*
* A macro to validate a length with
*/
#define ISO88025_IS_VALID_LEN(foo) \
((foo) >= ISO88025_MIN_LEN && (foo) <= ISO88025_MAX_LEN)
/* Access Control field */
#define AC_PRI_MASK 0xe0 /* Priority bits */
#define AC_TOKEN 0x10 /* Token bit: 0=Token, 1=Frame */
#define AC_MONITOR 0x08 /* Monitor */
#define AC_RESV_MASK 0x07 /* Reservation bits */
/* Frame Control field */
#define FC_FT_MASK 0xc0 /* Frame Type */
#define FC_FT_MAC 0x00 /* MAC frame */
#define FC_FT_LLC 0x40 /* LLC frame */
#define FC_ATTN_MASK 0x0f /* Attention bits */
#define FC_ATTN_EB 0x01 /* Express buffer */
#define FC_ATTN_BE 0x02 /* Beacon */
#define FC_ATTN_CT 0x03 /* Claim token */
#define FC_ATTN_RP 0x04 /* Ring purge */
#define FC_ATTN_AMP 0x05 /* Active monitor present */
#define FC_ATTN_SMP 0x06 /* Standby monitor present */
/* Token Ring destination address */
#define DA_IG 0x80 /* Individual/group address. */
/* 0=Individual, 1=Group */
#define DA_UL 0x40 /* Universal/local address. */
/* 0=Universal, 1=Local */
/* Token Ring source address */
#define SA_RII 0x80 /* Routing information indicator */
#define SA_IG 0x40 /* Individual/group address */
/* 0=Group, 1=Individual */
/*
* ISO 802.5 physical header
*/
struct iso88025_header {
u_int8_t ac; /* access control field */
u_int8_t fc; /* frame control field */
u_int8_t iso88025_dhost[ISO88025_ADDR_LEN]; /* destination address */
u_int8_t iso88025_shost[ISO88025_ADDR_LEN]; /* source address */
u_int16_t rcf; /* route control field */
u_int16_t rd[RIF_MAX_RD]; /* routing designators */
} __packed;
struct iso88025_rif {
u_int16_t rcf; /* route control field */
u_int16_t rd[RIF_MAX_RD]; /* routing designators */
} __packed;
struct iso88025_sockaddr_data {
u_char ether_dhost[ISO88025_ADDR_LEN];
u_char ether_shost[ISO88025_ADDR_LEN];
u_char ac;
u_char fc;
};
struct iso88025_sockaddr_dl_data {
u_short trld_rcf;
u_short *trld_route[RIF_MAX_LEN];
};
#define ISO88025_MAX(a, b) (((a)>(b))?(a):(b))
#define SDL_ISO88025(s) ((struct iso88025_sockaddr_dl_data *) \
((s)->sdl_data + \
ISO88025_MAX((s)->sdl_nlen + (s)->sdl_alen + \
(s)->sdl_slen, 12)))
/*
* Structure of a 48-bit iso 802.5 address.
* ( We could also add the 16 bit addresses as a union)
*/
struct iso88025_addr {
u_char octet[ISO88025_ADDR_LEN];
};
#define ISO88025_MAX_MTU 18000
#define ISO88025_DEFAULT_MTU 1500
#define ISO88025_BPF_UNSUPPORTED 0
#define ISO88025_BPF_SUPPORTED 1
#ifdef _KERNEL
void iso88025_ifattach (struct ifnet *, const u_int8_t *, int);
void iso88025_ifdetach (struct ifnet *, int);
int iso88025_ioctl (struct ifnet *, u_long, caddr_t );
int iso88025_output (struct ifnet *, struct mbuf *,
const struct sockaddr *, struct route *);
void iso88025_input (struct ifnet *, struct mbuf *);
#endif /* _KERNEL */
#endif /* !_NET_ISO88025_H_ */

View File

@ -93,7 +93,16 @@ typedef __uint32_t uint32_t;
#define _PATH_SERVICES "/etc/services"
#define _PATH_SERVICES_DB "/var/db/services.db"
#ifndef FSTACK
#define h_errno (*__h_errno())
#else
/* Error status for non-reentrant lookup functions.
We use a macro to access always the thread-specific `h_errno' variable. */
# define h_errno (*__h_errno_location ())
/* Function to get address of global `h_errno' variable. */
extern int *__h_errno_location (void) __THROW __attribute__ ((__const__));
#endif
/*
* Structures returned by network data base library. All addresses are
@ -250,5 +259,8 @@ struct hostent *gethostbyaddr(const void *addr,
socklen_t len, int type);
struct hostent *gethostbyname2(const char *name, int af);
struct hostent *gethostbyname(const char *name);
const char *hstrerror(int err);
#endif /* !_NETDB_H_ */

View File

@ -149,3 +149,4 @@ ioctl_va(int fd, unsigned long com, void *data, int argc, ...)
return ret;
}

139
tools/compat/rtioctl.c Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2017 THL A29 Limited, a Tencent company.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*
*/
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include "rtioctl.h"
#include "ff_ipc.h"
int rt_shutdown_rd = 0;
int rt_sofib = 0;
int
rt_socket(int domain, int type, int protocol)
{
if (domain != PF_ROUTE || type != SOCK_RAW) {
errno = EINVAL;
return -1;
}
return 0;
}
int
rt_shutdown(int fd, int how)
{
if (how == SHUT_RD) {
rt_shutdown_rd = 1;
}
return 0;
}
int
rt_setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen)
{
if (level == SOL_SOCKET && optname == SO_SETFIB) {
rt_sofib = *(int *)optval;
}
return 0;
}
void
rt_close(int fd)
{
return;
}
int
rtioctl(char *data, unsigned len, unsigned read_len)
{
struct ff_msg *msg, *retmsg = NULL;
unsigned maxlen;
msg = ff_ipc_msg_alloc();
if (msg == NULL) {
errno = ENOMEM;
return -1;
}
if (len > msg->buf_len) {
errno = EINVAL;
ff_ipc_msg_free(msg);
return -1;
}
if (read_len > msg->buf_len) {
read_len = msg->buf_len;
}
maxlen = read_len ? read_len : len;
msg->msg_type = FF_ROUTE;
msg->route.fib = rt_sofib;
msg->route.len = len;
msg->route.maxlen = maxlen;
msg->route.data = msg->buf_addr;
memcpy(msg->route.data, data, len);
msg->buf_addr += len;
int ret = ff_ipc_send(msg);
if (ret < 0) {
errno = EPIPE;
ff_ipc_msg_free(msg);
return -1;
}
do {
if (retmsg != NULL) {
ff_ipc_msg_free(retmsg);
}
ret = ff_ipc_recv(&retmsg);
if (ret < 0) {
errno = EPIPE;
ff_ipc_msg_free(msg);
return -1;
}
} while (msg != retmsg);
if (retmsg->result == 0) {
ret = retmsg->route.len;
if (!rt_shutdown_rd && read_len > 0) {
memcpy(data, retmsg->route.data, retmsg->route.len);
}
} else {
ret = -1;
errno = retmsg->result;
}
ff_ipc_msg_free(msg);
return ret;
}

41
tools/compat/rtioctl.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2017 THL A29 Limited, a Tencent company.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 RTIOCTL_H
#define RTIOCTL_H
extern int rt_shutdown_rd;
extern int rt_sofib;
int rtioctl(char *data, unsigned len, unsigned read_len);
int rt_socket(int domain, int type, int protocol);
int rt_shutdown(int fd, int how);
int rt_setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
void rt_close(int fd);
#endif

View File

@ -426,7 +426,9 @@ main(int argc, char *argv[])
struct option *p;
size_t iflen;
#ifdef FSTACK
ff_ipc_init();
#endif
all = downonly = uponly = namesonly = noload = verbose = 0;
f_inet = f_inet6 = f_ether = f_addr = NULL;

View File

@ -646,7 +646,9 @@ main(int ac, char *av[])
* If the last argument is an absolute pathname, interpret it
* as a file to be preprocessed.
*/
#ifdef FSTACK
ff_ipc_init();
#endif
if (ac > 1 && av[ac - 1][0] == '/') {
if (access(av[ac - 1], R_OK) == 0)
ipfw_readfile(ac, av);

View File

@ -247,7 +247,9 @@ main(int argc, char *argv[])
char *endptr;
bool first = true;
#ifdef FSTACK
ff_ipc_init();
#endif
af = AF_UNSPEC;

View File

@ -74,104 +74,13 @@ __FBSDID("$FreeBSD$");
#include <ifaddrs.h>
#ifdef FSTACK
#include "rtioctl.h"
#include "compat.h"
#include "ff_ipc.h"
static int shutdown_rd;
static int sofib;
static int
fake_socket(int domain, int type, int protocol)
{
return 0;
}
static int
fake_shutdown(int fd, int how)
{
if (how == SHUT_RD) {
shutdown_rd = 1;
}
return 0;
}
static int
fake_setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen)
{
return 0;
}
static int
rtioctl(char *data, unsigned len, unsigned read_len)
{
struct ff_msg *msg, *retmsg = NULL;
unsigned maxlen;
msg = ff_ipc_msg_alloc();
if (msg == NULL) {
errno = ENOMEM;
return -1;
}
if (len > msg->buf_len) {
errno = EINVAL;
ff_ipc_msg_free(msg);
return -1;
}
if (read_len > msg->buf_len) {
read_len = msg->buf_len;
}
maxlen = read_len ? read_len : len;
msg->msg_type = FF_ROUTE;
msg->route.fib = sofib;
msg->route.len = len;
msg->route.maxlen = maxlen;
msg->route.data = msg->buf_addr;
memcpy(msg->route.data, data, len);
msg->buf_addr += len;
int ret = ff_ipc_send(msg);
if (ret < 0) {
errno = EPIPE;
ff_ipc_msg_free(msg);
return -1;
}
do {
if (retmsg != NULL) {
ff_ipc_msg_free(retmsg);
}
ret = ff_ipc_recv(&retmsg);
if (ret < 0) {
errno = EPIPE;
ff_ipc_msg_free(msg);
return -1;
}
} while (msg != retmsg);
if (retmsg->result == 0) {
ret = retmsg->route.len;
if (!shutdown_rd && read_len > 0) {
memcpy(data, retmsg->route.data, retmsg->route.len);
}
} else {
ret = -1;
errno = retmsg->result;
}
ff_ipc_msg_free(msg);
return ret;
}
#define socket(a, b, c) fake_socket((a), (b), (c))
#define shutdown(a, b) fake_shutdown((a), (b))
#define setsockopt(a, b, c, d, e) fake_setsockopt((a), (b), (c), (d), (e))
#define socket(a, b, c) rt_socket((a), (b), (c))
#define shutdown(a, b) rt_shutdown((a), (b))
#define setsockopt(a, b, c, d, e) rt_setsockopt((a), (b), (c), (d), (e))
#define write(a, b, c) rtioctl((b), (c), (0))
@ -281,11 +190,10 @@ main(int argc, char **argv)
if (argc < 2)
usage(NULL);
ff_ipc_init();
#ifndef FSTACK
while ((ch = getopt(argc, argv, "46nqdtv")) != -1)
#else
ff_ipc_init();
while ((ch = getopt(argc, argv, "46nqdtvp:")) != -1)
#endif
switch(ch) {
@ -389,7 +297,8 @@ set_sofib(int fib)
if (fib < 0)
return (0);
#ifdef FSTACK
sofib = fib;
return (rt_setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib,
sizeof(fib)));
#endif
return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib,
sizeof(fib)));

View File

@ -241,7 +241,9 @@ main(int argc, char **argv)
int ch;
int warncount = 0;
#ifdef FSTACK
ff_ipc_init();
#endif
setlocale(LC_NUMERIC, "");
setbuf(stdout,0);