2017-11-20 19:49:47 +00:00
|
|
|
/*-
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*
|
1994-05-26 05:23:31 +00:00
|
|
|
* 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.
|
2017-02-28 23:42:47 +00:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1994-05-26 05:23:31 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2003-05-03 21:06:42 +00:00
|
|
|
#if 0
|
1994-05-26 05:23:31 +00:00
|
|
|
#ifndef lint
|
1996-02-08 21:05:52 +00:00
|
|
|
static char const copyright[] =
|
1994-05-26 05:23:31 +00:00
|
|
|
"@(#) Copyright (c) 1984, 1993\n\
|
|
|
|
The Regents of the University of California. All rights reserved.\n";
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#ifndef lint
|
1996-02-08 21:05:52 +00:00
|
|
|
static char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94";
|
1994-05-26 05:23:31 +00:00
|
|
|
#endif /* not lint */
|
2003-05-03 21:06:42 +00:00
|
|
|
#endif
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* arp - display, set, and delete arp table entries
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/socket.h>
|
1996-02-08 21:05:52 +00:00
|
|
|
#include <sys/sockio.h>
|
1994-05-26 05:23:31 +00:00
|
|
|
#include <sys/sysctl.h>
|
1996-02-08 21:05:52 +00:00
|
|
|
#include <sys/ioctl.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
#include <sys/time.h>
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/if_ether.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2002-12-27 10:09:04 +00:00
|
|
|
#include <ctype.h>
|
1997-09-03 06:32:31 +00:00
|
|
|
#include <err.h>
|
1994-05-26 05:23:31 +00:00
|
|
|
#include <errno.h>
|
1997-09-03 06:32:31 +00:00
|
|
|
#include <netdb.h>
|
1994-05-26 05:23:31 +00:00
|
|
|
#include <nlist.h>
|
1997-09-03 06:32:31 +00:00
|
|
|
#include <paths.h>
|
2023-04-25 11:24:42 +00:00
|
|
|
#include <stdbool.h>
|
1994-05-26 05:23:31 +00:00
|
|
|
#include <stdio.h>
|
1996-02-08 21:05:52 +00:00
|
|
|
#include <stdlib.h>
|
2002-04-01 21:13:17 +00:00
|
|
|
#include <string.h>
|
1996-02-08 21:05:52 +00:00
|
|
|
#include <strings.h>
|
1997-09-03 06:32:31 +00:00
|
|
|
#include <unistd.h>
|
2022-07-05 03:56:29 +00:00
|
|
|
#include <ifaddrs.h>
|
2017-04-06 22:50:28 +00:00
|
|
|
#include <libxo/xo.h>
|
2023-04-25 11:24:42 +00:00
|
|
|
#include "arp.h"
|
1994-05-26 05:23:31 +00:00
|
|
|
|
2017-02-08 20:21:29 +00:00
|
|
|
typedef void (action_fn)(struct sockaddr_dl *sdl, struct sockaddr_in *s_in,
|
|
|
|
struct rt_msghdr *rtm);
|
2023-04-25 11:24:42 +00:00
|
|
|
static void nuke_entries(uint32_t ifindex, struct in_addr addr);
|
|
|
|
static int print_entries(uint32_t ifindex, struct in_addr addr);
|
2004-04-13 08:34:52 +00:00
|
|
|
|
2013-01-31 08:55:21 +00:00
|
|
|
static int delete(char *host);
|
2004-04-13 08:34:52 +00:00
|
|
|
static void usage(void);
|
|
|
|
static int set(int argc, char **argv);
|
2005-06-09 15:27:46 +00:00
|
|
|
static int get(char *host);
|
2004-04-13 08:34:52 +00:00
|
|
|
static int file(char *name);
|
2004-04-13 14:16:37 +00:00
|
|
|
static struct rt_msghdr *rtmsg(int cmd,
|
2013-01-31 08:55:21 +00:00
|
|
|
struct sockaddr_in *dst, struct sockaddr_dl *sdl);
|
2005-06-09 15:27:46 +00:00
|
|
|
static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
|
2023-04-25 11:24:42 +00:00
|
|
|
static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m,
|
|
|
|
char *host);
|
2004-04-13 08:34:52 +00:00
|
|
|
|
2003-07-18 13:48:06 +00:00
|
|
|
static char *rifname;
|
1994-05-26 05:23:31 +00:00
|
|
|
|
2014-04-05 22:13:32 +00:00
|
|
|
struct if_nameindex *ifnameindex;
|
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
struct arp_opts opts = {};
|
|
|
|
|
1997-11-13 01:16:57 +00:00
|
|
|
/* 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); }
|
|
|
|
|
2017-04-06 22:50:28 +00:00
|
|
|
#define ARP_XO_VERSION "1"
|
|
|
|
|
1996-02-08 21:05:52 +00:00
|
|
|
int
|
2001-06-07 12:35:53 +00:00
|
|
|
main(int argc, char *argv[])
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
1997-11-13 01:16:57 +00:00
|
|
|
int ch, func = 0;
|
|
|
|
int rtn = 0;
|
1994-05-26 05:23:31 +00:00
|
|
|
|
2017-04-06 22:50:28 +00:00
|
|
|
argc = xo_parse_args(argc, argv);
|
|
|
|
if (argc < 0)
|
|
|
|
exit(1);
|
|
|
|
|
2003-07-18 13:48:06 +00:00
|
|
|
while ((ch = getopt(argc, argv, "andfsSi:")) != -1)
|
2009-08-14 18:18:51 +00:00
|
|
|
switch(ch) {
|
1994-05-26 05:23:31 +00:00
|
|
|
case 'a':
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.aflag = true;
|
1997-11-13 01:16:57 +00:00
|
|
|
break;
|
1994-05-26 05:23:31 +00:00
|
|
|
case 'd':
|
1997-11-13 01:16:57 +00:00
|
|
|
SETFUNC(F_DELETE);
|
|
|
|
break;
|
1994-05-26 05:23:31 +00:00
|
|
|
case 'n':
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.nflag = true;
|
1997-11-13 01:16:57 +00:00
|
|
|
break;
|
1996-02-08 21:05:52 +00:00
|
|
|
case 'S':
|
1997-11-13 01:16:57 +00:00
|
|
|
SETFUNC(F_REPLACE);
|
|
|
|
break;
|
1994-05-26 05:23:31 +00:00
|
|
|
case 's':
|
1997-11-13 01:16:57 +00:00
|
|
|
SETFUNC(F_SET);
|
|
|
|
break;
|
1995-08-03 03:56:48 +00:00
|
|
|
case 'f' :
|
1997-11-13 01:16:57 +00:00
|
|
|
SETFUNC(F_FILESET);
|
|
|
|
break;
|
2003-07-18 13:48:06 +00:00
|
|
|
case 'i':
|
|
|
|
rifname = optarg;
|
|
|
|
break;
|
1994-05-26 05:23:31 +00:00
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
1997-11-13 01:16:57 +00:00
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
|
|
|
if (!func)
|
|
|
|
func = F_GET;
|
2003-07-18 13:48:06 +00:00
|
|
|
if (rifname) {
|
2023-04-25 11:24:42 +00:00
|
|
|
if (func != F_GET && !(func == F_DELETE && opts.aflag))
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_errx(1, "-i not applicable to this operation");
|
2003-07-18 13:48:06 +00:00
|
|
|
if (if_nametoindex(rifname) == 0) {
|
|
|
|
if (errno == ENXIO)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_errx(1, "interface %s does not exist",
|
|
|
|
rifname);
|
2003-07-18 13:48:06 +00:00
|
|
|
else
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "if_nametoindex(%s)", rifname);
|
2003-07-18 13:48:06 +00:00
|
|
|
}
|
|
|
|
}
|
1997-11-13 01:16:57 +00:00
|
|
|
switch (func) {
|
|
|
|
case F_GET:
|
2023-04-25 11:24:42 +00:00
|
|
|
if (opts.aflag) {
|
1997-11-13 01:16:57 +00:00
|
|
|
if (argc != 0)
|
|
|
|
usage();
|
2017-04-06 22:50:28 +00:00
|
|
|
|
|
|
|
xo_set_version(ARP_XO_VERSION);
|
|
|
|
xo_open_container("arp");
|
|
|
|
xo_open_list("arp-cache");
|
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
struct in_addr all_addrs = {};
|
|
|
|
print_entries(0, all_addrs);
|
2017-04-06 22:50:28 +00:00
|
|
|
|
|
|
|
xo_close_list("arp-cache");
|
|
|
|
xo_close_container("arp");
|
|
|
|
xo_finish();
|
1997-11-13 01:16:57 +00:00
|
|
|
} else {
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
2005-06-09 15:27:46 +00:00
|
|
|
rtn = get(argv[0]);
|
1997-11-13 01:16:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case F_SET:
|
|
|
|
case F_REPLACE:
|
2001-06-07 12:35:53 +00:00
|
|
|
if (argc < 2 || argc > 6)
|
1997-11-13 01:16:57 +00:00
|
|
|
usage();
|
|
|
|
if (func == F_REPLACE)
|
2013-01-31 08:55:21 +00:00
|
|
|
(void)delete(argv[0]);
|
1997-11-13 01:16:57 +00:00
|
|
|
rtn = set(argc, argv) ? 1 : 0;
|
|
|
|
break;
|
|
|
|
case F_DELETE:
|
2023-04-25 11:24:42 +00:00
|
|
|
if (opts.aflag) {
|
1997-11-13 01:16:57 +00:00
|
|
|
if (argc != 0)
|
|
|
|
usage();
|
2023-04-25 11:24:42 +00:00
|
|
|
struct in_addr all_addrs = {};
|
|
|
|
nuke_entries(0, all_addrs);
|
2013-09-23 18:12:25 +00:00
|
|
|
} else {
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
2013-01-31 08:55:21 +00:00
|
|
|
rtn = delete(argv[0]);
|
2013-09-23 18:12:25 +00:00
|
|
|
}
|
1997-11-13 01:16:57 +00:00
|
|
|
break;
|
|
|
|
case F_FILESET:
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
|
|
|
rtn = file(argv[0]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-04-05 22:13:32 +00:00
|
|
|
if (ifnameindex != NULL)
|
|
|
|
if_freenameindex(ifnameindex);
|
|
|
|
|
2005-06-09 15:27:46 +00:00
|
|
|
return (rtn);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process a file to set standard arp entries
|
|
|
|
*/
|
2004-04-13 08:34:52 +00:00
|
|
|
static int
|
1996-02-08 21:05:52 +00:00
|
|
|
file(char *name)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
int i, retval;
|
2003-01-17 08:10:43 +00:00
|
|
|
char line[100], arg[5][50], *args[5], *p;
|
1994-05-26 05:23:31 +00:00
|
|
|
|
1997-09-03 06:32:31 +00:00
|
|
|
if ((fp = fopen(name, "r")) == NULL)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "cannot open %s", name);
|
1994-05-26 05:23:31 +00:00
|
|
|
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;
|
2007-03-06 09:32:41 +00:00
|
|
|
while(fgets(line, sizeof(line), fp) != NULL) {
|
2003-01-17 08:10:43 +00:00
|
|
|
if ((p = strchr(line, '#')) != NULL)
|
|
|
|
*p = '\0';
|
|
|
|
for (p = line; isblank(*p); p++);
|
2003-03-05 15:53:18 +00:00
|
|
|
if (*p == '\n' || *p == '\0')
|
2002-12-27 10:09:04 +00:00
|
|
|
continue;
|
2003-01-17 08:10:43 +00:00
|
|
|
i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1],
|
2000-01-17 01:44:16 +00:00
|
|
|
arg[2], arg[3], arg[4]);
|
1994-05-26 05:23:31 +00:00
|
|
|
if (i < 2) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("bad line: %s", line);
|
1994-05-26 05:23:31 +00:00
|
|
|
retval = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (set(i, args))
|
|
|
|
retval = 1;
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
return (retval);
|
|
|
|
}
|
|
|
|
|
2004-04-13 14:16:37 +00:00
|
|
|
/*
|
2013-01-31 08:55:21 +00:00
|
|
|
* Given a hostname, fills up a (static) struct sockaddr_in with
|
2004-04-13 14:16:37 +00:00
|
|
|
* the address of the host and returns a pointer to the
|
|
|
|
* structure.
|
|
|
|
*/
|
2023-04-25 11:24:42 +00:00
|
|
|
struct sockaddr_in *
|
2004-04-13 14:16:37 +00:00
|
|
|
getaddr(char *host)
|
|
|
|
{
|
|
|
|
struct hostent *hp;
|
2013-01-31 08:55:21 +00:00
|
|
|
static struct sockaddr_in reply;
|
2004-04-13 14:16:37 +00:00
|
|
|
|
|
|
|
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) {
|
|
|
|
if (!(hp = gethostbyname(host))) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("%s: %s", host, hstrerror(h_errno));
|
2005-06-09 15:27:46 +00:00
|
|
|
return (NULL);
|
2004-04-13 14:16:37 +00:00
|
|
|
}
|
|
|
|
bcopy((char *)hp->h_addr, (char *)&reply.sin_addr,
|
|
|
|
sizeof reply.sin_addr);
|
|
|
|
}
|
2005-06-09 15:27:46 +00:00
|
|
|
return (&reply);
|
2004-04-13 14:16:37 +00:00
|
|
|
}
|
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
int valid_type(int type);
|
2004-04-13 14:16:37 +00:00
|
|
|
/*
|
2005-06-09 15:27:46 +00:00
|
|
|
* Returns true if the type is a valid one for ARP.
|
2004-04-13 14:16:37 +00:00
|
|
|
*/
|
2023-04-25 11:24:42 +00:00
|
|
|
int
|
2004-04-13 14:16:37 +00:00
|
|
|
valid_type(int type)
|
|
|
|
{
|
2005-06-09 15:27:46 +00:00
|
|
|
|
2004-04-13 14:16:37 +00:00
|
|
|
switch (type) {
|
|
|
|
case IFT_ETHER:
|
|
|
|
case IFT_FDDI:
|
2021-04-12 06:27:03 +00:00
|
|
|
case IFT_IEEE1394:
|
2015-04-02 18:18:40 +00:00
|
|
|
case IFT_INFINIBAND:
|
2004-04-13 14:16:37 +00:00
|
|
|
case IFT_ISO88023:
|
|
|
|
case IFT_ISO88024:
|
|
|
|
case IFT_L2VLAN:
|
2005-11-03 00:56:43 +00:00
|
|
|
case IFT_BRIDGE:
|
2005-06-09 15:27:46 +00:00
|
|
|
return (1);
|
|
|
|
default:
|
|
|
|
return (0);
|
2004-04-13 14:16:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1994-05-26 05:23:31 +00:00
|
|
|
/*
|
1995-05-30 03:57:47 +00:00
|
|
|
* Set an individual arp entry
|
1994-05-26 05:23:31 +00:00
|
|
|
*/
|
2004-04-13 14:16:37 +00:00
|
|
|
static int
|
1996-02-08 21:05:52 +00:00
|
|
|
set(int argc, char **argv)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
2013-01-31 08:55:21 +00:00
|
|
|
struct sockaddr_in *dst; /* what are we looking for */
|
2002-04-06 09:01:44 +00:00
|
|
|
struct ether_addr *ea;
|
1994-05-26 05:23:31 +00:00
|
|
|
char *host = argv[0], *eaddr = argv[1];
|
2005-06-09 15:27:46 +00:00
|
|
|
struct sockaddr_dl sdl_m;
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
argc -= 2;
|
|
|
|
argv += 2;
|
2004-04-13 08:34:52 +00:00
|
|
|
|
|
|
|
bzero(&sdl_m, sizeof(sdl_m));
|
|
|
|
sdl_m.sdl_len = sizeof(sdl_m);
|
|
|
|
sdl_m.sdl_family = AF_LINK;
|
|
|
|
|
2004-04-13 14:16:37 +00:00
|
|
|
dst = getaddr(host);
|
|
|
|
if (dst == NULL)
|
|
|
|
return (1);
|
1994-05-26 05:23:31 +00:00
|
|
|
while (argc-- > 0) {
|
2017-02-09 19:58:12 +00:00
|
|
|
if (strcmp(argv[0], "temp") == 0) {
|
2010-11-30 16:14:19 +00:00
|
|
|
int max_age;
|
|
|
|
size_t len = sizeof(max_age);
|
|
|
|
|
|
|
|
if (sysctlbyname("net.link.ether.inet.max_age",
|
|
|
|
&max_age, &len, NULL, 0) != 0)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "sysctlbyname");
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.expire_time = max_age;
|
2017-02-09 19:58:12 +00:00
|
|
|
} else if (strcmp(argv[0], "pub") == 0) {
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.flags |= RTF_ANNOUNCE;
|
2017-02-09 19:58:12 +00:00
|
|
|
if (argc && strcmp(argv[1], "only") == 0) {
|
2013-01-31 08:55:21 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2001-06-07 12:35:53 +00:00
|
|
|
argc--; argv++;
|
|
|
|
}
|
2017-02-09 19:58:12 +00:00
|
|
|
} else if (strcmp(argv[0], "blackhole") == 0) {
|
2023-04-25 11:24:42 +00:00
|
|
|
if (opts.flags & RTF_REJECT) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_errx(1, "Choose one of blackhole or reject, "
|
2017-02-08 20:21:29 +00:00
|
|
|
"not both.");
|
2008-12-25 06:44:19 +00:00
|
|
|
}
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.flags |= RTF_BLACKHOLE;
|
2017-02-09 19:58:12 +00:00
|
|
|
} else if (strcmp(argv[0], "reject") == 0) {
|
2023-04-25 11:24:42 +00:00
|
|
|
if (opts.flags & RTF_BLACKHOLE) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_errx(1, "Choose one of blackhole or reject, "
|
2017-02-08 20:21:29 +00:00
|
|
|
"not both.");
|
2008-12-25 06:44:19 +00:00
|
|
|
}
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.flags |= RTF_REJECT;
|
2017-02-09 19:58:12 +00:00
|
|
|
} else {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("Invalid parameter '%s'", argv[0]);
|
2017-02-09 19:58:12 +00:00
|
|
|
usage();
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
|
|
|
argv++;
|
|
|
|
}
|
2002-04-06 09:01:44 +00:00
|
|
|
ea = (struct ether_addr *)LLADDR(&sdl_m);
|
2023-04-25 11:24:42 +00:00
|
|
|
if ((opts.flags & RTF_ANNOUNCE) && !strcmp(eaddr, "auto")) {
|
2004-04-13 14:16:37 +00:00
|
|
|
if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("no interface found for %s",
|
2004-04-13 14:16:37 +00:00
|
|
|
inet_ntoa(dst->sin_addr));
|
1996-02-08 21:05:52 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2002-04-06 09:01:44 +00:00
|
|
|
sdl_m.sdl_alen = ETHER_ADDR_LEN;
|
1996-02-08 21:05:52 +00:00
|
|
|
} else {
|
2004-04-13 14:16:37 +00:00
|
|
|
struct ether_addr *ea1 = ether_aton(eaddr);
|
|
|
|
|
2006-02-09 12:49:39 +00:00
|
|
|
if (ea1 == NULL) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("invalid Ethernet address '%s'", eaddr);
|
2006-02-09 12:49:39 +00:00
|
|
|
return (1);
|
|
|
|
} else {
|
2004-04-13 14:16:37 +00:00
|
|
|
*ea = *ea1;
|
2002-04-06 09:01:44 +00:00
|
|
|
sdl_m.sdl_alen = ETHER_ADDR_LEN;
|
2004-04-13 14:16:37 +00:00
|
|
|
}
|
1996-02-08 21:05:52 +00:00
|
|
|
}
|
2023-04-25 11:24:42 +00:00
|
|
|
#ifndef WITHOUT_NETLINK
|
|
|
|
return (set_nl(0, dst, &sdl_m, host));
|
|
|
|
#else
|
|
|
|
return (set_rtsock(dst, &sdl_m, host));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITHOUT_NETLINK
|
|
|
|
static int
|
|
|
|
set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m, char *host)
|
|
|
|
{
|
|
|
|
struct sockaddr_in *addr;
|
|
|
|
struct sockaddr_dl *sdl;
|
|
|
|
struct rt_msghdr *rtm;
|
2009-12-30 21:35:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* In the case a proxy-arp entry is being added for
|
2017-02-08 20:21:29 +00:00
|
|
|
* a remote end point, the RTF_ANNOUNCE flag in the
|
2009-12-30 21:35:34 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2017-04-16 19:17:10 +00:00
|
|
|
rtm = rtmsg(RTM_GET, dst, NULL);
|
2009-12-30 21:35:34 +00:00
|
|
|
if (rtm == NULL) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warn("%s", host);
|
2009-12-30 21:35:34 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2013-01-31 08:55:21 +00:00
|
|
|
addr = (struct sockaddr_in *)(rtm + 1);
|
2009-12-30 21:35:34 +00:00
|
|
|
sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
|
2004-04-13 14:16:37 +00:00
|
|
|
|
2009-12-30 21:35:34 +00:00
|
|
|
if ((sdl->sdl_family != AF_LINK) ||
|
|
|
|
(rtm->rtm_flags & RTF_GATEWAY) ||
|
|
|
|
!valid_type(sdl->sdl_type)) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("cannot intuit interface index and type for %s", host);
|
1994-05-26 05:23:31 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2023-04-25 11:24:42 +00:00
|
|
|
sdl_m->sdl_type = sdl->sdl_type;
|
|
|
|
sdl_m->sdl_index = sdl->sdl_index;
|
|
|
|
return (rtmsg(RTM_ADD, dst, sdl_m) == NULL);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
2023-04-25 11:24:42 +00:00
|
|
|
#endif
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Display an individual arp entry
|
|
|
|
*/
|
2005-06-09 15:27:46 +00:00
|
|
|
static int
|
1996-02-08 21:05:52 +00:00
|
|
|
get(char *host)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
2013-01-31 08:55:21 +00:00
|
|
|
struct sockaddr_in *addr;
|
2017-04-06 22:50:28 +00:00
|
|
|
int found;
|
2004-04-13 14:16:37 +00:00
|
|
|
|
|
|
|
addr = getaddr(host);
|
|
|
|
if (addr == NULL)
|
2005-06-09 15:27:46 +00:00
|
|
|
return (1);
|
2017-04-06 22:50:28 +00:00
|
|
|
|
|
|
|
xo_set_version(ARP_XO_VERSION);
|
|
|
|
xo_open_container("arp");
|
|
|
|
xo_open_list("arp-cache");
|
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
found = print_entries(0, addr->sin_addr);
|
2017-04-06 22:50:28 +00:00
|
|
|
|
|
|
|
if (found == 0) {
|
|
|
|
xo_emit("{d:hostname/%s} ({d:ip-address/%s}) -- no entry",
|
2001-12-10 06:42:56 +00:00
|
|
|
host, inet_ntoa(addr->sin_addr));
|
2003-07-18 13:48:06 +00:00
|
|
|
if (rifname)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" on {d:interface/%s}", rifname);
|
|
|
|
xo_emit("\n");
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
2017-04-06 22:50:28 +00:00
|
|
|
|
|
|
|
xo_close_list("arp-cache");
|
|
|
|
xo_close_container("arp");
|
|
|
|
xo_finish();
|
|
|
|
|
|
|
|
return (found == 0);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-05-30 03:57:47 +00:00
|
|
|
* Delete an arp entry
|
1994-05-26 05:23:31 +00:00
|
|
|
*/
|
2023-04-25 11:24:42 +00:00
|
|
|
#ifdef WITHOUT_NETLINK
|
2004-04-13 08:34:52 +00:00
|
|
|
static int
|
2023-04-25 11:24:42 +00:00
|
|
|
delete_rtsock(char *host)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
2013-01-31 08:55:21 +00:00
|
|
|
struct sockaddr_in *addr, *dst;
|
2004-04-13 08:34:52 +00:00
|
|
|
struct rt_msghdr *rtm;
|
1994-05-26 05:23:31 +00:00
|
|
|
struct sockaddr_dl *sdl;
|
|
|
|
|
2004-04-13 14:16:37 +00:00
|
|
|
dst = getaddr(host);
|
|
|
|
if (dst == NULL)
|
2005-06-09 15:27:46 +00:00
|
|
|
return (1);
|
2009-12-30 21:35:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform a regular entry delete first.
|
|
|
|
*/
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.flags &= ~RTF_ANNOUNCE;
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
|
2004-04-13 14:16:37 +00:00
|
|
|
for (;;) { /* try twice */
|
2017-04-16 19:17:10 +00:00
|
|
|
rtm = rtmsg(RTM_GET, dst, NULL);
|
2004-04-13 14:16:37 +00:00
|
|
|
if (rtm == NULL) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warn("%s", host);
|
1994-05-26 05:23:31 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2013-01-31 08:55:21 +00:00
|
|
|
addr = (struct sockaddr_in *)(rtm + 1);
|
2004-04-13 14:16:37 +00:00
|
|
|
sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
|
|
|
|
/*
|
2017-02-08 20:21:29 +00:00
|
|
|
* With the new L2/L3 restructure, the route
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
* 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 &&
|
2004-04-13 14:16:37 +00:00
|
|
|
!(rtm->rtm_flags & RTF_GATEWAY) &&
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
valid_type(sdl->sdl_type) ) {
|
|
|
|
addr->sin_addr.s_addr = dst->sin_addr.s_addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-30 21:35:34 +00:00
|
|
|
/*
|
2017-04-16 19:17:10 +00:00
|
|
|
* Regular entry delete failed, now check if there
|
2009-12-30 21:35:34 +00:00
|
|
|
* is a proxy-arp entry to remove.
|
|
|
|
*/
|
2023-04-25 11:24:42 +00:00
|
|
|
if (opts.flags & RTF_ANNOUNCE) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warnx("delete: cannot locate %s", host);
|
2004-04-13 14:16:37 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2009-12-30 21:35:34 +00:00
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.flags |= RTF_ANNOUNCE;
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
2008-12-26 19:45:24 +00:00
|
|
|
rtm->rtm_flags |= RTF_LLDATA;
|
2004-04-13 14:16:37 +00:00
|
|
|
if (rtmsg(RTM_DELETE, dst, NULL) != NULL) {
|
2001-12-10 06:42:56 +00:00
|
|
|
printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
|
1996-02-08 21:05:52 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
return (1);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
2023-04-25 11:24:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
|
|
|
delete(char *host)
|
|
|
|
{
|
|
|
|
#ifdef WITHOUT_NETLINK
|
|
|
|
return (delete_rtsock(host));
|
|
|
|
#else
|
|
|
|
return (delete_nl(0, host));
|
|
|
|
#endif
|
|
|
|
}
|
1994-05-26 05:23:31 +00:00
|
|
|
|
2009-12-30 21:35:34 +00:00
|
|
|
|
1994-05-26 05:23:31 +00:00
|
|
|
/*
|
1997-11-13 01:16:57 +00:00
|
|
|
* Search the arp table and do some action on matching entries
|
1994-05-26 05:23:31 +00:00
|
|
|
*/
|
2004-04-13 08:34:52 +00:00
|
|
|
static int
|
|
|
|
search(u_long addr, action_fn *action)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
|
|
|
int mib[6];
|
|
|
|
size_t needed;
|
2009-12-29 15:48:04 +00:00
|
|
|
char *lim, *buf, *next;
|
1994-05-26 05:23:31 +00:00
|
|
|
struct rt_msghdr *rtm;
|
2013-01-31 08:55:21 +00:00
|
|
|
struct sockaddr_in *sin2;
|
1994-05-26 05:23:31 +00:00
|
|
|
struct sockaddr_dl *sdl;
|
2003-07-18 13:48:06 +00:00
|
|
|
char ifname[IF_NAMESIZE];
|
2005-01-24 13:27:24 +00:00
|
|
|
int st, found_entry = 0;
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
mib[0] = CTL_NET;
|
|
|
|
mib[1] = PF_ROUTE;
|
|
|
|
mib[2] = 0;
|
|
|
|
mib[3] = AF_INET;
|
|
|
|
mib[4] = NET_RT_FLAGS;
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
#ifdef RTF_LLINFO
|
1994-05-26 05:23:31 +00:00
|
|
|
mib[5] = RTF_LLINFO;
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
#else
|
|
|
|
mib[5] = 0;
|
2017-02-08 20:21:29 +00:00
|
|
|
#endif
|
1994-05-26 05:23:31 +00:00
|
|
|
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "route-sysctl-estimate");
|
2004-04-13 14:16:37 +00:00
|
|
|
if (needed == 0) /* empty table */
|
2004-04-13 08:34:52 +00:00
|
|
|
return 0;
|
2005-01-24 13:27:24 +00:00
|
|
|
buf = NULL;
|
2005-01-24 17:01:48 +00:00
|
|
|
for (;;) {
|
2009-12-29 15:48:04 +00:00
|
|
|
buf = reallocf(buf, needed);
|
|
|
|
if (buf == NULL)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_errx(1, "could not reallocate memory");
|
2005-01-24 13:27:24 +00:00
|
|
|
st = sysctl(mib, 6, buf, &needed, NULL, 0);
|
2005-01-24 17:01:48 +00:00
|
|
|
if (st == 0 || errno != ENOMEM)
|
|
|
|
break;
|
|
|
|
needed += needed / 8;
|
|
|
|
}
|
2005-01-24 13:27:24 +00:00
|
|
|
if (st == -1)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "actual retrieval of routing table");
|
1994-05-26 05:23:31 +00:00
|
|
|
lim = buf + needed;
|
|
|
|
for (next = buf; next < lim; next += rtm->rtm_msglen) {
|
|
|
|
rtm = (struct rt_msghdr *)next;
|
2013-01-31 08:55:21 +00:00
|
|
|
sin2 = (struct sockaddr_in *)(rtm + 1);
|
2004-06-08 13:08:19 +00:00
|
|
|
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
|
2003-07-18 13:48:06 +00:00
|
|
|
if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
|
|
|
|
strcmp(ifname, rifname))
|
|
|
|
continue;
|
1994-05-26 05:23:31 +00:00
|
|
|
if (addr) {
|
2001-12-10 06:42:56 +00:00
|
|
|
if (addr != sin2->sin_addr.s_addr)
|
1994-05-26 05:23:31 +00:00
|
|
|
continue;
|
|
|
|
found_entry = 1;
|
|
|
|
}
|
2001-12-10 06:42:56 +00:00
|
|
|
(*action)(sdl, sin2, rtm);
|
1997-11-13 01:16:57 +00:00
|
|
|
}
|
2001-05-02 19:07:46 +00:00
|
|
|
free(buf);
|
2005-06-09 15:27:46 +00:00
|
|
|
return (found_entry);
|
1997-11-13 01:16:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display an arp entry
|
|
|
|
*/
|
2010-06-11 19:35:05 +00:00
|
|
|
|
2004-04-13 08:34:52 +00:00
|
|
|
static void
|
1997-11-13 01:16:57 +00:00
|
|
|
print_entry(struct sockaddr_dl *sdl,
|
2013-01-31 08:55:21 +00:00
|
|
|
struct sockaddr_in *addr, struct rt_msghdr *rtm)
|
1997-11-13 01:16:57 +00:00
|
|
|
{
|
2001-06-07 12:35:53 +00:00
|
|
|
const char *host;
|
1997-11-13 01:16:57 +00:00
|
|
|
struct hostent *hp;
|
2014-04-05 22:13:32 +00:00
|
|
|
struct if_nameindex *p;
|
1997-11-13 01:16:57 +00:00
|
|
|
|
2017-02-08 20:21:29 +00:00
|
|
|
if (ifnameindex == NULL)
|
2014-04-05 22:13:32 +00:00
|
|
|
if ((ifnameindex = if_nameindex()) == NULL)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "cannot retrieve interface names");
|
|
|
|
|
|
|
|
xo_open_instance("arp-cache");
|
2014-04-05 22:13:32 +00:00
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
if (!opts.nflag)
|
2001-12-10 06:42:56 +00:00
|
|
|
hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
|
|
|
|
sizeof addr->sin_addr, AF_INET);
|
1997-11-13 01:16:57 +00:00
|
|
|
else
|
|
|
|
hp = 0;
|
|
|
|
if (hp)
|
|
|
|
host = hp->h_name;
|
|
|
|
else {
|
|
|
|
host = "?";
|
|
|
|
if (h_errno == TRY_AGAIN)
|
2023-04-25 11:24:42 +00:00
|
|
|
opts.nflag = true;
|
1997-11-13 01:16:57 +00:00
|
|
|
}
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host,
|
|
|
|
inet_ntoa(addr->sin_addr));
|
2004-06-13 10:57:10 +00:00
|
|
|
if (sdl->sdl_alen) {
|
2004-12-24 22:16:38 +00:00
|
|
|
if ((sdl->sdl_type == IFT_ETHER ||
|
2005-11-03 00:56:43 +00:00
|
|
|
sdl->sdl_type == IFT_L2VLAN ||
|
|
|
|
sdl->sdl_type == IFT_BRIDGE) &&
|
2004-06-13 10:57:10 +00:00
|
|
|
sdl->sdl_alen == ETHER_ADDR_LEN)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{:mac-address/%s}",
|
2017-02-08 20:21:29 +00:00
|
|
|
ether_ntoa((struct ether_addr *)LLADDR(sdl)));
|
2004-06-13 10:57:10 +00:00
|
|
|
else {
|
|
|
|
int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
|
|
|
|
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{:mac-address/%s}", link_ntoa(sdl) + n);
|
2004-06-13 10:57:10 +00:00
|
|
|
}
|
|
|
|
} else
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{d:/(incomplete)}{en:incomplete/true}");
|
2014-04-05 22:13:32 +00:00
|
|
|
|
2020-01-09 11:58:26 +00:00
|
|
|
for (p = ifnameindex; p && p->if_index && p->if_name; p++) {
|
2014-04-05 22:13:32 +00:00
|
|
|
if (p->if_index == sdl->sdl_index) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" on {:interface/%s}", p->if_name);
|
2014-04-05 22:13:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-13 01:16:57 +00:00
|
|
|
if (rtm->rtm_rmx.rmx_expire == 0)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{d:/ permanent}{en:permanent/true}");
|
2010-02-15 14:29:17 +00:00
|
|
|
else {
|
2010-11-30 15:57:00 +00:00
|
|
|
static struct timespec tp;
|
2023-04-25 11:24:42 +00:00
|
|
|
time_t expire_time = 0;
|
|
|
|
|
2010-11-30 15:57:00 +00:00
|
|
|
if (tp.tv_sec == 0)
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tp);
|
|
|
|
if ((expire_time = rtm->rtm_rmx.rmx_expire - tp.tv_sec) > 0)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" expires in {:expires/%d} seconds",
|
|
|
|
(int)expire_time);
|
2010-02-15 14:29:17 +00:00
|
|
|
else
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{d:/ expired}{en:expired/true}");
|
2010-02-15 14:29:17 +00:00
|
|
|
}
|
2017-04-06 22:50:28 +00:00
|
|
|
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
if (rtm->rtm_flags & RTF_ANNOUNCE)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("{d:/ published}{en:published/true}");
|
|
|
|
|
This main goals of this project are:
1. separating L2 tables (ARP, NDP) from the L3 routing tables
2. removing as much locking dependencies among these layers as
possible to allow for some parallelism in the search operations
3. simplify the logic in the routing code,
The most notable end result is the obsolescent of the route
cloning (RTF_CLONING) concept, which translated into code reduction
in both IPv4 ARP and IPv6 NDP related modules, and size reduction in
struct rtentry{}. The change in design obsoletes the semantics of
RTF_CLONING, RTF_WASCLONE and RTF_LLINFO routing flags. The userland
applications such as "arp" and "ndp" have been modified to reflect
those changes. The output from "netstat -r" shows only the routing
entries.
Quite a few developers have contributed to this project in the
past: Glebius Smirnoff, Luigi Rizzo, Alessandro Cerri, and
Andre Oppermann. And most recently:
- Kip Macy revised the locking code completely, thus completing
the last piece of the puzzle, Kip has also been conducting
active functional testing
- Sam Leffler has helped me improving/refactoring the code, and
provided valuable reviews
- Julian Elischer setup the perforce tree for me and has helped
me maintaining that branch before the svn conversion
2008-12-15 06:10:57 +00:00
|
|
|
switch(sdl->sdl_type) {
|
2004-04-13 08:34:52 +00:00
|
|
|
case IFT_ETHER:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/ethernet}]");
|
2017-02-08 20:21:29 +00:00
|
|
|
break;
|
2004-04-13 08:34:52 +00:00
|
|
|
case IFT_FDDI:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/fddi}]");
|
2017-02-08 20:21:29 +00:00
|
|
|
break;
|
2004-04-13 08:34:52 +00:00
|
|
|
case IFT_ATM:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/atm}]");
|
2017-02-08 20:21:29 +00:00
|
|
|
break;
|
2004-04-13 08:34:52 +00:00
|
|
|
case IFT_L2VLAN:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/vlan}]");
|
2001-04-04 15:14:06 +00:00
|
|
|
break;
|
2004-06-13 10:57:10 +00:00
|
|
|
case IFT_IEEE1394:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/firewire}]");
|
2017-02-08 20:21:29 +00:00
|
|
|
break;
|
2005-11-03 00:56:43 +00:00
|
|
|
case IFT_BRIDGE:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/bridge}]");
|
2015-04-02 18:18:40 +00:00
|
|
|
break;
|
|
|
|
case IFT_INFINIBAND:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit(" [{:type/infiniband}]");
|
2005-11-03 00:56:43 +00:00
|
|
|
break;
|
2004-04-13 08:34:52 +00:00
|
|
|
default:
|
2002-04-07 12:05:05 +00:00
|
|
|
break;
|
2017-02-08 20:21:29 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_emit("\n");
|
1999-03-10 10:11:43 +00:00
|
|
|
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_close_instance("arp-cache");
|
1997-11-13 01:16:57 +00:00
|
|
|
}
|
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
static int
|
|
|
|
print_entries(uint32_t ifindex, struct in_addr addr)
|
|
|
|
{
|
|
|
|
#ifndef WITHOUT_NETLINK
|
|
|
|
return (print_entries_nl(ifindex, addr));
|
|
|
|
#else
|
|
|
|
return (search(addr.s_addr, print_entry));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-11-13 01:16:57 +00:00
|
|
|
/*
|
|
|
|
* Nuke an arp entry
|
|
|
|
*/
|
2004-04-13 08:34:52 +00:00
|
|
|
static void
|
2001-12-10 06:42:56 +00:00
|
|
|
nuke_entry(struct sockaddr_dl *sdl __unused,
|
2015-09-27 04:54:29 +00:00
|
|
|
struct sockaddr_in *addr, struct rt_msghdr *rtm)
|
1997-11-13 01:16:57 +00:00
|
|
|
{
|
|
|
|
char ip[20];
|
|
|
|
|
2015-09-27 04:54:29 +00:00
|
|
|
if (rtm->rtm_flags & RTF_PINNED)
|
|
|
|
return;
|
|
|
|
|
2001-12-10 06:42:56 +00:00
|
|
|
snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
|
2013-01-31 08:55:21 +00:00
|
|
|
delete(ip);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
|
|
|
|
2023-04-25 11:24:42 +00:00
|
|
|
static void
|
|
|
|
nuke_entries(uint32_t ifindex, struct in_addr addr)
|
|
|
|
{
|
|
|
|
search(addr.s_addr, nuke_entry);
|
|
|
|
}
|
|
|
|
|
2004-04-13 08:34:52 +00:00
|
|
|
static void
|
1996-02-08 21:05:52 +00:00
|
|
|
usage(void)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
1997-11-13 01:16:57 +00:00
|
|
|
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
2017-02-08 20:21:29 +00:00
|
|
|
"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");
|
1994-05-26 05:23:31 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2004-04-13 08:34:52 +00:00
|
|
|
static struct rt_msghdr *
|
2013-01-31 08:55:21 +00:00
|
|
|
rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl)
|
1994-05-26 05:23:31 +00:00
|
|
|
{
|
|
|
|
static int seq;
|
|
|
|
int rlen;
|
2004-04-13 08:34:52 +00:00
|
|
|
int l;
|
|
|
|
static int s = -1;
|
|
|
|
static pid_t pid;
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
struct rt_msghdr m_rtm;
|
|
|
|
char m_space[512];
|
|
|
|
} m_rtmsg;
|
|
|
|
|
2004-04-09 14:27:28 +00:00
|
|
|
struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
|
|
|
|
char *cp = m_rtmsg.m_space;
|
2004-04-13 08:34:52 +00:00
|
|
|
|
|
|
|
if (s < 0) { /* first time: open socket, get pid */
|
|
|
|
s = socket(PF_ROUTE, SOCK_RAW, 0);
|
|
|
|
if (s < 0)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_err(1, "socket");
|
2004-04-13 08:34:52 +00:00
|
|
|
pid = getpid();
|
|
|
|
}
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
errno = 0;
|
2004-04-13 14:16:37 +00:00
|
|
|
/*
|
|
|
|
* XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
|
|
|
|
* appropriately.
|
|
|
|
*/
|
1994-05-26 05:23:31 +00:00
|
|
|
if (cmd == RTM_DELETE)
|
|
|
|
goto doit;
|
|
|
|
bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
|
2023-04-25 11:24:42 +00:00
|
|
|
rtm->rtm_flags = opts.flags;
|
1994-05-26 05:23:31 +00:00
|
|
|
rtm->rtm_version = RTM_VERSION;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
default:
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_errx(1, "internal wrong cmd");
|
1994-05-26 05:23:31 +00:00
|
|
|
case RTM_ADD:
|
|
|
|
rtm->rtm_addrs |= RTA_GATEWAY;
|
2023-04-25 11:24:42 +00:00
|
|
|
if (opts.expire_time != 0) {
|
|
|
|
struct timespec tp;
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tp);
|
|
|
|
rtm->rtm_rmx.rmx_expire = opts.expire_time + tp.tv_sec;
|
|
|
|
}
|
1994-05-26 05:23:31 +00:00
|
|
|
rtm->rtm_inits = RTV_EXPIRE;
|
2008-12-26 19:45:24 +00:00
|
|
|
rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
|
1994-05-26 05:23:31 +00:00
|
|
|
/* FALLTHROUGH */
|
|
|
|
case RTM_GET:
|
|
|
|
rtm->rtm_addrs |= RTA_DST;
|
|
|
|
}
|
2017-02-08 20:21:29 +00:00
|
|
|
#define NEXTADDR(w, s) \
|
|
|
|
do { \
|
|
|
|
if ((s) != NULL && rtm->rtm_addrs & (w)) { \
|
|
|
|
bcopy((s), cp, sizeof(*(s))); \
|
|
|
|
cp += SA_SIZE(s); \
|
|
|
|
} \
|
2009-06-11 07:50:36 +00:00
|
|
|
} while (0)
|
1994-05-26 05:23:31 +00:00
|
|
|
|
2004-04-13 14:16:37 +00:00
|
|
|
NEXTADDR(RTA_DST, dst);
|
|
|
|
NEXTADDR(RTA_GATEWAY, sdl);
|
1994-05-26 05:23:31 +00:00
|
|
|
|
|
|
|
rtm->rtm_msglen = cp - (char *)&m_rtmsg;
|
|
|
|
doit:
|
|
|
|
l = rtm->rtm_msglen;
|
|
|
|
rtm->rtm_seq = ++seq;
|
|
|
|
rtm->rtm_type = cmd;
|
|
|
|
if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
|
|
|
|
if (errno != ESRCH || cmd != RTM_DELETE) {
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warn("writing to routing socket");
|
2005-06-09 15:27:46 +00:00
|
|
|
return (NULL);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
|
2017-04-16 19:17:10 +00:00
|
|
|
} while (l > 0 && (rtm->rtm_type != cmd || rtm->rtm_seq != seq ||
|
|
|
|
rtm->rtm_pid != pid));
|
1994-05-26 05:23:31 +00:00
|
|
|
if (l < 0)
|
2017-04-06 22:50:28 +00:00
|
|
|
xo_warn("read from routing socket");
|
2005-06-09 15:27:46 +00:00
|
|
|
return (rtm);
|
1994-05-26 05:23:31 +00:00
|
|
|
}
|
|
|
|
|
1996-02-08 21:05:52 +00:00
|
|
|
/*
|
|
|
|
* get_ether_addr - get the hardware address of an interface on the
|
|
|
|
* the same subnet as ipaddr.
|
|
|
|
*/
|
2004-04-13 08:34:52 +00:00
|
|
|
static int
|
2005-06-09 15:27:46 +00:00
|
|
|
get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
|
1996-02-08 21:05:52 +00:00
|
|
|
{
|
2022-07-05 03:56:29 +00:00
|
|
|
struct ifaddrs *ifa, *ifd, *ifas = NULL;
|
2005-06-09 15:27:46 +00:00
|
|
|
in_addr_t ina, mask;
|
1996-02-08 21:05:52 +00:00
|
|
|
struct sockaddr_dl *dla;
|
2004-04-13 14:16:37 +00:00
|
|
|
int retval = 0;
|
1996-02-08 21:05:52 +00:00
|
|
|
|
|
|
|
/*
|
2004-04-13 14:16:37 +00:00
|
|
|
* Scan through looking for an interface with an Internet
|
|
|
|
* address on the same subnet as `ipaddr'.
|
|
|
|
*/
|
2022-07-05 03:56:29 +00:00
|
|
|
if (getifaddrs(&ifas) < 0) {
|
|
|
|
xo_warnx("getifaddrs");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
|
|
|
|
if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL)
|
|
|
|
continue;
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
2004-04-13 14:16:37 +00:00
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Check that the interface is up,
|
|
|
|
* and not point-to-point or loopback.
|
|
|
|
*/
|
2022-07-05 03:56:29 +00:00
|
|
|
if ((ifa->ifa_flags &
|
2017-02-08 20:21:29 +00:00
|
|
|
(IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
|
|
|
|
IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST))
|
2004-04-13 14:16:37 +00:00
|
|
|
continue;
|
2017-02-08 20:21:29 +00:00
|
|
|
/* Get its netmask and check that it's on the right subnet. */
|
2004-04-13 14:16:37 +00:00
|
|
|
mask = ((struct sockaddr_in *)
|
2022-07-05 03:56:29 +00:00
|
|
|
ifa->ifa_netmask)->sin_addr.s_addr;
|
2004-04-13 14:16:37 +00:00
|
|
|
ina = ((struct sockaddr_in *)
|
2022-07-05 03:56:29 +00:00
|
|
|
ifa->ifa_addr)->sin_addr.s_addr;
|
2004-04-13 14:16:37 +00:00
|
|
|
if ((ipaddr & mask) == (ina & mask))
|
|
|
|
break; /* ok, we got it! */
|
1996-02-08 21:05:52 +00:00
|
|
|
}
|
2022-07-05 03:56:29 +00:00
|
|
|
if (ifa == NULL)
|
2004-04-13 14:16:37 +00:00
|
|
|
goto done;
|
1996-02-08 21:05:52 +00:00
|
|
|
|
|
|
|
/*
|
2004-04-13 14:16:37 +00:00
|
|
|
* Now scan through again looking for a link-level address
|
|
|
|
* for this interface.
|
|
|
|
*/
|
2022-07-05 03:56:29 +00:00
|
|
|
for (ifd = ifas; ifd != NULL; ifd = ifd->ifa_next) {
|
|
|
|
if (ifd->ifa_addr == NULL)
|
|
|
|
continue;
|
|
|
|
if (strcmp(ifa->ifa_name, ifd->ifa_name) == 0 &&
|
|
|
|
ifd->ifa_addr->sa_family == AF_LINK)
|
2004-04-13 14:16:37 +00:00
|
|
|
break;
|
2022-07-05 03:56:29 +00:00
|
|
|
}
|
|
|
|
if (ifd == NULL)
|
2004-04-13 14:16:37 +00:00
|
|
|
goto done;
|
|
|
|
/*
|
|
|
|
* Found the link-level address - copy it out
|
|
|
|
*/
|
2022-07-05 03:56:29 +00:00
|
|
|
dla = (struct sockaddr_dl *)ifd->ifa_addr;
|
2004-04-13 14:16:37 +00:00
|
|
|
memcpy(hwaddr, LLADDR(dla), dla->sdl_alen);
|
2022-07-05 03:56:29 +00:00
|
|
|
printf("using interface %s for proxy with address %s\n", ifa->ifa_name,
|
2017-02-09 19:58:12 +00:00
|
|
|
ether_ntoa(hwaddr));
|
2004-04-13 14:16:37 +00:00
|
|
|
retval = dla->sdl_alen;
|
|
|
|
done:
|
2022-07-05 03:56:29 +00:00
|
|
|
if (ifas != NULL)
|
|
|
|
freeifaddrs(ifas);
|
2005-06-09 15:27:46 +00:00
|
|
|
return (retval);
|
1996-02-08 21:05:52 +00:00
|
|
|
}
|