summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/atm/atmconfig/Makefile19
-rw-r--r--sbin/atm/atmconfig/main.c16
-rw-r--r--sbin/camcontrol/camcontrol.86
-rw-r--r--sbin/camcontrol/camcontrol.c36
-rw-r--r--sbin/conscontrol/conscontrol.81
-rw-r--r--sbin/devd/Makefile6
-rw-r--r--sbin/devd/devd.821
-rw-r--r--sbin/devd/devd.cc83
-rw-r--r--sbin/devd/tests/Makefile12
-rw-r--r--sbin/devd/tests/client_test.c198
-rw-r--r--sbin/dhclient/packet.c11
-rw-r--r--sbin/dhclient/tests/Makefile1
-rw-r--r--sbin/dump/traverse.c7
-rw-r--r--sbin/dumpon/dumpon.816
-rw-r--r--sbin/fdisk_pc98/Makefile4
-rw-r--r--sbin/fsck/Makefile2
-rw-r--r--sbin/fsck_msdosfs/boot.c2
-rw-r--r--sbin/fsck_msdosfs/dosfs.h4
-rw-r--r--sbin/fsirand/Makefile2
-rw-r--r--sbin/gbde/gbde.820
-rw-r--r--sbin/gbde/gbde.c7
-rw-r--r--sbin/geom/class/part/gpart.835
-rw-r--r--sbin/geom/class/virstor/gvirstor.88
-rw-r--r--sbin/geom/core/geom.c5
-rw-r--r--sbin/hastd/Makefile2
-rw-r--r--sbin/hastd/primary.c3
-rw-r--r--sbin/hastd/synch.h23
-rw-r--r--sbin/ifconfig/Makefile5
-rw-r--r--sbin/ifconfig/af_inet6.c4
-rw-r--r--sbin/ifconfig/ifconfig.8129
-rw-r--r--sbin/ifconfig/ifconfig.c5
-rw-r--r--sbin/ifconfig/ifconfig.h3
-rw-r--r--sbin/ifconfig/ifgre.c61
-rw-r--r--sbin/ifconfig/iflagg.c80
-rw-r--r--sbin/ifconfig/ifvxlan.c648
-rw-r--r--sbin/ifconfig/sfp.c827
-rw-r--r--sbin/init/init.c2
-rw-r--r--sbin/ipf/Makefile.inc8
-rw-r--r--sbin/ipf/ipf/Makefile2
-rw-r--r--sbin/ipf/ipfstat/Makefile2
-rw-r--r--sbin/ipf/ipftest/Makefile2
-rw-r--r--sbin/ipf/ipmon/Makefile2
-rw-r--r--sbin/ipf/ipnat/Makefile2
-rw-r--r--sbin/ipf/ippool/Makefile2
-rw-r--r--sbin/ipf/ipresend/Makefile2
-rw-r--r--sbin/ipfw/Makefile2
-rw-r--r--sbin/ipfw/altq.c6
-rw-r--r--sbin/ipfw/dummynet.c41
-rw-r--r--sbin/ipfw/ipfw.8388
-rw-r--r--sbin/ipfw/ipfw2.c2232
-rw-r--r--sbin/ipfw/ipfw2.h69
-rw-r--r--sbin/ipfw/ipv6.c54
-rw-r--r--sbin/ipfw/main.c4
-rw-r--r--sbin/ipfw/nat.c357
-rw-r--r--sbin/ipfw/tables.c2012
-rw-r--r--sbin/iscontrol/iscontrol.811
-rw-r--r--sbin/mksnap_ffs/Makefile4
-rw-r--r--sbin/mount/mntopts.h6
-rw-r--r--sbin/mount/mount.88
-rw-r--r--sbin/mount/mount.c1
-rw-r--r--sbin/mount_nfs/Makefile1
-rw-r--r--sbin/mount_nfs/mount_nfs.849
-rw-r--r--sbin/mount_nfs/mount_nfs.c411
-rw-r--r--sbin/newfs_msdos/newfs_msdos.c2
-rw-r--r--sbin/ping/Makefile2
-rw-r--r--sbin/ping/ping.c87
-rw-r--r--sbin/ping6/Makefile4
-rw-r--r--sbin/ping6/ping6.817
-rw-r--r--sbin/ping6/ping6.c642
-rw-r--r--sbin/rcorder/Makefile2
-rw-r--r--sbin/reboot/boot_i386.810
-rw-r--r--sbin/restore/tape.c8
-rw-r--r--sbin/route/keywords1
-rw-r--r--sbin/route/route.83
-rw-r--r--sbin/route/route.c19
-rw-r--r--sbin/routed/defs.h1
-rw-r--r--sbin/routed/input.c15
-rw-r--r--sbin/routed/main.c6
-rw-r--r--sbin/routed/output.c2
-rw-r--r--sbin/routed/routed.818
-rw-r--r--sbin/savecore/savecore.c6
-rw-r--r--sbin/shutdown/Makefile2
-rw-r--r--sbin/swapon/swapon.c9
-rw-r--r--sbin/sysctl/sysctl.c329
-rw-r--r--sbin/umount/umount.c2
85 files changed, 7091 insertions, 2088 deletions
diff --git a/sbin/atm/atmconfig/Makefile b/sbin/atm/atmconfig/Makefile
index 3e42d3f..ccf74d7 100644
--- a/sbin/atm/atmconfig/Makefile
+++ b/sbin/atm/atmconfig/Makefile
@@ -8,29 +8,24 @@
.include <src.opts.mk>
PROG= atmconfig
-.ifndef RESCUE
-SRCS= oid.h
-.endif
-SRCS+= main.c diag.c natm.c
-.ifndef RESCUE
-SRCS+= atmconfig_device.c
-.endif
+SRCS= main.c diag.c natm.c
MAN= atmconfig.8
# CFLAGS+= -DPATH_HELP='".:/usr/share/doc/atm:/usr/local/share/doc/atm"'
CFLAGS+= -I.
-.ifndef RESCUE
-DPADD= ${LIBBSNMP}
-LDADD= -lbsnmp
+.if !defined(RESCUE) && ${MK_BSNMP} != "no"
+CFLAGS+= -DWITH_BSNMP
+SRCS+= oid.h atmconfig_device.c
+DPADD+= ${LIBBSNMP}
+LDADD+= -lbsnmp
. if ${MK_DYNAMICROOT} == "no" && ${MK_OPENSSL} != "no"
+DPADD+= ${LIBCRYPTO}
LDADD+= -lcrypto
. endif
.endif
-.ifndef RESCUE
CLEANFILES+= oid.h
-.endif
# XXX - this is verboten
.if ${MACHINE_CPUARCH} == "arm"
diff --git a/sbin/atm/atmconfig/main.c b/sbin/atm/atmconfig/main.c
index 73e1fac..1374218 100644
--- a/sbin/atm/atmconfig/main.c
+++ b/sbin/atm/atmconfig/main.c
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$");
#include <stdint.h>
#include <fnmatch.h>
#include <dirent.h>
-#ifndef RESCUE
+#ifdef WITH_BSNMP
#include <bsnmp/asn1.h>
#include <bsnmp/snmp.h>
#include <bsnmp/snmpclient.h>
@@ -444,7 +444,7 @@ help_func(int argc, char *argv[])
exit(1);
}
-#ifndef RESCUE
+#ifdef WITH_BSNMP
/*
* Parse a server specification
*
@@ -527,16 +527,16 @@ main(int argc, char *argv[])
int opt, i;
const struct cmdtab *match, *cc, *tab;
-#ifndef RESCUE
+#ifdef WITH_BSNMP
snmp_client_init(&snmp_client);
snmp_client.trans = SNMP_TRANS_LOC_STREAM;
snmp_client_set_host(&snmp_client, PATH_ILMI_SOCK);
#endif
-#ifdef RESCUE
-#define OPTSTR "htv"
-#else
+#ifdef WITH_BSNMP
#define OPTSTR "htvs:"
+#else
+#define OPTSTR "htv"
#endif
while ((opt = getopt(argc, argv, OPTSTR)) != -1)
@@ -545,7 +545,7 @@ main(int argc, char *argv[])
case 'h':
help_func(0, argv);
-#ifndef RESCUE
+#ifdef WITH_BSNMP
case 's':
parse_server(optarg);
break;
@@ -570,7 +570,7 @@ main(int argc, char *argv[])
err(1, NULL);
memcpy(main_tab, static_main_tab, sizeof(static_main_tab));
-#ifndef RESCUE
+#ifdef WITH_BSNMP
/* XXX while this is compiled in */
device_register();
#endif
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 0c42564..0fc7c1a 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 20, 2013
+.Dd August 31, 2014
.Dt CAMCONTROL 8
.Os
.Sh NAME
@@ -1884,12 +1884,12 @@ camcontrol security ada0
.Pp
Report security support and settings for ada0
.Bd -literal -offset indent
-camcontrol security ada0 -u user -s MyPass
+camcontrol security ada0 -U user -s MyPass
.Ed
.Pp
Enable security on device ada0 with the password MyPass
.Bd -literal -offset indent
-camcontrol security ada0 -u user -e MyPass
+camcontrol security ada0 -U user -e MyPass
.Ed
.Pp
Secure erase ada0 which has had security enabled with user password MyPass
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 12a0e5c..cdb379d 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -4469,9 +4469,9 @@ tagcontrol(struct cam_device *device, int argc, char **argv,
fprintf(stdout, "%s", pathstr);
fprintf(stdout, "dev_active %d\n", ccb->cgds.dev_active);
fprintf(stdout, "%s", pathstr);
- fprintf(stdout, "devq_openings %d\n", ccb->cgds.devq_openings);
+ fprintf(stdout, "allocated %d\n", ccb->cgds.allocated);
fprintf(stdout, "%s", pathstr);
- fprintf(stdout, "devq_queued %d\n", ccb->cgds.devq_queued);
+ fprintf(stdout, "queued %d\n", ccb->cgds.queued);
fprintf(stdout, "%s", pathstr);
fprintf(stdout, "held %d\n", ccb->cgds.held);
fprintf(stdout, "%s", pathstr);
@@ -5827,15 +5827,31 @@ scsisanitize(struct cam_device *device, int argc, char **argv,
if (arglist & CAM_ARG_ERR_RECOVER)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
- if (((retval = cam_send_ccb(device, ccb)) < 0)
- || ((immediate == 0)
- && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP))) {
- const char errstr[] = "error sending sanitize command";
+ if (cam_send_ccb(device, ccb) < 0) {
+ warn("error sending sanitize command");
+ error = 1;
+ goto scsisanitize_bailout;
+ }
- if (retval < 0)
- warn(errstr);
- else
- warnx(errstr);
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ struct scsi_sense_data *sense;
+ int error_code, sense_key, asc, ascq;
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
+ CAM_SCSI_STATUS_ERROR) {
+ sense = &ccb->csio.sense_data;
+ scsi_extract_sense_len(sense, ccb->csio.sense_len -
+ ccb->csio.sense_resid, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+
+ if (sense_key == SSD_KEY_ILLEGAL_REQUEST &&
+ asc == 0x20 && ascq == 0x00)
+ warnx("sanitize is not supported by "
+ "this device");
+ else
+ warnx("error sanitizing this device");
+ } else
+ warnx("error sanitizing this device");
if (arglist & CAM_ARG_VERBOSE) {
cam_error_print(device, ccb, CAM_ESF_ALL,
diff --git a/sbin/conscontrol/conscontrol.8 b/sbin/conscontrol/conscontrol.8
index 3f34197..bbb4063 100644
--- a/sbin/conscontrol/conscontrol.8
+++ b/sbin/conscontrol/conscontrol.8
@@ -104,6 +104,7 @@ This is an interface to the tty ioctl
.Xr sio 4 ,
.Xr syscons 4 ,
.Xr tty 4 ,
+.Xr vt 4 ,
.Xr boot 8 ,
.Xr loader 8
.Sh HISTORY
diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile
index c53f094..518e5e2 100644
--- a/sbin/devd/Makefile
+++ b/sbin/devd/Makefile
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <src.opts.mk>
+
PROG_CXX=devd
SRCS= devd.cc token.l parse.y y.tab.h
MAN= devd.8 devd.conf.5
@@ -16,4 +18,8 @@ CFLAGS+=-I. -I${.CURDIR}
CLEANFILES= y.output
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/sbin/devd/devd.8 b/sbin/devd/devd.8
index fa34df2..12a92d9 100644
--- a/sbin/devd/devd.8
+++ b/sbin/devd/devd.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 30, 2013
+.Dd August 14, 2014
.Dt DEVD 8
.Os
.Sh NAME
@@ -55,9 +55,7 @@ If option
.Fl f
is specified more than once, the last file specified is used.
.It Fl l Ar num
-Limit concurrent
-.Pa /var/run/devd.pipe
-connections to
+Limit concurrent socket connections to
.Ar num .
The default connection limit is 10.
.It Fl n
@@ -130,22 +128,27 @@ wish to hook into the
system without modifying the user's other
config files.
.Pp
-All messages that
+Since
+.Xr devctl 4
+allows only one active reader,
.Nm
-receives are forwarded to the
+multiplexes it, forwarding all events to any number of connected clients.
+Clients connect by opening the SOCK_SEQPACKET
.Ux
domain socket at
-.Pa /var/run/devd.pipe .
+.Pa /var/run/devd.seqpacket.pipe .
.Sh FILES
-.Bl -tag -width ".Pa /var/run/devd.pipe" -compact
+.Bl -tag -width ".Pa /var/run/devd.seqpacket.pipe" -compact
.It Pa /etc/devd.conf
The default
.Nm
configuration file.
-.It Pa /var/run/devd.pipe
+.It Pa /var/run/devd.seqpacket.pipe
The socket used by
.Nm
to communicate with its clients.
+.It Pa /var/run/devd.pipe
+A deprecated socket retained for use with old clients.
.El
.Sh SEE ALSO
.Xr devctl 4 ,
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index ce2a4f3..c770204 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -100,7 +100,8 @@ __FBSDID("$FreeBSD$");
#include "devd.h" /* C compatible definitions */
#include "devd.hh" /* C++ class definitions */
-#define PIPE "/var/run/devd.pipe"
+#define STREAMPIPE "/var/run/devd.pipe"
+#define SEQPACKETPIPE "/var/run/devd.seqpacket.pipe"
#define CF "/etc/devd.conf"
#define SYSCTL "hw.bus.devctl_queue"
@@ -119,6 +120,11 @@ __FBSDID("$FreeBSD$");
using namespace std;
+typedef struct client {
+ int fd;
+ int socktype;
+} client_t;
+
extern FILE *yyin;
extern int lineno;
@@ -822,12 +828,12 @@ process_event(char *buffer)
}
int
-create_socket(const char *name)
+create_socket(const char *name, int socktype)
{
int fd, slen;
struct sockaddr_un sun;
- if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
+ if ((fd = socket(PF_LOCAL, socktype, 0)) < 0)
err(1, "socket");
bzero(&sun, sizeof(sun));
sun.sun_family = AF_UNIX;
@@ -846,12 +852,13 @@ create_socket(const char *name)
unsigned int max_clients = 10; /* Default, can be overriden on cmdline. */
unsigned int num_clients;
-list<int> clients;
+
+list<client_t> clients;
void
notify_clients(const char *data, int len)
{
- list<int>::iterator i;
+ list<client_t>::iterator i;
/*
* Deliver the data to all clients. Throw clients overboard at the
@@ -861,11 +868,17 @@ notify_clients(const char *data, int len)
* kernel memory or tie up the limited number of available connections).
*/
for (i = clients.begin(); i != clients.end(); ) {
- if (write(*i, data, len) != len) {
+ int flags;
+ if (i->socktype == SOCK_SEQPACKET)
+ flags = MSG_EOR;
+ else
+ flags = 0;
+
+ if (send(i->fd, data, len, flags) != len) {
--num_clients;
- close(*i);
+ close(i->fd);
i = clients.erase(i);
- devdlog(LOG_WARNING, "notify_clients: write() failed; "
+ devdlog(LOG_WARNING, "notify_clients: send() failed; "
"dropping unresponsive client\n");
} else
++i;
@@ -877,7 +890,7 @@ check_clients(void)
{
int s;
struct pollfd pfd;
- list<int>::iterator i;
+ list<client_t>::iterator i;
/*
* Check all existing clients to see if any of them have disappeared.
@@ -888,12 +901,12 @@ check_clients(void)
*/
pfd.events = 0;
for (i = clients.begin(); i != clients.end(); ) {
- pfd.fd = *i;
+ pfd.fd = i->fd;
s = poll(&pfd, 1, 0);
if ((s < 0 && s != EINTR ) ||
(s > 0 && (pfd.revents & POLLHUP))) {
--num_clients;
- close(*i);
+ close(i->fd);
i = clients.erase(i);
devdlog(LOG_NOTICE, "check_clients: "
"dropping disconnected client\n");
@@ -903,9 +916,9 @@ check_clients(void)
}
void
-new_client(int fd)
+new_client(int fd, int socktype)
{
- int s;
+ client_t s;
int sndbuf_size;
/*
@@ -914,13 +927,14 @@ new_client(int fd)
* by sending large buffers full of data we'll never read.
*/
check_clients();
- s = accept(fd, NULL, NULL);
- if (s != -1) {
+ s.socktype = socktype;
+ s.fd = accept(fd, NULL, NULL);
+ if (s.fd != -1) {
sndbuf_size = CLIENT_BUFSIZE;
- if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
+ if (setsockopt(s.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
sizeof(sndbuf_size)))
err(1, "setsockopt");
- shutdown(s, SHUT_RD);
+ shutdown(s.fd, SHUT_RD);
clients.push_back(s);
++num_clients;
} else
@@ -934,7 +948,7 @@ event_loop(void)
int fd;
char buffer[DEVCTL_MAXBUF];
int once = 0;
- int server_fd, max_fd;
+ int stream_fd, seqpacket_fd, max_fd;
int accepting;
timeval tv;
fd_set fds;
@@ -942,9 +956,10 @@ event_loop(void)
fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC);
if (fd == -1)
err(1, "Can't open devctl device %s", PATH_DEVCTL);
- server_fd = create_socket(PIPE);
+ stream_fd = create_socket(STREAMPIPE, SOCK_STREAM);
+ seqpacket_fd = create_socket(SEQPACKETPIPE, SOCK_SEQPACKET);
accepting = 1;
- max_fd = max(fd, server_fd) + 1;
+ max_fd = max(fd, max(stream_fd, seqpacket_fd)) + 1;
while (!romeo_must_die) {
if (!once && !no_daemon && !daemonize_quick) {
// Check to see if we have any events pending.
@@ -965,24 +980,28 @@ event_loop(void)
}
/*
* When we've already got the max number of clients, stop
- * accepting new connections (don't put server_fd in the set),
- * shrink the accept() queue to reject connections quickly, and
- * poll the existing clients more often, so that we notice more
- * quickly when any of them disappear to free up client slots.
+ * accepting new connections (don't put the listening sockets in
+ * the set), shrink the accept() queue to reject connections
+ * quickly, and poll the existing clients more often, so that we
+ * notice more quickly when any of them disappear to free up
+ * client slots.
*/
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (num_clients < max_clients) {
if (!accepting) {
- listen(server_fd, max_clients);
+ listen(stream_fd, max_clients);
+ listen(seqpacket_fd, max_clients);
accepting = 1;
}
- FD_SET(server_fd, &fds);
+ FD_SET(stream_fd, &fds);
+ FD_SET(seqpacket_fd, &fds);
tv.tv_sec = 60;
tv.tv_usec = 0;
} else {
if (accepting) {
- listen(server_fd, 0);
+ listen(stream_fd, 0);
+ listen(seqpacket_fd, 0);
accepting = 0;
}
tv.tv_sec = 2;
@@ -1022,8 +1041,14 @@ event_loop(void)
break;
}
}
- if (FD_ISSET(server_fd, &fds))
- new_client(server_fd);
+ if (FD_ISSET(stream_fd, &fds))
+ new_client(stream_fd, SOCK_STREAM);
+ /*
+ * Aside from the socket type, both sockets use the same
+ * protocol, so we can process clients the same way.
+ */
+ if (FD_ISSET(seqpacket_fd, &fds))
+ new_client(seqpacket_fd, SOCK_SEQPACKET);
}
close(fd);
}
diff --git a/sbin/devd/tests/Makefile b/sbin/devd/tests/Makefile
new file mode 100644
index 0000000..ee679ce
--- /dev/null
+++ b/sbin/devd/tests/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sbin/devd
+
+ATF_TESTS_C= client_test
+TEST_METADATA.client_test= required_programs="devd"
+TEST_METADATA.client_test+= required_user="root"
+TEST_METADATA.client_test+= timeout=15
+
+WARNS?= 5
+
+.include <bsd.test.mk>
diff --git a/sbin/devd/tests/client_test.c b/sbin/devd/tests/client_test.c
new file mode 100644
index 0000000..dda9a89
--- /dev/null
+++ b/sbin/devd/tests/client_test.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2014 Spectra Logic Corporation. 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 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <atf-c.h>
+/* Helper functions*/
+
+/*
+ * Create two devd events. The easiest way I know of, that requires no special
+ * hardware, is to create md(4) devices.
+ */
+static void
+create_two_events(void)
+{
+ FILE *create_stdout;
+ FILE *destroy_stdout;
+ char mdname[80];
+ char destroy_cmd[80];
+ char *error;
+
+ create_stdout = popen("mdconfig -a -s 64 -t null", "r");
+ ATF_REQUIRE(create_stdout != NULL);
+ error = fgets(mdname, sizeof(mdname), create_stdout);
+ ATF_REQUIRE(error != NULL);
+ /* We only expect one line of output */
+ ATF_REQUIRE_EQ(0, pclose(create_stdout));
+
+ snprintf(destroy_cmd, nitems(destroy_cmd), "mdconfig -d -u %s", mdname);
+ destroy_stdout = popen(destroy_cmd, "r");
+ ATF_REQUIRE(destroy_stdout != NULL);
+ /* We expect no output */
+ ATF_REQUIRE_EQ(0, pclose(destroy_stdout));
+}
+
+/*
+ * Test Cases
+ */
+
+/*
+ * Open a client connection to devd, create some events, and test that they can
+ * be read _whole_ and _one_at_a_time_ from the socket
+ */
+ATF_TC_WITHOUT_HEAD(seqpacket);
+ATF_TC_BODY(seqpacket, tc)
+{
+ int s;
+ int error;
+ struct sockaddr_un devd_addr;
+ bool got_create_event = false;
+ bool got_destroy_event = false;
+ const char create_pat[] =
+ "!system=DEVFS subsystem=CDEV type=CREATE cdev=md";
+ const char destroy_pat[] =
+ "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md";
+
+ memset(&devd_addr, 0, sizeof(devd_addr));
+ devd_addr.sun_family = PF_LOCAL;
+ strlcpy(devd_addr.sun_path, "/var/run/devd.seqpacket.pipe",
+ sizeof(devd_addr.sun_path));
+
+ s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+ ATF_REQUIRE(s >= 0);
+ error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr));
+ ATF_REQUIRE_EQ(0, error);
+
+ create_two_events();
+
+ /*
+ * Loop until both events are detected on _different_ reads
+ * There may be extra events due to unrelated system activity
+ * If we never get both events, then the test will timeout.
+ */
+ while (!(got_create_event && got_destroy_event)) {
+ int cmp;
+ ssize_t len;
+ char event[1024];
+
+ /* Read 1 less than sizeof(event) to allow space for NULL */
+ len = recv(s, event, sizeof(event) - 1, MSG_WAITALL);
+ ATF_REQUIRE(len != -1);
+ /* NULL terminate the result */
+ event[len] = '\0';
+ printf("%s", event);
+ cmp = strncmp(event, create_pat, sizeof(create_pat) - 1);
+ if (cmp == 0)
+ got_create_event = true;
+
+ cmp = strncmp(event, destroy_pat, sizeof(destroy_pat) - 1);
+ if (cmp == 0)
+ got_destroy_event = true;
+ }
+
+ close(s);
+}
+
+/*
+ * Open a client connection to devd using the stream socket, create some
+ * events, and test that they can be read in any number of reads.
+ */
+ATF_TC_WITHOUT_HEAD(stream);
+ATF_TC_BODY(stream, tc)
+{
+ int s;
+ int error;
+ struct sockaddr_un devd_addr;
+ bool got_create_event = false;
+ bool got_destroy_event = false;
+ const char create_pat[] =
+ "!system=DEVFS subsystem=CDEV type=CREATE cdev=md";
+ const char destroy_pat[] =
+ "!system=DEVFS subsystem=CDEV type=DESTROY cdev=md";
+ ssize_t len = 0;
+
+ memset(&devd_addr, 0, sizeof(devd_addr));
+ devd_addr.sun_family = PF_LOCAL;
+ strlcpy(devd_addr.sun_path, "/var/run/devd.pipe",
+ sizeof(devd_addr.sun_path));
+
+ s = socket(PF_LOCAL, SOCK_STREAM, 0);
+ ATF_REQUIRE(s >= 0);
+ error = connect(s, (struct sockaddr*)&devd_addr, SUN_LEN(&devd_addr));
+ ATF_REQUIRE_EQ(0, error);
+
+ create_two_events();
+
+ /*
+ * Loop until both events are detected on _different_ reads
+ * There may be extra events due to unrelated system activity
+ * If we never get both events, then the test will timeout.
+ */
+ while (!(got_create_event && got_destroy_event)) {
+ char event[1024];
+ ssize_t newlen;
+ char *create_pos, *destroy_pos;
+
+ /* Read 1 less than sizeof(event) to allow space for NULL */
+ newlen = read(s, &event[len], sizeof(event) - len - 1);
+ ATF_REQUIRE(newlen != -1);
+ len += newlen;
+ /* NULL terminate the result */
+ event[newlen] = '\0';
+ printf("%s", event);
+
+ create_pos = strstr(event, create_pat);
+ if (create_pos != NULL)
+ got_create_event = true;
+
+ destroy_pos = strstr(event, destroy_pat);
+ if (destroy_pos != NULL)
+ got_destroy_event = true;
+ }
+
+ close(s);
+}
+
+/*
+ * Main.
+ */
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, seqpacket);
+ ATF_TP_ADD_TC(tp, stream);
+
+ return (atf_no_error());
+}
+
diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c
index f79ca2f..859f48b 100644
--- a/sbin/dhclient/packet.c
+++ b/sbin/dhclient/packet.c
@@ -127,17 +127,6 @@ assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from,
ip.ip_dst.s_addr = to;
ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
-
- /*
- * While the BPF -- used for broadcasts -- expects a "true" IP header
- * with all the bytes in network byte order, the raw socket interface
- * which is used for unicasts expects the ip_len field to be in host
- * byte order. In both cases, the checksum has to be correct, so this
- * is as good a place as any to turn the bytes around again.
- */
- if (to != INADDR_BROADCAST)
- ip.ip_len = ntohs(ip.ip_len);
-
memcpy(&buf[*bufix], &ip, sizeof(ip));
*bufix += sizeof(ip);
diff --git a/sbin/dhclient/tests/Makefile b/sbin/dhclient/tests/Makefile
index b092eea..a460f7f 100644
--- a/sbin/dhclient/tests/Makefile
+++ b/sbin/dhclient/tests/Makefile
@@ -8,6 +8,7 @@ PLAIN_TESTS_C= option-domain-search_test
SRCS.option-domain-search_test= alloc.c convert.c hash.c options.c \
tables.c fake.c option-domain-search.c
CFLAGS.option-domain-search_test+= -I${.CURDIR}/..
+DPADD.option-domain-search_test= ${LIBUTIL}
LDADD.option-domain-search_test= -lutil
WARNS?= 2
diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c
index 8258f07..8a9a378 100644
--- a/sbin/dump/traverse.c
+++ b/sbin/dump/traverse.c
@@ -673,7 +673,12 @@ ufs2_blksout(union dinode *dp, ufs2_daddr_t *blkp, int frags, ino_t ino,
*/
blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
if (last) {
- resid = howmany(fragoff(sblock, dp->dp2.di_size), TP_BSIZE);
+ if (writingextdata)
+ resid = howmany(fragoff(sblock, spcl.c_extsize),
+ TP_BSIZE);
+ else
+ resid = howmany(fragoff(sblock, dp->dp2.di_size),
+ TP_BSIZE);
if (resid > 0)
blks -= howmany(sblock->fs_fsize, TP_BSIZE) - resid;
}
diff --git a/sbin/dumpon/dumpon.8 b/sbin/dumpon/dumpon.8
index 6be8090..c2601b2 100644
--- a/sbin/dumpon/dumpon.8
+++ b/sbin/dumpon/dumpon.8
@@ -28,7 +28,7 @@
.\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd April 29, 2013
+.Dd October 8, 2014
.Dt DUMPON 8
.Os
.Sh NAME
@@ -124,9 +124,18 @@ performs a
on
.Pa /dev/null
and thus instructs the kernel not to save crash dumps.
+.Pp
+Since
+.Nm
+cannot be used during kernel initialization, the
+.Va dumpdev
+variable of
+.Xr loader 8
+must be used to enable dumps for system panics which occur
+during kernel initialization.
.Sh FILES
-.Bl -tag -width "/dev/{ad,da}?s?b" -compact
-.It Pa /dev/{ad,da}?s?b
+.Bl -tag -width "/dev/{ada,da}?s?b" -compact
+.It Pa /dev/{ada,da}?s?b
standard swap areas
.It Pa /etc/rc.conf
boot-time system configuration
@@ -136,6 +145,7 @@ boot-time system configuration
.Xr rc.conf 5 ,
.Xr config 8 ,
.Xr init 8 ,
+.Xr loader 8 ,
.Xr rc 8 ,
.Xr savecore 8 ,
.Xr swapon 8 ,
diff --git a/sbin/fdisk_pc98/Makefile b/sbin/fdisk_pc98/Makefile
index e5932f8..6961d31 100644
--- a/sbin/fdisk_pc98/Makefile
+++ b/sbin/fdisk_pc98/Makefile
@@ -7,7 +7,7 @@ MAN= fdisk.8
.PATH: ${.CURDIR}/../../sys/geom
-DPADD += ${LIBGEOM}
-LDADD += -lgeom
+DPADD+= ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF}
+LDADD+= -lgeom -lbsdxml -lsbuf
.include <bsd.prog.mk>
diff --git a/sbin/fsck/Makefile b/sbin/fsck/Makefile
index d0c45db..22de03c 100644
--- a/sbin/fsck/Makefile
+++ b/sbin/fsck/Makefile
@@ -5,6 +5,4 @@ PROG= fsck
SRCS= fsck.c fsutil.c preen.c
MAN= fsck.8
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/sbin/fsck_msdosfs/boot.c b/sbin/fsck_msdosfs/boot.c
index 3195183..b1760c5 100644
--- a/sbin/fsck_msdosfs/boot.c
+++ b/sbin/fsck_msdosfs/boot.c
@@ -181,7 +181,7 @@ readboot(int dosfs, struct bootblock *boot)
boot->bpbResSectors + boot->bpbFATs * boot->FATsecs -
CLUST_FIRST * boot->bpbSecPerClust;
- if (boot->bpbBytesPerSec % DOSBOOTBLOCKSIZE != 0) {
+ if (boot->bpbBytesPerSec % DOSBOOTBLOCKSIZE_REAL != 0) {
pfatal("Invalid sector size: %u", boot->bpbBytesPerSec);
return FSFATAL;
}
diff --git a/sbin/fsck_msdosfs/dosfs.h b/sbin/fsck_msdosfs/dosfs.h
index bd01b24..485b3a1 100644
--- a/sbin/fsck_msdosfs/dosfs.h
+++ b/sbin/fsck_msdosfs/dosfs.h
@@ -30,7 +30,9 @@
#ifndef DOSFS_H
#define DOSFS_H
-#define DOSBOOTBLOCKSIZE 512
+/* support 4Kn disk reads */
+#define DOSBOOTBLOCKSIZE_REAL 512
+#define DOSBOOTBLOCKSIZE 4096
typedef u_int32_t cl_t; /* type holding a cluster number */
diff --git a/sbin/fsirand/Makefile b/sbin/fsirand/Makefile
index 19888df..2ae820a 100644
--- a/sbin/fsirand/Makefile
+++ b/sbin/fsirand/Makefile
@@ -4,7 +4,5 @@
PROG= fsirand
MAN= fsirand.8
WARNS?= 3
-DPADD= ${LIBUTIL}
-LDADD= -lutil
.include <bsd.prog.mk>
diff --git a/sbin/gbde/gbde.8 b/sbin/gbde/gbde.8
index 47c2e21..0578287 100644
--- a/sbin/gbde/gbde.8
+++ b/sbin/gbde/gbde.8
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 1, 2013
+.Dd August 27, 2014
.Dt GBDE 8
.Os
.Sh NAME
@@ -233,9 +233,23 @@ pass-phrase:
.Pp
.Dl "gbde setkey ada0s1f -n 2 -P foo -L key2.lockfile"
.Pp
-To destroy all copies of the masterkey:
+To invalidate your own masterkey:
.Pp
-.Dl "gbde destroy ada0s1f -n -1"
+.Dl "gbde nuke ada0s1f"
+.Pp
+This will overwrite your masterkey sector with zeros, and results in
+a diagnostic if you try to use the key again.
+You can also destroy the other three copies of the masterkey with the
+-n argument.
+.Pp
+You can also invalidate your masterkey without leaving a tell-tale sector
+full of zeros:
+.Pp
+.Dl "gbde destroy ada0s1f"
+.Pp
+This will overwrite the information fields in your masterkey sector,
+encrypt it and write it back.
+You get a (different) diagnostic if you try to use it.
.Sh SEE ALSO
.Xr gbde 4 ,
.Xr geom 4
diff --git a/sbin/gbde/gbde.c b/sbin/gbde/gbde.c
index b6baa95..3dca212 100644
--- a/sbin/gbde/gbde.c
+++ b/sbin/gbde/gbde.c
@@ -300,7 +300,6 @@ cmd_attach(const struct g_bde_softc *sc, const char *dest, const char *lfile)
gctl_ro_param(r, "key", 16, buf);
close(ffd);
}
- /* gctl_dump(r, stdout); */
errstr = gctl_issue(r);
if (errstr != NULL)
errx(1, "Attach to %s failed: %s", dest, errstr);
@@ -371,7 +370,7 @@ cmd_open(struct g_bde_softc *sc, int dfd , const char *l_opt, u_int *nkey)
if (error != 0)
errx(1, "Error %d decrypting lock", error);
if (nkey)
- printf("Opened with key %u\n", *nkey);
+ printf("Opened with key %u\n", 1 + *nkey);
return;
}
@@ -392,7 +391,7 @@ cmd_nuke(struct g_bde_key *gl, int dfd , int key)
free(sbuf);
if (i != (int)gl->sectorsize)
err(1, "write");
- printf("Nuked key %d\n", key);
+ printf("Nuked key %d\n", 1 + key);
}
static void
@@ -493,7 +492,7 @@ cmd_destroy(struct g_bde_key *gl, int nkey)
bzero(&gl->sector0, sizeof gl->sector0);
bzero(&gl->sectorN, sizeof gl->sectorN);
bzero(&gl->keyoffset, sizeof gl->keyoffset);
- bzero(&gl->flags, sizeof gl->flags);
+ gl->flags &= GBDE_F_SECT0;
bzero(gl->mkey, sizeof gl->mkey);
for (i = 0; i < G_BDE_MAXKEYS; i++)
if (i != nkey)
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index 0e3ed7f..e8c4dab 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 1, 2014
+.Dd August 12, 2014
.Dt GPART 8
.Os
.Sh NAME
@@ -129,6 +129,14 @@
.Op Fl f Ar flags
.Ar geom
.\"
+.Nm
+.Cm list
+.Nm
+.Cm status
+.Nm
+.Cm load
+.Nm
+.Cm unload
.Sh DESCRIPTION
The
.Nm
@@ -467,6 +475,18 @@ See the section entitled
below for a discussion
about its use.
.El
+.It Cm list
+See
+.Xr geom 8 .
+.It Cm status
+See
+.Xr geom 8 .
+.It Cm load
+See
+.Xr geom 8 .
+.It Cm unload
+See
+.Xr geom 8 .
.El
.Sh PARTITIONING SCHEMES
Several partitioning schemes are supported by the
@@ -639,13 +659,6 @@ Another symbolic names that can be used with
.Cm gpart
utility are:
.Bl -tag -width ".Cm dragonfly-disklabel64"
-.It Cm apple-boot
-An Apple Mac OS X partition dedicated to bootloader.
-The scheme-specific types are
-.Qq Li "!Apple_Bootstrap"
-for APM and
-.Qq Li "!426f6f74-0000-11aa-aa11-00306543ecac"
-for GPT.
.It Cm apple-hfs
An Apple Mac OS X partition that contains a HFS or HFS+ filesystem.
The scheme-specific types are
@@ -1163,6 +1176,12 @@ If this variable set to 1 each component of the mirrored volume will be
present as independent partition.
.Em NOTE :
This may break a mirrored volume and lead to data damage.
+.It Va kern.geom.part.mbr.enforce_chs : No 0
+Specify how the Master Boot Record (MBR) module does alignment.
+If this variable is set to a non-zero value, the module will automatically
+recalculate the user-specified offset and size for alignment with the CHS
+geometry.
+Otherwise the values will be left unchanged.
.El
.Sh EXIT STATUS
Exit status is 0 on success, and 1 if the command fails.
diff --git a/sbin/geom/class/virstor/gvirstor.8 b/sbin/geom/class/virstor/gvirstor.8
index bf04c1b..3d93e5b 100644
--- a/sbin/geom/class/virstor/gvirstor.8
+++ b/sbin/geom/class/virstor/gvirstor.8
@@ -257,6 +257,10 @@ The
.Nm
utility first appeared in
.Fx 7.0 .
+.Sh AUTHORS
+.An Ivan Voras Aq Mt ivoras@FreeBSD.org
+.Pp
+Sponsored by Google Summer of Code 2006.
.Sh BUGS
Commands
.Cm add
@@ -293,7 +297,3 @@ and all their structures will be physically allocated at the start
of the first virstor component.
This could have a significant impact on file system performance
.Pq which can in some rare cases be even positive .
-.Sh AUTHORS
-.An Ivan Voras Aq Mt ivoras@FreeBSD.org
-.Pp
-Sponsored by Google Summer of Code 2006.
diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c
index 8c15c21..5d23d93 100644
--- a/sbin/geom/core/geom.c
+++ b/sbin/geom/core/geom.c
@@ -640,6 +640,11 @@ get_class(int *argc, char ***argv)
#endif /* !STATIC_GEOM_CLASSES */
set_class_name();
+
+ /* If we can't load or list, it's not a class. */
+ if (!std_available("load") && !std_available("list"))
+ errx(EXIT_FAILURE, "Invalid class name.");
+
if (*argc < 1)
usage();
}
diff --git a/sbin/hastd/Makefile b/sbin/hastd/Makefile
index 306c83a..3604b5b 100644
--- a/sbin/hastd/Makefile
+++ b/sbin/hastd/Makefile
@@ -30,7 +30,7 @@ CFLAGS+=-DINET
CFLAGS+=-DINET6
.endif
-DPADD= ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} ${LIBL} ${LIBPTHREAD} ${LIBUTIL}
+DPADD= ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} ${LIBPTHREAD} ${LIBUTIL}
LDADD= -lgeom -lbsdxml -lsbuf -lpthread -lutil
.if ${MK_OPENSSL} != "no"
DPADD+= ${LIBCRYPTO}
diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c
index 385a52a..8fa3383 100644
--- a/sbin/hastd/primary.c
+++ b/sbin/hastd/primary.c
@@ -330,9 +330,8 @@ primary_exitx(int exitcode, const char *fmt, ...)
exit(exitcode);
}
-/* Expects res->hr_amp locked, returns unlocked. */
static int
-hast_activemap_flush(struct hast_resource *res)
+hast_activemap_flush(struct hast_resource *res) __unlocks(res->hr_amp_lock)
{
const unsigned char *buf;
size_t size;
diff --git a/sbin/hastd/synch.h b/sbin/hastd/synch.h
index 65360fd..db4d83b 100644
--- a/sbin/hastd/synch.h
+++ b/sbin/hastd/synch.h
@@ -46,7 +46,7 @@
#endif
static __inline void
-mtx_init(pthread_mutex_t *lock)
+mtx_init(pthread_mutex_t *lock) __requires_unlocked(*lock)
{
int error;
@@ -54,7 +54,7 @@ mtx_init(pthread_mutex_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-mtx_destroy(pthread_mutex_t *lock)
+mtx_destroy(pthread_mutex_t *lock) __requires_unlocked(*lock)
{
int error;
@@ -62,7 +62,7 @@ mtx_destroy(pthread_mutex_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-mtx_lock(pthread_mutex_t *lock)
+mtx_lock(pthread_mutex_t *lock) __locks_exclusive(*lock)
{
int error;
@@ -70,7 +70,7 @@ mtx_lock(pthread_mutex_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline bool
-mtx_trylock(pthread_mutex_t *lock)
+mtx_trylock(pthread_mutex_t *lock) __trylocks_exclusive(true, *lock)
{
int error;
@@ -79,7 +79,7 @@ mtx_trylock(pthread_mutex_t *lock)
return (error == 0);
}
static __inline void
-mtx_unlock(pthread_mutex_t *lock)
+mtx_unlock(pthread_mutex_t *lock) __unlocks(*lock)
{
int error;
@@ -94,7 +94,7 @@ mtx_owned(pthread_mutex_t *lock)
}
static __inline void
-rw_init(pthread_rwlock_t *lock)
+rw_init(pthread_rwlock_t *lock) __requires_unlocked(*lock)
{
int error;
@@ -102,7 +102,7 @@ rw_init(pthread_rwlock_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-rw_destroy(pthread_rwlock_t *lock)
+rw_destroy(pthread_rwlock_t *lock) __requires_unlocked(*lock)
{
int error;
@@ -110,7 +110,7 @@ rw_destroy(pthread_rwlock_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-rw_rlock(pthread_rwlock_t *lock)
+rw_rlock(pthread_rwlock_t *lock) __locks_shared(*lock)
{
int error;
@@ -118,7 +118,7 @@ rw_rlock(pthread_rwlock_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-rw_wlock(pthread_rwlock_t *lock)
+rw_wlock(pthread_rwlock_t *lock) __locks_exclusive(*lock)
{
int error;
@@ -126,7 +126,7 @@ rw_wlock(pthread_rwlock_t *lock)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-rw_unlock(pthread_rwlock_t *lock)
+rw_unlock(pthread_rwlock_t *lock) __unlocks(*lock)
{
int error;
@@ -150,7 +150,7 @@ cv_init(pthread_cond_t *cv)
PJDLOG_ASSERT(error == 0);
}
static __inline void
-cv_wait(pthread_cond_t *cv, pthread_mutex_t *lock)
+cv_wait(pthread_cond_t *cv, pthread_mutex_t *lock) __requires_exclusive(*lock)
{
int error;
@@ -159,6 +159,7 @@ cv_wait(pthread_cond_t *cv, pthread_mutex_t *lock)
}
static __inline bool
cv_timedwait(pthread_cond_t *cv, pthread_mutex_t *lock, int timeout)
+ __requires_exclusive(*lock)
{
struct timespec ts;
int error;
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index aae6724..8aba6b4 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -30,9 +30,14 @@ SRCS+= ifmac.c # MAC support
SRCS+= ifmedia.c # SIOC[GS]IFMEDIA support
SRCS+= iffib.c # non-default FIB support
SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
+SRCS+= ifvxlan.c # VXLAN support
SRCS+= ifgre.c # GRE keys etc
SRCS+= ifgif.c # GIF reversed header workaround
+SRCS+= sfp.c # SFP/SFP+ information
+DPADD+= ${LIBM}
+LDADD+= -lm
+
SRCS+= ifieee80211.c regdomain.c # SIOC[GS]IEEE80211 support
DPADD+= ${LIBBSDXML} ${LIBSBUF}
LDADD+= -lbsdxml -lsbuf
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index d2e65e4..0f8688a 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -254,6 +254,8 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
printf("autoconf ");
if ((flags6 & IN6_IFF_TEMPORARY) != 0)
printf("temporary ");
+ if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0)
+ printf("prefer_source ");
if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id)
printf("scopeid 0x%x ",
@@ -465,6 +467,8 @@ static struct cmd inet6_cmds[] = {
DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD("prefer_source",IN6_IFF_PREFER_SOURCE, setip6flags),
+ DEF_CMD("-prefer_source",-IN6_IFF_PREFER_SOURCE,setip6flags),
DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags),
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 5bf590d..064a62d 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
-.Dd June 5, 2014
+.Dd October 20, 2014
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -679,7 +679,7 @@ Set a flag to enable Neighbor Unreachability Detection.
Clear a flag
.Cm nud .
.It Cm no_prefer_iface
-Set a flag to not honor rule 5 of source address selection in RFC 3484.
+Set a flag to not honor rule 5 of source address selection in RFC 3484.
In practice this means the address on the outgoing interface will not be
preferred, effectively yielding the decision to the address selection
policy table, configurable with
@@ -689,6 +689,19 @@ Clear a flag
.Cm no_prefer_iface .
.El
.Pp
+The following parameters are specific for IPv6 addresses.
+Note that the address family keyword
+.Dq Li inet6
+is needed for them:
+.Bl -tag -width indent
+.It Cm prefer_source
+Set a flag to prefer address as a candidate of the source address for
+outgoing packets.
+.It Cm -prefer_source
+Clear a flag
+.Cm prefer_source .
+.El
+.Pp
The following parameters are specific to cloning
IEEE 802.11 wireless interfaces with the
.Cm create
@@ -2318,9 +2331,16 @@ Remove the interface named by
from the aggregation interface.
.It Cm laggproto Ar proto
Set the aggregation protocol.
-The default is failover.
-The available options are failover, fec, lacp, loadbalance, roundrobin and
-none.
+The default is
+.Li failover .
+The available options are
+.Li failover ,
+.Li lacp ,
+.Li loadbalance ,
+.Li roundrobin ,
+.Li broadcast
+and
+.Li none .
.It Cm lagghash Ar option Ns Oo , Ns Ar option Oc
Set the packet layers to hash for aggregation protocols which load balance.
The default is
@@ -2335,6 +2355,34 @@ src/dst address for IPv4 or IPv6.
.It Cm l4
src/dst port for TCP/UDP/SCTP.
.El
+.It Cm use_flowid
+Enable local hash computation for RSS hash on the interface.
+The
+.Li loadbalance
+and
+.Li lacp
+modes will use the RSS hash from the network card if available
+to avoid computing one, this may give poor traffic distribution
+if the hash is invalid or uses less of the protocol header information.
+.Cm use_flowid
+disables use of RSS hash from the network card.
+The default value can be set via the
+.Va net.link.lagg.default_use_flowid
+.Xr sysctl 8
+variable.
+.Li 0
+means
+.Dq disabled
+and
+.Li 1
+means
+.Dq enabled .
+.It Cm -use_flowid
+Disable local hash computation for RSS hash on the interface.
+.It Cm flowid_shift Ar number
+Set a shift parameter for RSS local hash computation.
+Hash is calculated by using flowid bits in a packet header mbuf
+which are shifted by the number of this parameter.
.El
.Pp
The following parameters are specific to IP tunnel interfaces,
@@ -2493,6 +2541,76 @@ argument is useless and hence deprecated.
.El
.Pp
The following parameters are used to configure
+.Xr vxlan 4
+interfaces.
+.Bl -tag -width indent
+.It Cm vni Ar identifier
+This value is a 24-bit VXLAN Network Identifier (VNI) that identifies the
+virtual network segment membership of the interface.
+.It Cm local Ar address
+The source address used in the encapsulating IPv4/IPv6 header.
+The address should already be assigned to an existing interface.
+When the interface is configured in unicast mode, the listening socket
+is bound to this address.
+.It Cm remote Ar address
+The interface can be configured in a unicast, or point-to-point, mode
+to create a tunnel between two hosts.
+This is the IP address of the remote end of the tunnel.
+.It Cm group Ar address
+The interface can be configured in a multicast mode
+to create a virtual network of hosts.
+This is the IP multicast group address the interface will join.
+.It Cm localport Ar port
+The port number the interface will listen on.
+The default port number is 4789.
+.It Cm remoteport Ar port
+The destination port number used in the encapsulating IPv4/IPv6 header.
+The remote host should be listening on this port.
+The default port number is 4789.
+Note some other implementations, such as Linux,
+do not default to the IANA assigned port,
+but instead listen on port 8472.
+.It Cm portrange Ar low high
+The range of source ports used in the encapsulating IPv4/IPv6 header.
+The port selected within the range is based on a hash of the inner frame.
+A range is useful to provide entropy within the outer IP header
+for more effective load balancing.
+The default range is between the
+.Xr sysctl 8
+variables
+.Va net.inet.ip.portrange.first
+and
+.Va net.inet.ip.portrange.last
+.It Cm timeout Ar timeout
+The maximum time, in seconds, before an entry in the forwarding table
+is pruned.
+The default is 1200 seconds (20 minutes).
+.It Cm maxaddr Ar max
+The maximum number of entries in the forwarding table.
+The default is 2000.
+.It Cm vxlandev Ar dev
+When the interface is configured in multicast mode, the
+.Cm dev
+interface is used to transmit IP multicast packets.
+.It Cm ttl Ar ttl
+The TTL used in the encapsulating IPv4/IPv6 header.
+The default is 64.
+.It Cm learn
+The source IP address and inner source Ethernet MAC address of
+received packets are used to dynamically populate the forwarding table.
+When in multicast mode, an entry in the forwarding table allows the
+interface to send the frame directly to the remote host instead of
+broadcasting the frame to the multicast group.
+This is the default.
+.It Fl learn
+The forwarding table is not populated by recevied packets.
+.It Cm flush
+Delete all dynamically-learned addresses from the forwarding table.
+.It Cm flushall
+Delete all addresses, including static addresses, from the forwarding table.
+.El
+.Pp
+The following parameters are used to configure
.Xr carp 4
protocol on an interface:
.Bl -tag -width indent
@@ -2697,6 +2815,7 @@ tried to alter an interface's configuration.
.Xr pfsync 4 ,
.Xr polling 4 ,
.Xr vlan 4 ,
+.Xr vxlan 4 ,
.Xr devd.conf 5 ,
.\" .Xr eon 5 ,
.Xr devd 8 ,
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index d2ddeca..61fd155 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -78,7 +78,7 @@ static const char rcsid[] =
/*
* Since "struct ifreq" is composed of various union members, callers
- * should pay special attention to interprete the value.
+ * should pay special attention to interpret the value.
* (.e.g. little/big endian difference in the structure.)
*/
struct ifreq ifr;
@@ -1011,6 +1011,9 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
printf("%s", ifs.ascii);
+ if (verbose > 0)
+ sfp_status(s, &ifr, verbose);
+
close(s);
return;
}
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index ea21db5..6df9acf 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -74,6 +74,7 @@ void callback_register(callback_func *, void *);
#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 0, NULL }
#define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1, NULL }
#define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1, NULL }
+#define DEF_CLONE_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 1, NULL }
struct ifaddrs;
struct addrinfo;
@@ -143,6 +144,8 @@ void ifmaybeload(const char *name);
typedef void clone_callback_func(int, struct ifreq *);
void clone_setdefcallback(const char *, clone_callback_func *);
+void sfp_status(int s, struct ifreq *ifr, int verbose);
+
/*
* XXX expose this so modules that neeed to know of any pending
* operations on ifmedia can avoid cmd line ordering confusion.
diff --git a/sbin/ifconfig/ifgre.c b/sbin/ifconfig/ifgre.c
index 8bf7ede..3ac7454 100644
--- a/sbin/ifconfig/ifgre.c
+++ b/sbin/ifconfig/ifgre.c
@@ -23,52 +23,50 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_gre.h>
-#include <net/route.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include <err.h>
-#include <errno.h>
#include "ifconfig.h"
+#define GREBITS "\020\01ENABLE_CSUM\02ENABLE_SEQ"
+
static void gre_status(int s);
static void
gre_status(int s)
{
- int grekey = 0;
+ uint32_t opts = 0;
- ifr.ifr_data = (caddr_t)&grekey;
+ ifr.ifr_data = (caddr_t)&opts;
if (ioctl(s, GREGKEY, &ifr) == 0)
- if (grekey != 0)
- printf("\tgrekey: %d\n", grekey);
+ if (opts != 0)
+ printf("\tgrekey: 0x%x (%u)\n", opts, opts);
+ opts = 0;
+ if (ioctl(s, GREGOPTS, &ifr) != 0 || opts == 0)
+ return;
+ printb("\toptions", opts, GREBITS);
+ putchar('\n');
}
static void
setifgrekey(const char *val, int dummy __unused, int s,
const struct afswtch *afp)
{
- uint32_t grekey = atol(val);
+ uint32_t grekey = strtol(val, NULL, 0);
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_data = (caddr_t)&grekey;
@@ -76,8 +74,35 @@ setifgrekey(const char *val, int dummy __unused, int s,
warn("ioctl (set grekey)");
}
+static void
+setifgreopts(const char *val, int d, int s, const struct afswtch *afp)
+{
+ uint32_t opts;
+
+ ifr.ifr_data = (caddr_t)&opts;
+ if (ioctl(s, GREGOPTS, &ifr) == -1) {
+ warn("ioctl(GREGOPTS)");
+ return;
+ }
+
+ if (d < 0)
+ opts &= ~(-d);
+ else
+ opts |= d;
+
+ if (ioctl(s, GRESOPTS, &ifr) == -1) {
+ warn("ioctl(GIFSOPTS)");
+ return;
+ }
+}
+
+
static struct cmd gre_cmds[] = {
DEF_CMD_ARG("grekey", setifgrekey),
+ DEF_CMD("enable_csum", GRE_ENABLE_CSUM, setifgreopts),
+ DEF_CMD("-enable_csum",-GRE_ENABLE_CSUM,setifgreopts),
+ DEF_CMD("enable_seq", GRE_ENABLE_SEQ, setifgreopts),
+ DEF_CMD("-enable_seq",-GRE_ENABLE_SEQ, setifgreopts),
};
static struct afswtch af_gre = {
.af_name = "af_gre",
diff --git a/sbin/ifconfig/iflagg.c b/sbin/ifconfig/iflagg.c
index 29b8574..51a6faa 100644
--- a/sbin/ifconfig/iflagg.c
+++ b/sbin/ifconfig/iflagg.c
@@ -17,6 +17,7 @@ static const char rcsid[] =
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_lagg.h>
+#include <net/ieee8023ad_lacp.h>
#include <net/route.h>
#include <ctype.h>
@@ -68,7 +69,7 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
bzero(&ra, sizeof(ra));
ra.ra_proto = LAGG_PROTO_MAX;
- for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+ for (i = 0; i < nitems(lpr); i++) {
if (strcmp(val, lpr[i].lpr_name) == 0) {
ra.ra_proto = lpr[i].lpr_proto;
break;
@@ -83,6 +84,48 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
}
static void
+setlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct lagg_reqopts ro;
+
+ bzero(&ro, sizeof(ro));
+ ro.ro_opts = LAGG_OPT_FLOWIDSHIFT;
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+ ro.ro_flowid_shift = (int)strtol(val, NULL, 10);
+ if (ro.ro_flowid_shift & ~LAGG_OPT_FLOWIDSHIFT_MASK)
+ errx(1, "Invalid flowid_shift option: %s", val);
+
+ if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
+ err(1, "SIOCSLAGGOPTS");
+}
+
+static void
+setlaggsetopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct lagg_reqopts ro;
+
+ bzero(&ro, sizeof(ro));
+ ro.ro_opts = d;
+ switch (ro.ro_opts) {
+ case LAGG_OPT_USE_FLOWID:
+ case -LAGG_OPT_USE_FLOWID:
+ case LAGG_OPT_LACP_STRICT:
+ case -LAGG_OPT_LACP_STRICT:
+ case LAGG_OPT_LACP_TXTEST:
+ case -LAGG_OPT_LACP_TXTEST:
+ case LAGG_OPT_LACP_RXTEST:
+ case -LAGG_OPT_LACP_RXTEST:
+ break;
+ default:
+ err(1, "Invalid lagg option");
+ }
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+
+ if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
+ err(1, "SIOCSLAGGOPTS");
+}
+
+static void
setlagghash(const char *val, int d, int s, const struct afswtch *afp)
{
struct lagg_reqflags rf;
@@ -144,6 +187,7 @@ lagg_status(int s)
struct lagg_protos lpr[] = LAGG_PROTOS;
struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
struct lagg_reqall ra;
+ struct lagg_reqopts ro;
struct lagg_reqflags rf;
struct lacp_opreq *lp;
const char *proto = "<unknown>";
@@ -151,6 +195,7 @@ lagg_status(int s)
bzero(&rp, sizeof(rp));
bzero(&ra, sizeof(ra));
+ bzero(&ro, sizeof(ro));
strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
@@ -162,6 +207,9 @@ lagg_status(int s)
ra.ra_size = sizeof(rpbuf);
ra.ra_port = rpbuf;
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+ ioctl(s, SIOCGLAGGOPTS, &ro);
+
strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
rf.rf_flags = 0;
@@ -169,7 +217,7 @@ lagg_status(int s)
if (ioctl(s, SIOCGLAGG, &ra) == 0) {
lp = (struct lacp_opreq *)&ra.ra_lacpreq;
- for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+ for (i = 0; i < nitems(lpr); i++) {
if (ra.ra_proto == lpr[i].lpr_proto) {
proto = lpr[i].lpr_name;
break;
@@ -197,16 +245,27 @@ lagg_status(int s)
if (isport)
printf(" laggdev %s", rp.rp_ifname);
putchar('\n');
- if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
- printf("\tlag id: %s\n",
- lacp_format_peer(lp, "\n\t\t "));
+ if (verbose) {
+ printf("\tlagg options:\n");
+ printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS);
+ putchar('\n');
+ printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift);
+ printf("\tlagg statistics:\n");
+ printf("\t\tactive ports: %d\n", ro.ro_active);
+ printf("\t\tflapping: %u\n", ro.ro_flapping);
+ if (ra.ra_proto == LAGG_PROTO_LACP) {
+ printf("\tlag id: %s\n",
+ lacp_format_peer(lp, "\n\t\t "));
+ }
+ }
for (i = 0; i < ra.ra_ports; i++) {
lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
printf("\tlaggport: %s ", rpbuf[i].rp_portname);
printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
- printf(" state=%X", lp->actor_state);
+ printb(" state", lp->actor_state,
+ LACP_STATE_BITS);
putchar('\n');
if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
printf("\t\t%s\n",
@@ -226,6 +285,15 @@ static struct cmd lagg_cmds[] = {
DEF_CMD_ARG("-laggport", unsetlaggport),
DEF_CMD_ARG("laggproto", setlaggproto),
DEF_CMD_ARG("lagghash", setlagghash),
+ DEF_CMD("use_flowid", LAGG_OPT_USE_FLOWID, setlaggsetopt),
+ DEF_CMD("-use_flowid", -LAGG_OPT_USE_FLOWID, setlaggsetopt),
+ DEF_CMD("lacp_strict", LAGG_OPT_LACP_STRICT, setlaggsetopt),
+ DEF_CMD("-lacp_strict", -LAGG_OPT_LACP_STRICT, setlaggsetopt),
+ DEF_CMD("lacp_txtest", LAGG_OPT_LACP_TXTEST, setlaggsetopt),
+ DEF_CMD("-lacp_txtest", -LAGG_OPT_LACP_TXTEST, setlaggsetopt),
+ DEF_CMD("lacp_rxtest", LAGG_OPT_LACP_RXTEST, setlaggsetopt),
+ DEF_CMD("-lacp_rxtest", -LAGG_OPT_LACP_RXTEST, setlaggsetopt),
+ DEF_CMD_ARG("flowid_shift", setlaggflowidshift),
};
static struct afswtch af_lagg = {
.af_name = "af_lagg",
diff --git a/sbin/ifconfig/ifvxlan.c b/sbin/ifconfig/ifvxlan.c
new file mode 100644
index 0000000..7234667
--- /dev/null
+++ b/sbin/ifconfig/ifvxlan.c
@@ -0,0 +1,648 @@
+/*-
+ * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
+ * 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 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 ``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 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_vxlan.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static struct ifvxlanparam params = {
+ .vxlp_vni = VXLAN_VNI_MAX,
+};
+
+static int
+get_val(const char *cp, u_long *valp)
+{
+ char *endptr;
+ u_long val;
+
+ errno = 0;
+ val = strtoul(cp, &endptr, 0);
+ if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
+ return (-1);
+
+ *valp = val;
+ return (0);
+}
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+ struct ifdrv ifd;
+
+ bzero(&ifd, sizeof(ifd));
+
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = op;
+ ifd.ifd_len = argsize;
+ ifd.ifd_data = arg;
+
+ return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static int
+vxlan_exists(int sock)
+{
+ struct ifvxlancfg cfg;
+
+ bzero(&cfg, sizeof(cfg));
+
+ return (do_cmd(sock, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) != -1);
+}
+
+static void
+vxlan_status(int s)
+{
+ struct ifvxlancfg cfg;
+ char src[NI_MAXHOST], dst[NI_MAXHOST];
+ char srcport[NI_MAXSERV], dstport[NI_MAXSERV];
+ struct sockaddr *lsa, *rsa;
+ int vni, mc, ipv6;
+
+ bzero(&cfg, sizeof(cfg));
+
+ if (do_cmd(s, VXLAN_CMD_GET_CONFIG, &cfg, sizeof(cfg), 0) < 0)
+ return;
+
+ vni = cfg.vxlc_vni;
+ lsa = &cfg.vxlc_local_sa.sa;
+ rsa = &cfg.vxlc_remote_sa.sa;
+ ipv6 = rsa->sa_family == AF_INET6;
+
+ /* Just report nothing if the network identity isn't set yet. */
+ if (vni >= VXLAN_VNI_MAX)
+ return;
+
+ if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src),
+ srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ src[0] = srcport[0] = '\0';
+ if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
+ dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ dst[0] = dstport[0] = '\0';
+
+ if (!ipv6) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)rsa;
+ mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
+ } else {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa;
+ mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr);
+ }
+
+ printf("\tvxlan vni %d", vni);
+ printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "",
+ srcport);
+ printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "",
+ dst, ipv6 ? "]" : "", dstport);
+
+ if (verbose) {
+ printf("\n\t\tconfig: ");
+ printf("%slearning portrange %d-%d ttl %d",
+ cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min,
+ cfg.vxlc_port_max, cfg.vxlc_ttl);
+ printf("\n\t\tftable: ");
+ printf("cnt %d max %d timeout %d",
+ cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max,
+ cfg.vxlc_ftable_timeout);
+ }
+
+ putchar('\n');
+}
+
+#define _LOCAL_ADDR46 \
+ (VXLAN_PARAM_WITH_LOCAL_ADDR4 | VXLAN_PARAM_WITH_LOCAL_ADDR6)
+#define _REMOTE_ADDR46 \
+ (VXLAN_PARAM_WITH_REMOTE_ADDR4 | VXLAN_PARAM_WITH_REMOTE_ADDR6)
+
+static void
+vxlan_check_params(void)
+{
+
+ if ((params.vxlp_with & _LOCAL_ADDR46) == _LOCAL_ADDR46)
+ errx(1, "cannot specify both local IPv4 and IPv6 addresses");
+ if ((params.vxlp_with & _REMOTE_ADDR46) == _REMOTE_ADDR46)
+ errx(1, "cannot specify both remote IPv4 and IPv6 addresses");
+ if ((params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR4 &&
+ params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) ||
+ (params.vxlp_with & VXLAN_PARAM_WITH_LOCAL_ADDR6 &&
+ params.vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4))
+ errx(1, "cannot mix IPv4 and IPv6 addresses");
+}
+
+#undef _LOCAL_ADDR46
+#undef _REMOTE_ADDR46
+
+static void
+vxlan_cb(int s, void *arg)
+{
+
+}
+
+static void
+vxlan_create(int s, struct ifreq *ifr)
+{
+
+ vxlan_check_params();
+
+ ifr->ifr_data = (caddr_t) &params;
+ if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+ err(1, "SIOCIFCREATE2");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_vni, arg, d)
+{
+ struct ifvxlancmd cmd;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val >= VXLAN_VNI_MAX)
+ errx(1, "invalid network identifier: %s", arg);
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_VNI;
+ params.vxlp_vni = val;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_vni = val;
+
+ if (do_cmd(s, VXLAN_CMD_SET_VNI, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_VNI");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_local, addr, d)
+{
+ struct ifvxlancmd cmd;
+ struct addrinfo *ai;
+ struct sockaddr *sa;
+ int error;
+
+ bzero(&cmd, sizeof(cmd));
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing local address string: %s",
+ gai_strerror(error));
+
+ sa = ai->ai_addr;
+
+ switch (ai->ai_family) {
+#ifdef INET
+ case AF_INET: {
+ struct in_addr addr = ((struct sockaddr_in *) sa)->sin_addr;
+
+ if (IN_MULTICAST(ntohl(addr.s_addr)))
+ errx(1, "local address cannot be multicast");
+
+ cmd.vxlcmd_sa.in4.sin_family = AF_INET;
+ cmd.vxlcmd_sa.in4.sin_addr = addr;
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+
+ if (IN6_IS_ADDR_MULTICAST(addr))
+ errx(1, "local address cannot be multicast");
+
+ cmd.vxlcmd_sa.in6.sin6_family = AF_INET6;
+ cmd.vxlcmd_sa.in6.sin6_addr = *addr;
+ break;
+ }
+#endif
+ default:
+ errx(1, "local address %s not supported", addr);
+ }
+
+ freeaddrinfo(ai);
+
+ if (!vxlan_exists(s)) {
+ if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR4;
+ params.vxlp_local_in4 = cmd.vxlcmd_sa.in4.sin_addr;
+ } else {
+ params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_ADDR6;
+ params.vxlp_local_in6 = cmd.vxlcmd_sa.in6.sin6_addr;
+ }
+ return;
+ }
+
+ if (do_cmd(s, VXLAN_CMD_SET_LOCAL_ADDR, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_LOCAL_ADDR");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_remote, addr, d)
+{
+ struct ifvxlancmd cmd;
+ struct addrinfo *ai;
+ struct sockaddr *sa;
+ int error;
+
+ bzero(&cmd, sizeof(cmd));
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing remote address string: %s",
+ gai_strerror(error));
+
+ sa = ai->ai_addr;
+
+ switch (ai->ai_family) {
+#ifdef INET
+ case AF_INET: {
+ struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr;
+
+ if (IN_MULTICAST(ntohl(addr.s_addr)))
+ errx(1, "remote address cannot be multicast");
+
+ cmd.vxlcmd_sa.in4.sin_family = AF_INET;
+ cmd.vxlcmd_sa.in4.sin_addr = addr;
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+
+ if (IN6_IS_ADDR_MULTICAST(addr))
+ errx(1, "remote address cannot be multicast");
+
+ cmd.vxlcmd_sa.in6.sin6_family = AF_INET6;
+ cmd.vxlcmd_sa.in6.sin6_addr = *addr;
+ break;
+ }
+#endif
+ default:
+ errx(1, "remote address %s not supported", addr);
+ }
+
+ freeaddrinfo(ai);
+
+ if (!vxlan_exists(s)) {
+ if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
+ params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr;
+ } else {
+ params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
+ params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr;
+ }
+ return;
+ }
+
+ if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_group, addr, d)
+{
+ struct ifvxlancmd cmd;
+ struct addrinfo *ai;
+ struct sockaddr *sa;
+ int error;
+
+ bzero(&cmd, sizeof(cmd));
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing group address string: %s",
+ gai_strerror(error));
+
+ sa = ai->ai_addr;
+
+ switch (ai->ai_family) {
+#ifdef INET
+ case AF_INET: {
+ struct in_addr addr = ((struct sockaddr_in *)sa)->sin_addr;
+
+ if (!IN_MULTICAST(ntohl(addr.s_addr)))
+ errx(1, "group address must be multicast");
+
+ cmd.vxlcmd_sa.in4.sin_family = AF_INET;
+ cmd.vxlcmd_sa.in4.sin_addr = addr;
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct in6_addr *addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+
+ if (!IN6_IS_ADDR_MULTICAST(addr))
+ errx(1, "group address must be multicast");
+
+ cmd.vxlcmd_sa.in6.sin6_family = AF_INET6;
+ cmd.vxlcmd_sa.in6.sin6_addr = *addr;
+ break;
+ }
+#endif
+ default:
+ errx(1, "group address %s not supported", addr);
+ }
+
+ freeaddrinfo(ai);
+
+ if (!vxlan_exists(s)) {
+ if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
+ params.vxlp_remote_in4 = cmd.vxlcmd_sa.in4.sin_addr;
+ } else {
+ params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
+ params.vxlp_remote_in6 = cmd.vxlcmd_sa.in6.sin6_addr;
+ }
+ return;
+ }
+
+ if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_local_port, arg, d)
+{
+ struct ifvxlancmd cmd;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
+ errx(1, "invalid local port: %s", arg);
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_LOCAL_PORT;
+ params.vxlp_local_port = val;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_port = val;
+
+ if (do_cmd(s, VXLAN_CMD_SET_LOCAL_PORT, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_LOCAL_PORT");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_remote_port, arg, d)
+{
+ struct ifvxlancmd cmd;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val >= UINT16_MAX)
+ errx(1, "invalid remote port: %s", arg);
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_PORT;
+ params.vxlp_remote_port = val;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_port = val;
+
+ if (do_cmd(s, VXLAN_CMD_SET_REMOTE_PORT, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_REMOTE_PORT");
+}
+
+static
+DECL_CMD_FUNC2(setvxlan_port_range, arg1, arg2)
+{
+ struct ifvxlancmd cmd;
+ u_long min, max;
+
+ if (get_val(arg1, &min) < 0 || min >= UINT16_MAX)
+ errx(1, "invalid port range minimum: %s", arg1);
+ if (get_val(arg2, &max) < 0 || max >= UINT16_MAX)
+ errx(1, "invalid port range maximum: %s", arg2);
+ if (max < min)
+ errx(1, "invalid port range");
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_PORT_RANGE;
+ params.vxlp_min_port = min;
+ params.vxlp_max_port = max;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_port_min = min;
+ cmd.vxlcmd_port_max = max;
+
+ if (do_cmd(s, VXLAN_CMD_SET_PORT_RANGE, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_PORT_RANGE");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_timeout, arg, d)
+{
+ struct ifvxlancmd cmd;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
+ errx(1, "invalid timeout value: %s", arg);
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_TIMEOUT;
+ params.vxlp_ftable_timeout = val & 0xFFFFFFFF;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_ftable_timeout = val & 0xFFFFFFFF;
+
+ if (do_cmd(s, VXLAN_CMD_SET_FTABLE_TIMEOUT, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_FTABLE_TIMEOUT");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_maxaddr, arg, d)
+{
+ struct ifvxlancmd cmd;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xFFFFFFFF) != 0)
+ errx(1, "invalid maxaddr value: %s", arg);
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_FTABLE_MAX;
+ params.vxlp_ftable_max = val & 0xFFFFFFFF;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_ftable_max = val & 0xFFFFFFFF;
+
+ if (do_cmd(s, VXLAN_CMD_SET_FTABLE_MAX, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_FTABLE_MAX");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_dev, arg, d)
+{
+ struct ifvxlancmd cmd;
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_MULTICAST_IF;
+ strlcpy(params.vxlp_mc_ifname, arg,
+ sizeof(params.vxlp_mc_ifname));
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ strlcpy(cmd.vxlcmd_ifname, arg, sizeof(cmd.vxlcmd_ifname));
+
+ if (do_cmd(s, VXLAN_CMD_SET_MULTICAST_IF, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_MULTICAST_IF");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_ttl, arg, d)
+{
+ struct ifvxlancmd cmd;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || val > 256)
+ errx(1, "invalid TTL value: %s", arg);
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_TTL;
+ params.vxlp_ttl = val;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.vxlcmd_ttl = val;
+
+ if (do_cmd(s, VXLAN_CMD_SET_TTL, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_TTL");
+}
+
+static
+DECL_CMD_FUNC(setvxlan_learn, arg, d)
+{
+ struct ifvxlancmd cmd;
+
+ if (!vxlan_exists(s)) {
+ params.vxlp_with |= VXLAN_PARAM_WITH_LEARN;
+ params.vxlp_learn = d;
+ return;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ if (d != 0)
+ cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_LEARN;
+
+ if (do_cmd(s, VXLAN_CMD_SET_LEARN, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_LEARN");
+}
+
+static void
+setvxlan_flush(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifvxlancmd cmd;
+
+ bzero(&cmd, sizeof(cmd));
+ if (d != 0)
+ cmd.vxlcmd_flags |= VXLAN_CMD_FLAG_FLUSH_ALL;
+
+ if (do_cmd(s, VXLAN_CMD_FLUSH, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_FLUSH");
+}
+
+static struct cmd vxlan_cmds[] = {
+
+ DEF_CLONE_CMD_ARG("vni", setvxlan_vni),
+ DEF_CLONE_CMD_ARG("local", setvxlan_local),
+ DEF_CLONE_CMD_ARG("remote", setvxlan_remote),
+ DEF_CLONE_CMD_ARG("group", setvxlan_group),
+ DEF_CLONE_CMD_ARG("localport", setvxlan_local_port),
+ DEF_CLONE_CMD_ARG("remoteport", setvxlan_remote_port),
+ DEF_CLONE_CMD_ARG2("portrange", setvxlan_port_range),
+ DEF_CLONE_CMD_ARG("timeout", setvxlan_timeout),
+ DEF_CLONE_CMD_ARG("maxaddr", setvxlan_maxaddr),
+ DEF_CLONE_CMD_ARG("vxlandev", setvxlan_dev),
+ DEF_CLONE_CMD_ARG("ttl", setvxlan_ttl),
+ DEF_CLONE_CMD("learn", 1, setvxlan_learn),
+ DEF_CLONE_CMD("-learn", 0, setvxlan_learn),
+
+ DEF_CMD_ARG("vni", setvxlan_vni),
+ DEF_CMD_ARG("local", setvxlan_local),
+ DEF_CMD_ARG("remote", setvxlan_remote),
+ DEF_CMD_ARG("group", setvxlan_group),
+ DEF_CMD_ARG("localport", setvxlan_local_port),
+ DEF_CMD_ARG("remoteport", setvxlan_remote_port),
+ DEF_CMD_ARG2("portrange", setvxlan_port_range),
+ DEF_CMD_ARG("timeout", setvxlan_timeout),
+ DEF_CMD_ARG("maxaddr", setvxlan_maxaddr),
+ DEF_CMD_ARG("vxlandev", setvxlan_dev),
+ DEF_CMD_ARG("ttl", setvxlan_ttl),
+ DEF_CMD("learn", 1, setvxlan_learn),
+ DEF_CMD("-learn", 0, setvxlan_learn),
+
+ DEF_CMD("flush", 0, setvxlan_flush),
+ DEF_CMD("flushall", 1, setvxlan_flush),
+};
+
+static struct afswtch af_vxlan = {
+ .af_name = "af_vxlan",
+ .af_af = AF_UNSPEC,
+ .af_other_status = vxlan_status,
+};
+
+static __constructor void
+vxlan_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ size_t i;
+
+ for (i = 0; i < N(vxlan_cmds); i++)
+ cmd_register(&vxlan_cmds[i]);
+ af_register(&af_vxlan);
+ callback_register(vxlan_cb, NULL);
+ clone_setdefcallback("vxlan", vxlan_create);
+#undef N
+}
diff --git a/sbin/ifconfig/sfp.c b/sbin/ifconfig/sfp.c
new file mode 100644
index 0000000..d4da8c3
--- /dev/null
+++ b/sbin/ifconfig/sfp.c
@@ -0,0 +1,827 @@
+/*-
+ * Copyright (c) 2014 Alexander V. Chernikov. 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 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.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/sff8436.h>
+#include <net/sff8472.h>
+
+#include <math.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+struct i2c_info;
+typedef int (read_i2c)(struct i2c_info *ii, uint8_t addr, uint8_t off,
+ uint8_t len, caddr_t buf);
+
+struct i2c_info {
+ int s;
+ int error;
+ int bshift;
+ int qsfp;
+ int do_diag;
+ struct ifreq *ifr;
+ read_i2c *f;
+ char *textbuf;
+ size_t bufsize;
+ int cfd;
+ int port_id;
+ int chip_id;
+};
+
+static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off,
+ uint8_t len);
+
+struct _nv {
+ int v;
+ const char *n;
+};
+
+const char *find_value(struct _nv *x, int value);
+const char *find_zero_bit(struct _nv *x, int value, int sz);
+
+/* SFF-8472 Rev. 11.4 table 3.4: Connector values */
+static struct _nv conn[] = {
+ { 0x00, "Unknown" },
+ { 0x01, "SC" },
+ { 0x02, "Fibre Channel Style 1 copper" },
+ { 0x03, "Fibre Channel Style 2 copper" },
+ { 0x04, "BNC/TNC" },
+ { 0x05, "Fibre Channel coaxial" },
+ { 0x06, "FiberJack" },
+ { 0x07, "LC" },
+ { 0x08, "MT-RJ" },
+ { 0x09, "MU" },
+ { 0x0A, "SG" },
+ { 0x0B, "Optical pigtail" },
+ { 0x0C, "MPO Parallel Optic" },
+ { 0x20, "HSSDC II" },
+ { 0x21, "Copper pigtail" },
+ { 0x22, "RJ45" },
+ { 0x23, "No separate connector" }, /* SFF-8436 */
+ { 0, NULL }
+};
+
+/* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */
+/* 10G Ethernet/IB compliance codes, byte 3 */
+static struct _nv eth_10g[] = {
+ { 0x80, "10G Base-ER" },
+ { 0x40, "10G Base-LRM" },
+ { 0x20, "10G Base-LR" },
+ { 0x10, "10G Base-SR" },
+ { 0x08, "1X SX" },
+ { 0x04, "1X LX" },
+ { 0x02, "1X Copper Active" },
+ { 0x01, "1X Copper Passive" },
+ { 0, NULL }
+};
+
+/* Ethernet compliance codes, byte 6 */
+static struct _nv eth_compat[] = {
+ { 0x80, "BASE-PX" },
+ { 0x40, "BASE-BX10" },
+ { 0x20, "100BASE-FX" },
+ { 0x10, "100BASE-LX/LX10" },
+ { 0x08, "1000BASE-T" },
+ { 0x04, "1000BASE-CX" },
+ { 0x02, "1000BASE-LX" },
+ { 0x01, "1000BASE-SX" },
+ { 0, NULL }
+};
+
+/* FC link length, byte 7 */
+static struct _nv fc_len[] = {
+ { 0x80, "very long distance" },
+ { 0x40, "short distance" },
+ { 0x20, "intermediate distance" },
+ { 0x10, "long distance" },
+ { 0x08, "medium distance" },
+ { 0, NULL }
+};
+
+/* Channel/Cable technology, byte 7-8 */
+static struct _nv cab_tech[] = {
+ { 0x0400, "Shortwave laser (SA)" },
+ { 0x0200, "Longwave laser (LC)" },
+ { 0x0100, "Electrical inter-enclosure (EL)" },
+ { 0x80, "Electrical intra-enclosure (EL)" },
+ { 0x40, "Shortwave laser (SN)" },
+ { 0x20, "Shortwave laser (SL)" },
+ { 0x10, "Longwave laser (LL)" },
+ { 0x08, "Active Cable" },
+ { 0x04, "Passive Cable" },
+ { 0, NULL }
+};
+
+/* FC Transmission media, byte 9 */
+static struct _nv fc_media[] = {
+ { 0x80, "Twin Axial Pair" },
+ { 0x40, "Twisted Pair" },
+ { 0x20, "Miniature Coax" },
+ { 0x10, "Viao Coax" },
+ { 0x08, "Miltimode, 62.5um" },
+ { 0x04, "Multimode, 50um" },
+ { 0x02, "" },
+ { 0x01, "Single Mode" },
+ { 0, NULL }
+};
+
+/* FC Speed, byte 10 */
+static struct _nv fc_speed[] = {
+ { 0x80, "1200 MBytes/sec" },
+ { 0x40, "800 MBytes/sec" },
+ { 0x20, "1600 MBytes/sec" },
+ { 0x10, "400 MBytes/sec" },
+ { 0x08, "3200 MBytes/sec" },
+ { 0x04, "200 MBytes/sec" },
+ { 0x01, "100 MBytes/sec" },
+ { 0, NULL }
+};
+
+/* SFF-8436 Rev. 4.8 table 33: Specification compliance */
+
+/* 10/40G Ethernet compliance codes, byte 128 + 3 */
+static struct _nv eth_1040g[] = {
+ { 0x80, "Reserved" },
+ { 0x40, "10GBASE-LRM" },
+ { 0x20, "10GBASE-LR" },
+ { 0x10, "10GBASE-SR" },
+ { 0x08, "40GBASE-CR4" },
+ { 0x04, "40GBASE-SR4" },
+ { 0x02, "40GBASE-LR4" },
+ { 0x01, "40G Active Cable" },
+ { 0, NULL }
+};
+
+const char *
+find_value(struct _nv *x, int value)
+{
+ for (; x->n != NULL; x++)
+ if (x->v == value)
+ return (x->n);
+ return (NULL);
+}
+
+const char *
+find_zero_bit(struct _nv *x, int value, int sz)
+{
+ int v, m;
+ const char *s;
+
+ v = 1;
+ for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) {
+ if ((value & v) == 0)
+ continue;
+ if ((s = find_value(x, value & v)) != NULL) {
+ value &= ~v;
+ return (s);
+ }
+ }
+
+ return (NULL);
+}
+
+static void
+convert_sff_identifier(char *buf, size_t size, uint8_t value)
+{
+ const char *x;
+
+ x = NULL;
+ if (value <= SFF_8024_ID_LAST)
+ x = sff_8024_id[value];
+ else {
+ if (value > 0x80)
+ x = "Vendor specific";
+ else
+ x = "Reserved";
+ }
+
+ snprintf(buf, size, "%s", x);
+}
+
+static void
+convert_sff_connector(char *buf, size_t size, uint8_t value)
+{
+ const char *x;
+
+ if ((x = find_value(conn, value)) == NULL) {
+ if (value >= 0x0D && value <= 0x1F)
+ x = "Unallocated";
+ else if (value >= 0x24 && value <= 0x7F)
+ x = "Unallocated";
+ else
+ x = "Vendor specific";
+ }
+
+ snprintf(buf, size, "%s", x);
+}
+
+static void
+get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ ii->f(ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&data);
+ convert_sff_identifier(buf, size, data);
+}
+
+static void
+get_sfp_connector(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ ii->f(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, (caddr_t)&data);
+ convert_sff_connector(buf, size, data);
+}
+
+static void
+get_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ ii->f(ii, SFF_8436_BASE, SFF_8436_ID, 1, (caddr_t)&data);
+ convert_sff_identifier(buf, size, data);
+}
+
+static void
+get_qsfp_connector(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ ii->f(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, (caddr_t)&data);
+ convert_sff_connector(buf, size, data);
+}
+
+static void
+printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[12];
+ const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed;
+
+ tech_class = NULL;
+ tech_len = NULL;
+ tech_tech = NULL;
+ tech_media = NULL;
+ tech_speed = NULL;
+
+ /* Read bytes 3-10 at once */
+ ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]);
+
+ /* Check 10G ethernet first */
+ tech_class = find_zero_bit(eth_10g, xbuf[3], 1);
+ if (tech_class == NULL) {
+ /* No match. Try 1G */
+ tech_class = find_zero_bit(eth_compat, xbuf[6], 1);
+ }
+
+ tech_len = find_zero_bit(fc_len, xbuf[7], 1);
+ tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2);
+ tech_media = find_zero_bit(fc_media, xbuf[9], 1);
+ tech_speed = find_zero_bit(fc_speed, xbuf[10], 1);
+
+ printf("Class: %s\n", tech_class);
+ printf("Length: %s\n", tech_len);
+ printf("Tech: %s\n", tech_tech);
+ printf("Media: %s\n", tech_media);
+ printf("Speed: %s\n", tech_speed);
+}
+
+static void
+get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
+{
+ const char *tech_class;
+ uint8_t code;
+
+ unsigned char qbuf[8];
+ ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (caddr_t)qbuf);
+
+ /* Check 10G Ethernet/IB first */
+ ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, (caddr_t)&code);
+ tech_class = find_zero_bit(eth_10g, code, 1);
+ if (tech_class == NULL) {
+ /* No match. Try Ethernet 1G */
+ ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
+ 1, (caddr_t)&code);
+ tech_class = find_zero_bit(eth_compat, code, 1);
+ }
+
+ if (tech_class == NULL)
+ tech_class = "Unknown";
+
+ snprintf(buf, size, "%s", tech_class);
+}
+
+static void
+get_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
+{
+ const char *tech_class;
+ uint8_t code;
+
+ /* Check 10/40G Ethernet class only */
+ ii->f(ii, SFF_8436_BASE, SFF_8436_CODE_E1040G, 1, (caddr_t)&code);
+ tech_class = find_zero_bit(eth_1040g, code, 1);
+ if (tech_class == NULL)
+ tech_class = "Unknown";
+
+ snprintf(buf, size, "%s", tech_class);
+}
+
+/*
+ * Print SFF-8472/SFF-8436 string to supplied buffer.
+ * All (vendor-specific) strings are padded right with '0x20'.
+ */
+static void
+convert_sff_name(char *buf, size_t size, char *xbuf)
+{
+ char *p;
+
+ for (p = &xbuf[16]; *(p - 1) == 0x20; p--)
+ ;
+ *p = '\0';
+ snprintf(buf, size, "%s", xbuf);
+}
+
+static void
+convert_sff_date(char *buf, size_t size, char *xbuf)
+{
+
+ snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1],
+ xbuf[2], xbuf[3], xbuf[4], xbuf[5]);
+}
+
+static void
+get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[6];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ /* Date code, see Table 3.8 for description */
+ ii->f(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, xbuf);
+ convert_sff_date(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[6];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, xbuf);
+ convert_sff_date(buf, size, xbuf);
+}
+
+static void
+print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[80];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ if (ii->qsfp != 0) {
+ get_qsfp_vendor_name(ii, xbuf, 20);
+ get_qsfp_vendor_pn(ii, &xbuf[20], 20);
+ get_qsfp_vendor_sn(ii, &xbuf[40], 20);
+ get_qsfp_vendor_date(ii, &xbuf[60], 20);
+ } else {
+ get_sfp_vendor_name(ii, xbuf, 20);
+ get_sfp_vendor_pn(ii, &xbuf[20], 20);
+ get_sfp_vendor_sn(ii, &xbuf[40], 20);
+ get_sfp_vendor_date(ii, &xbuf[60], 20);
+ }
+
+ snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s",
+ xbuf, &xbuf[20], &xbuf[40], &xbuf[60]);
+}
+
+/*
+ * Converts internal templerature (SFF-8472, SFF-8436)
+ * 16-bit unsigned value to human-readable representation:
+ *
+ * Internally measured Module temperature are represented
+ * as a 16-bit signed twos complement value in increments of
+ * 1/256 degrees Celsius, yielding a total range of –128C to +128C
+ * that is considered valid between –40 and +125C.
+ *
+ */
+static void
+convert_sff_temp(char *buf, size_t size, char *xbuf)
+{
+ double d;
+
+ d = (double)(int8_t)xbuf[0];
+ d += (double)(uint8_t)xbuf[1] / 256;
+
+ snprintf(buf, size, "%.2f C", d);
+}
+
+/*
+ * Retrieves supplied voltage (SFF-8472, SFF-8436).
+ * 16-bit usigned value, treated as range 0..+6.55 Volts
+ */
+static void
+convert_sff_voltage(char *buf, size_t size, char *xbuf)
+{
+ double d;
+
+ d = (double)(((uint8_t)xbuf[0] << 8) | (uint8_t)xbuf[1]);
+ snprintf(buf, size, "%.2f Volts", d / 10000);
+}
+
+/*
+ * Converts value in @xbuf to both milliwats and dBm
+ * human representation.
+ */
+static void
+convert_sff_power(struct i2c_info *ii, char *buf, size_t size, char *xbuf)
+{
+ uint16_t mW;
+ double dbm;
+
+ mW = ((uint8_t)xbuf[0] << 8) + (uint8_t)xbuf[1];
+
+ /* Convert mw to dbm */
+ dbm = 10.0 * log10(1.0 * mW / 10000);
+
+ /*
+ * Assume internally-calibrated data.
+ * This is always true for SFF-8346, and explicitly
+ * checked for SFF-8472.
+ */
+
+ /* Table 3.9, bit 5 is set, internally calibrated */
+ snprintf(buf, size, "%d.%02d mW (%.2f dBm)",
+ mW / 10000, (mW % 10000) / 100, dbm);
+}
+
+static void
+get_sfp_temp(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf);
+ convert_sff_temp(buf, size, xbuf);
+}
+
+static void
+get_sfp_voltage(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf);
+ convert_sff_voltage(buf, size, xbuf);
+}
+
+static void
+get_qsfp_temp(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf);
+ convert_sff_temp(buf, size, xbuf);
+}
+
+static void
+get_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf);
+ convert_sff_voltage(buf, size, xbuf);
+}
+
+static void
+get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan - 1) * 2, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
+{
+ char xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ ii->f(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan -1) * 2, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+/* Generic handler */
+static int
+read_i2c_generic(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
+ caddr_t buf)
+{
+ struct ifi2creq req;
+ int i, l;
+
+ if (ii->error != 0)
+ return (ii->error);
+
+ ii->ifr->ifr_data = (caddr_t)&req;
+
+ i = 0;
+ l = 0;
+ memset(&req, 0, sizeof(req));
+ req.dev_addr = addr;
+ req.offset = off;
+ req.len = len;
+
+ while (len > 0) {
+ l = (len > sizeof(req.data)) ? sizeof(req.data) : len;
+ req.len = l;
+ if (ioctl(ii->s, SIOCGI2C, ii->ifr) != 0) {
+ ii->error = errno;
+ return (errno);
+ }
+
+ memcpy(&buf[i], req.data, l);
+ len -= l;
+ i += l;
+ req.offset += l;
+ }
+
+ return (0);
+}
+
+static void
+dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len)
+{
+ unsigned char buf[16];
+ int i, read;
+
+ while (len > 0) {
+ memset(buf, 0, sizeof(buf));
+ read = (len > sizeof(buf)) ? sizeof(buf) : len;
+ ii->f(ii, addr, off, read, buf);
+ if (ii->error != 0) {
+ fprintf(stderr, "Error reading i2c info\n");
+ return;
+ }
+
+ printf("\t");
+ for (i = 0; i < read; i++)
+ printf("%02X ", buf[i]);
+ printf("\n");
+ len -= read;
+ off += read;
+ }
+}
+
+static void
+print_qsfp_status(struct i2c_info *ii, int verbose)
+{
+ char buf[80], buf2[40], buf3[40];
+ uint8_t diag_type;
+ int i;
+
+ /* Read diagnostic monitoring type */
+ ii->f(ii, SFF_8436_BASE, SFF_8436_DIAG_TYPE, 1, (caddr_t)&diag_type);
+ if (ii->error != 0)
+ return;
+
+ /*
+ * Read monitoring data it is supplied.
+ * XXX: It is not exactly clear from standard
+ * how one can specify lack of measurements (passive cables case).
+ */
+ if (diag_type != 0)
+ ii->do_diag = 1;
+ ii->qsfp = 1;
+
+ /* Transceiver type */
+ get_qsfp_identifier(ii, buf, sizeof(buf));
+ get_qsfp_transceiver_class(ii, buf2, sizeof(buf2));
+ get_qsfp_connector(ii, buf3, sizeof(buf3));
+ if (ii->error == 0)
+ printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
+ print_sfp_vendor(ii, buf, sizeof(buf));
+ if (ii->error == 0)
+ printf("\t%s\n", buf);
+
+ /* Request current measurements if they are provided: */
+ if (ii->do_diag != 0) {
+ get_qsfp_temp(ii, buf, sizeof(buf));
+ get_qsfp_voltage(ii, buf2, sizeof(buf2));
+ printf("\tmodule temperature: %s voltage: %s\n", buf, buf2);
+ for (i = 1; i <= 4; i++) {
+ get_qsfp_rx_power(ii, buf, sizeof(buf), i);
+ get_qsfp_tx_power(ii, buf2, sizeof(buf2), i);
+ printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2);
+ }
+ }
+
+ if (verbose > 2) {
+ printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n");
+ dump_i2c_data(ii, SFF_8436_BASE, 128, 128);
+ printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n");
+ dump_i2c_data(ii, SFF_8436_BASE, 0, 82);
+ }
+}
+
+static void
+print_sfp_status(struct i2c_info *ii, int verbose)
+{
+ char buf[80], buf2[40], buf3[40];
+ uint8_t diag_type, flags;
+
+ /* Read diagnostic monitoring type */
+ ii->f(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
+ if (ii->error != 0)
+ return;
+
+ /*
+ * Read monitoring data IFF it is supplied AND is
+ * internally calibrated
+ */
+ flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
+ if ((diag_type & flags) == flags)
+ ii->do_diag = 1;
+
+ /* Transceiver type */
+ get_sfp_identifier(ii, buf, sizeof(buf));
+ get_sfp_transceiver_class(ii, buf2, sizeof(buf2));
+ get_sfp_connector(ii, buf3, sizeof(buf3));
+ if (ii->error == 0)
+ printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
+ print_sfp_vendor(ii, buf, sizeof(buf));
+ if (ii->error == 0)
+ printf("\t%s\n", buf);
+
+ if (verbose > 5)
+ printf_sfp_transceiver_descr(ii, buf, sizeof(buf));
+ /*
+ * Request current measurements iff they are provided:
+ */
+ if (ii->do_diag != 0) {
+ get_sfp_temp(ii, buf, sizeof(buf));
+ get_sfp_voltage(ii, buf2, sizeof(buf2));
+ printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2);
+ get_sfp_rx_power(ii, buf, sizeof(buf));
+ get_sfp_tx_power(ii, buf2, sizeof(buf2));
+ printf("\tRX: %s TX: %s\n", buf, buf2);
+ }
+
+ if (verbose > 2) {
+ printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n");
+ dump_i2c_data(ii, SFF_8472_BASE, 0, 128);
+ }
+}
+
+void
+sfp_status(int s, struct ifreq *ifr, int verbose)
+{
+ struct i2c_info ii;
+ uint8_t id_byte;
+
+ memset(&ii, 0, sizeof(ii));
+ /* Prepare necessary into to pass to NIC handler */
+ ii.s = s;
+ ii.ifr = ifr;
+ ii.f = read_i2c_generic;
+
+ /*
+ * Try to read byte 0 from i2c:
+ * Both SFF-8472 and SFF-8436 use it as
+ * 'identification byte'.
+ * Stop reading status on zero as value -
+ * this might happen in case of empty transceiver slot.
+ */
+ id_byte = 0;
+ ii.f(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte);
+ if (ii.error != 0 || id_byte == 0)
+ return;
+
+ switch (id_byte) {
+ case SFF_8024_ID_QSFP:
+ case SFF_8024_ID_QSFPPLUS:
+ print_qsfp_status(&ii, verbose);
+ break;
+ default:
+ print_sfp_status(&ii, verbose);
+ };
+}
+
diff --git a/sbin/init/init.c b/sbin/init/init.c
index 8583ba5..5ab3527 100644
--- a/sbin/init/init.c
+++ b/sbin/init/init.c
@@ -242,7 +242,7 @@ invalid:
* Note that this does NOT open a file...
* Does 'init' deserve its own facility number?
*/
- openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
+ openlog("init", LOG_CONS, LOG_AUTH);
/*
* Create an initial session.
diff --git a/sbin/ipf/Makefile.inc b/sbin/ipf/Makefile.inc
index b3efd6f..2d7d7b1 100644
--- a/sbin/ipf/Makefile.inc
+++ b/sbin/ipf/Makefile.inc
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <src.opts.mk>
+
WARNS?= 2
NO_WFORMAT=
NO_WARRAY_BOUNDS=
@@ -10,6 +12,12 @@ CFLAGS+= -I${.CURDIR}/../../../sys
CFLAGS+= -I${.CURDIR}/../../../sys/contrib/ipfilter
CFLAGS+= -DSTATETOP -D__UIO_EXPOSE
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DUSE_INET6
+.else
+CFLAGS+= -DNOINET6
+.endif
+
LIBIPF= ${.OBJDIR}/../libipf/libipf.a
DPADD+= ${LIBIPF} ${LIBKVM}
LDADD+= ${LIBIPF} -lkvm
diff --git a/sbin/ipf/ipf/Makefile b/sbin/ipf/ipf/Makefile
index 73888b2..c3938c6 100644
--- a/sbin/ipf/ipf/Makefile
+++ b/sbin/ipf/ipf/Makefile
@@ -39,6 +39,4 @@ DPADD+= ${LIBPCAP}
LDADD+= -lpcap
.endif
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/sbin/ipf/ipfstat/Makefile b/sbin/ipf/ipfstat/Makefile
index c2b422d..a33c5df 100644
--- a/sbin/ipf/ipfstat/Makefile
+++ b/sbin/ipf/ipfstat/Makefile
@@ -8,6 +8,4 @@ MAN= ipfstat.8
DPADD+= ${LIBCURSES}
LDADD+= -lcurses
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/sbin/ipf/ipftest/Makefile b/sbin/ipf/ipftest/Makefile
index 57f3c4e..32b074c 100644
--- a/sbin/ipf/ipftest/Makefile
+++ b/sbin/ipf/ipftest/Makefile
@@ -32,8 +32,6 @@ CLEANFILES+= ipnat.tab.c ipnat.tab.h
CLEANFILES+= ippool_y.c ippool_l.c
CLEANFILES+= ippool.tab.c ippool.tab.h
-NO_PIE= yes
-
ipnat_y.c: ipnat_y.y
${YACC} -b ipnat -d ${.ALLSRC}
sed -e 's/yy/ipnat_yy/g' \
diff --git a/sbin/ipf/ipmon/Makefile b/sbin/ipf/ipmon/Makefile
index 2ecfed1..3639f87 100644
--- a/sbin/ipf/ipmon/Makefile
+++ b/sbin/ipf/ipmon/Makefile
@@ -11,8 +11,6 @@ DPSRCS+= ${GENHDRS}
CLEANFILES+= ${GENHDRS} ipmon_y.c ipmon_l.c
-NO_PIE= yes
-
ipmon_y.c: ipmon_y.y
${YACC} -d ${.ALLSRC}
sed -e 's/yy/ipmon_yy/g' \
diff --git a/sbin/ipf/ipnat/Makefile b/sbin/ipf/ipnat/Makefile
index aafb014..1c017e1 100644
--- a/sbin/ipf/ipnat/Makefile
+++ b/sbin/ipf/ipnat/Makefile
@@ -11,8 +11,6 @@ DPSRCS+= ${GENHDRS}
CLEANFILES+= ${GENHDRS} ipnat_y.c ipnat_l.c
-NO_PIE= yes
-
ipnat_y.c: ipnat_y.y
${YACC} -d ${.ALLSRC}
sed -e 's/yy/ipnat_yy/g' \
diff --git a/sbin/ipf/ippool/Makefile b/sbin/ipf/ippool/Makefile
index bb7e9ce..6e3f85d 100644
--- a/sbin/ipf/ippool/Makefile
+++ b/sbin/ipf/ippool/Makefile
@@ -10,8 +10,6 @@ DPSRCS+= ${GENHDRS}
CLEANFILES+= ${GENHDRS} ippool_y.c ippool_l.c
-NO_PIE= yes
-
ippool_y.c: ippool_y.y
${YACC} -d ${.ALLSRC}
sed -e 's/yy/ippool_yy/g' \
diff --git a/sbin/ipf/ipresend/Makefile b/sbin/ipf/ipresend/Makefile
index 492451c..5e0ac15 100644
--- a/sbin/ipf/ipresend/Makefile
+++ b/sbin/ipf/ipresend/Makefile
@@ -4,8 +4,6 @@ PROG= ipresend
SRCS= ipresend.c ip.c resend.c sbpf.c sock.c 44arp.c
MAN= ipresend.1
-NO_PIE= yes
-
.PATH: ${.CURDIR}/../../../contrib/ipfilter/ipsend
.include <bsd.prog.mk>
diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile
index de27e3e..9eb4511 100644
--- a/sbin/ipfw/Makefile
+++ b/sbin/ipfw/Makefile
@@ -3,7 +3,7 @@
.include <src.opts.mk>
PROG= ipfw
-SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c
+SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c tables.c
WARNS?= 2
.if ${MK_PF} != "no"
diff --git a/sbin/ipfw/altq.c b/sbin/ipfw/altq.c
index 8dced11..8398ab6 100644
--- a/sbin/ipfw/altq.c
+++ b/sbin/ipfw/altq.c
@@ -137,15 +137,15 @@ altq_qid_to_name(u_int32_t qid)
}
void
-print_altq_cmd(ipfw_insn_altq *altqptr)
+print_altq_cmd(struct buf_pr *bp, ipfw_insn_altq *altqptr)
{
if (altqptr) {
const char *qname;
qname = altq_qid_to_name(altqptr->qid);
if (qname == NULL)
- printf(" altq ?<%u>", altqptr->qid);
+ bprintf(bp, " altq ?<%u>", altqptr->qid);
else
- printf(" altq %s", qname);
+ bprintf(bp, " altq %s", qname);
}
}
diff --git a/sbin/ipfw/dummynet.c b/sbin/ipfw/dummynet.c
index cb62853..dc95a19 100644
--- a/sbin/ipfw/dummynet.c
+++ b/sbin/ipfw/dummynet.c
@@ -174,48 +174,44 @@ print_header(struct ipfw_flow_id *id)
}
static void
-list_flow(struct dn_flow *ni, int *print)
+list_flow(struct buf_pr *bp, struct dn_flow *ni)
{
char buff[255];
struct protoent *pe = NULL;
struct in_addr ina;
struct ipfw_flow_id *id = &ni->fid;
- if (*print) {
- print_header(&ni->fid);
- *print = 0;
- }
pe = getprotobynumber(id->proto);
/* XXX: Should check for IPv4 flows */
- printf("%3u%c", (ni->oid.id) & 0xff,
+ bprintf(bp, "%3u%c", (ni->oid.id) & 0xff,
id->extra ? '*' : ' ');
if (!IS_IP6_FLOW_ID(id)) {
if (pe)
- printf("%-4s ", pe->p_name);
+ bprintf(bp, "%-4s ", pe->p_name);
else
- printf("%4u ", id->proto);
+ bprintf(bp, "%4u ", id->proto);
ina.s_addr = htonl(id->src_ip);
- printf("%15s/%-5d ",
+ bprintf(bp, "%15s/%-5d ",
inet_ntoa(ina), id->src_port);
ina.s_addr = htonl(id->dst_ip);
- printf("%15s/%-5d ",
+ bprintf(bp, "%15s/%-5d ",
inet_ntoa(ina), id->dst_port);
} else {
/* Print IPv6 flows */
if (pe != NULL)
- printf("%9s ", pe->p_name);
+ bprintf(bp, "%9s ", pe->p_name);
else
- printf("%9u ", id->proto);
- printf("%7d %39s/%-5d ", id->flow_id6,
+ bprintf(bp, "%9u ", id->proto);
+ bprintf(bp, "%7d %39s/%-5d ", id->flow_id6,
inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)),
id->src_port);
- printf(" %39s/%-5d ",
+ bprintf(bp, " %39s/%-5d ",
inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),
id->dst_port);
}
- pr_u64(&ni->tot_pkts, 4);
- pr_u64(&ni->tot_bytes, 8);
- printf("%2u %4u %3u\n",
+ pr_u64(bp, &ni->tot_pkts, 4);
+ pr_u64(bp, &ni->tot_bytes, 8);
+ bprintf(bp, "%2u %4u %3u",
ni->length, ni->len_bytes, ni->drops);
}
@@ -303,8 +299,10 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
{
char buf[160]; /* pending buffer */
int toPrint = 1; /* print header */
+ struct buf_pr bp;
buf[0] = '\0';
+ bp_alloc(&bp, 4096);
for (; oid != end; oid = O_NEXT(oid, oid->len)) {
if (oid->len < sizeof(*oid))
errx(1, "invalid oid len %d\n", oid->len);
@@ -346,7 +344,12 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
break;
case DN_FLOW:
- list_flow((struct dn_flow *)oid, &toPrint);
+ if (toPrint != 0) {
+ print_header(&((struct dn_flow *)oid)->fid);
+ toPrint = 0;
+ }
+ list_flow(&bp, (struct dn_flow *)oid);
+ printf("%s\n", bp.buf);
break;
case DN_LINK: {
@@ -384,6 +387,8 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
}
flush_buf(buf); // XXX does it really go here ?
}
+
+ bp_free(&bp);
}
/*
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 5b56b39..0c6edb2 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 31, 2014
+.Dd Aug 13, 2014
.Dt IPFW 8
.Os
.Sh NAME
@@ -48,17 +48,43 @@ in-kernel NAT.
.Brq Cm firewall | altq | one_pass | debug | verbose | dyn_keepalive
.Ss LOOKUP TABLES
.Nm
-.Cm table Ar number Cm add Ar addr Ns Oo / Ns Ar masklen Oc Op Ar value
+.Oo Cm set Ar N Oc Cm table Ar name Cm create Ar create-options
.Nm
-.Cm table Ar number Cm delete Ar addr Ns Op / Ns Ar masklen
+.Oo Cm set Ar N Oc Cm table Ar name Cm destroy
.Nm
-.Cm table
-.Brq Ar number | all
-.Cm flush
+.Oo Cm set Ar N Oc Cm table Ar name Cm modify Ar modify-options
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm swap Ar name
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm add Ar table-key Op Ar value
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm add Op Ar table-key Ar value ...
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm atomic add Op Ar table-key Ar value ...
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm delete Op Ar table-key ...
.Nm
-.Cm table
-.Brq Ar number | all
+.Oo Cm set Ar N Oc Cm table Ar name Cm lookup Ar addr
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm lock
+.Nm
+.Oo Cm set Ar N Oc Cm table Ar name Cm unlock
+.Nm
+.Oo Cm set Ar N Oc Cm table
+.Brq Ar name | all
.Cm list
+.Nm
+.Oo Cm set Ar N Oc Cm table
+.Brq Ar name | all
+.Cm info
+.Nm
+.Oo Cm set Ar N Oc Cm table
+.Brq Ar name | all
+.Cm detail
+.Nm
+.Oo Cm set Ar N Oc Cm table
+.Brq Ar name | all
+.Cm flush
.Ss DUMMYNET CONFIGURATION (TRAFFIC SHAPER AND PACKET SCHEDULER)
.Nm
.Brq Cm pipe | queue | sched
@@ -87,6 +113,13 @@ in-kernel NAT.
.Oc
.Oc
.Ar pathname
+.Ss INTERNAL DIAGNOSTICS
+.Nm
+.Cm internal iflist
+.Nm
+.Cm internal talist
+.Nm
+.Cm internal vlist
.Sh DESCRIPTION
The
.Nm
@@ -822,10 +855,11 @@ It is possible to use the
.Cm tablearg
keyword with a skipto for a
.Em computed
-skipto, but care should be used, as no destination caching
-is possible in this case so the rules are always walked to find it,
-starting from the
-.Cm skipto .
+skipto. Skipto may work either in O(log(N)) or in O(1) depending
+on amount of memory and/or sysctl variables.
+See the
+.Sx SYSCTL VARIABLES
+section for more details.
.It Cm call Ar number | tablearg
The current rule number is saved in the internal stack and
ruleset processing continues with the first rule numbered
@@ -1152,7 +1186,7 @@ with multiple addresses) is provided for convenience only and
its use is discouraged.
.It Ar addr : Oo Cm not Oc Bro
.Cm any | me | me6 |
-.Cm table Ns Pq Ar number Ns Op , Ns Ar value
+.Cm table Ns Pq Ar name Ns Op , Ns Ar value
.Ar | addr-list | addr-set
.Brc
.Bl -tag -width indent
@@ -1164,8 +1198,8 @@ matches any IP address configured on an interface in the system.
matches any IPv6 address configured on an interface in the system.
The address list is evaluated at the time the packet is
analysed.
-.It Cm table Ns Pq Ar number Ns Op , Ns Ar value
-Matches any IPv4 address for which an entry exists in the lookup table
+.It Cm table Ns Pq Ar name Ns Op , Ns Ar value
+Matches any IPv4 or IPv6 address for which an entry exists in the lookup table
.Ar number .
If an optional 32-bit unsigned
.Ar value
@@ -1359,6 +1393,19 @@ and IPsec encapsulated security payload headers
.It Cm fib Ar fibnum
Matches a packet that has been tagged to use
the given FIB (routing table) number.
+.It Cm flow Ar table Ns Pq Ar name Ns Op , Ns Ar value
+Search for the flow entry in lookup table
+.Ar name .
+If not found, the match fails.
+Otherwise, the match succeeds and
+.Cm tablearg
+is set to the value extracted from the table.
+.Pp
+This option can be useful to quickly dispatch traffic based on
+certain packet fields.
+See the
+.Sx LOOKUP TABLES
+section below for more information on lookup tables.
.It Cm flow-id Ar labels
Matches IPv6 packets containing any of the flow labels given in
.Ar labels .
@@ -1550,9 +1597,9 @@ of source and destination addresses and ports can be
specified.
Currently,
only IPv4 flows are supported.
-.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar N
+.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar name
Search an entry in lookup table
-.Ar N
+.Ar name
that matches the field specified as argument.
If not found, the match fails.
Otherwise, the match succeeds and
@@ -1616,13 +1663,19 @@ and they are always printed as hexadecimal (unless the
option is used, in which case symbolic resolution will be attempted).
.It Cm proto Ar protocol
Matches packets with the corresponding IP protocol.
-.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar table Ns Pq Ar number Ns Op , Ns Ar value | Ar ipno | Ar any
+.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar table Ns Po Ar name Ns Oo , Ns Ar value Oc Pc | Ar ipno | Ar any
Matches packets received, transmitted or going through,
respectively, the interface specified by exact name
.Po Ar ifX Pc ,
by device name
.Po Ar if* Pc ,
by IP address, or through some interface.
+Table
+.Ar name
+may be used to match interface by its kernel ifindex.
+See the
+.Sx LOOKUP TABLES
+section below for more information on lookup tables.
.Pp
The
.Cm via
@@ -1817,15 +1870,35 @@ connected networks instead of all source addresses.
.Sh LOOKUP TABLES
Lookup tables are useful to handle large sparse sets of
addresses or other search keys (e.g., ports, jail IDs, interface names).
-In the rest of this section we will use the term ``address''.
-There may be up to 65535 different lookup tables, numbered 0 to 65534.
+In the rest of this section we will use the term ``key''.
+Table name needs to match the following spec:
+.Ar table-name .
+Tables with the same name can be created in different
+.Ar sets .
+However, rule links to the tables in
+.Ar set 0
+by default.
+This behavior can be controlled by
+.Va net.inet.ip.fw.tables_sets
+variable.
+See the
+.Sx SETS OF RULES
+section for more information.
+There may be up to 65535 different lookup tables.
.Pp
+The following table types are supported:
+.Bl -tag -width indent
+.It Ar table-type : Ar addr | iface | number | flow
+.It Ar table-key : Ar addr Ns Oo / Ns Ar masklen Oc | iface-name | number | flow-spec
+.It Ar flow-spec : Ar flow-field Ns Op , Ns Ar flow-spec
+.It Ar flow-field : src-ip | proto | src-port | dst-ip | dst-port
+.It Cm addr
+matches IPv4 or IPv6 address.
Each entry is represented by an
.Ar addr Ns Op / Ns Ar masklen
and will match all addresses with base
.Ar addr
-(specified as an IPv4/IPv6 address, a hostname or an unsigned integer)
-and mask width of
+(specified as an IPv4/IPv6 address, or a hostname) and mask width of
.Ar masklen
bits.
If
@@ -1833,29 +1906,140 @@ If
is not specified, it defaults to 32 for IPv4 and 128 for IPv6.
When looking up an IP address in a table, the most specific
entry will match.
-Associated with each entry is a 32-bit unsigned
-.Ar value ,
-which can optionally be checked by a rule matching code.
-When adding an entry, if
-.Ar value
-is not specified, it defaults to 0.
-.Pp
-An entry can be added to a table
-.Pq Cm add ,
-or removed from a table
-.Pq Cm delete .
-A table can be examined
-.Pq Cm list
-or flushed
-.Pq Cm flush .
-.Pp
-Internally, each table is stored in a Radix tree, the same way as
-the routing table (see
-.Xr route 4 ) .
+.It Cm iface
+matches interface names.
+Each entry is represented by string treated as interface name.
+Wildcards are not supported.
+.It Cm number
+maches protocol ports, uids/gids or jail IDs.
+Each entry is represented by 32-bit unsigned integer.
+Ranges are not supported.
+.It Cm flow
+Matches packet fields specified by
+.Ar flow
+type suboptions with table entries.
+.El
+.Pp
+Tables require explicit creation via
+.Cm create
+before use.
+.Pp
+The following creation options are supported:
+.Bl -tag -width indent
+.It Ar create-options : Ar create-option | create-options
+.It Ar create-option : Cm type Ar table-type | Cm valtype Ar value-mask | Cm algo Ar algo-desc |
+.Cm limit Ar number | Cm locked
+.It Cm type
+Table key type.
+.It Cm valtype
+Table value mask.
+.It Cm algo
+Table algorithm to use (see below).
+.It Cm limit
+Maximum number of items that may be inserted into table.
+.It Cm locked
+Restrict any table modifications.
+.El
+.Pp
+Some of these options may be modified later via
+.Cm modify
+keyword.
+The following options can be changed:
+.Bl -tag -width indent
+.It Ar modify-options : Ar modify-option | modify-options
+.It Ar modify-option : Cm limit Ar number
+.It Cm limit
+Alter maximum number of items that may be inserted into table.
+.El
+.Pp
+Additionally, table can be locked or unlocked using
+.Cm lock
+or
+.Cm unlock
+commands.
+.Pp
+Tables of the same
+.Ar type
+can be swapped with each other using
+.Cm swap Ar name
+command.
+Swap may fail if tables limits are set and data exchange
+would result in limits hit.
+Operation is performed atomically.
+.Pp
+One or more entries can be added to a table at once using
+.Cm add
+command.
+Addition of all items are performed atomically.
+By default, error in addition of one entry does not influence
+addition of other entries. However, non-zero error code is returned
+in that case.
+Special
+.Cm atomic
+keyword may be specified before
+.Cm add
+to indicate all-or-none add request.
.Pp
-Lookup tables currently support only ports, jail IDs, IPv4/IPv6 addresses
-and interface names.
-Wildcards is not supported for interface names.
+One or more entries can be removed from a table at once using
+.Cm delete
+command.
+By default, error in removal of one entry does not influence
+removing of other entries. However, non-zero error code is returned
+in that case.
+.Pp
+It may be possible to check what entry will be found on particular
+.Ar table-key
+using
+.Cm lookup
+.Ae table-key
+command.
+This functionality is optional and may be unsupported in some algorithms.
+.Pp
+The following operations can be performed on
+.Ar one
+or
+.Cm all
+tables:
+.Bl -tag -width indent
+.It Cm list
+List all entries.
+.It Cm flush
+Removes all entries.
+.It Cm info
+Shows generic table information.
+.It Cm detail
+Shows generic table information and algo-specific data.
+.El
+.Pp
+The following lookup algorithms are supported:
+.Bl -tag -width indent
+.It Ar algo-desc : algo-name | "algo-name algo-data"
+.It Ar algo-name: Ar addr:radix | addr:hash | iface:array | number:array | flow:hash
+.It Cm addr:radix
+Separate Radix trees for IPv4 and IPv6, the same way as the routing table (see
+.Xr route 4 ) .
+Default choice for
+.Ar addr
+type.
+.It Cm addr:hash
+Separate auto-growing hashes for IPv4 and IPv6.
+Accepts entries with the same mask length specified initially via
+.Cm "addr:hash masks=/v4,/v6"
+algorithm creation options.
+Assume /32 and /128 masks by default.
+Search removes host bits (according to mask) from supplied address and checks
+resulting key in appropriate hash.
+Mostly optimized for /64 and byte-ranged IPv6 masks.
+.It Cm iface:array
+Array storing sorted indexes for entries which are presented in the system.
+Optimized for very fast lookup.
+.It Cm number:array
+Array storing sorted u32 numbers.
+.It Cm flow:hash
+Auto-growing hash storing flow entries.
+Search calculates hash on required packet fields and searches for matching
+entries in selected bucket.
+.El
.Pp
The
.Cm tablearg
@@ -1864,6 +2048,39 @@ the argument for a rule action, action parameter or rule option.
This can significantly reduce number of rules in some configurations.
If two tables are used in a rule, the result of the second (destination)
is used.
+.Pp
+Each record may hold one or more values according to
+.Ar value-mask .
+This mask is set on table creation via
+.Cm valtype
+option.
+The following value types are supported:
+.Bl -tag -width indent
+.It Ar value-mask : Ar value-type Ns Op , Ns Ar value-mask
+.It Ar value-type : Ar skipto | pipe | fib | nat | dscp | tag | divert |
+.Ar netgraph | limit | ipv4
+.It Cm skipto
+rule number to jump to.
+.It Cm pipe
+Pipe number to use.
+.It Cm fib
+fib number to match/set.
+.It Cm nat
+nat number to jump to.
+.It Cm dscp
+dscp value to match/set.
+.It Cm tag
+tag number to match/set.
+.It Cm divert
+port number to divert traffic to.
+.It Cm netgraph
+hook number to move packet to.
+.It Cm limit
+maximum number of connections.
+.It Cm ipv4
+IPv4 nexthop to fwd packets to.
+.El
+.Pp
The
.Cm tablearg
argument can be used with the following actions:
@@ -1873,32 +2090,34 @@ action parameters:
rule options:
.Cm limit, tagged.
.Pp
-When used with
-.Cm fwd
-it is possible to supply table entries with values
-that are in the form of IP addresses or hostnames.
-See the
-.Sx EXAMPLES
-Section for example usage of tables and the tablearg keyword.
-.Pp
When used with the
.Cm skipto
action, the user should be aware that the code will walk the ruleset
-up to a rule equal to, or past, the given number,
-and should therefore try keep the
-ruleset compact between the skipto and the target rules.
+up to a rule equal to, or past, the given number.
+.Pp
+See the
+.Sx EXAMPLES
+Section for example usage of tables and the tablearg keyword.
.Sh SETS OF RULES
-Each rule belongs to one of 32 different
+Each rule or table belongs to one of 32 different
.Em sets
, numbered 0 to 31.
Set 31 is reserved for the default rule.
.Pp
-By default, rules are put in set 0, unless you use the
+By default, rules or tables are put in set 0, unless you use the
.Cm set N
-attribute when entering a new rule.
+attribute when adding a new rule or table.
Sets can be individually and atomically enabled or disabled,
so this mechanism permits an easy way to store multiple configurations
of the firewall and quickly (and atomically) switch between them.
+.Pp
+By default, tables from set 0 are referenced when adding rule with
+table opcodes regardless of rule set.
+This behavior can be changed by setting
+.Va net.inet.ip.fw.tables_set
+variable to 1.
+Rule's set will then be used for table references.
+.Pp
The command to enable/disable sets is
.Bd -ragged -offset indent
.Nm
@@ -2968,6 +3187,22 @@ Controls whether bridged packets are passed to
.Nm .
Default is no.
.El
+.Sh INTERNAL DIAGNOSTICS
+There are some commands that may be useful to understand current state
+of certain subsystems inside kernel module.
+These commands provide debugging output which may change without notice.
+.Pp
+Currently the following commands are available as
+.Cm internal
+sub-options:
+.Bl -tag -width indent
+.It Cm iflist
+Lists all interface which are currently tracked by
+.Nm
+with their in-kernel status.
+.It Cm talist
+List all table lookup algorithms currently available.
+.El
.Sh EXAMPLES
There are far too many possible uses of
.Nm
@@ -3220,30 +3455,43 @@ Then we classify traffic using a single rule:
.Dl "ipfw pipe 1 config bw 1000Kbyte/s"
.Dl "ipfw pipe 4 config bw 4000Kbyte/s"
.Dl "..."
-.Dl "ipfw table 1 add 192.168.2.0/24 1"
-.Dl "ipfw table 1 add 192.168.0.0/27 4"
-.Dl "ipfw table 1 add 192.168.0.2 1"
+.Dl "ipfw table T1 create type addr"
+.Dl "ipfw table T1 add 192.168.2.0/24 1"
+.Dl "ipfw table T1 add 192.168.0.0/27 4"
+.Dl "ipfw table T1 add 192.168.0.2 1"
.Dl "..."
-.Dl "ipfw add pipe tablearg ip from table(1) to any"
+.Dl "ipfw add pipe tablearg ip from 'table(T1)' to any"
.Pp
Using the
.Cm fwd
action, the table entries may include hostnames and IP addresses.
.Pp
-.Dl "ipfw table 1 add 192.168.2.0/24 10.23.2.1"
-.Dl "ipfw table 1 add 192.168.0.0/27 router1.dmz"
+.Dl "ipfw table T2 create type addr ftype ip"
+.Dl "ipfw table T2 add 192.168.2.0/24 10.23.2.1"
+.Dl "ipfw table T21 add 192.168.0.0/27 router1.dmz"
.Dl "..."
.Dl "ipfw add 100 fwd tablearg ip from any to table(1)"
.Pp
In the following example per-interface firewall is created:
.Pp
-.Dl "ipfw table 10 add vlan20 12000"
-.Dl "ipfw table 10 add vlan30 13000"
-.Dl "ipfw table 20 add vlan20 22000"
-.Dl "ipfw table 20 add vlan30 23000"
+.Dl "ipfw table IN create type iface valtype skipto,fib"
+.Dl "ipfw table IN add vlan20 12000,12"
+.Dl "ipfw table IN add vlan30 13000,13"
+.Dl "ipfw table OUT create type iface valtype skipto"
+.Dl "ipfw table OUT add vlan20 22000"
+.Dl "ipfw table OUT add vlan30 23000"
+.Dl ".."
+.Dl "ipfw add 100 ipfw setfib tablearg ip from any to any recv 'table(IN)' in"
+.Dl "ipfw add 200 ipfw skipto tablearg ip from any to any recv 'table(IN)' in"
+.Dl "ipfw add 300 ipfw skipto tablearg ip from any to any xmit 'table(OUT)' out"
+.Pp
+The following example illustrate usage of flow tables:
+.Pp
+.Dl "ipfw table fl create type flow:flow:src-ip,proto,dst-ip,dst-port"
+.Dl "ipfw table fl add 2a02:6b8:77::88,tcp,2a02:6b8:77::99,80 11"
+.Dl "ipfw table fl add 10.0.0.1,udp,10.0.0.2,53 12"
.Dl ".."
-.Dl "ipfw add 100 ipfw skipto tablearg ip from any to any recv 'table(10)' in"
-.Dl "ipfw add 200 ipfw skipto tablearg ip from any to any xmit 'table(10)' out"
+.Dl "ipfw add 100 allow ip from any to any flow 'table(fl,11)' recv ix0"
.Ss SETS OF RULES
To add a set of rules atomically, e.g.\& set 18:
.Pp
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 25d6afd..2c98466 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -35,6 +35,7 @@
#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
@@ -56,16 +57,22 @@
struct cmdline_opts co; /* global options */
+struct format_opts {
+ int bcwidth;
+ int pcwidth;
+ int show_counters;
+ uint32_t set_mask; /* enabled sets mask */
+ uint32_t flags; /* request flags */
+ uint32_t first; /* first rule to request */
+ uint32_t last; /* last rule to request */
+ uint32_t dcnt; /* number of dynamic states */
+ ipfw_obj_ctlv *tstate; /* table state data */
+};
+
int resvd_set_number = RESVD_SET;
int ipfw_socket = -1;
-uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
-
-#ifndef s6_addr32
-#define s6_addr32 __u6_addr.__u6_addr32
-#endif
-
#define CHECK_LENGTH(v, len) do { \
if ((v) < (len)) \
errx(EX_DATAERR, "Rule too long"); \
@@ -86,7 +93,7 @@ uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
if (!av[0]) \
errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \
if (_substrcmp(*av, "tablearg") == 0) { \
- arg = IP_FW_TABLEARG; \
+ arg = IP_FW_TARG; \
break; \
} \
\
@@ -104,24 +111,13 @@ uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \
match_value(s_x, tok), min, max, *av); \
\
- if (_xval == IP_FW_TABLEARG) \
+ if (_xval == IP_FW_TARG) \
errx(EX_DATAERR, "%s: illegal argument value: %s", \
match_value(s_x, tok), *av); \
arg = _xval; \
} \
} while (0)
-static void
-PRINT_UINT_ARG(const char *str, uint32_t arg)
-{
- if (str != NULL)
- printf("%s",str);
- if (arg == IP_FW_TABLEARG)
- printf("tablearg");
- else
- printf("%u", arg);
-}
-
static struct _s_x f_tcpflags[] = {
{ "syn", TH_SYN },
{ "fin", TH_FIN },
@@ -169,7 +165,7 @@ static struct _s_x f_iptos[] = {
{ NULL, 0 }
};
-static struct _s_x f_ipdscp[] = {
+struct _s_x f_ipdscp[] = {
{ "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */
{ "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */
{ "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */
@@ -357,6 +353,7 @@ static struct _s_x rule_options[] = {
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
{ "lookup", TOK_LOOKUP},
+ { "flow", TOK_FLOW},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -370,6 +367,103 @@ static struct _s_x rule_options[] = {
{ NULL, 0 } /* terminator */
};
+void bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg);
+static int ipfw_get_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader **pcfg, size_t *psize);
+static int ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader *cfg, size_t sz, int ac, char **av);
+static void ipfw_list_tifaces(void);
+
+/*
+ * Simple string buffer API.
+ * Used to simplify buffer passing between function and for
+ * transparent overrun handling.
+ */
+
+/*
+ * Allocates new buffer of given size @sz.
+ *
+ * Returns 0 on success.
+ */
+int
+bp_alloc(struct buf_pr *b, size_t size)
+{
+ memset(b, 0, sizeof(struct buf_pr));
+
+ if ((b->buf = calloc(1, size)) == NULL)
+ return (ENOMEM);
+
+ b->ptr = b->buf;
+ b->size = size;
+ b->avail = b->size;
+
+ return (0);
+}
+
+void
+bp_free(struct buf_pr *b)
+{
+
+ free(b->buf);
+}
+
+/*
+ * Flushes buffer so new writer start from beginning.
+ */
+void
+bp_flush(struct buf_pr *b)
+{
+
+ b->ptr = b->buf;
+ b->avail = b->size;
+}
+
+/*
+ * Print message specified by @format and args.
+ * Automatically manage buffer space and transparently handle
+ * buffer overruns.
+ *
+ * Returns number of bytes that should have been printed.
+ */
+int
+bprintf(struct buf_pr *b, char *format, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, format);
+
+ i = vsnprintf(b->ptr, b->avail, format, args);
+ va_end(args);
+
+ if (i > b->avail || i < 0) {
+ /* Overflow or print error */
+ b->avail = 0;
+ } else {
+ b->ptr += i;
+ b->avail -= i;
+ }
+
+ b->needed += i;
+
+ return (i);
+}
+
+/*
+ * Special values printer for tablearg-aware opcodes.
+ */
+void
+bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg)
+{
+
+ if (str != NULL)
+ bprintf(bp, "%s", str);
+ if (arg == IP_FW_TARG)
+ bprintf(bp, "tablearg");
+ else
+ bprintf(bp, "%u", arg);
+}
+
/*
* Helper routine to print a possibly unaligned uint64_t on
* various platform. If width > 0, print the value with
@@ -377,7 +471,7 @@ static struct _s_x rule_options[] = {
* otherwise, return the required width.
*/
int
-pr_u64(uint64_t *pd, int width)
+pr_u64(struct buf_pr *b, uint64_t *pd, int width)
{
#ifdef TCC
#define U64_FMT "I64"
@@ -390,11 +484,12 @@ pr_u64(uint64_t *pd, int width)
bcopy (pd, &u, sizeof(u));
d = u;
return (width > 0) ?
- printf("%*" U64_FMT " ", width, d) :
+ bprintf(b, "%*" U64_FMT " ", width, d) :
snprintf(NULL, 0, "%" U64_FMT, d) ;
#undef U64_FMT
}
+
void *
safe_calloc(size_t number, size_t size)
{
@@ -416,6 +511,26 @@ safe_realloc(void *ptr, size_t size)
}
/*
+ * Compare things like interface or table names.
+ */
+int
+stringnum_cmp(const char *a, const char *b)
+{
+ int la, lb;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ if (la > lb)
+ return (1);
+ else if (la < lb)
+ return (-01);
+
+ return (strcmp(a, b));
+}
+
+
+/*
* conditionally runs the command.
* Selected options or negative -> getsockopt
*/
@@ -448,20 +563,18 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
}
/*
- * do_setcmd3 - pass ipfw control cmd to kernel
+ * do_set3 - pass ipfw control cmd to kernel
* @optname: option name
* @optval: pointer to option data
* @optlen: option length
*
- * Function encapsulates option value in IP_FW3 socket option
- * and calls setsockopt().
- * Function returns 0 on success or -1 otherwise.
+ * Assumes op3 header is already embedded.
+ * Calls setsockopt() with IP_FW3 as kernel-visible opcode.
+ * Returns 0 on success or errno otherwise.
*/
-static int
-do_setcmd3(int optname, void *optval, socklen_t optlen)
+int
+do_set3(int optname, ip_fw3_opheader *op3, uintptr_t optlen)
{
- socklen_t len;
- ip_fw3_opheader *op3;
if (co.test_only)
return (0);
@@ -471,14 +584,40 @@ do_setcmd3(int optname, void *optval, socklen_t optlen)
if (ipfw_socket < 0)
err(EX_UNAVAILABLE, "socket");
- len = sizeof(ip_fw3_opheader) + optlen;
- op3 = alloca(len);
- /* Zero reserved fields */
- memset(op3, 0, sizeof(ip_fw3_opheader));
- memcpy(op3 + 1, optval, optlen);
op3->opcode = optname;
- return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
+ return (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen));
+}
+
+/*
+ * do_get3 - pass ipfw control cmd to kernel
+ * @optname: option name
+ * @optval: pointer to option data
+ * @optlen: pointer to option length
+ *
+ * Assumes op3 header is already embedded.
+ * Calls getsockopt() with IP_FW3 as kernel-visible opcode.
+ * Returns 0 on success or errno otherwise.
+ */
+int
+do_get3(int optname, ip_fw3_opheader *op3, size_t *optlen)
+{
+ int error;
+
+ if (co.test_only)
+ return (0);
+
+ if (ipfw_socket == -1)
+ ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (ipfw_socket < 0)
+ err(EX_UNAVAILABLE, "socket");
+
+ op3->opcode = optname;
+
+ error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3,
+ (socklen_t *)optlen);
+
+ return (error);
}
/**
@@ -494,7 +633,38 @@ match_token(struct _s_x *table, char *string)
for (pt = table ; i && pt->s != NULL ; pt++)
if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
return pt->x;
- return -1;
+ return (-1);
+}
+
+/**
+ * match_token takes a table and a string, returns the value associated
+ * with the string for the best match.
+ *
+ * Returns:
+ * value from @table for matched records
+ * -1 for non-matched records
+ * -2 if more than one records match @string.
+ */
+int
+match_token_relaxed(struct _s_x *table, char *string)
+{
+ struct _s_x *pt, *m;
+ int i, c;
+
+ i = strlen(string);
+ c = 0;
+
+ for (pt = table ; i != 0 && pt->s != NULL ; pt++) {
+ if (strncmp(pt->s, string, i) != 0)
+ continue;
+ m = pt;
+ c++;
+ }
+
+ if (c == 1)
+ return (m->x);
+
+ return (c > 0 ? -2: -1);
}
/**
@@ -510,6 +680,78 @@ match_value(struct _s_x *p, int value)
return NULL;
}
+size_t
+concat_tokens(char *buf, size_t bufsize, struct _s_x *table, char *delimiter)
+{
+ struct _s_x *pt;
+ int l;
+ size_t sz;
+
+ for (sz = 0, pt = table ; pt->s != NULL; pt++) {
+ l = snprintf(buf + sz, bufsize - sz, "%s%s",
+ (sz == 0) ? "" : delimiter, pt->s);
+ sz += l;
+ bufsize += l;
+ if (sz > bufsize)
+ return (bufsize);
+ }
+
+ return (sz);
+}
+
+/*
+ * helper function to process a set of flags and set bits in the
+ * appropriate masks.
+ */
+int
+fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+ uint32_t *clear)
+{
+ char *q; /* points to the separator */
+ int val;
+ uint32_t *which; /* mask we are working on */
+
+ while (p && *p) {
+ if (*p == '!') {
+ p++;
+ which = clear;
+ } else
+ which = set;
+ q = strchr(p, ',');
+ if (q)
+ *q++ = '\0';
+ val = match_token(flags, p);
+ if (val <= 0) {
+ if (e != NULL)
+ *e = p;
+ return (-1);
+ }
+ *which |= (uint32_t)val;
+ p = q;
+ }
+ return (0);
+}
+
+void
+print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set)
+{
+ char const *comma = "";
+ int i, l;
+
+ for (i = 0; list[i].x != 0; i++) {
+ if ((set & list[i].x) == 0)
+ continue;
+
+ set &= ~list[i].x;
+ l = snprintf(buf, sz, "%s%s", comma, list[i].s);
+ if (l >= sz)
+ return;
+ comma = ",";
+ buf += l;
+ sz -=l;
+ }
+}
+
/*
* _substrcmp takes two strings and returns 1 if they do not match,
* and 0 if they match exactly or the first string is a sub-string
@@ -564,16 +806,16 @@ _substrcmp2(const char *str1, const char* str2, const char* str3)
* prints one port, symbolic or numeric
*/
static void
-print_port(int proto, uint16_t port)
+print_port(struct buf_pr *bp, int proto, uint16_t port)
{
if (proto == IPPROTO_ETHERTYPE) {
char const *s;
if (co.do_resolv && (s = match_value(ether_types, port)) )
- printf("%s", s);
+ bprintf(bp, "%s", s);
else
- printf("0x%04x", port);
+ bprintf(bp, "0x%04x", port);
} else {
struct servent *se = NULL;
if (co.do_resolv) {
@@ -582,9 +824,9 @@ print_port(int proto, uint16_t port)
se = getservbyport(htons(port), pe ? pe->p_name : NULL);
}
if (se)
- printf("%s", se->s_name);
+ bprintf(bp, "%s", se->s_name);
else
- printf("%d", port);
+ bprintf(bp, "%d", port);
}
}
@@ -606,7 +848,7 @@ static struct _s_x _port_name[] = {
* XXX todo: add support for mask.
*/
static void
-print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
+print_newports(struct buf_pr *bp, ipfw_insn_u16 *cmd, int proto, int opcode)
{
uint16_t *p = cmd->ports;
int i;
@@ -616,15 +858,15 @@ print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
sep = match_value(_port_name, opcode);
if (sep == NULL)
sep = "???";
- printf (" %s", sep);
+ bprintf(bp, " %s", sep);
}
sep = " ";
for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
- printf("%s", sep);
- print_port(proto, p[0]);
+ bprintf(bp, "%s", sep);
+ print_port(bp, proto, p[0]);
if (p[0] != p[1]) {
- printf("-");
- print_port(proto, p[1]);
+ bprintf(bp, "-");
+ print_port(bp, proto, p[1]);
}
sep = ",";
}
@@ -824,14 +1066,14 @@ fill_reject_code(u_short *codep, char *str)
}
static void
-print_reject_code(uint16_t code)
+print_reject_code(struct buf_pr *bp, uint16_t code)
{
- char const *s = match_value(icmpcodes, code);
+ char const *s;
- if (s != NULL)
- printf("unreach %s", s);
+ if ((s = match_value(icmpcodes, code)) != NULL)
+ bprintf(bp, "unreach %s", s);
else
- printf("unreach %u", code);
+ bprintf(bp, "unreach %u", code);
}
/*
@@ -864,7 +1106,8 @@ contigmask(uint8_t *p, int len)
* There is a specialized check for f_tcpflags.
*/
static void
-print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
+print_flags(struct buf_pr *bp, char const *name, ipfw_insn *cmd,
+ struct _s_x *list)
{
char const *comma = "";
int i;
@@ -872,34 +1115,38 @@ print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
uint8_t clear = (cmd->arg1 >> 8) & 0xff;
if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
- printf(" setup");
+ bprintf(bp, " setup");
return;
}
- printf(" %s ", name);
+ bprintf(bp, " %s ", name);
for (i=0; list[i].x != 0; i++) {
if (set & list[i].x) {
set &= ~list[i].x;
- printf("%s%s", comma, list[i].s);
+ bprintf(bp, "%s%s", comma, list[i].s);
comma = ",";
}
if (clear & list[i].x) {
clear &= ~list[i].x;
- printf("%s!%s", comma, list[i].s);
+ bprintf(bp, "%s!%s", comma, list[i].s);
comma = ",";
}
}
}
+
/*
* Print the ip address contained in a command.
*/
static void
-print_ip(ipfw_insn_ip *cmd, char const *s)
+print_ip(struct buf_pr *bp, struct format_opts *fo, ipfw_insn_ip *cmd,
+ char const *s)
{
struct hostent *he = NULL;
+ struct in_addr *ia;
uint32_t len = F_LEN((ipfw_insn *)cmd);
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
+ char *t;
if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
uint32_t d = a[1];
@@ -907,22 +1154,24 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
arg = match_value(rule_options, lookup_key[d]);
- printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "",
- arg, cmd->o.arg1);
+ t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
+ bprintf(bp, "%s lookup %s %s", cmd->o.len & F_NOT ? " not": "",
+ arg, t);
return;
}
- printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
+ bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s);
if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
- printf("me");
+ bprintf(bp, "me");
return;
}
if (cmd->o.opcode == O_IP_SRC_LOOKUP ||
cmd->o.opcode == O_IP_DST_LOOKUP) {
- printf("table(%u", ((ipfw_insn *)cmd)->arg1);
+ t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
+ bprintf(bp, "table(%s", t);
if (len == F_INSN_SIZE(ipfw_insn_u32))
- printf(",%u", *a);
- printf(")");
+ bprintf(bp, ",%u", *a);
+ bprintf(bp, ")");
return;
}
if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {
@@ -933,7 +1182,7 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
x = cmd->o.arg1 - 1;
x = htonl( ~x );
cmd->addr.s_addr = htonl(cmd->addr.s_addr);
- printf("%s/%d", inet_ntoa(cmd->addr),
+ bprintf(bp, "%s/%d", inet_ntoa(cmd->addr),
contigmask((uint8_t *)&x, 32));
x = cmd->addr.s_addr = htonl(cmd->addr.s_addr);
x &= 0xff; /* base */
@@ -948,14 +1197,14 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
for (j=i+1; j < cmd->o.arg1; j++)
if (!(map[ j/32] & (1<<(j & 31))))
break;
- printf("%c%d", comma, i+x);
+ bprintf(bp, "%c%d", comma, i+x);
if (j>i+2) { /* range has at least 3 elements */
- printf("-%d", j-1+x);
+ bprintf(bp, "-%d", j-1+x);
i = j-1;
}
comma = ',';
}
- printf("}");
+ bprintf(bp, "}");
return;
}
/*
@@ -970,18 +1219,20 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
if (mb == 32 && co.do_resolv)
he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET);
if (he != NULL) /* resolved to name */
- printf("%s", he->h_name);
+ bprintf(bp, "%s", he->h_name);
else if (mb == 0) /* any */
- printf("any");
+ bprintf(bp, "any");
else { /* numeric IP followed by some kind of mask */
- printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) );
- if (mb < 0)
- printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) );
- else if (mb < 32)
- printf("/%d", mb);
+ ia = (struct in_addr *)&a[0];
+ bprintf(bp, "%s", inet_ntoa(*ia));
+ if (mb < 0) {
+ ia = (struct in_addr *)&a[1];
+ bprintf(bp, ":%s", inet_ntoa(*ia));
+ } else if (mb < 32)
+ bprintf(bp, "/%d", mb);
}
if (len > 1)
- printf(",");
+ bprintf(bp, ",");
}
}
@@ -989,21 +1240,21 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
* prints a MAC address/mask pair
*/
static void
-print_mac(uint8_t *addr, uint8_t *mask)
+print_mac(struct buf_pr *bp, uint8_t *addr, uint8_t *mask)
{
int l = contigmask(mask, 48);
if (l == 0)
- printf(" any");
+ bprintf(bp, " any");
else {
- printf(" %02x:%02x:%02x:%02x:%02x:%02x",
+ bprintf(bp, " %02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
if (l == -1)
- printf("&%02x:%02x:%02x:%02x:%02x:%02x",
+ bprintf(bp, "&%02x:%02x:%02x:%02x:%02x:%02x",
mask[0], mask[1], mask[2],
mask[3], mask[4], mask[5]);
else if (l < 48)
- printf("/%d", l);
+ bprintf(bp, "/%d", l);
}
}
@@ -1032,38 +1283,38 @@ fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
}
static void
-print_icmptypes(ipfw_insn_u32 *cmd)
+print_icmptypes(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
int i;
char sep= ' ';
- printf(" icmptypes");
+ bprintf(bp, " icmptypes");
for (i = 0; i < 32; i++) {
if ( (cmd->d[0] & (1 << (i))) == 0)
continue;
- printf("%c%d", sep, i);
+ bprintf(bp, "%c%d", sep, i);
sep = ',';
}
}
static void
-print_dscp(ipfw_insn_u32 *cmd)
+print_dscp(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
int i, c;
uint32_t *v;
char sep= ' ';
const char *code;
- printf(" dscp");
+ bprintf(bp, " dscp");
i = 0;
c = 0;
v = cmd->d;
while (i < 64) {
if (*v & (1 << i)) {
if ((code = match_value(f_ipdscp, i)) != NULL)
- printf("%c%s", sep, code);
+ bprintf(bp, "%c%s", sep, code);
else
- printf("%c%d", sep, i);
+ bprintf(bp, "%c%d", sep, i);
sep = ',';
}
@@ -1094,7 +1345,7 @@ print_dscp(ipfw_insn_u32 *cmd)
#define HAVE_OPTIONS 0x8000
static void
-show_prerequisites(int *flags, int want, int cmd)
+show_prerequisites(struct buf_pr *bp, int *flags, int want, int cmd)
{
(void)cmd; /* UNUSED */
if (co.comment_only)
@@ -1105,22 +1356,23 @@ show_prerequisites(int *flags, int want, int cmd)
if ( !(*flags & HAVE_OPTIONS)) {
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) {
if ( (*flags & HAVE_PROTO4))
- printf(" ip4");
+ bprintf(bp, " ip4");
else if ( (*flags & HAVE_PROTO6))
- printf(" ip6");
+ bprintf(bp, " ip6");
else
- printf(" ip");
+ bprintf(bp, " ip");
}
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
- printf(" from any");
+ bprintf(bp, " from any");
if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
- printf(" to any");
+ bprintf(bp, " to any");
}
*flags |= want;
}
static void
-show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
+show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, struct ip_fw_rule *rule, struct ip_fw_bcounter *cntr)
{
static int twidth = 0;
int l;
@@ -1131,26 +1383,26 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */
int or_block = 0; /* we are in an or block */
- uint32_t set_disable;
+ uint32_t uval;
- bcopy(&rule->next_rule, &set_disable, sizeof(set_disable));
-
- if (set_disable & (1 << rule->set)) { /* disabled */
- if (!co.show_sets)
+ if ((fo->set_mask & (1 << rule->set)) == 0) {
+ /* disabled mask */
+ if (!co->show_sets)
return;
else
- printf("# DISABLED ");
+ bprintf(bp, "# DISABLED ");
}
- printf("%05u ", rule->rulenum);
+ bprintf(bp, "%05u ", rule->rulenum);
- if (pcwidth > 0 || bcwidth > 0) {
- pr_u64(&rule->pcnt, pcwidth);
- pr_u64(&rule->bcnt, bcwidth);
+ /* Print counters if enabled */
+ if (fo->pcwidth > 0 || fo->bcwidth > 0) {
+ pr_u64(bp, &cntr->pcnt, fo->pcwidth);
+ pr_u64(bp, &cntr->bcnt, fo->bcwidth);
}
- if (co.do_time == 2)
- printf("%10u ", rule->timestamp);
- else if (co.do_time == 1) {
+ if (co->do_time == 2)
+ bprintf(bp, "%10u ", cntr->timestamp);
+ else if (co->do_time == 1) {
char timestr[30];
time_t t = (time_t)0;
@@ -1159,19 +1411,19 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
*strchr(timestr, '\n') = '\0';
twidth = strlen(timestr);
}
- if (rule->timestamp) {
- t = _long_to_time(rule->timestamp);
+ if (cntr->timestamp > 0) {
+ t = _long_to_time(cntr->timestamp);
strcpy(timestr, ctime(&t));
*strchr(timestr, '\n') = '\0';
- printf("%s ", timestr);
+ bprintf(bp, "%s ", timestr);
} else {
- printf("%*s", twidth, " ");
+ bprintf(bp, "%*s", twidth, " ");
}
}
- if (co.show_sets)
- printf("set %d ", rule->set);
+ if (co->show_sets)
+ bprintf(bp, "set %d ", rule->set);
/*
* print the optional "match probability"
@@ -1183,7 +1435,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
double d = 1.0 * p->d[0];
d = (d / 0x7fffffff);
- printf("prob %f ", d);
+ bprintf(bp, "prob %f ", d);
}
}
@@ -1194,66 +1446,66 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
switch(cmd->opcode) {
case O_CHECK_STATE:
- printf("check-state");
+ bprintf(bp, "check-state");
/* avoid printing anything else */
flags = HAVE_PROTO | HAVE_SRCIP |
HAVE_DSTIP | HAVE_IP;
break;
case O_ACCEPT:
- printf("allow");
+ bprintf(bp, "allow");
break;
case O_COUNT:
- printf("count");
+ bprintf(bp, "count");
break;
case O_DENY:
- printf("deny");
+ bprintf(bp, "deny");
break;
case O_REJECT:
if (cmd->arg1 == ICMP_REJECT_RST)
- printf("reset");
+ bprintf(bp, "reset");
else if (cmd->arg1 == ICMP_UNREACH_HOST)
- printf("reject");
+ bprintf(bp, "reject");
else
- print_reject_code(cmd->arg1);
+ print_reject_code(bp, cmd->arg1);
break;
case O_UNREACH6:
if (cmd->arg1 == ICMP6_UNREACH_RST)
- printf("reset6");
+ bprintf(bp, "reset6");
else
print_unreach6_code(cmd->arg1);
break;
case O_SKIPTO:
- PRINT_UINT_ARG("skipto ", cmd->arg1);
+ bprint_uint_arg(bp, "skipto ", cmd->arg1);
break;
case O_PIPE:
- PRINT_UINT_ARG("pipe ", cmd->arg1);
+ bprint_uint_arg(bp, "pipe ", cmd->arg1);
break;
case O_QUEUE:
- PRINT_UINT_ARG("queue ", cmd->arg1);
+ bprint_uint_arg(bp, "queue ", cmd->arg1);
break;
case O_DIVERT:
- PRINT_UINT_ARG("divert ", cmd->arg1);
+ bprint_uint_arg(bp, "divert ", cmd->arg1);
break;
case O_TEE:
- PRINT_UINT_ARG("tee ", cmd->arg1);
+ bprint_uint_arg(bp, "tee ", cmd->arg1);
break;
case O_NETGRAPH:
- PRINT_UINT_ARG("netgraph ", cmd->arg1);
+ bprint_uint_arg(bp, "netgraph ", cmd->arg1);
break;
case O_NGTEE:
- PRINT_UINT_ARG("ngtee ", cmd->arg1);
+ bprint_uint_arg(bp, "ngtee ", cmd->arg1);
break;
case O_FORWARD_IP:
@@ -1261,12 +1513,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
if (s->sa.sin_addr.s_addr == INADDR_ANY) {
- printf("fwd tablearg");
+ bprintf(bp, "fwd tablearg");
} else {
- printf("fwd %s", inet_ntoa(s->sa.sin_addr));
+ bprintf(bp, "fwd %s",inet_ntoa(s->sa.sin_addr));
}
if (s->sa.sin_port)
- printf(",%d", s->sa.sin_port);
+ bprintf(bp, ",%d", s->sa.sin_port);
}
break;
@@ -1275,10 +1527,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
char buf[4 + INET6_ADDRSTRLEN + 1];
ipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd;
- printf("fwd %s", inet_ntop(AF_INET6, &s->sa.sin6_addr,
- buf, sizeof(buf)));
+ bprintf(bp, "fwd %s", inet_ntop(AF_INET6,
+ &s->sa.sin6_addr, buf, sizeof(buf)));
if (s->sa.sin6_port)
- printf(",%d", s->sa.sin6_port);
+ bprintf(bp, ",%d", s->sa.sin6_port);
}
break;
@@ -1296,64 +1548,69 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_NAT:
if (cmd->arg1 != 0)
- PRINT_UINT_ARG("nat ", cmd->arg1);
+ bprint_uint_arg(bp, "nat ", cmd->arg1);
else
- printf("nat global");
+ bprintf(bp, "nat global");
break;
case O_SETFIB:
- PRINT_UINT_ARG("setfib ", cmd->arg1);
+ bprint_uint_arg(bp, "setfib ", cmd->arg1 & 0x7FFF);
break;
case O_SETDSCP:
{
const char *code;
- if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
- printf("setdscp %s", code);
+ if (cmd->arg1 == IP_FW_TARG) {
+ bprint_uint_arg(bp, "setdscp ", cmd->arg1);
+ break;
+ }
+ uval = cmd->arg1 & 0x3F;
+ if ((code = match_value(f_ipdscp, uval)) != NULL)
+ bprintf(bp, "setdscp %s", code);
else
- PRINT_UINT_ARG("setdscp ", cmd->arg1);
+ bprint_uint_arg(bp, "setdscp ", uval);
}
break;
case O_REASS:
- printf("reass");
+ bprintf(bp, "reass");
break;
case O_CALLRETURN:
if (cmd->len & F_NOT)
- printf("return");
+ bprintf(bp, "return");
else
- PRINT_UINT_ARG("call ", cmd->arg1);
+ bprint_uint_arg(bp, "call ", cmd->arg1);
break;
default:
- printf("** unrecognized action %d len %d ",
+ bprintf(bp, "** unrecognized action %d len %d ",
cmd->opcode, cmd->len);
}
}
if (logptr) {
if (logptr->max_log > 0)
- printf(" log logamount %d", logptr->max_log);
+ bprintf(bp, " log logamount %d", logptr->max_log);
else
- printf(" log");
+ bprintf(bp, " log");
}
#ifndef NO_ALTQ
if (altqptr) {
- print_altq_cmd(altqptr);
+ print_altq_cmd(bp, altqptr);
}
#endif
if (tagptr) {
if (tagptr->len & F_NOT)
- PRINT_UINT_ARG(" untag ", tagptr->arg1);
+ bprint_uint_arg(bp, " untag ", tagptr->arg1);
else
- PRINT_UINT_ARG(" tag ", tagptr->arg1);
+ bprint_uint_arg(bp, " tag ", tagptr->arg1);
}
/*
* then print the body.
*/
- for (l = rule->act_ofs, cmd = rule->cmd ;
+ for (l = rule->act_ofs, cmd = rule->cmd;
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
if ((cmd->len & F_OR) || (cmd->len & F_NOT))
continue;
@@ -1365,31 +1622,31 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
break;
}
}
- if (rule->_pad & 1) { /* empty rules before options */
- if (!co.do_compact) {
- show_prerequisites(&flags, HAVE_PROTO, 0);
- printf(" from any to any");
+ if (rule->flags & IPFW_RULE_NOOPT) { /* empty rules before options */
+ if (!co->do_compact) {
+ show_prerequisites(bp, &flags, HAVE_PROTO, 0);
+ bprintf(bp, " from any to any");
}
flags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO |
HAVE_SRCIP | HAVE_DSTIP;
}
- if (co.comment_only)
+ if (co->comment_only)
comment = "...";
- for (l = rule->act_ofs, cmd = rule->cmd ;
+ for (l = rule->act_ofs, cmd = rule->cmd;
l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
/* useful alias */
ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
- if (co.comment_only) {
+ if (co->comment_only) {
if (cmd->opcode != O_NOP)
continue;
- printf(" // %s\n", (char *)(cmd + 1));
+ bprintf(bp, " // %s\n", (char *)(cmd + 1));
return;
}
- show_prerequisites(&flags, 0, cmd->opcode);
+ show_prerequisites(bp, &flags, 0, cmd->opcode);
switch(cmd->opcode) {
case O_PROB:
@@ -1403,12 +1660,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP_SRC_MASK:
case O_IP_SRC_ME:
case O_IP_SRC_SET:
- show_prerequisites(&flags, HAVE_PROTO, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO, 0);
if (!(flags & HAVE_SRCIP))
- printf(" from");
+ bprintf(bp, " from");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip((ipfw_insn_ip *)cmd,
+ bprintf(bp, " {");
+ print_ip(bp, fo, (ipfw_insn_ip *)cmd,
(flags & HAVE_OPTIONS) ? " src-ip" : "");
flags |= HAVE_SRCIP;
break;
@@ -1418,12 +1675,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP_DST_MASK:
case O_IP_DST_ME:
case O_IP_DST_SET:
- show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO|HAVE_SRCIP, 0);
if (!(flags & HAVE_DSTIP))
- printf(" to");
+ bprintf(bp, " to");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip((ipfw_insn_ip *)cmd,
+ bprintf(bp, " {");
+ print_ip(bp, fo, (ipfw_insn_ip *)cmd,
(flags & HAVE_OPTIONS) ? " dst-ip" : "");
flags |= HAVE_DSTIP;
break;
@@ -1431,12 +1688,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP6_SRC:
case O_IP6_SRC_MASK:
case O_IP6_SRC_ME:
- show_prerequisites(&flags, HAVE_PROTO, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO, 0);
if (!(flags & HAVE_SRCIP))
- printf(" from");
+ bprintf(bp, " from");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip6((ipfw_insn_ip6 *)cmd,
+ bprintf(bp, " {");
+ print_ip6(bp, (ipfw_insn_ip6 *)cmd,
(flags & HAVE_OPTIONS) ? " src-ip6" : "");
flags |= HAVE_SRCIP | HAVE_PROTO;
break;
@@ -1444,35 +1701,35 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP6_DST:
case O_IP6_DST_MASK:
case O_IP6_DST_ME:
- show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO|HAVE_SRCIP, 0);
if (!(flags & HAVE_DSTIP))
- printf(" to");
+ bprintf(bp, " to");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip6((ipfw_insn_ip6 *)cmd,
+ bprintf(bp, " {");
+ print_ip6(bp, (ipfw_insn_ip6 *)cmd,
(flags & HAVE_OPTIONS) ? " dst-ip6" : "");
flags |= HAVE_DSTIP;
break;
case O_FLOW6ID:
- print_flow6id( (ipfw_insn_u32 *) cmd );
- flags |= HAVE_OPTIONS;
- break;
+ print_flow6id(bp, (ipfw_insn_u32 *) cmd );
+ flags |= HAVE_OPTIONS;
+ break;
case O_IP_DSTPORT:
- show_prerequisites(&flags,
+ show_prerequisites(bp, &flags,
HAVE_PROTO | HAVE_SRCIP |
HAVE_DSTIP | HAVE_IP, 0);
case O_IP_SRCPORT:
if (flags & HAVE_DSTIP)
flags |= HAVE_IP;
- show_prerequisites(&flags,
+ show_prerequisites(bp, &flags,
HAVE_PROTO | HAVE_SRCIP, 0);
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
+ bprintf(bp, " {");
if (cmd->len & F_NOT)
- printf(" not");
- print_newports((ipfw_insn_u16 *)cmd, proto,
+ bprintf(bp, " not");
+ print_newports(bp, (ipfw_insn_u16 *)cmd, proto,
(flags & HAVE_OPTIONS) ? cmd->opcode : 0);
break;
@@ -1480,22 +1737,22 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
struct protoent *pe = NULL;
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
+ bprintf(bp, " {");
if (cmd->len & F_NOT)
- printf(" not");
+ bprintf(bp, " not");
proto = cmd->arg1;
pe = getprotobynumber(cmd->arg1);
if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) &&
!(flags & HAVE_PROTO))
- show_prerequisites(&flags,
+ show_prerequisites(bp, &flags,
HAVE_PROTO | HAVE_IP | HAVE_SRCIP |
HAVE_DSTIP | HAVE_OPTIONS, 0);
if (flags & HAVE_OPTIONS)
- printf(" proto");
+ bprintf(bp, " proto");
if (pe)
- printf(" %s", pe->p_name);
+ bprintf(bp, " %s", pe->p_name);
else
- printf(" %u", cmd->arg1);
+ bprintf(bp, " %u", cmd->arg1);
}
flags |= HAVE_PROTO;
break;
@@ -1507,68 +1764,68 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
((cmd->opcode == O_IP4) &&
(flags & HAVE_PROTO4)))
break;
- show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP |
+ show_prerequisites(bp, &flags, HAVE_PROTO | HAVE_SRCIP |
HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0);
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
+ bprintf(bp, " {");
if (cmd->len & F_NOT && cmd->opcode != O_IN)
- printf(" not");
+ bprintf(bp, " not");
switch(cmd->opcode) {
case O_MACADDR2: {
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
- printf(" MAC");
- print_mac(m->addr, m->mask);
- print_mac(m->addr + 6, m->mask + 6);
+ bprintf(bp, " MAC");
+ print_mac(bp, m->addr, m->mask);
+ print_mac(bp, m->addr + 6, m->mask + 6);
}
break;
case O_MAC_TYPE:
- print_newports((ipfw_insn_u16 *)cmd,
+ print_newports(bp, (ipfw_insn_u16 *)cmd,
IPPROTO_ETHERTYPE, cmd->opcode);
break;
case O_FRAG:
- printf(" frag");
+ bprintf(bp, " frag");
break;
case O_FIB:
- printf(" fib %u", cmd->arg1 );
+ bprintf(bp, " fib %u", cmd->arg1 );
break;
case O_SOCKARG:
- printf(" sockarg");
+ bprintf(bp, " sockarg");
break;
case O_IN:
- printf(cmd->len & F_NOT ? " out" : " in");
+ bprintf(bp, cmd->len & F_NOT ? " out" : " in");
break;
case O_DIVERTED:
switch (cmd->arg1) {
case 3:
- printf(" diverted");
+ bprintf(bp, " diverted");
break;
case 1:
- printf(" diverted-loopback");
+ bprintf(bp, " diverted-loopback");
break;
case 2:
- printf(" diverted-output");
+ bprintf(bp, " diverted-output");
break;
default:
- printf(" diverted-?<%u>", cmd->arg1);
+ bprintf(bp, " diverted-?<%u>", cmd->arg1);
break;
}
break;
case O_LAYER2:
- printf(" layer2");
+ bprintf(bp, " layer2");
break;
case O_XMIT:
case O_RECV:
case O_VIA:
{
- char const *s;
+ char const *s, *t;
ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
if (cmd->opcode == O_XMIT)
@@ -1578,97 +1835,112 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
else /* if (cmd->opcode == O_VIA) */
s = "via";
if (cmdif->name[0] == '\0')
- printf(" %s %s", s,
+ bprintf(bp, " %s %s", s,
inet_ntoa(cmdif->p.ip));
- else if (cmdif->name[0] == '\1') /* interface table */
- printf(" %s table(%d)", s, cmdif->p.glob);
- else
- printf(" %s %s", s, cmdif->name);
+ else if (cmdif->name[0] == '\1') {
+ /* interface table */
+ t = table_search_ctlv(fo->tstate,
+ cmdif->p.kidx);
+ bprintf(bp, " %s table(%s)", s, t);
+ } else
+ bprintf(bp, " %s %s", s, cmdif->name);
break;
}
+ case O_IP_FLOW_LOOKUP:
+ {
+ char *t;
+
+ t = table_search_ctlv(fo->tstate, cmd->arg1);
+ bprintf(bp, " flow table(%s", t);
+ if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))
+ bprintf(bp, ",%u",
+ ((ipfw_insn_u32 *)cmd)->d[0]);
+ bprintf(bp, ")");
+ break;
+ }
case O_IPID:
if (F_LEN(cmd) == 1)
- printf(" ipid %u", cmd->arg1 );
+ bprintf(bp, " ipid %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_IPID);
break;
case O_IPTTL:
if (F_LEN(cmd) == 1)
- printf(" ipttl %u", cmd->arg1 );
+ bprintf(bp, " ipttl %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_IPTTL);
break;
case O_IPVER:
- printf(" ipver %u", cmd->arg1 );
+ bprintf(bp, " ipver %u", cmd->arg1 );
break;
case O_IPPRECEDENCE:
- printf(" ipprecedence %u", (cmd->arg1) >> 5 );
+ bprintf(bp, " ipprecedence %u", cmd->arg1 >> 5);
break;
case O_DSCP:
- print_dscp((ipfw_insn_u32 *)cmd);
+ print_dscp(bp, (ipfw_insn_u32 *)cmd);
break;
case O_IPLEN:
if (F_LEN(cmd) == 1)
- printf(" iplen %u", cmd->arg1 );
+ bprintf(bp, " iplen %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_IPLEN);
break;
case O_IPOPT:
- print_flags("ipoptions", cmd, f_ipopts);
+ print_flags(bp, "ipoptions", cmd, f_ipopts);
break;
case O_IPTOS:
- print_flags("iptos", cmd, f_iptos);
+ print_flags(bp, "iptos", cmd, f_iptos);
break;
case O_ICMPTYPE:
- print_icmptypes((ipfw_insn_u32 *)cmd);
+ print_icmptypes(bp, (ipfw_insn_u32 *)cmd);
break;
case O_ESTAB:
- printf(" established");
+ bprintf(bp, " established");
break;
case O_TCPDATALEN:
if (F_LEN(cmd) == 1)
- printf(" tcpdatalen %u", cmd->arg1 );
+ bprintf(bp, " tcpdatalen %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_TCPDATALEN);
break;
case O_TCPFLAGS:
- print_flags("tcpflags", cmd, f_tcpflags);
+ print_flags(bp, "tcpflags", cmd, f_tcpflags);
break;
case O_TCPOPTS:
- print_flags("tcpoptions", cmd, f_tcpopts);
+ print_flags(bp, "tcpoptions", cmd, f_tcpopts);
break;
case O_TCPWIN:
if (F_LEN(cmd) == 1)
- printf(" tcpwin %u", cmd->arg1);
+ bprintf(bp, " tcpwin %u", cmd->arg1);
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_TCPWIN);
break;
case O_TCPACK:
- printf(" tcpack %d", ntohl(cmd32->d[0]));
+ bprintf(bp, " tcpack %d", ntohl(cmd32->d[0]));
break;
case O_TCPSEQ:
- printf(" tcpseq %d", ntohl(cmd32->d[0]));
+ bprintf(bp, " tcpseq %d", ntohl(cmd32->d[0]));
break;
case O_UID:
@@ -1676,9 +1948,9 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
struct passwd *pwd = getpwuid(cmd32->d[0]);
if (pwd)
- printf(" uid %s", pwd->pw_name);
+ bprintf(bp, " uid %s", pwd->pw_name);
else
- printf(" uid %u", cmd32->d[0]);
+ bprintf(bp, " uid %u", cmd32->d[0]);
}
break;
@@ -1687,30 +1959,30 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
struct group *grp = getgrgid(cmd32->d[0]);
if (grp)
- printf(" gid %s", grp->gr_name);
+ bprintf(bp, " gid %s", grp->gr_name);
else
- printf(" gid %u", cmd32->d[0]);
+ bprintf(bp, " gid %u", cmd32->d[0]);
}
break;
case O_JAIL:
- printf(" jail %d", cmd32->d[0]);
+ bprintf(bp, " jail %d", cmd32->d[0]);
break;
case O_VERREVPATH:
- printf(" verrevpath");
+ bprintf(bp, " verrevpath");
break;
case O_VERSRCREACH:
- printf(" versrcreach");
+ bprintf(bp, " versrcreach");
break;
case O_ANTISPOOF:
- printf(" antispoof");
+ bprintf(bp, " antispoof");
break;
case O_IPSEC:
- printf(" ipsec");
+ bprintf(bp, " ipsec");
break;
case O_NOP:
@@ -1718,7 +1990,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
break;
case O_KEEP_STATE:
- printf(" keep-state");
+ bprintf(bp, " keep-state");
break;
case O_LIMIT: {
@@ -1727,113 +1999,132 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
uint8_t x = c->limit_mask;
char const *comma = " ";
- printf(" limit");
+ bprintf(bp, " limit");
for (; p->x != 0 ; p++)
if ((x & p->x) == p->x) {
x &= ~p->x;
- printf("%s%s", comma, p->s);
+ bprintf(bp, "%s%s", comma,p->s);
comma = ",";
}
- PRINT_UINT_ARG(" ", c->conn_limit);
+ bprint_uint_arg(bp, " ", c->conn_limit);
break;
}
case O_IP6:
- printf(" ip6");
+ bprintf(bp, " ip6");
break;
case O_IP4:
- printf(" ip4");
+ bprintf(bp, " ip4");
break;
case O_ICMP6TYPE:
- print_icmp6types((ipfw_insn_u32 *)cmd);
+ print_icmp6types(bp, (ipfw_insn_u32 *)cmd);
break;
case O_EXT_HDR:
- print_ext6hdr( (ipfw_insn *) cmd );
+ print_ext6hdr(bp, (ipfw_insn *)cmd);
break;
case O_TAGGED:
if (F_LEN(cmd) == 1)
- PRINT_UINT_ARG(" tagged ", cmd->arg1);
+ bprint_uint_arg(bp, " tagged ",
+ cmd->arg1);
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
- O_TAGGED);
+ print_newports(bp, (ipfw_insn_u16 *)cmd,
+ 0, O_TAGGED);
break;
default:
- printf(" [opcode %d len %d]",
+ bprintf(bp, " [opcode %d len %d]",
cmd->opcode, cmd->len);
}
}
if (cmd->len & F_OR) {
- printf(" or");
+ bprintf(bp, " or");
or_block = 1;
} else if (or_block) {
- printf(" }");
+ bprintf(bp, " }");
or_block = 0;
}
}
- show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP
+ show_prerequisites(bp, &flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP
| HAVE_IP, 0);
if (comment)
- printf(" // %s", comment);
- printf("\n");
+ bprintf(bp, " // %s", comment);
+ bprintf(bp, "\n");
}
static void
-show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
+show_dyn_state(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, ipfw_dyn_rule *d)
{
struct protoent *pe;
struct in_addr a;
uint16_t rulenum;
char buf[INET6_ADDRSTRLEN];
- if (!co.do_expired) {
+ if (!co->do_expired) {
if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
return;
}
bcopy(&d->rule, &rulenum, sizeof(rulenum));
- printf("%05d", rulenum);
- if (pcwidth > 0 || bcwidth > 0) {
- printf(" ");
- pr_u64(&d->pcnt, pcwidth);
- pr_u64(&d->bcnt, bcwidth);
- printf("(%ds)", d->expire);
+ bprintf(bp, "%05d", rulenum);
+ if (fo->pcwidth > 0 || fo->bcwidth > 0) {
+ bprintf(bp, " ");
+ pr_u64(bp, &d->pcnt, fo->pcwidth);
+ pr_u64(bp, &d->bcnt, fo->bcwidth);
+ bprintf(bp, "(%ds)", d->expire);
}
switch (d->dyn_type) {
case O_LIMIT_PARENT:
- printf(" PARENT %d", d->count);
+ bprintf(bp, " PARENT %d", d->count);
break;
case O_LIMIT:
- printf(" LIMIT");
+ bprintf(bp, " LIMIT");
break;
case O_KEEP_STATE: /* bidir, no mask */
- printf(" STATE");
+ bprintf(bp, " STATE");
break;
}
if ((pe = getprotobynumber(d->id.proto)) != NULL)
- printf(" %s", pe->p_name);
+ bprintf(bp, " %s", pe->p_name);
else
- printf(" proto %u", d->id.proto);
+ bprintf(bp, " proto %u", d->id.proto);
if (d->id.addr_type == 4) {
a.s_addr = htonl(d->id.src_ip);
- printf(" %s %d", inet_ntoa(a), d->id.src_port);
+ bprintf(bp, " %s %d", inet_ntoa(a), d->id.src_port);
a.s_addr = htonl(d->id.dst_ip);
- printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port);
+ bprintf(bp, " <-> %s %d", inet_ntoa(a), d->id.dst_port);
} else if (d->id.addr_type == 6) {
- printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf,
+ bprintf(bp, " %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf,
sizeof(buf)), d->id.src_port);
- printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf,
- sizeof(buf)), d->id.dst_port);
+ bprintf(bp, " <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6,
+ buf, sizeof(buf)), d->id.dst_port);
} else
- printf(" UNKNOWN <-> UNKNOWN\n");
+ bprintf(bp, " UNKNOWN <-> UNKNOWN\n");
+}
- printf("\n");
+static int
+do_range_cmd(int cmd, ipfw_range_tlv *rt)
+{
+ ipfw_range_header rh;
+ size_t sz;
+
+ memset(&rh, 0, sizeof(rh));
+ memcpy(&rh.range, rt, sizeof(*rt));
+ rh.range.head.length = sizeof(*rt);
+ rh.range.head.type = IPFW_TLV_RANGE;
+ sz = sizeof(rh);
+
+ if (do_get3(cmd, &rh.opheader, &sz) != 0)
+ return (-1);
+ /* Save number of matched objects */
+ rt->new_set = rh.range.new_set;
+ return (0);
}
/*
@@ -1846,77 +2137,75 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
void
ipfw_sets_handler(char *av[])
{
- uint32_t set_disable, masks[2];
- int i, nbytes;
- uint16_t rulenum;
- uint8_t cmd, new_set;
+ uint32_t masks[2];
+ int i;
+ uint8_t cmd, rulenum;
+ ipfw_range_tlv rt;
+ char *msg;
+ size_t size;
av++;
+ memset(&rt, 0, sizeof(rt));
if (av[0] == NULL)
errx(EX_USAGE, "set needs command");
if (_substrcmp(*av, "show") == 0) {
- void *data = NULL;
- char const *msg;
- int nalloc;
-
- nalloc = nbytes = sizeof(struct ip_fw);
- while (nbytes >= nalloc) {
- if (data)
- free(data);
- nalloc = nalloc * 2 + 200;
- nbytes = nalloc;
- data = safe_calloc(1, nbytes);
- if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_GET)");
- }
+ struct format_opts fo;
+ ipfw_cfg_lheader *cfg;
- bcopy(&((struct ip_fw *)data)->next_rule,
- &set_disable, sizeof(set_disable));
+ memset(&fo, 0, sizeof(fo));
+ if (ipfw_get_config(&co, &fo, &cfg, &size) != 0)
+ err(EX_OSERR, "requesting config failed");
- for (i = 0, msg = "disable" ; i < RESVD_SET; i++)
- if ((set_disable & (1<<i))) {
+ for (i = 0, msg = "disable"; i < RESVD_SET; i++)
+ if ((cfg->set_mask & (1<<i)) == 0) {
printf("%s %d", msg, i);
msg = "";
}
- msg = (set_disable) ? " enable" : "enable";
+ msg = (cfg->set_mask != (uint32_t)-1) ? " enable" : "enable";
for (i = 0; i < RESVD_SET; i++)
- if (!(set_disable & (1<<i))) {
+ if ((cfg->set_mask & (1<<i)) != 0) {
printf("%s %d", msg, i);
msg = "";
}
printf("\n");
+ free(cfg);
} else if (_substrcmp(*av, "swap") == 0) {
av++;
if ( av[0] == NULL || av[1] == NULL )
errx(EX_USAGE, "set swap needs 2 set numbers\n");
- rulenum = atoi(av[0]);
- new_set = atoi(av[1]);
- if (!isdigit(*(av[0])) || rulenum > RESVD_SET)
+ rt.set = atoi(av[0]);
+ rt.new_set = atoi(av[1]);
+ if (!isdigit(*(av[0])) || rt.set > RESVD_SET)
errx(EX_DATAERR, "invalid set number %s\n", av[0]);
- if (!isdigit(*(av[1])) || new_set > RESVD_SET)
+ if (!isdigit(*(av[1])) || rt.new_set > RESVD_SET)
errx(EX_DATAERR, "invalid set number %s\n", av[1]);
- masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
- i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
+ i = do_range_cmd(IP_FW_SET_SWAP, &rt);
} else if (_substrcmp(*av, "move") == 0) {
av++;
if (av[0] && _substrcmp(*av, "rule") == 0) {
- cmd = 2;
+ rt.flags = IPFW_RCFLAG_RANGE; /* move rules to new set */
+ cmd = IP_FW_XMOVE;
av++;
} else
- cmd = 3;
+ cmd = IP_FW_SET_MOVE; /* Move set to new one */
if (av[0] == NULL || av[1] == NULL || av[2] == NULL ||
av[3] != NULL || _substrcmp(av[1], "to") != 0)
errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
rulenum = atoi(av[0]);
- new_set = atoi(av[2]);
- if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) ||
- (cmd == 2 && rulenum == IPFW_DEFAULT_RULE) )
+ rt.new_set = atoi(av[2]);
+ if (cmd == IP_FW_XMOVE) {
+ rt.start_rule = rulenum;
+ rt.end_rule = rulenum;
+ } else
+ rt.set = rulenum;
+ rt.new_set = atoi(av[2]);
+ if (!isdigit(*(av[0])) || (cmd == 3 && rt.set > RESVD_SET) ||
+ (cmd == 2 && rt.start_rule == IPFW_DEFAULT_RULE) )
errx(EX_DATAERR, "invalid source number %s\n", av[0]);
- if (!isdigit(*(av[2])) || new_set > RESVD_SET)
+ if (!isdigit(*(av[2])) || rt.new_set > RESVD_SET)
errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
- masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
- i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
+ i = do_range_cmd(cmd, &rt);
} else if (_substrcmp(*av, "disable") == 0 ||
_substrcmp(*av, "enable") == 0 ) {
int which = _substrcmp(*av, "enable") == 0 ? 1 : 0;
@@ -1944,9 +2233,11 @@ ipfw_sets_handler(char *av[])
errx(EX_DATAERR,
"cannot enable and disable the same set\n");
- i = do_cmd(IP_FW_DEL, masks, sizeof(masks));
+ rt.set = masks[0];
+ rt.new_set = masks[1];
+ i = do_range_cmd(IP_FW_SET_ENABLE, &rt);
if (i)
- warn("set enable/disable: setsockopt(IP_FW_DEL)");
+ warn("set enable/disable: setsockopt(IP_FW_SET_ENABLE)");
} else
errx(EX_USAGE, "invalid set command %s\n", *av);
}
@@ -1984,28 +2275,204 @@ ipfw_sysctl_handler(char *av[], int which)
}
}
+typedef void state_cb(struct cmdline_opts *co, struct format_opts *fo,
+ void *arg, void *state);
+
+static void
+prepare_format_dyn(struct cmdline_opts *co, struct format_opts *fo,
+ void *arg, void *_state)
+{
+ ipfw_dyn_rule *d;
+ int width;
+ uint8_t set;
+
+ d = (ipfw_dyn_rule *)_state;
+ /* Count _ALL_ states */
+ fo->dcnt++;
+
+ if (fo->show_counters == 0)
+ return;
+
+ if (co->use_set) {
+ /* skip states from another set */
+ bcopy((char *)&d->rule + sizeof(uint16_t), &set,
+ sizeof(uint8_t));
+ if (set != co->use_set - 1)
+ return;
+ }
+
+ width = pr_u64(NULL, &d->pcnt, 0);
+ if (width > fo->pcwidth)
+ fo->pcwidth = width;
+
+ width = pr_u64(NULL, &d->bcnt, 0);
+ if (width > fo->bcwidth)
+ fo->bcwidth = width;
+}
+
+static int
+foreach_state(struct cmdline_opts *co, struct format_opts *fo,
+ caddr_t base, size_t sz, state_cb dyn_bc, void *dyn_arg)
+{
+ int ttype;
+ state_cb *fptr;
+ void *farg;
+ ipfw_obj_tlv *tlv;
+ ipfw_obj_ctlv *ctlv;
+
+ fptr = NULL;
+ ttype = 0;
+
+ while (sz > 0) {
+ ctlv = (ipfw_obj_ctlv *)base;
+ switch (ctlv->head.type) {
+ case IPFW_TLV_DYNSTATE_LIST:
+ base += sizeof(*ctlv);
+ sz -= sizeof(*ctlv);
+ ttype = IPFW_TLV_DYN_ENT;
+ fptr = dyn_bc;
+ farg = dyn_arg;
+ break;
+ default:
+ return (sz);
+ }
+
+ while (sz > 0) {
+ tlv = (ipfw_obj_tlv *)base;
+ if (tlv->type != ttype)
+ break;
+
+ fptr(co, fo, farg, tlv + 1);
+ sz -= tlv->length;
+ base += tlv->length;
+ }
+ }
+
+ return (sz);
+}
+
+static void
+prepare_format_opts(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_obj_tlv *rtlv, int rcnt, caddr_t dynbase, size_t dynsz)
+{
+ int bcwidth, pcwidth, width;
+ int n;
+ struct ip_fw_bcounter *cntr;
+ struct ip_fw_rule *r;
+
+ bcwidth = 0;
+ pcwidth = 0;
+ if (fo->show_counters != 0) {
+ for (n = 0; n < rcnt; n++,
+ rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
+ cntr = (struct ip_fw_bcounter *)(rtlv + 1);
+ r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size);
+ /* skip rules from another set */
+ if (co->use_set && r->set != co->use_set - 1)
+ continue;
+
+ /* packet counter */
+ width = pr_u64(NULL, &cntr->pcnt, 0);
+ if (width > pcwidth)
+ pcwidth = width;
+
+ /* byte counter */
+ width = pr_u64(NULL, &cntr->bcnt, 0);
+ if (width > bcwidth)
+ bcwidth = width;
+ }
+ }
+ fo->bcwidth = bcwidth;
+ fo->pcwidth = pcwidth;
+
+ fo->dcnt = 0;
+ if (co->do_dynamic && dynsz > 0)
+ foreach_state(co, fo, dynbase, dynsz, prepare_format_dyn, NULL);
+}
+
+static int
+list_static_range(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, ipfw_obj_tlv *rtlv, int rcnt)
+{
+ int n, seen;
+ struct ip_fw_rule *r;
+ struct ip_fw_bcounter *cntr;
+ int c = 0;
+
+ for (n = seen = 0; n < rcnt; n++,
+ rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
+
+ if (fo->show_counters != 0) {
+ cntr = (struct ip_fw_bcounter *)(rtlv + 1);
+ r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size);
+ } else {
+ cntr = NULL;
+ r = (struct ip_fw_rule *)(rtlv + 1);
+ }
+ if (r->rulenum > fo->last)
+ break;
+ if (co->use_set && r->set != co->use_set - 1)
+ continue;
+ if (r->rulenum >= fo->first && r->rulenum <= fo->last) {
+ show_static_rule(co, fo, bp, r, cntr);
+ printf("%s", bp->buf);
+ c += rtlv->length;
+ bp_flush(bp);
+ seen++;
+ }
+ }
+
+ return (seen);
+}
+
+static void
+list_dyn_state(struct cmdline_opts *co, struct format_opts *fo,
+ void *_arg, void *_state)
+{
+ uint16_t rulenum;
+ uint8_t set;
+ ipfw_dyn_rule *d;
+ struct buf_pr *bp;
+
+ d = (ipfw_dyn_rule *)_state;
+ bp = (struct buf_pr *)_arg;
+
+ bcopy(&d->rule, &rulenum, sizeof(rulenum));
+ if (rulenum > fo->last)
+ return;
+ if (co->use_set) {
+ bcopy((char *)&d->rule + sizeof(uint16_t),
+ &set, sizeof(uint8_t));
+ if (set != co->use_set - 1)
+ return;
+ }
+ if (rulenum >= fo->first) {
+ show_dyn_state(co, fo, bp, d);
+ printf("%s\n", bp->buf);
+ bp_flush(bp);
+ }
+}
+
+static int
+list_dyn_range(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, caddr_t base, size_t sz)
+{
+
+ sz = foreach_state(co, fo, base, sz, list_dyn_state, bp);
+ return (sz);
+}
+
void
ipfw_list(int ac, char *av[], int show_counters)
{
- struct ip_fw *r;
- ipfw_dyn_rule *dynrules, *d;
-
-#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
- char *lim;
- void *data = NULL;
- int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
- int exitval = EX_OK;
+ ipfw_cfg_lheader *cfg;
+ struct format_opts sfo;
+ size_t sz;
+ int error;
int lac;
char **lav;
- u_long rnum, last;
+ uint32_t rnum;
char *endptr;
- int seen = 0;
- uint8_t set;
-
- const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
- int nalloc = 1024; /* start somewhere... */
-
- last = 0;
if (co.test_only) {
fprintf(stderr, "Testing only, list disabled\n");
@@ -2018,162 +2485,216 @@ ipfw_list(int ac, char *av[], int show_counters)
ac--;
av++;
+ memset(&sfo, 0, sizeof(sfo));
- /* get rules or pipes from kernel, resizing array as necessary */
- nbytes = nalloc;
+ /* Determine rule range to request */
+ if (ac > 0) {
+ for (lac = ac, lav = av; lac != 0; lac--) {
+ rnum = strtoul(*lav++, &endptr, 10);
+ if (sfo.first == 0 || rnum < sfo.first)
+ sfo.first = rnum;
- while (nbytes >= nalloc) {
- nalloc = nalloc * 2 + 200;
- nbytes = nalloc;
- data = safe_realloc(data, nbytes);
- if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0)
- err(EX_OSERR, "getsockopt(IP_%s_GET)",
- co.do_pipe ? "DUMMYNET" : "FW");
+ if (*endptr == '-')
+ rnum = strtoul(endptr + 1, &endptr, 10);
+ if (sfo.last == 0 || rnum > sfo.last)
+ sfo.last = rnum;
+ }
}
- /*
- * Count static rules. They have variable size so we
- * need to scan the list to count them.
- */
- for (nstat = 1, r = data, lim = (char *)data + nbytes;
- r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim;
- ++nstat, r = NEXT(r) )
- ; /* nothing */
+ /* get configuraion from kernel */
+ cfg = NULL;
+ sfo.show_counters = show_counters;
+ sfo.flags = IPFW_CFG_GET_STATIC;
+ if (co.do_dynamic != 0)
+ sfo.flags |= IPFW_CFG_GET_STATES;
+ if (sfo.show_counters != 0)
+ sfo.flags |= IPFW_CFG_GET_COUNTERS;
+ if (ipfw_get_config(&co, &sfo, &cfg, &sz) != 0)
+ err(EX_OSERR, "retrieving config failed");
+
+ error = ipfw_show_config(&co, &sfo, cfg, sz, ac, av);
+
+ free(cfg);
+
+ if (error != EX_OK)
+ exit(error);
+}
+
+static int
+ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader *cfg, size_t sz, int ac, char *av[])
+{
+ caddr_t dynbase;
+ size_t dynsz;
+ int rcnt;
+ int exitval = EX_OK;
+ int lac;
+ char **lav;
+ char *endptr;
+ size_t readsz;
+ struct buf_pr bp;
+ ipfw_obj_ctlv *ctlv, *tstate;
+ ipfw_obj_tlv *rbase;
/*
- * Count dynamic rules. This is easier as they have
- * fixed size.
+ * Handle tablenames TLV first, if any
*/
- r = NEXT(r);
- dynrules = (ipfw_dyn_rule *)r ;
- n = (char *)r - (char *)data;
- ndyn = (nbytes - n) / sizeof *dynrules;
-
- /* if showing stats, figure out column widths ahead of time */
- bcwidth = pcwidth = 0;
- if (show_counters) {
- for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
- /* skip rules from another set */
- if (co.use_set && r->set != co.use_set - 1)
- continue;
-
- /* packet counter */
- width = pr_u64(&r->pcnt, 0);
- if (width > pcwidth)
- pcwidth = width;
+ tstate = NULL;
+ rbase = NULL;
+ dynbase = NULL;
+ dynsz = 0;
+ readsz = sizeof(*cfg);
+ rcnt = 0;
+
+ fo->set_mask = cfg->set_mask;
+
+ ctlv = (ipfw_obj_ctlv *)(cfg + 1);
+
+ if (cfg->flags & IPFW_CFG_GET_STATIC) {
+ /* We've requested static rules */
+ if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
+ fo->tstate = ctlv;
+ readsz += ctlv->head.length;
+ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
+ ctlv->head.length);
+ }
- /* byte counter */
- width = pr_u64(&r->bcnt, 0);
- if (width > bcwidth)
- bcwidth = width;
+ if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
+ rbase = (ipfw_obj_tlv *)(ctlv + 1);
+ rcnt = ctlv->count;
+ readsz += ctlv->head.length;
+ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
+ ctlv->head.length);
}
}
- if (co.do_dynamic && ndyn) {
- for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- if (co.use_set) {
- /* skip rules from another set */
- bcopy((char *)&d->rule + sizeof(uint16_t),
- &set, sizeof(uint8_t));
- if (set != co.use_set - 1)
- continue;
- }
- width = pr_u64(&d->pcnt, 0);
- if (width > pcwidth)
- pcwidth = width;
- width = pr_u64(&d->bcnt, 0);
- if (width > bcwidth)
- bcwidth = width;
- }
+ if ((cfg->flags & IPFW_CFG_GET_STATES) && (readsz != sz)) {
+ /* We may have some dynamic states */
+ dynsz = sz - readsz;
+ /* Skip empty header */
+ if (dynsz != sizeof(ipfw_obj_ctlv))
+ dynbase = (caddr_t)ctlv;
+ else
+ dynsz = 0;
}
+
+ prepare_format_opts(co, fo, rbase, rcnt, dynbase, dynsz);
+ bp_alloc(&bp, 4096);
+
/* if no rule numbers were specified, list all rules */
if (ac == 0) {
- for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
- if (co.use_set && r->set != co.use_set - 1)
- continue;
- show_ipfw(r, pcwidth, bcwidth);
- }
+ fo->first = 0;
+ fo->last = IPFW_DEFAULT_RULE;
+ list_static_range(co, fo, &bp, rbase, rcnt);
- if (co.do_dynamic && ndyn) {
- printf("## Dynamic rules (%d):\n", ndyn);
- for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- if (co.use_set) {
- bcopy((char *)&d->rule + sizeof(uint16_t),
- &set, sizeof(uint8_t));
- if (set != co.use_set - 1)
- continue;
- }
- show_dyn_ipfw(d, pcwidth, bcwidth);
- }
+ if (co->do_dynamic && dynsz > 0) {
+ printf("## Dynamic rules (%d %zu):\n", fo->dcnt, dynsz);
+ list_dyn_range(co, fo, &bp, dynbase, dynsz);
}
- goto done;
+
+ bp_free(&bp);
+ return (EX_OK);
}
/* display specific rules requested on command line */
-
for (lac = ac, lav = av; lac != 0; lac--) {
/* convert command line rule # */
- last = rnum = strtoul(*lav++, &endptr, 10);
+ fo->last = fo->first = strtoul(*lav++, &endptr, 10);
if (*endptr == '-')
- last = strtoul(endptr+1, &endptr, 10);
+ fo->last = strtoul(endptr + 1, &endptr, 10);
if (*endptr) {
exitval = EX_USAGE;
warnx("invalid rule number: %s", *(lav - 1));
continue;
}
- for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) {
- if (r->rulenum > last)
- break;
- if (co.use_set && r->set != co.use_set - 1)
- continue;
- if (r->rulenum >= rnum && r->rulenum <= last) {
- show_ipfw(r, pcwidth, bcwidth);
- seen = 1;
- }
- }
- if (!seen) {
+
+ if (list_static_range(co, fo, &bp, rbase, rcnt) == 0) {
/* give precedence to other error(s) */
if (exitval == EX_OK)
exitval = EX_UNAVAILABLE;
- warnx("rule %lu does not exist", rnum);
+ if (fo->first == fo->last)
+ warnx("rule %u does not exist", fo->first);
+ else
+ warnx("no rules in range %u-%u",
+ fo->first, fo->last);
}
}
- if (co.do_dynamic && ndyn) {
+ if (co->do_dynamic && dynsz > 0) {
printf("## Dynamic rules:\n");
for (lac = ac, lav = av; lac != 0; lac--) {
- last = rnum = strtoul(*lav++, &endptr, 10);
+ fo->last = fo->first = strtoul(*lav++, &endptr, 10);
if (*endptr == '-')
- last = strtoul(endptr+1, &endptr, 10);
+ fo->last = strtoul(endptr+1, &endptr, 10);
if (*endptr)
/* already warned */
continue;
- for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- uint16_t rulenum;
-
- bcopy(&d->rule, &rulenum, sizeof(rulenum));
- if (rulenum > rnum)
- break;
- if (co.use_set) {
- bcopy((char *)&d->rule + sizeof(uint16_t),
- &set, sizeof(uint8_t));
- if (set != co.use_set - 1)
- continue;
- }
- if (r->rulenum >= rnum && r->rulenum <= last)
- show_dyn_ipfw(d, pcwidth, bcwidth);
- }
+ list_dyn_range(co, fo, &bp, dynbase, dynsz);
}
}
- ac = 0;
+ bp_free(&bp);
+ return (exitval);
+}
-done:
- free(data);
- if (exitval != EX_OK)
- exit(exitval);
-#undef NEXT
+/*
+ * Retrieves current ipfw configuration of given type
+ * and stores its pointer to @pcfg.
+ *
+ * Caller is responsible for freeing @pcfg.
+ *
+ * Returns 0 on success.
+ */
+
+static int
+ipfw_get_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader **pcfg, size_t *psize)
+{
+ ipfw_cfg_lheader *cfg;
+ size_t sz;
+ int i;
+
+
+ if (co->test_only != 0) {
+ fprintf(stderr, "Testing only, list disabled\n");
+ return (0);
+ }
+
+ /* Start with some data size */
+ sz = 4096;
+ cfg = NULL;
+
+ for (i = 0; i < 16; i++) {
+ if (cfg != NULL)
+ free(cfg);
+ if ((cfg = calloc(1, sz)) == NULL)
+ return (ENOMEM);
+
+ cfg->flags = fo->flags;
+ cfg->start_rule = fo->first;
+ cfg->end_rule = fo->last;
+
+ if (do_get3(IP_FW_XGET, &cfg->opheader, &sz) != 0) {
+ if (errno != ENOMEM) {
+ free(cfg);
+ return (errno);
+ }
+
+ /* Buffer size is not enough. Try to increase */
+ sz = sz * 2;
+ if (sz < cfg->size)
+ sz = cfg->size;
+ continue;
+ }
+
+ *pcfg = cfg;
+ *psize = sz;
+ return (0);
+ }
+
+ free(cfg);
+ return (ENOMEM);
}
static int
@@ -2189,6 +2710,79 @@ lookup_host (char *host, struct in_addr *ipaddr)
return(0);
}
+struct tidx {
+ ipfw_obj_ntlv *idx;
+ uint32_t count;
+ uint32_t size;
+ uint16_t counter;
+ uint8_t set;
+};
+
+static uint16_t
+pack_table(struct tidx *tstate, char *name)
+{
+ int i;
+ ipfw_obj_ntlv *ntlv;
+
+ if (table_check_name(name) != 0)
+ return (0);
+
+ for (i = 0; i < tstate->count; i++) {
+ if (strcmp(tstate->idx[i].name, name) != 0)
+ continue;
+ if (tstate->idx[i].set != tstate->set)
+ continue;
+
+ return (tstate->idx[i].idx);
+ }
+
+ if (tstate->count + 1 > tstate->size) {
+ tstate->size += 4;
+ tstate->idx = realloc(tstate->idx, tstate->size *
+ sizeof(ipfw_obj_ntlv));
+ if (tstate->idx == NULL)
+ return (0);
+ }
+
+ ntlv = &tstate->idx[i];
+ memset(ntlv, 0, sizeof(ipfw_obj_ntlv));
+ strlcpy(ntlv->name, name, sizeof(ntlv->name));
+ ntlv->head.type = IPFW_TLV_TBL_NAME;
+ ntlv->head.length = sizeof(ipfw_obj_ntlv);
+ ntlv->set = tstate->set;
+ ntlv->idx = ++tstate->counter;
+ tstate->count++;
+
+ return (ntlv->idx);
+}
+
+static void
+fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate)
+{
+ uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
+ uint16_t uidx;
+ char *p;
+
+ if ((p = strchr(av + 6, ')')) == NULL)
+ errx(EX_DATAERR, "forgotten parenthesis: '%s'", av);
+ *p = '\0';
+ p = strchr(av + 6, ',');
+ if (p)
+ *p++ = '\0';
+
+ if ((uidx = pack_table(tstate, av + 6)) == 0)
+ errx(EX_DATAERR, "Invalid table name: %s", av + 6);
+
+ cmd->opcode = opcode;
+ cmd->arg1 = uidx;
+ if (p) {
+ cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
+ d[0] = strtoul(p, NULL, 0);
+ } else
+ cmd->len |= F_INSN_SIZE(ipfw_insn);
+}
+
+
/*
* fills the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
@@ -2201,11 +2795,10 @@ lookup_host (char *host, struct in_addr *ipaddr)
* We can have multiple comma-separated address/mask entries.
*/
static void
-fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
+fill_ip(ipfw_insn_ip *cmd, char *av, int cblen, struct tidx *tstate)
{
int len = 0;
uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
- uint32_t tables_max;
cmd->o.len &= ~F_LEN_MASK; /* zero len */
@@ -2218,21 +2811,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
}
if (strncmp(av, "table(", 6) == 0) {
- char *p = strchr(av + 6, ',');
-
- if (p)
- *p++ = '\0';
- cmd->o.opcode = O_IP_DST_LOOKUP;
- cmd->o.arg1 = strtoul(av + 6, NULL, 0);
- tables_max = ipfw_get_tables_max();
- if (cmd->o.arg1 > tables_max)
- errx(EX_USAGE, "The table number exceeds the maximum "
- "allowed value (%u)", tables_max - 1);
- if (p) {
- cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
- d[0] = strtoul(p, NULL, 0);
- } else
- cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate);
return;
}
@@ -2413,35 +2992,16 @@ n2mask(struct in6_addr *mask, int n)
return;
}
-/*
- * helper function to process a set of flags and set bits in the
- * appropriate masks.
- */
static void
-fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
+fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode,
struct _s_x *flags, char *p)
{
- uint8_t set=0, clear=0;
+ char *e;
+ uint32_t set = 0, clear = 0;
- while (p && *p) {
- char *q; /* points to the separator */
- int val;
- uint8_t *which; /* mask we are working on */
+ if (fill_flags(flags, p, &e, &set, &clear) != 0)
+ errx(EX_DATAERR, "invalid flag %s", e);
- if (*p == '!') {
- p++;
- which = &clear;
- } else
- which = &set;
- q = strchr(p, ',');
- if (q)
- *q++ = '\0';
- val = match_token(flags, p);
- if (val <= 0)
- errx(EX_DATAERR, "invalid flag %s", p);
- *which |= (uint8_t)val;
- p = q;
- }
cmd->opcode = opcode;
cmd->len = (cmd->len & (F_NOT | F_OR)) | 1;
cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8);
@@ -2451,13 +3011,14 @@ fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
void
ipfw_delete(char *av[])
{
- uint32_t rulenum;
int i;
int exitval = EX_OK;
int do_set = 0;
+ ipfw_range_tlv rt;
av++;
NEED1("missing rule specification");
+ memset(&rt, 0, sizeof(rt));
if ( *av && _substrcmp(*av, "set") == 0) {
/* Do not allow using the following syntax:
* ipfw set N delete set M
@@ -2480,16 +3041,34 @@ ipfw_delete(char *av[])
} else if (co.do_pipe) {
exitval = ipfw_delete_pipe(co.do_pipe, i);
} else {
- if (co.use_set)
- rulenum = (i & 0xffff) | (5 << 24) |
- ((co.use_set - 1) << 16);
- else
- rulenum = (i & 0xffff) | (do_set << 24);
- i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum);
- if (i) {
+ if (do_set != 0) {
+ rt.set = i & 31;
+ rt.flags = IPFW_RCFLAG_SET;
+ } else {
+ rt.start_rule = i & 0xffff;
+ rt.end_rule = i & 0xffff;
+ if (rt.start_rule == 0 && rt.end_rule == 0)
+ rt.flags |= IPFW_RCFLAG_ALL;
+ else
+ rt.flags |= IPFW_RCFLAG_RANGE;
+ if (co.use_set != 0) {
+ rt.set = co.use_set - 1;
+ rt.flags |= IPFW_RCFLAG_SET;
+ }
+ }
+ i = do_range_cmd(IP_FW_XDEL, &rt);
+ if (i != 0) {
exitval = EX_UNAVAILABLE;
- warn("rule %u: setsockopt(IP_FW_DEL)",
- rulenum);
+ warn("rule %u: setsockopt(IP_FW_XDEL)",
+ rt.start_rule);
+ } else if (rt.new_set == 0) {
+ exitval = EX_UNAVAILABLE;
+ if (rt.start_rule != rt.end_rule)
+ warnx("no rules rules in %u-%u range",
+ rt.start_rule, rt.end_rule);
+ else
+ warnx("rule %u not found",
+ rt.start_rule);
}
}
}
@@ -2506,8 +3085,11 @@ ipfw_delete(char *av[])
* patterns which match interfaces.
*/
static void
-fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
+fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate)
{
+ char *p;
+ uint16_t uidx;
+
cmd->name[0] = '\0';
cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
@@ -2517,11 +3099,17 @@ fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
if (strcmp(arg, "any") == 0)
cmd->o.len = 0; /* effectively ignore this command */
else if (strncmp(arg, "table(", 6) == 0) {
- char *p = strchr(arg + 6, ',');
+ if ((p = strchr(arg + 6, ')')) == NULL)
+ errx(EX_DATAERR, "forgotten parenthesis: '%s'", arg);
+ *p = '\0';
+ p = strchr(arg + 6, ',');
if (p)
*p++ = '\0';
+ if ((uidx = pack_table(tstate, arg + 6)) == 0)
+ errx(EX_DATAERR, "Invalid table name: %s", arg + 6);
+
cmd->name[0] = '\1'; /* Special value indicating table */
- cmd->p.glob = strtoul(arg + 6, NULL, 0);
+ cmd->p.kidx = uidx;
} else if (!isdigit(*arg)) {
strlcpy(cmd->name, arg, sizeof(cmd->name));
cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0;
@@ -2735,9 +3323,9 @@ add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop)
}
static ipfw_insn *
-add_srcip(ipfw_insn *cmd, char *av, int cblen)
+add_srcip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
{
- fill_ip((ipfw_insn_ip *)cmd, av, cblen);
+ fill_ip((ipfw_insn_ip *)cmd, av, cblen, tstate);
if (cmd->opcode == O_IP_DST_SET) /* set */
cmd->opcode = O_IP_SRC_SET;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -2752,9 +3340,9 @@ add_srcip(ipfw_insn *cmd, char *av, int cblen)
}
static ipfw_insn *
-add_dstip(ipfw_insn *cmd, char *av, int cblen)
+add_dstip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
{
- fill_ip((ipfw_insn_ip *)cmd, av, cblen);
+ fill_ip((ipfw_insn_ip *)cmd, av, cblen, tstate);
if (cmd->opcode == O_IP_DST_SET) /* set */
;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -2768,13 +3356,34 @@ add_dstip(ipfw_insn *cmd, char *av, int cblen)
return cmd;
}
+static struct _s_x f_reserved_keywords[] = {
+ { "altq", TOK_OR },
+ { "//", TOK_OR },
+ { "diverted", TOK_OR },
+ { "dst-port", TOK_OR },
+ { "src-port", TOK_OR },
+ { "established", TOK_OR },
+ { "keep-state", TOK_OR },
+ { "frag", TOK_OR },
+ { "icmptypes", TOK_OR },
+ { "in", TOK_OR },
+ { "out", TOK_OR },
+ { "ip6", TOK_OR },
+ { "any", TOK_OR },
+ { "to", TOK_OR },
+ { "via", TOK_OR },
+ { "{", TOK_OR },
+ { NULL, 0 } /* terminator */
+};
+
static ipfw_insn *
add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
{
- /* XXX "any" is trapped before. Perhaps "to" */
- if (_substrcmp(av, "any") == 0) {
- return NULL;
- } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
+
+ if (match_token(f_reserved_keywords, av) != -1)
+ return (NULL);
+
+ if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
/* XXX todo: check that we have a protocol with ports */
cmd->opcode = opcode;
return cmd;
@@ -2783,7 +3392,7 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
}
static ipfw_insn *
-add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
+add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate)
{
struct in6_addr a;
char *host, *ch, buf[INET6_ADDRSTRLEN];
@@ -2806,7 +3415,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
inet_pton(AF_INET6, host, &a) != 1))
- ret = add_srcip(cmd, av, cblen);
+ ret = add_srcip(cmd, av, cblen, tstate);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2814,7 +3423,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
}
static ipfw_insn *
-add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
+add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate)
{
struct in6_addr a;
char *host, *ch, buf[INET6_ADDRSTRLEN];
@@ -2837,7 +3446,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
inet_pton(AF_INET6, host, &a) != 1))
- ret = add_dstip(cmd, av, cblen);
+ ret = add_dstip(cmd, av, cblen, tstate);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2857,7 +3466,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
*
*/
void
-ipfw_add(char *av[])
+compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
{
/*
* rules are added into the 'rulebuf' and then copied in
@@ -2865,13 +3474,13 @@ ipfw_add(char *av[])
* Some things that need to go out of order (prob, action etc.)
* go into actbuf[].
*/
- static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
+ static uint32_t actbuf[255], cmdbuf[255];
int rblen, ablen, cblen;
ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
ipfw_insn *first_cmd; /* first match pattern */
- struct ip_fw *rule;
+ struct ip_fw_rule *rule;
/*
* various flags used to record that we entered some fields.
@@ -2891,14 +3500,14 @@ ipfw_add(char *av[])
bzero(actbuf, sizeof(actbuf)); /* actions go here */
bzero(cmdbuf, sizeof(cmdbuf));
- bzero(rulebuf, sizeof(rulebuf));
+ bzero(rbuf, *rbufsize);
- rule = (struct ip_fw *)rulebuf;
+ rule = (struct ip_fw_rule *)rbuf;
cmd = (ipfw_insn *)cmdbuf;
action = (ipfw_insn *)actbuf;
- rblen = sizeof(rulebuf) / sizeof(rulebuf[0]);
- rblen -= offsetof(struct ip_fw, cmd) / sizeof(rulebuf[0]);
+ rblen = *rbufsize / sizeof(uint32_t);
+ rblen -= sizeof(struct ip_fw_rule) / sizeof(uint32_t);
ablen = sizeof(actbuf) / sizeof(actbuf[0]);
cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]);
cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
@@ -2920,6 +3529,7 @@ ipfw_add(char *av[])
if (set < 0 || set > RESVD_SET)
errx(EX_DATAERR, "illegal set %s", av[1]);
rule->set = set;
+ tstate->set = set;
av += 2;
}
@@ -3029,7 +3639,7 @@ chkarg:
errx(EX_DATAERR, "illegal argument for %s",
*(av - 1));
} else if (_substrcmp(*av, "tablearg") == 0) {
- action->arg1 = IP_FW_TABLEARG;
+ action->arg1 = IP_FW_TARG;
} else if (i == TOK_DIVERT || i == TOK_TEE) {
struct servent *s;
setservent(1);
@@ -3153,7 +3763,7 @@ chkarg:
action->opcode = O_SETFIB;
NEED1("missing fib number");
if (_substrcmp(*av, "tablearg") == 0) {
- action->arg1 = IP_FW_TABLEARG;
+ action->arg1 = IP_FW_TARG;
} else {
action->arg1 = strtoul(*av, NULL, 10);
if (sysctlbyname("net.fibs", &numfibs, &intsize,
@@ -3161,6 +3771,8 @@ chkarg:
errx(EX_DATAERR, "fibs not suported.\n");
if (action->arg1 >= numfibs) /* Temporary */
errx(EX_DATAERR, "fib too large.\n");
+ /* Add high-order bit to fib to make room for tablearg*/
+ action->arg1 |= 0x8000;
}
av++;
break;
@@ -3173,13 +3785,16 @@ chkarg:
action->opcode = O_SETDSCP;
NEED1("missing DSCP code");
if (_substrcmp(*av, "tablearg") == 0) {
- action->arg1 = IP_FW_TABLEARG;
+ action->arg1 = IP_FW_TARG;
} else if (isalpha(*av[0])) {
if ((code = match_token(f_ipdscp, *av)) == -1)
errx(EX_DATAERR, "Unknown DSCP code");
action->arg1 = code;
} else
action->arg1 = strtoul(*av, NULL, 10);
+ /* Add high-order bit to DSCP to make room for tablearg */
+ if (action->arg1 != IP_FW_TARG)
+ action->arg1 |= 0x8000;
av++;
break;
}
@@ -3386,7 +4001,7 @@ chkarg:
OR_START(source_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing source address");
- if (add_src(cmd, *av, proto, cblen)) {
+ if (add_src(cmd, *av, proto, cblen, tstate)) {
av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
@@ -3422,7 +4037,7 @@ chkarg:
OR_START(dest_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing dst address");
- if (add_dst(cmd, *av, proto, cblen)) {
+ if (add_dst(cmd, *av, proto, cblen, tstate)) {
av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
@@ -3451,7 +4066,7 @@ read_options:
* nothing specified so far, store in the rule to ease
* printout later.
*/
- rule->_pad = 1;
+ rule->flags |= IPFW_RULE_NOOPT;
}
prev = NULL;
while ( av[0] != NULL ) {
@@ -3529,7 +4144,7 @@ read_options:
case TOK_VIA:
NEED1("recv, xmit, via require interface name"
" or address");
- fill_iface((ipfw_insn_if *)cmd, av[0], cblen);
+ fill_iface((ipfw_insn_if *)cmd, av[0], cblen, tstate);
av++;
if (F_LEN(cmd) == 0) /* not a valid address */
break;
@@ -3604,13 +4219,13 @@ read_options:
case TOK_IPOPTS:
NEED1("missing argument for ipoptions");
- fill_flags(cmd, O_IPOPT, f_ipopts, *av);
+ fill_flags_cmd(cmd, O_IPOPT, f_ipopts, *av);
av++;
break;
case TOK_IPTOS:
NEED1("missing argument for iptos");
- fill_flags(cmd, O_IPTOS, f_iptos, *av);
+ fill_flags_cmd(cmd, O_IPTOS, f_iptos, *av);
av++;
break;
@@ -3688,7 +4303,7 @@ read_options:
case TOK_TCPOPTS:
NEED1("missing argument for tcpoptions");
- fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);
+ fill_flags_cmd(cmd, O_TCPOPTS, f_tcpopts, *av);
av++;
break;
@@ -3715,7 +4330,7 @@ read_options:
case TOK_TCPFLAGS:
NEED1("missing argument for tcpflags");
cmd->opcode = O_TCPFLAGS;
- fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);
+ fill_flags_cmd(cmd, O_TCPFLAGS, f_tcpflags, *av);
av++;
break;
@@ -3775,14 +4390,14 @@ read_options:
case TOK_SRCIP:
NEED1("missing source IP");
- if (add_srcip(cmd, *av, cblen)) {
+ if (add_srcip(cmd, *av, cblen, tstate)) {
av++;
}
break;
case TOK_DSTIP:
NEED1("missing destination IP");
- if (add_dstip(cmd, *av, cblen)) {
+ if (add_dstip(cmd, *av, cblen, tstate)) {
av++;
}
break;
@@ -3901,7 +4516,6 @@ read_options:
case TOK_LOOKUP: {
ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
- char *p;
int j;
if (!av[0] || !av[1])
@@ -3917,12 +4531,22 @@ read_options:
errx(EX_USAGE, "format: cannot lookup on %s", *av);
__PAST_END(c->d, 1) = j; // i converted to option
av++;
- cmd->arg1 = strtoul(*av, &p, 0);
- if (p && *p)
- errx(EX_USAGE, "format: lookup argument tablenum");
+
+ if ((j = pack_table(tstate, *av)) == 0)
+ errx(EX_DATAERR, "Invalid table name: %s", *av);
+
+ cmd->arg1 = j;
av++;
}
break;
+ case TOK_FLOW:
+ NEED1("missing table name");
+ if (strncmp(*av, "table(", 6) != 0)
+ errx(EX_DATAERR,
+ "enclose table name into \"table()\"");
+ fill_table(cmd, *av, O_IP_FLOW_LOOKUP, tstate);
+ av++;
+ break;
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
@@ -4024,34 +4648,143 @@ done:
}
rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd);
- i = (char *)dst - (char *)rule;
- if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1)
- err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
- if (!co.do_quiet)
- show_ipfw(rule, 0, 0);
+ *rbufsize = (char *)dst - (char *)rule;
+}
+
+/*
+ * Adds one or more rules to ipfw chain.
+ * Data layout:
+ * Request:
+ * [
+ * ip_fw3_opheader
+ * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
+ * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ] (*2) (*3)
+ * ]
+ * Reply:
+ * [
+ * ip_fw3_opheader
+ * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
+ * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ]
+ * ]
+ *
+ * Rules in reply are modified to store their actual ruleset number.
+ *
+ * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
+ * accoring to their idx field and there has to be no duplicates.
+ * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
+ * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
+ */
+void
+ipfw_add(char *av[])
+{
+ uint32_t rulebuf[1024];
+ int rbufsize, default_off, tlen, rlen;
+ size_t sz;
+ struct tidx ts;
+ struct ip_fw_rule *rule;
+ caddr_t tbuf;
+ ip_fw3_opheader *op3;
+ ipfw_obj_ctlv *ctlv, *tstate;
+
+ rbufsize = sizeof(rulebuf);
+ memset(rulebuf, 0, rbufsize);
+ memset(&ts, 0, sizeof(ts));
+
+ /* Optimize case with no tables */
+ default_off = sizeof(ipfw_obj_ctlv) + sizeof(ip_fw3_opheader);
+ op3 = (ip_fw3_opheader *)rulebuf;
+ ctlv = (ipfw_obj_ctlv *)(op3 + 1);
+ rule = (struct ip_fw_rule *)(ctlv + 1);
+ rbufsize -= default_off;
+
+ compile_rule(av, (uint32_t *)rule, &rbufsize, &ts);
+ /* Align rule size to u64 boundary */
+ rlen = roundup2(rbufsize, sizeof(uint64_t));
+
+ tbuf = NULL;
+ sz = 0;
+ tstate = NULL;
+ if (ts.count != 0) {
+ /* Some tables. We have to alloc more data */
+ tlen = ts.count * sizeof(ipfw_obj_ntlv);
+ sz = default_off + sizeof(ipfw_obj_ctlv) + tlen + rlen;
+
+ if ((tbuf = calloc(1, sz)) == NULL)
+ err(EX_UNAVAILABLE, "malloc() failed for IP_FW_ADD");
+ op3 = (ip_fw3_opheader *)tbuf;
+ /* Tables first */
+ ctlv = (ipfw_obj_ctlv *)(op3 + 1);
+ ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
+ ctlv->head.length = sizeof(ipfw_obj_ctlv) + tlen;
+ ctlv->count = ts.count;
+ ctlv->objsize = sizeof(ipfw_obj_ntlv);
+ memcpy(ctlv + 1, ts.idx, tlen);
+ table_sort_ctlv(ctlv);
+ tstate = ctlv;
+ /* Rule next */
+ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
+ ctlv->head.type = IPFW_TLV_RULE_LIST;
+ ctlv->head.length = sizeof(ipfw_obj_ctlv) + rlen;
+ ctlv->count = 1;
+ memcpy(ctlv + 1, rule, rbufsize);
+ } else {
+ /* Simply add header */
+ sz = rlen + default_off;
+ memset(ctlv, 0, sizeof(*ctlv));
+ ctlv->head.type = IPFW_TLV_RULE_LIST;
+ ctlv->head.length = sizeof(ipfw_obj_ctlv) + rlen;
+ ctlv->count = 1;
+ }
+
+ if (do_get3(IP_FW_XADD, op3, &sz) != 0)
+ err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_XADD");
+
+ if (!co.do_quiet) {
+ struct format_opts sfo;
+ struct buf_pr bp;
+ memset(&sfo, 0, sizeof(sfo));
+ sfo.tstate = tstate;
+ sfo.set_mask = (uint32_t)(-1);
+ bp_alloc(&bp, 4096);
+ show_static_rule(&co, &sfo, &bp, rule, NULL);
+ printf("%s", bp.buf);
+ bp_free(&bp);
+ }
+
+ if (tbuf != NULL)
+ free(tbuf);
+
+ if (ts.idx != NULL)
+ free(ts.idx);
}
/*
* clear the counters or the log counters.
+ * optname has the following values:
+ * 0 (zero both counters and logging)
+ * 1 (zero logging only)
*/
void
-ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG */)
+ipfw_zero(int ac, char *av[], int optname)
{
- uint32_t arg, saved_arg;
+ ipfw_range_tlv rt;
+ uint32_t arg;
int failed = EX_OK;
char const *errstr;
char const *name = optname ? "RESETLOG" : "ZERO";
- optname = optname ? IP_FW_RESETLOG : IP_FW_ZERO;
+ optname = optname ? IP_FW_XRESETLOG : IP_FW_XZERO;
+ memset(&rt, 0, sizeof(rt));
av++; ac--;
- if (!ac) {
+ if (ac == 0) {
/* clear all entries */
- if (do_cmd(optname, NULL, 0) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name);
+ rt.flags = IPFW_RCFLAG_ALL;
+ if (do_range_cmd(optname, &rt) < 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_FW_X%s)", name);
if (!co.do_quiet)
- printf("%s.\n", optname == IP_FW_ZERO ?
+ printf("%s.\n", optname == IP_FW_XZERO ?
"Accounting cleared":"Logging counts reset");
return;
@@ -4064,22 +4797,28 @@ ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG
if (errstr)
errx(EX_DATAERR,
"invalid rule number %s\n", *av);
- saved_arg = arg;
- if (co.use_set)
- arg |= (1 << 24) | ((co.use_set - 1) << 16);
- av++;
- ac--;
- if (do_cmd(optname, &arg, sizeof(arg))) {
- warn("rule %u: setsockopt(IP_FW_%s)",
- saved_arg, name);
+ rt.start_rule = arg;
+ rt.end_rule = arg;
+ rt.flags |= IPFW_RCFLAG_RANGE;
+ if (co.use_set != 0) {
+ rt.set = co.use_set - 1;
+ rt.flags |= IPFW_RCFLAG_SET;
+ }
+ if (do_range_cmd(optname, &rt) != 0) {
+ warn("rule %u: setsockopt(IP_FW_X%s)",
+ arg, name);
+ failed = EX_UNAVAILABLE;
+ } else if (rt.new_set == 0) {
+ printf("Entry %d not found\n", arg);
failed = EX_UNAVAILABLE;
} else if (!co.do_quiet)
- printf("Entry %d %s.\n", saved_arg,
- optname == IP_FW_ZERO ?
+ printf("Entry %d %s.\n", arg,
+ optname == IP_FW_XZERO ?
"cleared" : "logging count reset");
} else {
errx(EX_USAGE, "invalid rule number ``%s''", *av);
}
+ av++; ac--;
}
if (failed != EX_OK)
exit(failed);
@@ -4088,7 +4827,7 @@ ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG
void
ipfw_flush(int force)
{
- int cmd = co.do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH;
+ ipfw_range_tlv rt;
if (!force && !co.do_quiet) { /* need to ask user */
int c;
@@ -4110,316 +4849,121 @@ ipfw_flush(int force)
return;
}
/* `ipfw set N flush` - is the same that `ipfw delete set N` */
- if (co.use_set) {
- uint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24);
- if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)");
- } else if (do_cmd(cmd, NULL, 0) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
- co.do_pipe ? "DUMMYNET" : "FW");
+ memset(&rt, 0, sizeof(rt));
+ if (co.use_set != 0) {
+ rt.set = co.use_set - 1;
+ rt.flags = IPFW_RCFLAG_SET;
+ } else
+ rt.flags = IPFW_RCFLAG_ALL;
+ if (do_range_cmd(IP_FW_XDEL, &rt) != 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_FW_XDEL)");
if (!co.do_quiet)
printf("Flushed all %s.\n", co.do_pipe ? "pipes" : "rules");
}
+static struct _s_x intcmds[] = {
+ { "talist", TOK_TALIST },
+ { "iflist", TOK_IFLIST },
+ { "vlist", TOK_VLIST },
+ { NULL, 0 }
+};
-static void table_list(uint16_t num, int need_header);
-static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
-
-/*
- * Retrieve maximum number of tables supported by ipfw(4) module.
- */
-uint32_t
-ipfw_get_tables_max()
-{
- size_t len;
- uint32_t tables_max;
-
- if (ipfw_tables_max != 0)
- return (ipfw_tables_max);
-
- len = sizeof(tables_max);
- if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
- NULL, 0) == -1) {
- if (co.test_only)
- tables_max = 128; /* Old conservative default */
- else
- errx(1, "Can't determine maximum number of ipfw tables."
- " Perhaps you forgot to load ipfw module?");
- }
-
- ipfw_tables_max = tables_max;
-
- return (ipfw_tables_max);
-}
-
-/*
- * This one handles all table-related commands
- * ipfw table N add addr[/masklen] [value]
- * ipfw table N delete addr[/masklen]
- * ipfw table {N | all} flush
- * ipfw table {N | all} list
- */
void
-ipfw_table_handler(int ac, char *av[])
+ipfw_internal_handler(int ac, char *av[])
{
- ipfw_table_xentry xent;
- int do_add;
- int is_all;
- uint32_t a;
- uint32_t tables_max;
+ int tcmd;
- tables_max = ipfw_get_tables_max();
+ ac--; av++;
+ NEED1("internal cmd required");
- memset(&xent, 0, sizeof(xent));
+ if ((tcmd = match_token(intcmds, *av)) == -1)
+ errx(EX_USAGE, "invalid internal sub-cmd: %s", *av);
- ac--; av++;
- if (ac && isdigit(**av)) {
- xent.tbl = atoi(*av);
- is_all = 0;
- ac--; av++;
- } else if (ac && _substrcmp(*av, "all") == 0) {
- xent.tbl = 0;
- is_all = 1;
- ac--; av++;
- } else
- errx(EX_USAGE, "table number or 'all' keyword required");
- if (xent.tbl >= tables_max)
- errx(EX_USAGE, "The table number exceeds the maximum allowed "
- "value (%d)", tables_max - 1);
- NEED1("table needs command");
- if (is_all && _substrcmp(*av, "list") != 0
- && _substrcmp(*av, "flush") != 0)
- errx(EX_USAGE, "table number required");
-
- if (_substrcmp(*av, "add") == 0 ||
- _substrcmp(*av, "delete") == 0) {
- do_add = **av == 'a';
- ac--; av++;
- if (!ac)
- errx(EX_USAGE, "address required");
-
- table_fill_xentry(*av, &xent);
-
- ac--; av++;
- if (do_add && ac) {
- unsigned int tval;
- /* isdigit is a bit of a hack here.. */
- if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
- xent.value = strtoul(*av, NULL, 0);
- } else {
- if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
- /* The value must be stored in host order *
- * so that the values < 65k can be distinguished */
- xent.value = ntohl(tval);
- } else {
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
- }
- }
- } else
- xent.value = 0;
- if (do_setcmd3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL,
- &xent, xent.len) < 0) {
- /* If running silent, don't bomb out on these errors. */
- if (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH))))
- err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)",
- do_add ? "XADD" : "XDEL");
- /* In silent mode, react to a failed add by deleting */
- if (do_add) {
- do_setcmd3(IP_FW_TABLE_XDEL, &xent, xent.len);
- if (do_setcmd3(IP_FW_TABLE_XADD, &xent, xent.len) < 0)
- err(EX_OSERR,
- "setsockopt(IP_FW_TABLE_XADD)");
- }
- }
- } else if (_substrcmp(*av, "flush") == 0) {
- a = is_all ? tables_max : (uint32_t)(xent.tbl + 1);
- do {
- if (do_cmd(IP_FW_TABLE_FLUSH, &xent.tbl,
- sizeof(xent.tbl)) < 0)
- err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)");
- } while (++xent.tbl < a);
- } else if (_substrcmp(*av, "list") == 0) {
- a = is_all ? tables_max : (uint32_t)(xent.tbl + 1);
- do {
- table_list(xent.tbl, is_all);
- } while (++xent.tbl < a);
- } else
- errx(EX_USAGE, "invalid table command %s", *av);
+ switch (tcmd) {
+ case TOK_IFLIST:
+ ipfw_list_tifaces();
+ break;
+ case TOK_TALIST:
+ ipfw_list_ta(ac, av);
+ break;
+ case TOK_VLIST:
+ ipfw_list_values(ac, av);
+ break;
+ }
}
-static void
-table_fill_xentry(char *arg, ipfw_table_xentry *xent)
+static int
+ipfw_get_tracked_ifaces(ipfw_obj_lheader **polh)
{
- int addrlen, mask, masklen, type;
- struct in6_addr *paddr;
- uint32_t *pkey;
- char *p;
- uint32_t key;
-
- mask = 0;
- type = 0;
- addrlen = 0;
- masklen = 0;
-
- /*
- * Let's try to guess type by agrument.
- * Possible types:
- * 1) IPv4[/mask]
- * 2) IPv6[/mask]
- * 3) interface name
- * 4) port, uid/gid or other u32 key (base 10 format)
- * 5) hostname
- */
- paddr = &xent->k.addr6;
- if (ishexnumber(*arg) != 0 || *arg == ':') {
- /* Remove / if exists */
- if ((p = strchr(arg, '/')) != NULL) {
- *p = '\0';
- mask = atoi(p + 1);
- }
-
- if (inet_pton(AF_INET, arg, paddr) == 1) {
- if (p != NULL && mask > 32)
- errx(EX_DATAERR, "bad IPv4 mask width: %s",
- p + 1);
+ ipfw_obj_lheader req, *olh;
+ size_t sz;
- type = IPFW_TABLE_CIDR;
- masklen = p ? mask : 32;
- addrlen = sizeof(struct in_addr);
- } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
- if (IN6_IS_ADDR_V4COMPAT(paddr))
- errx(EX_DATAERR,
- "Use IPv4 instead of v4-compatible");
- if (p != NULL && mask > 128)
- errx(EX_DATAERR, "bad IPv6 mask width: %s",
- p + 1);
-
- type = IPFW_TABLE_CIDR;
- masklen = p ? mask : 128;
- addrlen = sizeof(struct in6_addr);
- } else {
- /* Port or any other key */
- /* Skip non-base 10 entries like 'fa1' */
- key = strtol(arg, &p, 10);
- if (*p == '\0') {
- pkey = (uint32_t *)paddr;
- *pkey = htonl(key);
- type = IPFW_TABLE_CIDR;
- masklen = 32;
- addrlen = sizeof(uint32_t);
- } else if ((p != arg) && (*p == '.')) {
- /*
- * Warn on IPv4 address strings
- * which are "valid" for inet_aton() but not
- * in inet_pton().
- *
- * Typical examples: '10.5' or '10.0.0.05'
- */
- errx(EX_DATAERR,
- "Invalid IPv4 address: %s", arg);
- }
- }
- }
+ memset(&req, 0, sizeof(req));
+ sz = sizeof(req);
- if (type == 0 && strchr(arg, '.') == NULL) {
- /* Assume interface name. Copy significant data only */
- mask = MIN(strlen(arg), IF_NAMESIZE - 1);
- memcpy(xent->k.iface, arg, mask);
- /* Set mask to exact match */
- masklen = 8 * IF_NAMESIZE;
- type = IPFW_TABLE_INTERFACE;
- addrlen = IF_NAMESIZE;
+ if (do_get3(IP_FW_XIFLIST, &req.opheader, &sz) != 0) {
+ if (errno != ENOMEM)
+ return (errno);
}
- if (type == 0) {
- if (lookup_host(arg, (struct in_addr *)paddr) != 0)
- errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
+ sz = req.size;
+ if ((olh = calloc(1, sz)) == NULL)
+ return (ENOMEM);
- masklen = 32;
- type = IPFW_TABLE_CIDR;
- addrlen = sizeof(struct in_addr);
+ olh->size = sz;
+ if (do_get3(IP_FW_XIFLIST, &olh->opheader, &sz) != 0) {
+ free(olh);
+ return (errno);
}
- xent->type = type;
- xent->masklen = masklen;
- xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+ *polh = olh;
+ return (0);
}
-static void
-table_list(uint16_t num, int need_header)
+static int
+ifinfo_cmp(const void *a, const void *b)
{
- ipfw_xtable *tbl;
- ipfw_table_xentry *xent;
- socklen_t l;
- uint32_t *a, sz, tval;
- char tbuf[128];
- struct in6_addr *addr6;
- ip_fw3_opheader *op3;
+ ipfw_iface_info *ia, *ib;
- /* Prepend value with IP_FW3 header */
- l = sizeof(ip_fw3_opheader) + sizeof(uint32_t);
- op3 = alloca(l);
- /* Zero reserved fields */
- memset(op3, 0, sizeof(ip_fw3_opheader));
- a = (uint32_t *)(op3 + 1);
- *a = num;
- op3->opcode = IP_FW_TABLE_XGETSIZE;
- if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)");
-
- /* If a is zero we have nothing to do, the table is empty. */
- if (*a == 0)
- return;
+ ia = (ipfw_iface_info *)a;
+ ib = (ipfw_iface_info *)b;
- l = *a;
- tbl = safe_calloc(1, l);
- tbl->opheader.opcode = IP_FW_TABLE_XLIST;
- tbl->tbl = num;
- if (do_cmd(IP_FW3, tbl, (uintptr_t)&l) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_TABLE_XLIST)");
- if (tbl->cnt && need_header)
- printf("---table(%d)---\n", tbl->tbl);
- sz = tbl->size - sizeof(ipfw_xtable);
- xent = &tbl->xent[0];
- while (sz > 0) {
- switch (tbl->type) {
- case IPFW_TABLE_CIDR:
- /* IPv4 or IPv6 prefixes */
- tval = xent->value;
- addr6 = &xent->k.addr6;
+ return (stringnum_cmp(ia->ifname, ib->ifname));
+}
+/*
+ * Retrieves table list from kernel,
+ * optionally sorts it and calls requested function for each table.
+ * Returns 0 on success.
+ */
+static void
+ipfw_list_tifaces()
+{
+ ipfw_obj_lheader *olh;
+ ipfw_iface_info *info;
+ int i, error;
- if ((xent->flags & IPFW_TCF_INET) != 0) {
- /* IPv4 address */
- inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
- } else {
- /* IPv6 address */
- inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
- }
+ if ((error = ipfw_get_tracked_ifaces(&olh)) != 0)
+ err(EX_OSERR, "Unable to request ipfw tracked interface list");
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%s/%u %s\n", tbuf, xent->masklen,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%s/%u %u\n", tbuf, xent->masklen, tval);
- break;
- case IPFW_TABLE_INTERFACE:
- /* Interface names */
- tval = xent->value;
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%s %s\n", xent->k.iface,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%s %u\n", xent->k.iface, tval);
- }
- if (sz < xent->len)
- break;
- sz -= xent->len;
- xent = (ipfw_table_xentry *)((char *)xent + xent->len);
+ qsort(olh + 1, olh->count, olh->objsize, ifinfo_cmp);
+
+ info = (ipfw_iface_info *)(olh + 1);
+ for (i = 0; i < olh->count; i++) {
+ if (info->flags & IPFW_IFFLAG_RESOLVED)
+ printf("%s ifindex: %d refcount: %u changes: %u\n",
+ info->ifname, info->ifindex, info->refcnt,
+ info->gencnt);
+ else
+ printf("%s ifindex: unresolved refcount: %u changes: %u\n",
+ info->ifname, info->refcnt, info->gencnt);
+ info = (ipfw_iface_info *)((caddr_t)info + olh->objsize);
}
- free(tbl);
+ free(olh);
}
+
+
+
+
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 2301c40..80970ef 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -71,6 +71,8 @@ struct _s_x {
int x;
};
+extern struct _s_x f_ipdscp[];
+
enum tokens {
TOK_NULL=0,
@@ -205,7 +207,28 @@ enum tokens {
TOK_LOOKUP,
TOK_SOCKARG,
TOK_SETDSCP,
+ TOK_FLOW,
+ TOK_IFLIST,
+ /* Table tokens */
+ TOK_CREATE,
+ TOK_DESTROY,
+ TOK_LIST,
+ TOK_INFO,
+ TOK_DETAIL,
+ TOK_MODIFY,
+ TOK_FLUSH,
+ TOK_SWAP,
+ TOK_ADD,
+ TOK_DEL,
+ TOK_VALTYPE,
+ TOK_ALGO,
+ TOK_TALIST,
+ TOK_ATOMIC,
+ TOK_LOCK,
+ TOK_UNLOCK,
+ TOK_VLIST,
};
+
/*
* the following macro returns an error message if we run out of
* arguments.
@@ -213,7 +236,19 @@ enum tokens {
#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
#define NEED1(msg) {if (!(*av)) errx(EX_USAGE, msg);}
-int pr_u64(uint64_t *pd, int width);
+struct buf_pr {
+ char *buf; /* allocated buffer */
+ char *ptr; /* current pointer */
+ size_t size; /* total buffer size */
+ size_t avail; /* available storage */
+ size_t needed; /* length needed */
+};
+
+int pr_u64(struct buf_pr *bp, uint64_t *pd, int width);
+int bp_alloc(struct buf_pr *b, size_t size);
+void bp_free(struct buf_pr *b);
+int bprintf(struct buf_pr *b, char *format, ...);
+
/* memory allocation support */
void *safe_calloc(size_t number, size_t size);
@@ -222,14 +257,22 @@ void *safe_realloc(void *ptr, size_t size);
/* string comparison functions used for historical compatibility */
int _substrcmp(const char *str1, const char* str2);
int _substrcmp2(const char *str1, const char* str2, const char* str3);
+int stringnum_cmp(const char *a, const char *b);
/* utility functions */
int match_token(struct _s_x *table, char *string);
+int match_token_relaxed(struct _s_x *table, char *string);
char const *match_value(struct _s_x *p, int value);
+size_t concat_tokens(char *buf, size_t bufsize, struct _s_x *table,
+ char *delimiter);
+int fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+ uint32_t *clear);
+void print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set);
+struct _ip_fw3_opheader;
int do_cmd(int optname, void *optval, uintptr_t optlen);
-
-uint32_t ipfw_get_tables_max(void);
+int do_set3(int optname, struct _ip_fw3_opheader *op3, uintptr_t optlen);
+int do_get3(int optname, struct _ip_fw3_opheader *op3, size_t *optlen);
struct in6_addr;
void n2mask(struct in6_addr *mask, int n);
@@ -268,12 +311,13 @@ void ipfw_delete(char *av[]);
void ipfw_flush(int force);
void ipfw_zero(int ac, char *av[], int optname);
void ipfw_list(int ac, char *av[], int show_counters);
+void ipfw_internal_handler(int ac, char *av[]);
#ifdef PF
/* altq.c */
void altq_set_enabled(int enabled);
u_int32_t altq_name_to_qid(const char *name);
-void print_altq_cmd(struct _ipfw_insn_altq *altqptr);
+void print_altq_cmd(struct buf_pr *bp, struct _ipfw_insn_altq *altqptr);
#else
#define NO_ALTQ
#endif
@@ -285,10 +329,10 @@ int ipfw_delete_pipe(int pipe_or_queue, int n);
/* ipv6.c */
void print_unreach6_code(uint16_t code);
-void print_ip6(struct _ipfw_insn_ip6 *cmd, char const *s);
-void print_flow6id(struct _ipfw_insn_u32 *cmd);
-void print_icmp6types(struct _ipfw_insn_u32 *cmd);
-void print_ext6hdr(struct _ipfw_insn *cmd );
+void print_ip6(struct buf_pr *bp, struct _ipfw_insn_ip6 *cmd, char const *s);
+void print_flow6id(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd);
+void print_icmp6types(struct buf_pr *bp, struct _ipfw_insn_u32 *cmd);
+void print_ext6hdr(struct buf_pr *bp, struct _ipfw_insn *cmd );
struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen);
struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen);
@@ -297,3 +341,12 @@ void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
void fill_unreach6_code(u_short *codep, char *str);
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
+
+/* tables.c */
+struct _ipfw_obj_ctlv;
+char *table_search_ctlv(struct _ipfw_obj_ctlv *ctlv, uint16_t idx);
+void table_sort_ctlv(struct _ipfw_obj_ctlv *ctlv);
+int table_check_name(char *tablename);
+void ipfw_list_ta(int ac, char *av[]);
+void ipfw_list_values(int ac, char *av[]);
+
diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c
index ee9bb62..36ee675 100644
--- a/sbin/ipfw/ipv6.c
+++ b/sbin/ipfw/ipv6.c
@@ -85,21 +85,21 @@ print_unreach6_code(uint16_t code)
* Print the ip address contained in a command.
*/
void
-print_ip6(ipfw_insn_ip6 *cmd, char const *s)
+print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd, char const *s)
{
struct hostent *he = NULL;
int len = F_LEN((ipfw_insn *) cmd) - 1;
struct in6_addr *a = &(cmd->addr6);
char trad[255];
- printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
+ bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s);
if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
- printf("me6");
+ bprintf(bp, "me6");
return;
}
if (cmd->o.opcode == O_IP6) {
- printf(" ip6");
+ bprintf(bp, " ip6");
return;
}
@@ -117,21 +117,21 @@ print_ip6(ipfw_insn_ip6 *cmd, char const *s)
if (mb == 128 && co.do_resolv)
he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
if (he != NULL) /* resolved to name */
- printf("%s", he->h_name);
+ bprintf(bp, "%s", he->h_name);
else if (mb == 0) /* any */
- printf("any");
+ bprintf(bp, "any");
else { /* numeric IP followed by some kind of mask */
if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL)
- printf("Error ntop in print_ip6\n");
- printf("%s", trad );
+ bprintf(bp, "Error ntop in print_ip6\n");
+ bprintf(bp, "%s", trad );
if (mb < 0) /* XXX not really legal... */
- printf(":%s",
+ bprintf(bp, ":%s",
inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
else if (mb < 128)
- printf("/%d", mb);
+ bprintf(bp, "/%d", mb);
}
if (len > 2)
- printf(",");
+ bprintf(bp, ",");
}
}
@@ -165,32 +165,32 @@ fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
void
-print_icmp6types(ipfw_insn_u32 *cmd)
+print_icmp6types(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
int i, j;
char sep= ' ';
- printf(" ip6 icmp6types");
+ bprintf(bp, " ip6 icmp6types");
for (i = 0; i < 7; i++)
for (j=0; j < 32; ++j) {
if ( (cmd->d[i] & (1 << (j))) == 0)
continue;
- printf("%c%d", sep, (i*32 + j));
+ bprintf(bp, "%c%d", sep, (i*32 + j));
sep = ',';
}
}
void
-print_flow6id( ipfw_insn_u32 *cmd)
+print_flow6id(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
uint16_t i, limit = cmd->o.arg1;
char sep = ',';
- printf(" flow-id ");
+ bprintf(bp, " flow-id ");
for( i=0; i < limit; ++i) {
if (i == limit - 1)
sep = ' ';
- printf("%d%c", cmd->d[i], sep);
+ bprintf(bp, "%d%c", cmd->d[i], sep);
}
}
@@ -265,41 +265,41 @@ fill_ext6hdr( ipfw_insn *cmd, char *av)
}
void
-print_ext6hdr( ipfw_insn *cmd )
+print_ext6hdr(struct buf_pr *bp, ipfw_insn *cmd )
{
char sep = ' ';
- printf(" extension header:");
+ bprintf(bp, " extension header:");
if (cmd->arg1 & EXT_FRAGMENT ) {
- printf("%cfragmentation", sep);
+ bprintf(bp, "%cfragmentation", sep);
sep = ',';
}
if (cmd->arg1 & EXT_HOPOPTS ) {
- printf("%chop options", sep);
+ bprintf(bp, "%chop options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_ROUTING ) {
- printf("%crouting options", sep);
+ bprintf(bp, "%crouting options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_RTHDR0 ) {
- printf("%crthdr0", sep);
+ bprintf(bp, "%crthdr0", sep);
sep = ',';
}
if (cmd->arg1 & EXT_RTHDR2 ) {
- printf("%crthdr2", sep);
+ bprintf(bp, "%crthdr2", sep);
sep = ',';
}
if (cmd->arg1 & EXT_DSTOPTS ) {
- printf("%cdestination options", sep);
+ bprintf(bp, "%cdestination options", sep);
sep = ',';
}
if (cmd->arg1 & EXT_AH ) {
- printf("%cauthentication header", sep);
+ bprintf(bp, "%cauthentication header", sep);
sep = ',';
}
if (cmd->arg1 & EXT_ESP ) {
- printf("%cencapsulated security payload", sep);
+ bprintf(bp, "%cencapsulated security payload", sep);
}
}
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index 82a299b..f25578f 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -436,6 +436,10 @@ ipfw_main(int oldac, char **oldav)
ipfw_list(ac, av, do_acct);
else if (_substrcmp(*av, "show") == 0)
ipfw_list(ac, av, 1 /* show counters */);
+ else if (_substrcmp(*av, "table") == 0)
+ ipfw_table_handler(ac, av);
+ else if (_substrcmp(*av, "internal") == 0)
+ ipfw_internal_handler(ac, av);
else
errx(EX_USAGE, "bad command `%s'", *av);
}
diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c
index bff28e1..3bd0259 100644
--- a/sbin/ipfw/nat.c
+++ b/sbin/ipfw/nat.c
@@ -30,14 +30,13 @@
#include <ctype.h>
#include <err.h>
+#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
-#define IPFW_INTERNAL /* Access to protected structures in ip_fw.h. */
-
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h> /* def. of struct route */
@@ -46,6 +45,14 @@
#include <arpa/inet.h>
#include <alias.h>
+typedef int (nat_cb_t)(struct nat44_cfg_nat *cfg, void *arg);
+static void nat_show_cfg(struct nat44_cfg_nat *n, void *arg);
+static void nat_show_log(struct nat44_cfg_nat *n, void *arg);
+static int nat_show_data(struct nat44_cfg_nat *cfg, void *arg);
+static int natname_cmp(const void *a, const void *b);
+static int nat_foreach(nat_cb_t *f, void *arg, int sort);
+static int nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh);
+
static struct _s_x nat_params[] = {
{ "ip", TOK_IP },
{ "if", TOK_IF },
@@ -71,7 +78,7 @@ static struct _s_x nat_params[] = {
* n->if_name copy of interface name "ifn"
*/
static void
-set_addr_dynamic(const char *ifn, struct cfg_nat *n)
+set_addr_dynamic(const char *ifn, struct nat44_cfg_nat *n)
{
size_t needed;
int mib[6];
@@ -288,15 +295,15 @@ StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto,
* and SetupProtoRedirect() from natd.c.
*
* Every setup_* function fills at least one redirect entry
- * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool)
- * in buf.
+ * (struct nat44_cfg_redir) and zero or more server pool entry
+ * (struct nat44_cfg_spool) in buf.
*
* The format of data in buf is:
*
- * cfg_nat cfg_redir cfg_spool ...... cfg_spool
+ * nat44_cfg_nat nat44_cfg_redir nat44_cfg_spool ...... nat44_cfg_spool
*
* ------------------------------------- ------------
- * | | .....X ... | | | | .....
+ * | | .....X ..... | | | | .....
* ------------------------------------- ...... ------------
* ^
* spool_cnt n=0 ...... n=(X-1)
@@ -314,7 +321,7 @@ StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto,
static int
estimate_redir_addr(int *ac, char ***av)
{
- size_t space = sizeof(struct cfg_redir);
+ size_t space = sizeof(struct nat44_cfg_redir);
char *sep = **av;
u_int c = 0;
@@ -327,7 +334,7 @@ estimate_redir_addr(int *ac, char ***av)
if (c > 0)
c++;
- space += c * sizeof(struct cfg_spool);
+ space += c * sizeof(struct nat44_cfg_spool);
return (space);
}
@@ -335,31 +342,31 @@ estimate_redir_addr(int *ac, char ***av)
static int
setup_redir_addr(char *buf, int *ac, char ***av)
{
- struct cfg_redir *r;
+ struct nat44_cfg_redir *r;
char *sep;
size_t space;
- r = (struct cfg_redir *)buf;
+ r = (struct nat44_cfg_redir *)buf;
r->mode = REDIR_ADDR;
- /* Skip cfg_redir at beginning of buf. */
- buf = &buf[sizeof(struct cfg_redir)];
- space = sizeof(struct cfg_redir);
+ /* Skip nat44_cfg_redir at beginning of buf. */
+ buf = &buf[sizeof(struct nat44_cfg_redir)];
+ space = sizeof(struct nat44_cfg_redir);
/* Extract local address. */
if (strchr(**av, ',') != NULL) {
- struct cfg_spool *spool;
+ struct nat44_cfg_spool *spool;
/* Setup LSNAT server pool. */
r->laddr.s_addr = INADDR_NONE;
sep = strtok(**av, ",");
while (sep != NULL) {
- spool = (struct cfg_spool *)buf;
- space += sizeof(struct cfg_spool);
+ spool = (struct nat44_cfg_spool *)buf;
+ space += sizeof(struct nat44_cfg_spool);
StrToAddr(sep, &spool->addr);
spool->port = ~0;
r->spool_cnt++;
- /* Point to the next possible cfg_spool. */
- buf = &buf[sizeof(struct cfg_spool)];
+ /* Point to the next possible nat44_cfg_spool. */
+ buf = &buf[sizeof(struct nat44_cfg_spool)];
sep = strtok(NULL, ",");
}
} else
@@ -376,7 +383,7 @@ setup_redir_addr(char *buf, int *ac, char ***av)
static int
estimate_redir_port(int *ac, char ***av)
{
- size_t space = sizeof(struct cfg_redir);
+ size_t space = sizeof(struct nat44_cfg_redir);
char *sep = **av;
u_int c = 0;
@@ -389,7 +396,7 @@ estimate_redir_port(int *ac, char ***av)
if (c > 0)
c++;
- space += c * sizeof(struct cfg_spool);
+ space += c * sizeof(struct nat44_cfg_spool);
return (space);
}
@@ -397,7 +404,7 @@ estimate_redir_port(int *ac, char ***av)
static int
setup_redir_port(char *buf, int *ac, char ***av)
{
- struct cfg_redir *r;
+ struct nat44_cfg_redir *r;
char *sep, *protoName, *lsnat = NULL;
size_t space;
u_short numLocalPorts;
@@ -405,11 +412,11 @@ setup_redir_port(char *buf, int *ac, char ***av)
numLocalPorts = 0;
- r = (struct cfg_redir *)buf;
+ r = (struct nat44_cfg_redir *)buf;
r->mode = REDIR_PORT;
- /* Skip cfg_redir at beginning of buf. */
- buf = &buf[sizeof(struct cfg_redir)];
- space = sizeof(struct cfg_redir);
+ /* Skip nat44_cfg_redir at beginning of buf. */
+ buf = &buf[sizeof(struct nat44_cfg_redir)];
+ space = sizeof(struct nat44_cfg_redir);
/*
* Extract protocol.
@@ -516,12 +523,12 @@ setup_redir_port(char *buf, int *ac, char ***av)
/* Setup LSNAT server pool. */
if (lsnat != NULL) {
- struct cfg_spool *spool;
+ struct nat44_cfg_spool *spool;
sep = strtok(lsnat, ",");
while (sep != NULL) {
- spool = (struct cfg_spool *)buf;
- space += sizeof(struct cfg_spool);
+ spool = (struct nat44_cfg_spool *)buf;
+ space += sizeof(struct nat44_cfg_spool);
/*
* The sctp nat does not allow the port numbers to
* be mapped to new port numbers. Therefore, no ports
@@ -549,8 +556,8 @@ setup_redir_port(char *buf, int *ac, char ***av)
spool->port = GETLOPORT(portRange);
}
r->spool_cnt++;
- /* Point to the next possible cfg_spool. */
- buf = &buf[sizeof(struct cfg_spool)];
+ /* Point to the next possible nat44_cfg_spool. */
+ buf = &buf[sizeof(struct nat44_cfg_spool)];
sep = strtok(NULL, ",");
}
}
@@ -561,15 +568,15 @@ setup_redir_port(char *buf, int *ac, char ***av)
static int
setup_redir_proto(char *buf, int *ac, char ***av)
{
- struct cfg_redir *r;
+ struct nat44_cfg_redir *r;
struct protoent *protoent;
size_t space;
- r = (struct cfg_redir *)buf;
+ r = (struct nat44_cfg_redir *)buf;
r->mode = REDIR_PROTO;
- /* Skip cfg_redir at beginning of buf. */
- buf = &buf[sizeof(struct cfg_redir)];
- space = sizeof(struct cfg_redir);
+ /* Skip nat44_cfg_redir at beginning of buf. */
+ buf = &buf[sizeof(struct nat44_cfg_redir)];
+ space = sizeof(struct nat44_cfg_redir);
/*
* Extract protocol.
@@ -616,18 +623,28 @@ setup_redir_proto(char *buf, int *ac, char ***av)
}
static void
-print_nat_config(unsigned char *buf)
+nat_show_log(struct nat44_cfg_nat *n, void *arg)
+{
+ char *buf;
+
+ buf = (char *)(n + 1);
+ if (buf[0] != '\0')
+ printf("nat %s: %s\n", n->name, buf);
+}
+
+static void
+nat_show_cfg(struct nat44_cfg_nat *n, void *arg)
{
- struct cfg_nat *n;
int i, cnt, flag, off;
- struct cfg_redir *t;
- struct cfg_spool *s;
+ struct nat44_cfg_redir *t;
+ struct nat44_cfg_spool *s;
+ caddr_t buf;
struct protoent *p;
- n = (struct cfg_nat *)buf;
+ buf = (caddr_t)n;
flag = 1;
- off = sizeof(*n);
- printf("ipfw nat %u config", n->id);
+ off = sizeof(*n);
+ printf("ipfw nat %s config", n->name);
if (strlen(n->if_name) != 0)
printf(" if %s", n->if_name);
else if (n->ip.s_addr != 0)
@@ -661,8 +678,8 @@ print_nat_config(unsigned char *buf)
}
/* Print all the redirect's data configuration. */
for (cnt = 0; cnt < n->redir_cnt; cnt++) {
- t = (struct cfg_redir *)&buf[off];
- off += SOF_REDIR;
+ t = (struct nat44_cfg_redir *)&buf[off];
+ off += sizeof(struct nat44_cfg_redir);
switch (t->mode) {
case REDIR_ADDR:
printf(" redirect_addr");
@@ -670,13 +687,13 @@ print_nat_config(unsigned char *buf)
printf(" %s", inet_ntoa(t->laddr));
else
for (i = 0; i < t->spool_cnt; i++) {
- s = (struct cfg_spool *)&buf[off];
+ s = (struct nat44_cfg_spool *)&buf[off];
if (i)
printf(",");
else
printf(" ");
printf("%s", inet_ntoa(s->addr));
- off += SOF_SPOOL;
+ off += sizeof(struct nat44_cfg_spool);
}
printf(" %s", inet_ntoa(t->paddr));
break;
@@ -690,12 +707,12 @@ print_nat_config(unsigned char *buf)
t->pport_cnt - 1);
} else
for (i=0; i < t->spool_cnt; i++) {
- s = (struct cfg_spool *)&buf[off];
+ s = (struct nat44_cfg_spool *)&buf[off];
if (i)
printf(",");
printf("%s:%u", inet_ntoa(s->addr),
s->port);
- off += SOF_SPOOL;
+ off += sizeof(struct nat44_cfg_spool);
}
printf(" ");
@@ -736,7 +753,8 @@ print_nat_config(unsigned char *buf)
void
ipfw_config_nat(int ac, char **av)
{
- struct cfg_nat *n; /* Nat instance configuration. */
+ ipfw_obj_header *oh;
+ struct nat44_cfg_nat *n; /* Nat instance configuration. */
int i, off, tok, ac1;
char *id, *buf, **av1, *end;
size_t len;
@@ -755,7 +773,7 @@ ipfw_config_nat(int ac, char **av)
if (ac == 0)
errx(EX_DATAERR, "missing option");
- len = sizeof(struct cfg_nat);
+ len = sizeof(*oh) + sizeof(*n);
ac1 = ac;
av1 = av;
while (ac1 > 0) {
@@ -804,7 +822,7 @@ ipfw_config_nat(int ac, char **av)
if (ac1 < 2)
errx(EX_DATAERR, "redirect_proto: "
"not enough arguments");
- len += sizeof(struct cfg_redir);
+ len += sizeof(struct nat44_cfg_redir);
av1 += 2;
ac1 -= 2;
/* Skip optional remoteIP/port */
@@ -825,11 +843,14 @@ ipfw_config_nat(int ac, char **av)
if ((buf = malloc(len)) == NULL)
errx(EX_OSERR, "malloc failed");
- /* Offset in buf: save space for n at the beginning. */
- off = sizeof(*n);
+ /* Offset in buf: save space for header at the beginning. */
+ off = sizeof(*oh) + sizeof(*n);
memset(buf, 0, len);
- n = (struct cfg_nat *)buf;
- n->id = i;
+ oh = (ipfw_obj_header *)buf;
+ n = (struct nat44_cfg_nat *)(oh + 1);
+ oh->ntlv.head.length = sizeof(oh->ntlv);
+ snprintf(oh->ntlv.name, sizeof(oh->ntlv.name), "%d", i);
+ snprintf(n->name, sizeof(n->name), "%d", i);
while (ac > 0) {
tok = match_token(nat_params, *av);
@@ -900,9 +921,9 @@ ipfw_config_nat(int ac, char **av)
}
}
- i = do_cmd(IP_FW_NAT_CFG, buf, off);
- if (i)
- err(1, "setsockopt(%s)", "IP_FW_NAT_CFG");
+ i = do_set3(IP_FW_NAT44_XCONFIG, &oh->opheader, len);
+ if (i != 0)
+ err(1, "setsockopt(%s)", "IP_FW_NAT44_XCONFIG");
if (!co.do_quiet) {
/* After every modification, we show the resultant rule. */
@@ -912,23 +933,147 @@ ipfw_config_nat(int ac, char **av)
}
}
+struct nat_list_arg {
+ uint16_t cmd;
+ int is_all;
+};
+
+static int
+nat_show_data(struct nat44_cfg_nat *cfg, void *arg)
+{
+ struct nat_list_arg *nla;
+ ipfw_obj_header *oh;
+
+ nla = (struct nat_list_arg *)arg;
+
+ switch (nla->cmd) {
+ case IP_FW_NAT44_XGETCONFIG:
+ if (nat_get_cmd(cfg->name, nla->cmd, &oh) != 0) {
+ warnx("Error getting nat instance %s info", cfg->name);
+ break;
+ }
+ nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL);
+ free(oh);
+ break;
+ case IP_FW_NAT44_XGETLOG:
+ if (nat_get_cmd(cfg->name, nla->cmd, &oh) == 0) {
+ nat_show_log((struct nat44_cfg_nat *)(oh + 1), NULL);
+ free(oh);
+ break;
+ }
+ /* Handle error */
+ if (nla->is_all != 0 && errno == ENOENT)
+ break;
+ warn("Error getting nat instance %s info", cfg->name);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Compare nat names.
+ * Honor number comparison.
+ */
+static int
+natname_cmp(const void *a, const void *b)
+{
+ struct nat44_cfg_nat *ia, *ib;
+
+ ia = (struct nat44_cfg_nat *)a;
+ ib = (struct nat44_cfg_nat *)b;
+
+ return (stringnum_cmp(ia->name, ib->name));
+}
+
+/*
+ * Retrieves nat list from kernel,
+ * optionally sorts it and calls requested function for each table.
+ * Returns 0 on success.
+ */
+static int
+nat_foreach(nat_cb_t *f, void *arg, int sort)
+{
+ ipfw_obj_lheader *olh;
+ struct nat44_cfg_nat *cfg;
+ size_t sz;
+ int i, error;
+
+ /* Start with reasonable default */
+ sz = sizeof(*olh) + 16 * sizeof(struct nat44_cfg_nat);
+
+ for (;;) {
+ if ((olh = calloc(1, sz)) == NULL)
+ return (ENOMEM);
+
+ olh->size = sz;
+ if (do_get3(IP_FW_NAT44_LIST_NAT, &olh->opheader, &sz) != 0) {
+ free(olh);
+ if (errno == ENOMEM) {
+ sz = olh->size;
+ continue;
+ }
+ return (errno);
+ }
+
+ if (sort != 0)
+ qsort(olh + 1, olh->count, olh->objsize, natname_cmp);
+
+ cfg = (struct nat44_cfg_nat*)(olh + 1);
+ for (i = 0; i < olh->count; i++) {
+ error = f(cfg, arg); /* Ignore errors for now */
+ cfg = (struct nat44_cfg_nat *)((caddr_t)cfg +
+ olh->objsize);
+ }
+
+ free(olh);
+ break;
+ }
+
+ return (0);
+}
+
+static int
+nat_get_cmd(char *name, uint16_t cmd, ipfw_obj_header **ooh)
+{
+ ipfw_obj_header *oh;
+ struct nat44_cfg_nat *cfg;
+ size_t sz;
+
+ /* Start with reasonable default */
+ sz = sizeof(*oh) + sizeof(*cfg) + 128;
+
+ for (;;) {
+ if ((oh = calloc(1, sz)) == NULL)
+ return (ENOMEM);
+ cfg = (struct nat44_cfg_nat *)(oh + 1);
+ oh->ntlv.head.length = sizeof(oh->ntlv);
+ strlcpy(oh->ntlv.name, name, sizeof(oh->ntlv.name));
+ strlcpy(cfg->name, name, sizeof(cfg->name));
+
+ if (do_get3(cmd, &oh->opheader, &sz) != 0) {
+ sz = cfg->size;
+ free(oh);
+ if (errno == ENOMEM)
+ continue;
+ return (errno);
+ }
+
+ *ooh = oh;
+ break;
+ }
+
+ return (0);
+}
void
ipfw_show_nat(int ac, char **av)
{
- struct cfg_nat *n;
- struct cfg_redir *e;
- int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size;
- int nat_cnt, redir_cnt, r;
- uint8_t *data, *p;
- char *endptr;
-
- do_rule = 0;
- nalloc = 1024;
- size = 0;
- data = NULL;
- frule = 0;
- lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */
+ ipfw_obj_header *oh;
+ char *name;
+ int cmd;
+ struct nat_list_arg nla;
+
ac--;
av++;
@@ -936,55 +1081,35 @@ ipfw_show_nat(int ac, char **av)
return;
/* Parse parameters. */
- for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) {
+ cmd = 0; /* XXX: Change to IP_FW_NAT44_XGETLOG @ MFC */
+ name = NULL;
+ for ( ; ac != 0; ac--, av++) {
if (!strncmp(av[0], "config", strlen(av[0]))) {
- cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1;
+ cmd = IP_FW_NAT44_XGETCONFIG;
+ continue;
+ }
+ if (strcmp(av[0], "log") == 0) {
+ cmd = IP_FW_NAT44_XGETLOG;
continue;
}
- /* Convert command line rule #. */
- frule = lrule = strtoul(av[0], &endptr, 10);
- if (*endptr == '-')
- lrule = strtoul(endptr+1, &endptr, 10);
- if (lrule == 0)
- err(EX_USAGE, "invalid rule number: %s", av[0]);
- do_rule = 1;
+ if (name != NULL)
+ err(EX_USAGE,"only one instance name may be specified");
+ name = av[0];
}
- nbytes = nalloc;
- while (nbytes >= nalloc) {
- nalloc = nalloc * 2;
- nbytes = nalloc;
- data = safe_realloc(data, nbytes);
- if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_GET_%s)",
- (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG");
- }
- if (nbytes == 0)
- exit(0);
- if (do_cfg) {
- nat_cnt = *((int *)data);
- for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
- n = (struct cfg_nat *)&data[i];
- if (frule <= n->id && lrule >= n->id)
- print_nat_config(&data[i]);
- i += sizeof(struct cfg_nat);
- for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
- e = (struct cfg_redir *)&data[i];
- i += sizeof(struct cfg_redir) + e->spool_cnt *
- sizeof(struct cfg_spool);
- }
- }
+ if (cmd == 0)
+ errx(EX_USAGE, "Please specify action. Available: config,log");
+
+ if (name == NULL) {
+ memset(&nla, 0, sizeof(nla));
+ nla.cmd = cmd;
+ nla.is_all = 1;
+ nat_foreach(nat_show_data, &nla, 1);
} else {
- for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) {
- p = &data[i];
- if (p == data + nbytes)
- break;
- bcopy(p, &r, sizeof(int));
- if (do_rule) {
- if (!(frule <= r && lrule >= r))
- continue;
- }
- printf("nat %u: %s\n", r, p+sizeof(int));
- }
+ if (nat_get_cmd(name, cmd, &oh) != 0)
+ err(EX_OSERR, "Error getting nat %s instance info", name);
+ nat_show_cfg((struct nat44_cfg_nat *)(oh + 1), NULL);
+ free(oh);
}
}
+
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
new file mode 100644
index 0000000..4829fec
--- /dev/null
+++ b/sbin/ipfw/tables.c
@@ -0,0 +1,2012 @@
+/*
+ * Copyright (c) 2014 Yandex LLC
+ * Copyright (c) 2014 Alexander V. Chernikov
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ *
+ * in-kernel ipfw tables support.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip_fw.h>
+#include <arpa/inet.h>
+
+#include "ipfw2.h"
+
+static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
+ int add, int quiet, int update, int atomic);
+static int table_flush(ipfw_obj_header *oh);
+static int table_destroy(ipfw_obj_header *oh);
+static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
+static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i);
+static int table_do_swap(ipfw_obj_header *oh, char *second);
+static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
+static void table_modify(ipfw_obj_header *oh, int ac, char *av[]);
+static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
+static void table_lock(ipfw_obj_header *oh, int lock);
+static int table_swap(ipfw_obj_header *oh, char *second);
+static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
+static int table_show_info(ipfw_xtable_info *i, void *arg);
+static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set,
+ uint16_t uidx);
+
+static int table_flush_one(ipfw_xtable_info *i, void *arg);
+static int table_show_one(ipfw_xtable_info *i, void *arg);
+static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh);
+static void table_show_list(ipfw_obj_header *oh, int need_header);
+static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
+
+static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
+ char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi);
+static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
+ char *arg, uint8_t type, uint32_t vmask);
+static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
+ uint32_t vmask, int print_ip);
+
+typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
+static int tables_foreach(table_cb_t *f, void *arg, int sort);
+
+#ifndef s6_addr32
+#define s6_addr32 __u6_addr.__u6_addr32
+#endif
+
+static struct _s_x tabletypes[] = {
+ { "addr", IPFW_TABLE_ADDR },
+ { "iface", IPFW_TABLE_INTERFACE },
+ { "number", IPFW_TABLE_NUMBER },
+ { "flow", IPFW_TABLE_FLOW },
+ { NULL, 0 }
+};
+
+static struct _s_x tablevaltypes[] = {
+ { "skipto", IPFW_VTYPE_SKIPTO },
+ { "pipe", IPFW_VTYPE_PIPE },
+ { "fib", IPFW_VTYPE_FIB },
+ { "nat", IPFW_VTYPE_NAT },
+ { "dscp", IPFW_VTYPE_DSCP },
+ { "tag", IPFW_VTYPE_TAG },
+ { "divert", IPFW_VTYPE_DIVERT },
+ { "netgraph", IPFW_VTYPE_NETGRAPH },
+ { "limit", IPFW_VTYPE_LIMIT },
+ { "ipv4", IPFW_VTYPE_NH4 },
+ { "ipv6", IPFW_VTYPE_NH6 },
+ { NULL, 0 }
+};
+
+static struct _s_x tablecmds[] = {
+ { "add", TOK_ADD },
+ { "delete", TOK_DEL },
+ { "create", TOK_CREATE },
+ { "destroy", TOK_DESTROY },
+ { "flush", TOK_FLUSH },
+ { "modify", TOK_MODIFY },
+ { "swap", TOK_SWAP },
+ { "info", TOK_INFO },
+ { "detail", TOK_DETAIL },
+ { "list", TOK_LIST },
+ { "lookup", TOK_LOOKUP },
+ { "atomic", TOK_ATOMIC },
+ { "lock", TOK_LOCK },
+ { "unlock", TOK_UNLOCK },
+ { NULL, 0 }
+};
+
+static int
+lookup_host (char *host, struct in_addr *ipaddr)
+{
+ struct hostent *he;
+
+ if (!inet_aton(host, ipaddr)) {
+ if ((he = gethostbyname(host)) == NULL)
+ return(-1);
+ *ipaddr = *(struct in_addr *)he->h_addr_list[0];
+ }
+ return(0);
+}
+
+static int
+get_token(struct _s_x *table, char *string, char *errbase)
+{
+ int tcmd;
+
+ if ((tcmd = match_token_relaxed(table, string)) < 0)
+ errx(EX_USAGE, "%s %s %s",
+ (tcmd == 0) ? "invalid" : "ambiguous", errbase, string);
+
+ return (tcmd);
+}
+
+/*
+ * This one handles all table-related commands
+ * ipfw table NAME create ...
+ * ipfw table NAME modify ...
+ * ipfw table NAME destroy
+ * ipfw table NAME swap NAME
+ * ipfw table NAME lock
+ * ipfw table NAME unlock
+ * ipfw table NAME add addr[/masklen] [value]
+ * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] ..
+ * ipfw table NAME delete addr[/masklen] [addr[/masklen]] ..
+ * ipfw table NAME lookup addr
+ * ipfw table {NAME | all} flush
+ * ipfw table {NAME | all} list
+ * ipfw table {NAME | all} info
+ * ipfw table {NAME | all} detail
+ */
+void
+ipfw_table_handler(int ac, char *av[])
+{
+ int do_add, is_all;
+ int atomic, error, tcmd;
+ ipfw_xtable_info i;
+ ipfw_obj_header oh;
+ char *tablename;
+ uint32_t set;
+ void *arg;
+
+ memset(&oh, 0, sizeof(oh));
+ is_all = 0;
+ if (co.use_set != 0)
+ set = co.use_set - 1;
+ else
+ set = 0;
+
+ ac--; av++;
+ NEED1("table needs name");
+ tablename = *av;
+
+ if (table_check_name(tablename) == 0) {
+ table_fill_ntlv(&oh.ntlv, *av, set, 1);
+ oh.idx = 1;
+ } else {
+ if (strcmp(tablename, "all") == 0)
+ is_all = 1;
+ else
+ errx(EX_USAGE, "table name %s is invalid", tablename);
+ }
+ ac--; av++;
+ NEED1("table needs command");
+
+ tcmd = get_token(tablecmds, *av, "table command");
+ /* Check if atomic operation was requested */
+ atomic = 0;
+ if (tcmd == TOK_ATOMIC) {
+ ac--; av++;
+ NEED1("atomic needs command");
+ tcmd = get_token(tablecmds, *av, "table command");
+ switch (tcmd) {
+ case TOK_ADD:
+ break;
+ default:
+ errx(EX_USAGE, "atomic is not compatible with %s", *av);
+ }
+ atomic = 1;
+ }
+
+ switch (tcmd) {
+ case TOK_LIST:
+ case TOK_INFO:
+ case TOK_DETAIL:
+ case TOK_FLUSH:
+ break;
+ default:
+ if (is_all != 0)
+ errx(EX_USAGE, "table name required");
+ }
+
+ switch (tcmd) {
+ case TOK_ADD:
+ case TOK_DEL:
+ do_add = **av == 'a';
+ ac--; av++;
+ table_modify_record(&oh, ac, av, do_add, co.do_quiet,
+ co.do_quiet, atomic);
+ break;
+ case TOK_CREATE:
+ ac--; av++;
+ table_create(&oh, ac, av);
+ break;
+ case TOK_MODIFY:
+ ac--; av++;
+ table_modify(&oh, ac, av);
+ break;
+ case TOK_DESTROY:
+ if (table_destroy(&oh) != 0)
+ err(EX_OSERR, "failed to destroy table %s", tablename);
+ break;
+ case TOK_FLUSH:
+ if (is_all == 0) {
+ if ((error = table_flush(&oh)) != 0)
+ err(EX_OSERR, "failed to flush table %s info",
+ tablename);
+ } else {
+ error = tables_foreach(table_flush_one, &oh, 1);
+ if (error != 0)
+ err(EX_OSERR, "failed to flush tables list");
+ }
+ break;
+ case TOK_SWAP:
+ ac--; av++;
+ NEED1("second table name required");
+ table_swap(&oh, *av);
+ break;
+ case TOK_LOCK:
+ case TOK_UNLOCK:
+ table_lock(&oh, (tcmd == TOK_LOCK));
+ break;
+ case TOK_DETAIL:
+ case TOK_INFO:
+ arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
+ if (is_all == 0) {
+ if ((error = table_get_info(&oh, &i)) != 0)
+ err(EX_OSERR, "failed to request table info");
+ table_show_info(&i, arg);
+ } else {
+ error = tables_foreach(table_show_info, arg, 1);
+ if (error != 0)
+ err(EX_OSERR, "failed to request tables list");
+ }
+ break;
+ case TOK_LIST:
+ if (is_all == 0) {
+ ipfw_xtable_info i;
+ if ((error = table_get_info(&oh, &i)) != 0)
+ err(EX_OSERR, "failed to request table info");
+ table_show_one(&i, NULL);
+ } else {
+ error = tables_foreach(table_show_one, NULL, 1);
+ if (error != 0)
+ err(EX_OSERR, "failed to request tables list");
+ }
+ break;
+ case TOK_LOOKUP:
+ ac--; av++;
+ table_lookup(&oh, ac, av);
+ break;
+ }
+}
+
+static void
+table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint32_t set, uint16_t uidx)
+{
+
+ ntlv->head.type = IPFW_TLV_TBL_NAME;
+ ntlv->head.length = sizeof(ipfw_obj_ntlv);
+ ntlv->idx = uidx;
+ ntlv->set = set;
+ strlcpy(ntlv->name, name, sizeof(ntlv->name));
+}
+
+static void
+table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
+{
+
+ oh->idx = 1;
+ table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
+}
+
+static struct _s_x tablenewcmds[] = {
+ { "type", TOK_TYPE },
+ { "valtype", TOK_VALTYPE },
+ { "algo", TOK_ALGO },
+ { "limit", TOK_LIMIT },
+ { "locked", TOK_LOCK },
+ { NULL, 0 }
+};
+
+static struct _s_x flowtypecmds[] = {
+ { "src-ip", IPFW_TFFLAG_SRCIP },
+ { "proto", IPFW_TFFLAG_PROTO },
+ { "src-port", IPFW_TFFLAG_SRCPORT },
+ { "dst-ip", IPFW_TFFLAG_DSTIP },
+ { "dst-port", IPFW_TFFLAG_DSTPORT },
+ { NULL, 0 }
+};
+
+int
+table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
+{
+ uint32_t fset, fclear;
+ char *e;
+
+ /* Parse type options */
+ switch(ttype) {
+ case IPFW_TABLE_FLOW:
+ fset = fclear = 0;
+ if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0)
+ errx(EX_USAGE,
+ "unable to parse flow option %s", e);
+ *tflags = fset;
+ break;
+ default:
+ return (EX_USAGE);
+ }
+
+ return (0);
+}
+
+void
+table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
+{
+ const char *tname;
+ int l;
+
+ if ((tname = match_value(tabletypes, type)) == NULL)
+ tname = "unknown";
+
+ l = snprintf(tbuf, size, "%s", tname);
+ tbuf += l;
+ size -= l;
+
+ switch(type) {
+ case IPFW_TABLE_FLOW:
+ if (tflags != 0) {
+ *tbuf++ = ':';
+ l--;
+ print_flags_buffer(tbuf, size, flowtypecmds, tflags);
+ }
+ break;
+ }
+}
+
+/*
+ * Creates new table
+ *
+ * ipfw table NAME create [ type { addr | iface | number | flow } ]
+ * [ algo algoname ]
+ */
+static void
+table_create(ipfw_obj_header *oh, int ac, char *av[])
+{
+ ipfw_xtable_info xi;
+ int error, tcmd, val;
+ uint32_t fset, fclear;
+ size_t sz;
+ char *e, *p;
+ char tbuf[128];
+
+ sz = sizeof(tbuf);
+ memset(&xi, 0, sizeof(xi));
+
+ while (ac > 0) {
+ tcmd = get_token(tablenewcmds, *av, "option");
+ ac--; av++;
+
+ switch (tcmd) {
+ case TOK_LIMIT:
+ NEED1("limit value required");
+ xi.limit = strtol(*av, NULL, 10);
+ ac--; av++;
+ break;
+ case TOK_TYPE:
+ NEED1("table type required");
+ /* Type may have suboptions after ':' */
+ if ((p = strchr(*av, ':')) != NULL)
+ *p++ = '\0';
+ val = match_token(tabletypes, *av);
+ if (val == -1) {
+ concat_tokens(tbuf, sizeof(tbuf), tabletypes,
+ ", ");
+ errx(EX_USAGE,
+ "Unknown tabletype: %s. Supported: %s",
+ *av, tbuf);
+ }
+ xi.type = val;
+ if (p != NULL) {
+ error = table_parse_type(val, p, &xi.tflags);
+ if (error != 0)
+ errx(EX_USAGE,
+ "Unsupported suboptions: %s", p);
+ }
+ ac--; av++;
+ break;
+ case TOK_VALTYPE:
+ NEED1("table value type required");
+ fset = fclear = 0;
+ val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear);
+ if (val != -1) {
+ xi.vmask = fset;
+ ac--; av++;
+ break;
+ }
+ concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
+ errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
+ e, tbuf);
+ break;
+ case TOK_ALGO:
+ NEED1("table algorithm name required");
+ if (strlen(*av) > sizeof(xi.algoname))
+ errx(EX_USAGE, "algorithm name too long");
+ strlcpy(xi.algoname, *av, sizeof(xi.algoname));
+ ac--; av++;
+ break;
+ case TOK_LOCK:
+ xi.flags |= IPFW_TGFLAGS_LOCKED;
+ break;
+ }
+ }
+
+ /* Set some defaults to preserve compability */
+ if (xi.algoname[0] == '\0' && xi.type == 0)
+ xi.type = IPFW_TABLE_ADDR;
+ if (xi.vmask == 0)
+ xi.vmask = IPFW_VTYPE_LEGACY;
+
+ if ((error = table_do_create(oh, &xi)) != 0)
+ err(EX_OSERR, "Table creation failed");
+}
+
+/*
+ * Creates new table
+ *
+ * Request: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * Returns 0 on success.
+ */
+static int
+table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
+{
+ char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
+ int error;
+
+ memcpy(tbuf, oh, sizeof(*oh));
+ memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
+ oh = (ipfw_obj_header *)tbuf;
+
+ error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
+
+ return (error);
+}
+
+/*
+ * Modifies existing table
+ *
+ * ipfw table NAME modify [ limit number ]
+ */
+static void
+table_modify(ipfw_obj_header *oh, int ac, char *av[])
+{
+ ipfw_xtable_info xi;
+ int tcmd;
+ size_t sz;
+ char tbuf[128];
+
+ sz = sizeof(tbuf);
+ memset(&xi, 0, sizeof(xi));
+
+ while (ac > 0) {
+ tcmd = get_token(tablenewcmds, *av, "option");
+ ac--; av++;
+
+ switch (tcmd) {
+ case TOK_LIMIT:
+ NEED1("limit value required");
+ xi.limit = strtol(*av, NULL, 10);
+ xi.mflags |= IPFW_TMFLAGS_LIMIT;
+ ac--; av++;
+ break;
+ default:
+ errx(EX_USAGE, "cmd is not supported for modificatiob");
+ }
+ }
+
+ if (table_do_modify(oh, &xi) != 0)
+ err(EX_OSERR, "Table modification failed");
+}
+
+/*
+ * Modifies existing table.
+ *
+ * Request: [ ipfw_obj_header ipfw_xtable_info ]
+ *
+ * Returns 0 on success.
+ */
+static int
+table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
+{
+ char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
+ int error;
+
+ memcpy(tbuf, oh, sizeof(*oh));
+ memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
+ oh = (ipfw_obj_header *)tbuf;
+
+ error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
+
+ return (error);
+}
+
+/*
+ * Locks or unlocks given table
+ */
+static void
+table_lock(ipfw_obj_header *oh, int lock)
+{
+ ipfw_xtable_info xi;
+
+ memset(&xi, 0, sizeof(xi));
+
+ xi.mflags |= IPFW_TMFLAGS_LOCK;
+ xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0;
+
+ if (table_do_modify(oh, &xi) != 0)
+ err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock");
+}
+
+/*
+ * Destroys given table specified by @oh->ntlv.
+ * Returns 0 on success.
+ */
+static int
+table_destroy(ipfw_obj_header *oh)
+{
+
+ if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Flushes given table specified by @oh->ntlv.
+ * Returns 0 on success.
+ */
+static int
+table_flush(ipfw_obj_header *oh)
+{
+
+ if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+table_do_swap(ipfw_obj_header *oh, char *second)
+{
+ char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
+ int error;
+
+ memset(tbuf, 0, sizeof(tbuf));
+ memcpy(tbuf, oh, sizeof(*oh));
+ oh = (ipfw_obj_header *)tbuf;
+ table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
+
+ error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
+
+ return (error);
+}
+
+/*
+ * Swaps given table with @second one.
+ */
+static int
+table_swap(ipfw_obj_header *oh, char *second)
+{
+ int error;
+
+ if (table_check_name(second) != 0)
+ errx(EX_USAGE, "table name %s is invalid", second);
+
+ error = table_do_swap(oh, second);
+
+ switch (error) {
+ case EINVAL:
+ errx(EX_USAGE, "Unable to swap table: check types");
+ case EFBIG:
+ errx(EX_USAGE, "Unable to swap table: check limits");
+ }
+
+ return (0);
+}
+
+
+/*
+ * Retrieves table in given table specified by @oh->ntlv.
+ * it inside @i.
+ * Returns 0 on success.
+ */
+static int
+table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
+{
+ char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
+ size_t sz;
+
+ sz = sizeof(tbuf);
+ memset(tbuf, 0, sizeof(tbuf));
+ memcpy(tbuf, oh, sizeof(*oh));
+ oh = (ipfw_obj_header *)tbuf;
+
+ if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0)
+ return (errno);
+
+ if (sz < sizeof(tbuf))
+ return (EINVAL);
+
+ *i = *(ipfw_xtable_info *)(oh + 1);
+
+ return (0);
+}
+
+static struct _s_x tablealgoclass[] = {
+ { "hash", IPFW_TACLASS_HASH },
+ { "array", IPFW_TACLASS_ARRAY },
+ { "radix", IPFW_TACLASS_RADIX },
+ { NULL, 0 }
+};
+
+struct ta_cldata {
+ uint8_t taclass;
+ uint8_t spare4;
+ uint16_t itemsize;
+ uint16_t itemsize6;
+ uint32_t size;
+ uint32_t count;
+};
+
+/*
+ * Print global/per-AF table @i algorithm info.
+ */
+static void
+table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
+ const char *af, const char *taclass)
+{
+
+ switch (d->taclass) {
+ case IPFW_TACLASS_HASH:
+ case IPFW_TACLASS_ARRAY:
+ printf(" %salgorithm %s info\n", af, taclass);
+ if (d->itemsize == d->itemsize6)
+ printf(" size: %u items: %u itemsize: %u\n",
+ d->size, d->count, d->itemsize);
+ else
+ printf(" size: %u items: %u "
+ "itemsize4: %u itemsize6: %u\n",
+ d->size, d->count,
+ d->itemsize, d->itemsize6);
+ break;
+ case IPFW_TACLASS_RADIX:
+ printf(" %salgorithm %s info\n", af, taclass);
+ if (d->itemsize == d->itemsize6)
+ printf(" items: %u itemsize: %u\n",
+ d->count, d->itemsize);
+ else
+ printf(" items: %u "
+ "itemsize4: %u itemsize6: %u\n",
+ d->count, d->itemsize, d->itemsize6);
+ break;
+ default:
+ printf(" algo class: %s\n", taclass);
+ }
+}
+
+static void
+table_print_valheader(char *buf, size_t bufsize, uint32_t vmask)
+{
+
+ if (vmask == IPFW_VTYPE_LEGACY) {
+ snprintf(buf, bufsize, "legacy");
+ return;
+ }
+
+ print_flags_buffer(buf, bufsize, tablevaltypes, vmask);
+}
+
+/*
+ * Prints table info struct @i in human-readable form.
+ */
+static int
+table_show_info(ipfw_xtable_info *i, void *arg)
+{
+ const char *vtype;
+ ipfw_ta_tinfo *tainfo;
+ int afdata, afitem;
+ struct ta_cldata d;
+ char ttype[64], tvtype[64];
+
+ table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
+ table_print_valheader(tvtype, sizeof(tvtype), i->vmask);
+
+ printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
+ if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
+ printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
+ else
+ printf(" kindex: %d, type: %s\n", i->kidx, ttype);
+ printf(" references: %u, valtype: %s\n", i->refcnt, tvtype);
+ printf(" algorithm: %s\n", i->algoname);
+ printf(" items: %u, size: %u\n", i->count, i->size);
+ if (i->limit > 0)
+ printf(" limit: %u\n", i->limit);
+
+ /* Print algo-specific info if requested & set */
+ if (arg == NULL)
+ return (0);
+
+ if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
+ return (0);
+ tainfo = &i->ta_info;
+
+ afdata = 0;
+ afitem = 0;
+ if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
+ afdata = 1;
+ if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
+ afitem = 1;
+
+ memset(&d, 0, sizeof(d));
+ d.taclass = tainfo->taclass4;
+ d.size = tainfo->size4;
+ d.count = tainfo->count4;
+ d.itemsize = tainfo->itemsize4;
+ if (afdata == 0 && afitem != 0)
+ d.itemsize6 = tainfo->itemsize6;
+ else
+ d.itemsize6 = d.itemsize;
+ if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
+ vtype = "unknown";
+
+ if (afdata == 0) {
+ table_show_tainfo(i, &d, "", vtype);
+ } else {
+ table_show_tainfo(i, &d, "IPv4 ", vtype);
+ memset(&d, 0, sizeof(d));
+ d.taclass = tainfo->taclass6;
+ if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
+ vtype = "unknown";
+ d.size = tainfo->size6;
+ d.count = tainfo->count6;
+ d.itemsize = tainfo->itemsize6;
+ d.itemsize6 = d.itemsize;
+ table_show_tainfo(i, &d, "IPv6 ", vtype);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Function wrappers which can be used either
+ * as is or as foreach function parameter.
+ */
+
+static int
+table_show_one(ipfw_xtable_info *i, void *arg)
+{
+ ipfw_obj_header *oh;
+ int error;
+
+ if ((error = table_do_get_list(i, &oh)) != 0) {
+ err(EX_OSERR, "Error requesting table %s list", i->tablename);
+ return (error);
+ }
+
+ table_show_list(oh, 1);
+
+ free(oh);
+ return (0);
+}
+
+static int
+table_flush_one(ipfw_xtable_info *i, void *arg)
+{
+ ipfw_obj_header *oh;
+
+ oh = (ipfw_obj_header *)arg;
+
+ table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
+
+ return (table_flush(oh));
+}
+
+static int
+table_do_modify_record(int cmd, ipfw_obj_header *oh,
+ ipfw_obj_tentry *tent, int count, int atomic)
+{
+ ipfw_obj_ctlv *ctlv;
+ ipfw_obj_tentry *tent_base;
+ caddr_t pbuf;
+ char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
+ int error, i;
+ size_t sz;
+
+ sz = sizeof(*ctlv) + sizeof(*tent) * count;
+ if (count == 1) {
+ memset(xbuf, 0, sizeof(xbuf));
+ pbuf = xbuf;
+ } else {
+ if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL)
+ return (ENOMEM);
+ }
+
+ memcpy(pbuf, oh, sizeof(*oh));
+ oh = (ipfw_obj_header *)pbuf;
+ oh->opheader.version = 1;
+
+ ctlv = (ipfw_obj_ctlv *)(oh + 1);
+ ctlv->count = count;
+ ctlv->head.length = sz;
+ if (atomic != 0)
+ ctlv->flags |= IPFW_CTF_ATOMIC;
+
+ tent_base = tent;
+ memcpy(ctlv + 1, tent, sizeof(*tent) * count);
+ tent = (ipfw_obj_tentry *)(ctlv + 1);
+ for (i = 0; i < count; i++, tent++) {
+ tent->head.length = sizeof(ipfw_obj_tentry);
+ tent->idx = oh->idx;
+ }
+
+ sz += sizeof(*oh);
+ error = do_get3(cmd, &oh->opheader, &sz);
+ tent = (ipfw_obj_tentry *)(ctlv + 1);
+ /* Copy result back to provided buffer */
+ memcpy(tent_base, ctlv + 1, sizeof(*tent) * count);
+
+ if (pbuf != xbuf)
+ free(pbuf);
+
+ return (error);
+}
+
+static void
+table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add,
+ int quiet, int update, int atomic)
+{
+ ipfw_obj_tentry *ptent, tent, *tent_buf;
+ ipfw_xtable_info xi;
+ uint8_t type;
+ uint32_t vmask;
+ int cmd, count, error, i, ignored;
+ char *texterr, *etxt, *px;
+
+ if (ac == 0)
+ errx(EX_USAGE, "address required");
+
+ if (add != 0) {
+ cmd = IP_FW_TABLE_XADD;
+ texterr = "Adding record failed";
+ } else {
+ cmd = IP_FW_TABLE_XDEL;
+ texterr = "Deleting record failed";
+ }
+
+ /*
+ * Calculate number of entries:
+ * Assume [key val] x N for add
+ * and
+ * key x N for delete
+ */
+ count = (add != 0) ? ac / 2 + 1 : ac;
+
+ if (count <= 1) {
+ /* Adding single entry with/without value */
+ memset(&tent, 0, sizeof(tent));
+ tent_buf = &tent;
+ } else {
+
+ if ((tent_buf = calloc(count, sizeof(tent))) == NULL)
+ errx(EX_OSERR,
+ "Unable to allocate memory for all entries");
+ }
+ ptent = tent_buf;
+
+ memset(&xi, 0, sizeof(xi));
+ count = 0;
+ while (ac > 0) {
+ tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi);
+
+ /*
+ * compability layer: auto-create table if not exists
+ */
+ if (xi.tablename[0] == '\0') {
+ xi.type = type;
+ xi.vmask = vmask;
+ strlcpy(xi.tablename, oh->ntlv.name,
+ sizeof(xi.tablename));
+ fprintf(stderr, "DEPRECATED: inserting data info "
+ "non-existent table %s. (auto-created)\n",
+ xi.tablename);
+ table_do_create(oh, &xi);
+ }
+
+ oh->ntlv.type = type;
+ ac--; av++;
+
+ if (add != 0 && ac > 0) {
+ tentry_fill_value(oh, ptent, *av, type, vmask);
+ ac--; av++;
+ }
+
+ if (update != 0)
+ ptent->head.flags |= IPFW_TF_UPDATE;
+
+ count++;
+ ptent++;
+ }
+
+ error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
+
+ quiet = 0;
+
+ /*
+ * Compatibility stuff: do not yell on duplicate keys or
+ * failed deletions.
+ */
+ if (error == 0 || (error == EEXIST && add != 0) ||
+ (error == ENOENT && add == 0)) {
+ if (quiet != 0) {
+ if (tent_buf != &tent)
+ free(tent_buf);
+ return;
+ }
+ }
+
+ /* Report results back */
+ ptent = tent_buf;
+ for (i = 0; i < count; ptent++, i++) {
+ ignored = 0;
+ switch (ptent->result) {
+ case IPFW_TR_ADDED:
+ px = "added";
+ break;
+ case IPFW_TR_DELETED:
+ px = "deleted";
+ break;
+ case IPFW_TR_UPDATED:
+ px = "updated";
+ break;
+ case IPFW_TR_LIMIT:
+ px = "limit";
+ ignored = 1;
+ break;
+ case IPFW_TR_ERROR:
+ px = "error";
+ ignored = 1;
+ break;
+ case IPFW_TR_NOTFOUND:
+ px = "notfound";
+ ignored = 1;
+ break;
+ case IPFW_TR_EXISTS:
+ px = "exists";
+ ignored = 1;
+ break;
+ case IPFW_TR_IGNORED:
+ px = "ignored";
+ ignored = 1;
+ break;
+ default:
+ px = "unknown";
+ ignored = 1;
+ }
+
+ if (error != 0 && atomic != 0 && ignored == 0)
+ printf("%s(reverted): ", px);
+ else
+ printf("%s: ", px);
+
+ table_show_entry(&xi, ptent);
+ }
+
+ if (tent_buf != &tent)
+ free(tent_buf);
+
+ if (error == 0)
+ return;
+ /* Get real OS error */
+ error = errno;
+
+ /* Try to provide more human-readable error */
+ switch (error) {
+ case EEXIST:
+ etxt = "record already exists";
+ break;
+ case EFBIG:
+ etxt = "limit hit";
+ break;
+ case ESRCH:
+ etxt = "table not found";
+ break;
+ case ENOENT:
+ etxt = "record not found";
+ break;
+ case EACCES:
+ etxt = "table is locked";
+ break;
+ default:
+ etxt = strerror(error);
+ }
+
+ errx(EX_OSERR, "%s: %s", texterr, etxt);
+}
+
+static int
+table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
+ ipfw_obj_tentry *xtent)
+{
+ char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
+ ipfw_obj_tentry *tent;
+ uint8_t type;
+ uint32_t vmask;
+ size_t sz;
+
+ memcpy(xbuf, oh, sizeof(*oh));
+ oh = (ipfw_obj_header *)xbuf;
+ tent = (ipfw_obj_tentry *)(oh + 1);
+
+ memset(tent, 0, sizeof(*tent));
+ tent->head.length = sizeof(*tent);
+ tent->idx = 1;
+
+ tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi);
+ oh->ntlv.type = type;
+
+ sz = sizeof(xbuf);
+ if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0)
+ return (errno);
+
+ if (sz < sizeof(xbuf))
+ return (EINVAL);
+
+ *xtent = *tent;
+
+ return (0);
+}
+
+static void
+table_lookup(ipfw_obj_header *oh, int ac, char *av[])
+{
+ ipfw_obj_tentry xtent;
+ ipfw_xtable_info xi;
+ char key[64];
+ int error;
+
+ if (ac == 0)
+ errx(EX_USAGE, "address required");
+
+ strlcpy(key, *av, sizeof(key));
+
+ memset(&xi, 0, sizeof(xi));
+ error = table_do_lookup(oh, key, &xi, &xtent);
+
+ switch (error) {
+ case 0:
+ break;
+ case ESRCH:
+ errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
+ case ENOENT:
+ errx(EX_UNAVAILABLE, "Entry %s not found", *av);
+ case ENOTSUP:
+ errx(EX_UNAVAILABLE, "Table %s algo does not support "
+ "\"lookup\" method", oh->ntlv.name);
+ default:
+ err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
+ }
+
+ table_show_entry(&xi, &xtent);
+}
+
+static void
+tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
+ uint8_t tflags)
+{
+ char *p, *pp;
+ int mask, af;
+ struct in6_addr *paddr, tmp;
+ struct tflow_entry *tfe;
+ uint32_t key, *pkey;
+ uint16_t port;
+ struct protoent *pent;
+ struct servent *sent;
+ int masklen;
+
+ masklen = 0;
+ af = 0;
+ paddr = (struct in6_addr *)&tentry->k;
+
+ switch (type) {
+ case IPFW_TABLE_ADDR:
+ /* Remove / if exists */
+ if ((p = strchr(arg, '/')) != NULL) {
+ *p = '\0';
+ mask = atoi(p + 1);
+ }
+
+ if (inet_pton(AF_INET, arg, paddr) == 1) {
+ if (p != NULL && mask > 32)
+ errx(EX_DATAERR, "bad IPv4 mask width: %s",
+ p + 1);
+
+ masklen = p ? mask : 32;
+ af = AF_INET;
+ } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
+ if (IN6_IS_ADDR_V4COMPAT(paddr))
+ errx(EX_DATAERR,
+ "Use IPv4 instead of v4-compatible");
+ if (p != NULL && mask > 128)
+ errx(EX_DATAERR, "bad IPv6 mask width: %s",
+ p + 1);
+
+ masklen = p ? mask : 128;
+ af = AF_INET6;
+ } else {
+ /* Assume FQDN */
+ if (lookup_host(arg, (struct in_addr *)paddr) != 0)
+ errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
+
+ masklen = 32;
+ type = IPFW_TABLE_ADDR;
+ af = AF_INET;
+ }
+ break;
+ case IPFW_TABLE_INTERFACE:
+ /* Assume interface name. Copy significant data only */
+ mask = MIN(strlen(arg), IF_NAMESIZE - 1);
+ memcpy(paddr, arg, mask);
+ /* Set mask to exact match */
+ masklen = 8 * IF_NAMESIZE;
+ break;
+ case IPFW_TABLE_NUMBER:
+ /* Port or any other key */
+ key = strtol(arg, &p, 10);
+ if (*p != '\0')
+ errx(EX_DATAERR, "Invalid number: %s", arg);
+
+ pkey = (uint32_t *)paddr;
+ *pkey = key;
+ masklen = 32;
+ break;
+ case IPFW_TABLE_FLOW:
+ /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
+ tfe = &tentry->k.flow;
+ af = 0;
+
+ /* Handle <ipv4|ipv6> */
+ if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+ /* Determine family using temporary storage */
+ if (inet_pton(AF_INET, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET)
+ errx(EX_DATAERR,
+ "Inconsistent address family\n");
+ af = AF_INET;
+ memcpy(&tfe->a.a4.sip, &tmp, 4);
+ } else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET6)
+ errx(EX_DATAERR,
+ "Inconsistent address family\n");
+ af = AF_INET6;
+ memcpy(&tfe->a.a6.sip6, &tmp, 16);
+ }
+
+ arg = p;
+ }
+
+ /* Handle <proto-num|proto-name> */
+ if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
+ if (arg == NULL)
+ errx(EX_DATAERR, "invalid key: proto missing");
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+
+ key = strtol(arg, &pp, 10);
+ if (*pp != '\0') {
+ if ((pent = getprotobyname(arg)) == NULL)
+ errx(EX_DATAERR, "Unknown proto: %s",
+ arg);
+ else
+ key = pent->p_proto;
+ }
+
+ if (key > 255)
+ errx(EX_DATAERR, "Bad protocol number: %u",key);
+
+ tfe->proto = key;
+
+ arg = p;
+ }
+
+ /* Handle <port-num|service-name> */
+ if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
+ if (arg == NULL)
+ errx(EX_DATAERR, "invalid key: src port missing");
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+
+ if ((port = htons(strtol(arg, NULL, 10))) == 0) {
+ if ((sent = getservbyname(arg, NULL)) == NULL)
+ errx(EX_DATAERR, "Unknown service: %s",
+ arg);
+ else
+ key = sent->s_port;
+ }
+
+ tfe->sport = port;
+
+ arg = p;
+ }
+
+ /* Handle <ipv4|ipv6>*/
+ if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
+ if (arg == NULL)
+ errx(EX_DATAERR, "invalid key: dst ip missing");
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+ /* Determine family using temporary storage */
+ if (inet_pton(AF_INET, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET)
+ errx(EX_DATAERR,
+ "Inconsistent address family");
+ af = AF_INET;
+ memcpy(&tfe->a.a4.dip, &tmp, 4);
+ } else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
+ if (af != 0 && af != AF_INET6)
+ errx(EX_DATAERR,
+ "Inconsistent address family");
+ af = AF_INET6;
+ memcpy(&tfe->a.a6.dip6, &tmp, 16);
+ }
+
+ arg = p;
+ }
+
+ /* Handle <port-num|service-name> */
+ if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
+ if (arg == NULL)
+ errx(EX_DATAERR, "invalid key: dst port missing");
+ if ((p = strchr(arg, ',')) != NULL)
+ *p++ = '\0';
+
+ if ((port = htons(strtol(arg, NULL, 10))) == 0) {
+ if ((sent = getservbyname(arg, NULL)) == NULL)
+ errx(EX_DATAERR, "Unknown service: %s",
+ arg);
+ else
+ key = sent->s_port;
+ }
+
+ tfe->dport = port;
+
+ arg = p;
+ }
+
+ tfe->af = af;
+
+ break;
+
+ default:
+ errx(EX_DATAERR, "Unsupported table type: %d", type);
+ }
+
+ tentry->subtype = af;
+ tentry->masklen = masklen;
+}
+
+static void
+tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
+ int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi)
+{
+ uint8_t type, tflags;
+ uint32_t vmask;
+ int error;
+ char *del;
+
+ type = 0;
+ tflags = 0;
+ vmask = 0;
+
+ if (xi->tablename[0] == '\0')
+ error = table_get_info(oh, xi);
+ else
+ error = 0;
+
+ if (error == 0) {
+ /* Table found. */
+ type = xi->type;
+ tflags = xi->tflags;
+ vmask = xi->vmask;
+ } else {
+ if (error != ESRCH)
+ errx(EX_OSERR, "Error requesting table %s info",
+ oh->ntlv.name);
+ if (add == 0)
+ errx(EX_DATAERR, "Table %s does not exist",
+ oh->ntlv.name);
+ /*
+ * Table does not exist.
+ * Compability layer: try to interpret data as ADDR
+ * before failing.
+ */
+ if ((del = strchr(key, '/')) != NULL)
+ *del = '\0';
+ if (inet_pton(AF_INET, key, &tent->k.addr6) == 1 ||
+ inet_pton(AF_INET6, key, &tent->k.addr6) == 1) {
+ /* OK Prepare and send */
+ type = IPFW_TABLE_ADDR;
+ vmask = IPFW_VTYPE_LEGACY;
+ } else {
+ /* Inknown key */
+ errx(EX_USAGE, "Table %s does not exist, cannot guess "
+ "key '%s' type", oh->ntlv.name, key);
+ }
+ if (del != NULL)
+ *del = '/';
+ }
+
+ tentry_fill_key_type(key, tent, type, tflags);
+
+ *ptype = type;
+ *pvmask = vmask;
+}
+
+static void
+set_legacy_value(uint32_t val, ipfw_table_value *v)
+{
+ v->tag = val;
+ v->pipe = val;
+ v->divert = val;
+ v->skipto = val;
+ v->netgraph = val;
+ v->fib = val;
+ v->nat = val;
+ v->nh4 = val;
+ v->dscp = (uint8_t)val;
+ v->limit = val;
+}
+
+static void
+tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
+ uint8_t type, uint32_t vmask)
+{
+ uint32_t a4, flag, val, vm;
+ ipfw_table_value *v;
+ uint32_t i;
+ int dval;
+ char *comma, *e, *etype, *n, *p;
+
+ v = &tent->v.value;
+ vm = vmask;
+
+ /* Compat layer: keep old behavior for legacy value types */
+ if (vmask == IPFW_VTYPE_LEGACY) {
+ /* Try to interpret as number first */
+ val = strtoul(arg, &p, 0);
+ if (*p == '\0') {
+ set_legacy_value(val, v);
+ return;
+ }
+ if (inet_pton(AF_INET, arg, &val) == 1) {
+ set_legacy_value(ntohl(val), v);
+ return;
+ }
+ /* Try hostname */
+ if (lookup_host(arg, (struct in_addr *)&val) == 0) {
+ set_legacy_value(val, v);
+ return;
+ }
+ errx(EX_OSERR, "Unable to parse value %s", arg);
+ }
+
+ /*
+ * Shorthands: handle single value if vmask consists
+ * of numbers only. e.g.:
+ * vmask = "fib,skipto" -> treat input "1" as "1,1"
+ */
+
+ n = arg;
+ etype = NULL;
+ for (i = 1; i < (1 << 31); i *= 2) {
+ if ((flag = (vmask & i)) == 0)
+ continue;
+ vmask &= ~flag;
+
+ if ((comma = strchr(n, ',')) != NULL)
+ *comma = '\0';
+
+ switch (flag) {
+ case IPFW_VTYPE_TAG:
+ v->tag = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "tag";
+ break;
+ case IPFW_VTYPE_PIPE:
+ v->pipe = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "pipe";
+ break;
+ case IPFW_VTYPE_DIVERT:
+ v->divert = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "divert";
+ break;
+ case IPFW_VTYPE_SKIPTO:
+ v->skipto = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "skipto";
+ break;
+ case IPFW_VTYPE_NETGRAPH:
+ v->netgraph = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "netgraph";
+ break;
+ case IPFW_VTYPE_FIB:
+ v->fib = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "fib";
+ break;
+ case IPFW_VTYPE_NAT:
+ v->nat = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "nat";
+ break;
+ case IPFW_VTYPE_LIMIT:
+ v->limit = strtol(n, &e, 10);
+ if (*e != '\0')
+ etype = "limit";
+ break;
+ case IPFW_VTYPE_NH4:
+ if (strchr(n, '.') != NULL &&
+ inet_pton(AF_INET, n, &a4) == 1) {
+ v->nh4 = ntohl(a4);
+ break;
+ }
+ if (lookup_host(n, (struct in_addr *)&v->nh4) == 0)
+ break;
+ etype = "ipv4";
+ break;
+ case IPFW_VTYPE_DSCP:
+ if (isalpha(*n)) {
+ if ((dval = match_token(f_ipdscp, n)) != -1) {
+ v->dscp = dval;
+ break;
+ } else
+ etype = "DSCP code";
+ } else {
+ v->dscp = strtol(n, &e, 10);
+ if (v->dscp > 63 || *e != '\0')
+ etype = "DSCP value";
+ }
+ break;
+ case IPFW_VTYPE_NH6:
+ if (strchr(n, ':') != NULL &&
+ inet_pton(AF_INET6, n, &v->nh6) == 1)
+ break;
+ etype = "ipv6";
+ break;
+ }
+
+ if (etype != NULL)
+ errx(EX_USAGE, "Unable to parse %s as %s", n, etype);
+
+ if (comma != NULL)
+ *comma++ = ',';
+
+ if ((n = comma) != NULL)
+ continue;
+
+ /* End of input. */
+ if (vmask != 0)
+ errx(EX_USAGE, "Not enough fields inside value");
+ }
+}
+
+/*
+ * Compare table names.
+ * Honor number comparison.
+ */
+static int
+tablename_cmp(const void *a, const void *b)
+{
+ ipfw_xtable_info *ia, *ib;
+
+ ia = (ipfw_xtable_info *)a;
+ ib = (ipfw_xtable_info *)b;
+
+ return (stringnum_cmp(ia->tablename, ib->tablename));
+}
+
+/*
+ * Retrieves table list from kernel,
+ * optionally sorts it and calls requested function for each table.
+ * Returns 0 on success.
+ */
+static int
+tables_foreach(table_cb_t *f, void *arg, int sort)
+{
+ ipfw_obj_lheader *olh;
+ ipfw_xtable_info *info;
+ size_t sz;
+ int i, error;
+
+ /* Start with reasonable default */
+ sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
+
+ for (;;) {
+ if ((olh = calloc(1, sz)) == NULL)
+ return (ENOMEM);
+
+ olh->size = sz;
+ if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) {
+ sz = olh->size;
+ free(olh);
+ if (errno != ENOMEM)
+ return (errno);
+ continue;
+ }
+
+ if (sort != 0)
+ qsort(olh + 1, olh->count, olh->objsize, tablename_cmp);
+
+ info = (ipfw_xtable_info *)(olh + 1);
+ for (i = 0; i < olh->count; i++) {
+ error = f(info, arg); /* Ignore errors for now */
+ info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize);
+ }
+
+ free(olh);
+ break;
+ }
+
+ return (0);
+}
+
+
+/*
+ * Retrieves all entries for given table @i in
+ * eXtended format. Allocate buffer large enough
+ * to store result. Called needs to free it later.
+ *
+ * Returns 0 on success.
+ */
+static int
+table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
+{
+ ipfw_obj_header *oh;
+ size_t sz;
+ int c;
+
+ sz = 0;
+ oh = NULL;
+ for (c = 0; c < 8; c++) {
+ if (sz < i->size)
+ sz = i->size + 44;
+ if (oh != NULL)
+ free(oh);
+ if ((oh = calloc(1, sz)) == NULL)
+ continue;
+ table_fill_objheader(oh, i);
+ oh->opheader.version = 1; /* Current version */
+ if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) {
+ *poh = oh;
+ return (0);
+ }
+
+ if (errno != ENOMEM)
+ break;
+ }
+ free(oh);
+
+ return (errno);
+}
+
+/*
+ * Shows all entries from @oh in human-readable format
+ */
+static void
+table_show_list(ipfw_obj_header *oh, int need_header)
+{
+ ipfw_obj_tentry *tent;
+ uint32_t count;
+ ipfw_xtable_info *i;
+
+ i = (ipfw_xtable_info *)(oh + 1);
+ tent = (ipfw_obj_tentry *)(i + 1);
+
+ if (need_header)
+ printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
+
+ count = i->count;
+ while (count > 0) {
+ table_show_entry(i, tent);
+ tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
+ count--;
+ }
+}
+
+static void
+table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
+ uint32_t vmask, int print_ip)
+{
+ uint32_t flag, i, l;
+ size_t sz;
+ struct in_addr a4;
+ char abuf[INET6_ADDRSTRLEN];
+
+ sz = bufsize;
+
+ /*
+ * Some shorthands for printing values:
+ * legacy assumes all values are equal, so keep the first one.
+ */
+ if (vmask == IPFW_VTYPE_LEGACY) {
+ if (print_ip != 0) {
+ flag = htonl(v->tag);
+ inet_ntop(AF_INET, &flag, buf, sz);
+ } else
+ snprintf(buf, sz, "%u", v->tag);
+ return;
+ }
+
+ for (i = 1; i < (1 << 31); i *= 2) {
+ if ((flag = (vmask & i)) == 0)
+ continue;
+ l = 0;
+
+ switch (flag) {
+ case IPFW_VTYPE_TAG:
+ l = snprintf(buf, sz, "%u,", v->tag);
+ break;
+ case IPFW_VTYPE_PIPE:
+ l = snprintf(buf, sz, "%u,", v->pipe);
+ break;
+ case IPFW_VTYPE_DIVERT:
+ l = snprintf(buf, sz, "%d,", v->divert);
+ break;
+ case IPFW_VTYPE_SKIPTO:
+ l = snprintf(buf, sz, "%d,", v->skipto);
+ break;
+ case IPFW_VTYPE_NETGRAPH:
+ l = snprintf(buf, sz, "%u,", v->netgraph);
+ break;
+ case IPFW_VTYPE_FIB:
+ l = snprintf(buf, sz, "%u,", v->fib);
+ break;
+ case IPFW_VTYPE_NAT:
+ l = snprintf(buf, sz, "%u,", v->nat);
+ break;
+ case IPFW_VTYPE_LIMIT:
+ l = snprintf(buf, sz, "%u,", v->limit);
+ break;
+ case IPFW_VTYPE_NH4:
+ a4.s_addr = htonl(v->nh4);
+ inet_ntop(AF_INET, &a4, abuf, sizeof(abuf));
+ l = snprintf(buf, sz, "%s,", abuf);
+ break;
+ case IPFW_VTYPE_DSCP:
+ l = snprintf(buf, sz, "%d,", v->dscp);
+ break;
+ case IPFW_VTYPE_NH6:
+ inet_ntop(AF_INET6, &v->nh6, abuf, sizeof(abuf));
+ l = snprintf(buf, sz, "%s,", abuf);
+ break;
+ }
+
+ buf += l;
+ sz -= l;
+ }
+
+ if (sz != bufsize)
+ *(buf - 1) = '\0';
+}
+
+static void
+table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
+{
+ char *comma, tbuf[128], pval[128];
+ void *paddr;
+ struct tflow_entry *tfe;
+
+ table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask,
+ co.do_value_as_ip);
+
+ switch (i->type) {
+ case IPFW_TABLE_ADDR:
+ /* IPv4 or IPv6 prefixes */
+ inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
+ printf("%s/%u %s\n", tbuf, tent->masklen, pval);
+ break;
+ case IPFW_TABLE_INTERFACE:
+ /* Interface names */
+ printf("%s %s\n", tent->k.iface, pval);
+ break;
+ case IPFW_TABLE_NUMBER:
+ /* numbers */
+ printf("%u %s\n", tent->k.key, pval);
+ break;
+ case IPFW_TABLE_FLOW:
+ /* flows */
+ tfe = &tent->k.flow;
+ comma = "";
+
+ if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
+ if (tfe->af == AF_INET)
+ paddr = &tfe->a.a4.sip;
+ else
+ paddr = &tfe->a.a6.sip6;
+
+ inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
+ printf("%s%s", comma, tbuf);
+ comma = ",";
+ }
+
+ if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
+ printf("%s%d", comma, tfe->proto);
+ comma = ",";
+ }
+
+ if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
+ printf("%s%d", comma, ntohs(tfe->sport));
+ comma = ",";
+ }
+ if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
+ if (tfe->af == AF_INET)
+ paddr = &tfe->a.a4.dip;
+ else
+ paddr = &tfe->a.a6.dip6;
+
+ inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
+ printf("%s%s", comma, tbuf);
+ comma = ",";
+ }
+
+ if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
+ printf("%s%d", comma, ntohs(tfe->dport));
+ comma = ",";
+ }
+
+ printf(" %s\n", pval);
+ }
+}
+
+static int
+table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh)
+{
+ ipfw_obj_lheader req, *olh;
+ size_t sz;
+
+ memset(&req, 0, sizeof(req));
+ sz = sizeof(req);
+
+ if (do_get3(opcode, &req.opheader, &sz) != 0)
+ if (errno != ENOMEM)
+ return (errno);
+
+ sz = req.size;
+ if ((olh = calloc(1, sz)) == NULL)
+ return (ENOMEM);
+
+ olh->size = sz;
+ if (do_get3(opcode, &olh->opheader, &sz) != 0) {
+ free(olh);
+ return (errno);
+ }
+
+ *polh = olh;
+ return (0);
+}
+
+static int
+table_do_get_algolist(ipfw_obj_lheader **polh)
+{
+
+ return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh));
+}
+
+static int
+table_do_get_vlist(ipfw_obj_lheader **polh)
+{
+
+ return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh));
+}
+
+void
+ipfw_list_ta(int ac, char *av[])
+{
+ ipfw_obj_lheader *olh;
+ ipfw_ta_info *info;
+ int error, i;
+ const char *atype;
+
+ error = table_do_get_algolist(&olh);
+ if (error != 0)
+ err(EX_OSERR, "Unable to request algorithm list");
+
+ info = (ipfw_ta_info *)(olh + 1);
+ for (i = 0; i < olh->count; i++) {
+ if ((atype = match_value(tabletypes, info->type)) == NULL)
+ atype = "unknown";
+ printf("--- %s ---\n", info->algoname);
+ printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
+
+ info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
+ }
+
+ free(olh);
+}
+
+
+/* Copy of current kernel table_value structure */
+struct _table_value {
+ uint32_t tag; /* O_TAG/O_TAGGED */
+ uint32_t pipe; /* O_PIPE/O_QUEUE */
+ uint16_t divert; /* O_DIVERT/O_TEE */
+ uint16_t skipto; /* skipto, CALLRET */
+ uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */
+ uint32_t fib; /* O_SETFIB */
+ uint32_t nat; /* O_NAT */
+ uint32_t nh4;
+ uint8_t dscp;
+ uint8_t spare0[3];
+ /* -- 32 bytes -- */
+ struct in6_addr nh6;
+ uint32_t limit; /* O_LIMIT */
+ uint32_t spare1;
+ uint64_t refcnt; /* Number of references */
+};
+
+int
+compare_values(const void *_a, const void *_b)
+{
+ struct _table_value *a, *b;
+
+ a = (struct _table_value *)_a;
+ b = (struct _table_value *)_b;
+
+ if (a->spare1 < b->spare1)
+ return (-1);
+ else if (a->spare1 > b->spare1)
+ return (1);
+
+ return (0);
+}
+
+void
+ipfw_list_values(int ac, char *av[])
+{
+ ipfw_obj_lheader *olh;
+ struct _table_value *v;
+ int error, i;
+ uint32_t vmask;
+ char buf[128];
+
+ error = table_do_get_vlist(&olh);
+ if (error != 0)
+ err(EX_OSERR, "Unable to request value list");
+
+ vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */
+
+ table_print_valheader(buf, sizeof(buf), vmask);
+ printf("HEADER: %s\n", buf);
+ v = (struct _table_value *)(olh + 1);
+ qsort(v, olh->count, olh->objsize, compare_values);
+ for (i = 0; i < olh->count; i++) {
+ table_show_value(buf, sizeof(buf), (ipfw_table_value *)v,
+ vmask, 0);
+ printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf);
+ v = (struct _table_value *)((caddr_t)v + olh->objsize);
+ }
+
+ free(olh);
+}
+
+int
+compare_ntlv(const void *_a, const void *_b)
+{
+ ipfw_obj_ntlv *a, *b;
+
+ a = (ipfw_obj_ntlv *)_a;
+ b = (ipfw_obj_ntlv *)_b;
+
+ if (a->set < b->set)
+ return (-1);
+ else if (a->set > b->set)
+ return (1);
+
+ if (a->idx < b->idx)
+ return (-1);
+ else if (a->idx > b->idx)
+ return (1);
+
+ return (0);
+}
+
+int
+compare_kntlv(const void *k, const void *v)
+{
+ ipfw_obj_ntlv *ntlv;
+ uint16_t key;
+
+ key = *((uint16_t *)k);
+ ntlv = (ipfw_obj_ntlv *)v;
+
+ if (key < ntlv->idx)
+ return (-1);
+ else if (key > ntlv->idx)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Finds table name in @ctlv by @idx.
+ * Uses the following facts:
+ * 1) All TLVs are the same size
+ * 2) Kernel implementation provides already sorted list.
+ *
+ * Returns table name or NULL.
+ */
+char *
+table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
+{
+ ipfw_obj_ntlv *ntlv;
+
+ ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
+ compare_kntlv);
+
+ if (ntlv != 0)
+ return (ntlv->name);
+
+ return (NULL);
+}
+
+void
+table_sort_ctlv(ipfw_obj_ctlv *ctlv)
+{
+
+ qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv);
+}
+
+int
+table_check_name(char *tablename)
+{
+ int c, i, l;
+
+ /*
+ * Check if tablename is null-terminated and contains
+ * valid symbols only. Valid mask is:
+ * [a-zA-Z0-9\-_\.]{1,63}
+ */
+ l = strlen(tablename);
+ if (l == 0 || l >= 64)
+ return (EINVAL);
+ for (i = 0; i < l; i++) {
+ c = tablename[i];
+ if (isalpha(c) || isdigit(c) || c == '_' ||
+ c == '-' || c == '.')
+ continue;
+ return (EINVAL);
+ }
+
+ /* Restrict some 'special' names */
+ if (strcmp(tablename, "all") == 0)
+ return (EINVAL);
+
+ return (0);
+}
+
diff --git a/sbin/iscontrol/iscontrol.8 b/sbin/iscontrol/iscontrol.8
index 860b35a..eee8776 100644
--- a/sbin/iscontrol/iscontrol.8
+++ b/sbin/iscontrol/iscontrol.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 9, 2010
+.Dd October 9, 2014
.Dt ISCONTROL 8
.Os
.Sh NAME
@@ -41,6 +41,15 @@
.Op Fl t Ar target
.Op Ar variable Ns = Ns Ar value
.Sh DESCRIPTION
+.Bf -symbolic
+This command, along with its kernel counterpart
+.Xr iscsi_initiator 4 ,
+is obsolete.
+Users are advised to use
+.Xr iscsictl 8
+instead.
+.Ef
+.Pp
Internet SCSI (iSCSI) is a network protocol standard, that allows the
use of the SCSI protocol over TCP/IP networks,
the
diff --git a/sbin/mksnap_ffs/Makefile b/sbin/mksnap_ffs/Makefile
index 9247cb2..de96fa0 100644
--- a/sbin/mksnap_ffs/Makefile
+++ b/sbin/mksnap_ffs/Makefile
@@ -10,9 +10,9 @@ WARNS?= 2
CFLAGS+=-I${.CURDIR}/../mount
.if defined(NOSUID)
-BINMODE=550
+BINMODE=554
.else
-BINMODE=4550
+BINMODE=4554
BINOWN= root
.endif
BINGRP= operator
diff --git a/sbin/mount/mntopts.h b/sbin/mount/mntopts.h
index 86a350f..d273dde 100644
--- a/sbin/mount/mntopts.h
+++ b/sbin/mount/mntopts.h
@@ -33,7 +33,7 @@
struct mntopt {
const char *m_option; /* option name */
int m_inverse; /* if a negative option, e.g. "atime" */
- int m_flag; /* bit to set, e.g. MNT_RDONLY */
+ long long m_flag; /* bit to set, e.g. MNT_RDONLY */
int m_altloc; /* 1 => set bit in altflags */
};
@@ -55,6 +55,7 @@ struct mntopt {
#define MOPT_MULTILABEL { "multilabel", 0, MNT_MULTILABEL, 0 }
#define MOPT_ACLS { "acls", 0, MNT_ACLS, 0 }
#define MOPT_NFS4ACLS { "nfsv4acls", 0, MNT_NFS4ACLS, 0 }
+#define MOPT_AUTOMOUNTED { "automounted",0, MNT_AUTOMOUNTED, 0 }
/* Control flags. */
#define MOPT_FORCE { "force", 0, MNT_FORCE, 0 }
@@ -89,7 +90,8 @@ struct mntopt {
MOPT_NOCLUSTERW, \
MOPT_MULTILABEL, \
MOPT_ACLS, \
- MOPT_NFS4ACLS
+ MOPT_NFS4ACLS, \
+ MOPT_AUTOMOUNTED
void getmntopts(const char *, const struct mntopt *, int *, int *);
void rmslashes(char *, char *);
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index 50c5a8b..bfa70b6 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
.\" $FreeBSD$
.\"
-.Dd June 6, 2011
+.Dd August 20, 2014
.Dt MOUNT 8
.Os
.Sh NAME
@@ -150,6 +150,11 @@ For this reason, the
.Cm async
flag should be used sparingly, and only when some data recovery
mechanism is present.
+.It Cm automounted
+This flag indicates that the file system was mounted by
+.Xr automountd 8 .
+Automounted file systems are automatically unmounted by
+.Xr autounmountd 8 .
.It Cm current
When used with the
.Fl u
@@ -551,6 +556,7 @@ support for a particular file system might be provided either on a static
.Xr mount_smbfs 8 ,
.Xr mount_udf 8 ,
.Xr mount_unionfs 8 ,
+.Xr tmpfs 5 ,
.Xr umount 8 ,
.Xr zfs 8 ,
.Xr zpool 8
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c
index 91c7d7c..5ea45df 100644
--- a/sbin/mount/mount.c
+++ b/sbin/mount/mount.c
@@ -114,6 +114,7 @@ static struct opt {
{ MNT_ACLS, "acls" },
{ MNT_NFS4ACLS, "nfsv4acls" },
{ MNT_GJOURNAL, "gjournal" },
+ { MNT_AUTOMOUNTED, "automounted" },
{ 0, NULL }
};
diff --git a/sbin/mount_nfs/Makefile b/sbin/mount_nfs/Makefile
index cccc517..eceed2b 100644
--- a/sbin/mount_nfs/Makefile
+++ b/sbin/mount_nfs/Makefile
@@ -10,7 +10,6 @@ MLINKS= mount_nfs.8 mount_oldnfs.8
MOUNT= ${.CURDIR}/../mount
UMNTALL= ${.CURDIR}/../../usr.sbin/rpc.umntall
CFLAGS+= -DNFS -I${MOUNT} -I${UMNTALL}
-WARNS?= 3
LINKS= ${BINDIR}/mount_nfs ${BINDIR}/mount_oldnfs
diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index da11c29..473f519 100644
--- a/sbin/mount_nfs/mount_nfs.8
+++ b/sbin/mount_nfs/mount_nfs.8
@@ -28,7 +28,7 @@
.\" @(#)mount_nfs.8 8.3 (Berkeley) 3/29/95
.\" $FreeBSD$
.\"
-.Dd December 7, 2013
+.Dd October 30, 2014
.Dt MOUNT_NFS 8
.Os
.Sh NAME
@@ -118,6 +118,8 @@ for regular files, and 30 -> 60 seconds for directories.
The algorithm to calculate the timeout is based on the age of the file.
The older the file,
the longer the cache is considered valid, subject to the limits above.
+.It Cm actimeo Ns = Ns Aq Ar seconds
+Set four cache timeouts above to specified value.
.It Cm allgssname
This option can be used along with
.Fl o Cm gssname
@@ -211,6 +213,8 @@ NFS Version 4 protocol.
This option is only meaningful when used with the
.Cm minorversion
option.
+.It Cm noac
+Disable attribute caching.
.It Cm noconn
For UDP mount points, do not do a
.Xr connect 2 .
@@ -282,6 +286,15 @@ use a reserved socket port number (see below).
.It Cm port Ns = Ns Aq Ar port_number
Use specified port number for NFS requests.
The default is to query the portmapper for the NFS port.
+.It Cm proto Ns = Ns Aq Ar protocol
+Specify transport protocol version to use.
+Currently, they are:
+.Bd -literal
+udp - Use UDP over IPv4
+tcp - Use TCP over IPv4
+udp6 - Use UDP over IPv6
+tcp6 - Use TCP over IPv6
+.Ed
.It Cm rdirplus
Used with NFSV3 to specify that the \fBReaddirPlus\fR RPC should
be used.
@@ -357,7 +370,8 @@ LAN and WAN configurations compared to UDP.
Some old NFS servers do not support this method; UDP mounts may be required
for interoperability.
.It Cm timeout Ns = Ns Aq Ar value
-Set the initial retransmit timeout to the specified value.
+Set the initial retransmit timeout to the specified value,
+expressed in tenths of a second.
May be useful for fine tuning UDP mounts over internetworks
with high packet loss rates or an overloaded server.
Try increasing the interval if
@@ -369,8 +383,19 @@ value if there is a low retransmit rate but long response delay observed.
option should be specified when using this option to manually
tune the timeout
interval.)
+.It Cm timeo Ns = Ns Aq Ar value
+Alias for
+.Cm timeout .
.It Cm udp
Use UDP transport.
+.It Cm vers Ns = Ns Aq Ar vers_number
+Use the specified version number for NFS requests.
+See the
+.Cm nfsv2 ,
+.Cm nfsv3 ,
+and
+.Cm nfsv4
+options for details.
.It Cm wcommitsize Ns = Ns Aq Ar value
Set the maximum pending write commit size to the specified value.
This determines the maximum amount of pending write data that the NFS
@@ -466,6 +491,26 @@ Same as
Same as
.Fl o Cm retrans Ns = Ns Aq Ar value
.El
+.Pp
+The following
+.Fl o
+named options are equivalent to other
+.Fl o
+named options and are supported for compatibility with other
+operating systems (e.g., Linux, Solaris, and OSX) to ease usage of
+.Xr autofs 5
+support.
+.Bl -tag -width indent
+.It Fl o Cm vers Ns = Ns 2
+Same as
+.Fl o Cm nfsv2
+.It Fl o Cm vers Ns = Ns 3
+Same as
+.Fl o Cm nfsv3
+.It Fl o Cm vers Ns = Ns 4
+Same as
+.Fl o Cm nfsv4
+.El
.Sh SEE ALSO
.Xr nmount 2 ,
.Xr unmount 2 ,
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c
index bd016f3..7f53581 100644
--- a/sbin/mount_nfs/mount_nfs.c
+++ b/sbin/mount_nfs/mount_nfs.c
@@ -79,7 +79,7 @@ __FBSDID("$FreeBSD$");
#include "mounttab.h"
/* Table for af,sotype -> netid conversions. */
-struct nc_protos {
+static struct nc_protos {
const char *netid;
int af;
int sotype;
@@ -102,20 +102,21 @@ struct nfhret {
#define ISBGRND 2
#define OF_NOINET4 4
#define OF_NOINET6 8
-int retrycnt = -1;
-int opflags = 0;
-int nfsproto = IPPROTO_TCP;
-int mnttcp_ok = 1;
-int noconn = 0;
-char *portspec = NULL; /* Server nfs port; NULL means look up via rpcbind. */
-struct sockaddr *addr;
-int addrlen = 0;
-u_char *fh = NULL;
-int fhsize = 0;
-int secflavor = -1;
-int got_principal = 0;
-
-enum mountmode {
+static int retrycnt = -1;
+static int opflags = 0;
+static int nfsproto = IPPROTO_TCP;
+static int mnttcp_ok = 1;
+static int noconn = 0;
+/* The 'portspec' is the server nfs port; NULL means look up via rpcbind. */
+static const char *portspec = NULL;
+static struct sockaddr *addr;
+static int addrlen = 0;
+static u_char *fh = NULL;
+static int fhsize = 0;
+static int secflavor = -1;
+static int got_principal = 0;
+
+static enum mountmode {
ANY,
V2,
V3,
@@ -130,9 +131,8 @@ enum tryret {
TRYRET_LOCALERR /* Local failure. */
};
-static int fallback_mount(struct iovec *iov, int iovlen);
-static int sec_name_to_num(char *sec);
-static char *sec_num_to_name(int num);
+static int sec_name_to_num(const char *sec);
+static const char *sec_num_to_name(int num);
static int getnfsargs(char *, struct iovec **iov, int *iovlen);
/* void set_rpc_maxgrouplist(int); */
static struct netconfig *getnetconf_cached(const char *netid);
@@ -150,10 +150,10 @@ main(int argc, char *argv[])
int c;
struct iovec *iov;
int num, iovlen;
- int osversion;
- char *name, *p, *spec, *fstype;
+ char *mntname, *p, *spec, *tmp;
char mntpath[MAXPATHLEN], errmsg[255];
- char hostname[MAXHOSTNAMELEN + 1], *gssname, gssn[MAXHOSTNAMELEN + 50];
+ char hostname[MAXHOSTNAMELEN + 1], gssn[MAXHOSTNAMELEN + 50];
+ const char *fstype, *gssname;
iov = NULL;
iovlen = 0;
@@ -228,7 +228,7 @@ main(int argc, char *argv[])
while (opt) {
char *pval = NULL;
char *pnextopt = NULL;
- char *val = "";
+ const char *val = "";
pass_flag_to_nmount = 1;
pnextopt = strchr(opt, ',');
if (pnextopt != NULL) {
@@ -278,12 +278,41 @@ main(int argc, char *argv[])
portspec = "2049";
} else if (strcmp(opt, "port") == 0) {
pass_flag_to_nmount=0;
- asprintf(&portspec, "%d",
- atoi(val));
- if (portspec == NULL)
+ asprintf(&tmp, "%d", atoi(val));
+ if (tmp == NULL)
err(1, "asprintf");
+ portspec = tmp;
} else if (strcmp(opt, "principal") == 0) {
got_principal = 1;
+ } else if (strcmp(opt, "proto") == 0) {
+ pass_flag_to_nmount=0;
+ if (strcmp(val, "tcp") == 0) {
+ nfsproto = IPPROTO_TCP;
+ opflags |= OF_NOINET6;
+ build_iovec(&iov, &iovlen,
+ "tcp", NULL, 0);
+ } else if (strcmp(val, "udp") == 0) {
+ mnttcp_ok = 0;
+ nfsproto = IPPROTO_UDP;
+ opflags |= OF_NOINET6;
+ build_iovec(&iov, &iovlen,
+ "udp", NULL, 0);
+ } else if (strcmp(val, "tcp6") == 0) {
+ nfsproto = IPPROTO_TCP;
+ opflags |= OF_NOINET4;
+ build_iovec(&iov, &iovlen,
+ "tcp", NULL, 0);
+ } else if (strcmp(val, "udp6") == 0) {
+ mnttcp_ok = 0;
+ nfsproto = IPPROTO_UDP;
+ opflags |= OF_NOINET4;
+ build_iovec(&iov, &iovlen,
+ "udp", NULL, 0);
+ } else {
+ errx(1,
+ "illegal proto value -- %s",
+ val);
+ }
} else if (strcmp(opt, "sec") == 0) {
/*
* Don't add this option to
@@ -310,10 +339,38 @@ main(int argc, char *argv[])
if (*p || num <= 0)
errx(1, "illegal maxgroups value -- %s", val);
//set_rpc_maxgrouplist(num);
+ } else if (strcmp(opt, "vers") == 0) {
+ num = strtol(val, &p, 10);
+ if (*p || num <= 0)
+ errx(1, "illegal vers value -- "
+ "%s", val);
+ switch (num) {
+ case 2:
+ mountmode = V2;
+ break;
+ case 3:
+ mountmode = V3;
+ build_iovec(&iov, &iovlen,
+ "nfsv3", NULL, 0);
+ break;
+ case 4:
+ mountmode = V4;
+ fstype = "nfs";
+ nfsproto = IPPROTO_TCP;
+ if (portspec == NULL)
+ portspec = "2049";
+ break;
+ default:
+ errx(1, "illegal nfs version "
+ "value -- %s", val);
+ }
+ pass_flag_to_nmount=0;
}
- if (pass_flag_to_nmount)
- build_iovec(&iov, &iovlen, opt, val,
+ if (pass_flag_to_nmount) {
+ build_iovec(&iov, &iovlen, opt,
+ __DECONST(void *, val),
strlen(val) + 1);
+ }
opt = pnextopt;
}
}
@@ -373,7 +430,7 @@ main(int argc, char *argv[])
}
spec = *argv++;
- name = *argv;
+ mntname = *argv;
if (retrycnt == -1)
/* The default is to keep retrying forever. */
@@ -402,271 +459,30 @@ main(int argc, char *argv[])
hostname);
gssname = gssn;
}
- build_iovec(&iov, &iovlen, "gssname", gssname,
- strlen(gssname) + 1);
+ build_iovec(&iov, &iovlen, "gssname",
+ __DECONST(void *, gssname), strlen(gssname) + 1);
}
if (!getnfsargs(spec, &iov, &iovlen))
exit(1);
/* resolve the mountpoint with realpath(3) */
- if (checkpath(name, mntpath) != 0)
+ if (checkpath(mntname, mntpath) != 0)
err(1, "%s", mntpath);
- build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
+ build_iovec(&iov, &iovlen, "fstype",
+ __DECONST(void *, fstype), (size_t)-1);
build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1);
build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
- /*
- * XXX:
- * Backwards compatibility routines for older kernels.
- * Remove this and fallback_mount() code when we do not need to support
- * NFS mounts against older kernels which still need
- * struct nfs_args to be passed in via nmount().
- */
- osversion = getosreldate();
- if (osversion >= 702100) {
- if (nmount(iov, iovlen, 0))
- err(1, "%s, %s", mntpath, errmsg);
- } else {
- if (fallback_mount(iov, iovlen))
- err(1, "%s, %s", mntpath, errmsg);
- }
+ if (nmount(iov, iovlen, 0))
+ err(1, "%s, %s", mntpath, errmsg);
exit(0);
}
static int
-findopt(struct iovec *iov, int iovlen, const char *name,
- char **valuep, int *lenp)
-{
- int i;
-
- for (i = 0; i < iovlen/2; i++, iov += 2) {
- if (strcmp(name, iov[0].iov_base) == 0) {
- if (valuep)
- *valuep = iov[1].iov_base;
- if (lenp)
- *lenp = iov[1].iov_len;
- return (0);
- }
- }
- return (ENOENT);
-}
-
-static void
-copyopt(struct iovec **newiov, int *newiovlen,
- struct iovec *iov, int iovlen, const char *name)
-{
- char *value;
- int len;
-
- if (findopt(iov, iovlen, name, &value, &len) == 0)
- build_iovec(newiov, newiovlen, name, value, len);
-}
-
-/*
- * XXX: This function is provided for backwards
- * compatibility with older kernels which did not support
- * passing NFS mount options to nmount() as individual
- * parameters. It should be eventually be removed.
- */
-static int
-fallback_mount(struct iovec *iov, int iovlen)
-{
- struct nfs_args args = {
- .version = NFS_ARGSVERSION,
- .addr = NULL,
- .addrlen = sizeof (struct sockaddr_in),
- .sotype = SOCK_STREAM,
- .proto = 0,
- .fh = NULL,
- .fhsize = 0,
- .flags = NFSMNT_RESVPORT,
- .wsize = NFS_WSIZE,
- .rsize = NFS_RSIZE,
- .readdirsize = NFS_READDIRSIZE,
- .timeo = 10,
- .retrans = NFS_RETRANS,
- .maxgrouplist = NFS_MAXGRPS,
- .readahead = NFS_DEFRAHEAD,
- .wcommitsize = 0, /* was: NQ_DEFLEASE */
- .deadthresh = NFS_MAXDEADTHRESH, /* was: NQ_DEADTHRESH */
- .hostname = NULL,
- /* args version 4 */
- .acregmin = NFS_MINATTRTIMO,
- .acregmax = NFS_MAXATTRTIMO,
- .acdirmin = NFS_MINDIRATTRTIMO,
- .acdirmax = NFS_MAXDIRATTRTIMO,
- };
- int ret;
- char *opt;
- struct iovec *newiov;
- int newiovlen;
-
- if (findopt(iov, iovlen, "dumbtimer", NULL, NULL) == 0)
- args.flags |= NFSMNT_DUMBTIMR;
- if (findopt(iov, iovlen, "noconn", NULL, NULL) == 0)
- args.flags |= NFSMNT_NOCONN;
- if (findopt(iov, iovlen, "conn", NULL, NULL) == 0)
- args.flags |= NFSMNT_NOCONN;
- if (findopt(iov, iovlen, "nolockd", NULL, NULL) == 0)
- args.flags |= NFSMNT_NOLOCKD;
- if (findopt(iov, iovlen, "lockd", NULL, NULL) == 0)
- args.flags &= ~NFSMNT_NOLOCKD;
- if (findopt(iov, iovlen, "intr", NULL, NULL) == 0)
- args.flags |= NFSMNT_INT;
- if (findopt(iov, iovlen, "rdirplus", NULL, NULL) == 0)
- args.flags |= NFSMNT_RDIRPLUS;
- if (findopt(iov, iovlen, "resvport", NULL, NULL) == 0)
- args.flags |= NFSMNT_RESVPORT;
- if (findopt(iov, iovlen, "noresvport", NULL, NULL) == 0)
- args.flags &= ~NFSMNT_RESVPORT;
- if (findopt(iov, iovlen, "soft", NULL, NULL) == 0)
- args.flags |= NFSMNT_SOFT;
- if (findopt(iov, iovlen, "hard", NULL, NULL) == 0)
- args.flags &= ~NFSMNT_SOFT;
- if (findopt(iov, iovlen, "mntudp", NULL, NULL) == 0)
- args.sotype = SOCK_DGRAM;
- if (findopt(iov, iovlen, "udp", NULL, NULL) == 0)
- args.sotype = SOCK_DGRAM;
- if (findopt(iov, iovlen, "tcp", NULL, NULL) == 0)
- args.sotype = SOCK_STREAM;
- if (findopt(iov, iovlen, "nfsv3", NULL, NULL) == 0)
- args.flags |= NFSMNT_NFSV3;
- if (findopt(iov, iovlen, "readdirsize", &opt, NULL) == 0) {
- if (opt == NULL) {
- errx(1, "illegal readdirsize");
- }
- ret = sscanf(opt, "%d", &args.readdirsize);
- if (ret != 1 || args.readdirsize <= 0) {
- errx(1, "illegal readdirsize: %s", opt);
- }
- args.flags |= NFSMNT_READDIRSIZE;
- }
- if (findopt(iov, iovlen, "readahead", &opt, NULL) == 0) {
- if (opt == NULL) {
- errx(1, "illegal readahead");
- }
- ret = sscanf(opt, "%d", &args.readahead);
- if (ret != 1 || args.readahead <= 0) {
- errx(1, "illegal readahead: %s", opt);
- }
- args.flags |= NFSMNT_READAHEAD;
- }
- if (findopt(iov, iovlen, "wsize", &opt, NULL) == 0) {
- if (opt == NULL) {
- errx(1, "illegal wsize");
- }
- ret = sscanf(opt, "%d", &args.wsize);
- if (ret != 1 || args.wsize <= 0) {
- errx(1, "illegal wsize: %s", opt);
- }
- args.flags |= NFSMNT_WSIZE;
- }
- if (findopt(iov, iovlen, "rsize", &opt, NULL) == 0) {
- if (opt == NULL) {
- errx(1, "illegal rsize");
- }
- ret = sscanf(opt, "%d", &args.rsize);
- if (ret != 1 || args.rsize <= 0) {
- errx(1, "illegal wsize: %s", opt);
- }
- args.flags |= NFSMNT_RSIZE;
- }
- if (findopt(iov, iovlen, "retrans", &opt, NULL) == 0) {
- if (opt == NULL) {
- errx(1, "illegal retrans");
- }
- ret = sscanf(opt, "%d", &args.retrans);
- if (ret != 1 || args.retrans <= 0) {
- errx(1, "illegal retrans: %s", opt);
- }
- args.flags |= NFSMNT_RETRANS;
- }
- if (findopt(iov, iovlen, "acregmin", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.acregmin);
- if (ret != 1 || args.acregmin < 0) {
- errx(1, "illegal acregmin: %s", opt);
- }
- args.flags |= NFSMNT_ACREGMIN;
- }
- if (findopt(iov, iovlen, "acregmax", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.acregmax);
- if (ret != 1 || args.acregmax < 0) {
- errx(1, "illegal acregmax: %s", opt);
- }
- args.flags |= NFSMNT_ACREGMAX;
- }
- if (findopt(iov, iovlen, "acdirmin", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.acdirmin);
- if (ret != 1 || args.acdirmin < 0) {
- errx(1, "illegal acdirmin: %s", opt);
- }
- args.flags |= NFSMNT_ACDIRMIN;
- }
- if (findopt(iov, iovlen, "acdirmax", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.acdirmax);
- if (ret != 1 || args.acdirmax < 0) {
- errx(1, "illegal acdirmax: %s", opt);
- }
- args.flags |= NFSMNT_ACDIRMAX;
- }
- if (findopt(iov, iovlen, "wcommitsize", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.wcommitsize);
- if (ret != 1 || args.wcommitsize < 0) {
- errx(1, "illegal wcommitsize: %s", opt);
- }
- args.flags |= NFSMNT_WCOMMITSIZE;
- }
- if (findopt(iov, iovlen, "deadthresh", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.deadthresh);
- if (ret != 1 || args.deadthresh <= 0) {
- errx(1, "illegal deadthresh: %s", opt);
- }
- args.flags |= NFSMNT_DEADTHRESH;
- }
- if (findopt(iov, iovlen, "timeout", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.timeo);
- if (ret != 1 || args.timeo <= 0) {
- errx(1, "illegal timeout: %s", opt);
- }
- args.flags |= NFSMNT_TIMEO;
- }
- if (findopt(iov, iovlen, "maxgroups", &opt, NULL) == 0) {
- ret = sscanf(opt, "%d", &args.maxgrouplist);
- if (ret != 1 || args.timeo <= 0) {
- errx(1, "illegal maxgroups: %s", opt);
- }
- args.flags |= NFSMNT_MAXGRPS;
- }
- if (findopt(iov, iovlen, "addr", &opt,
- &args.addrlen) == 0) {
- args.addr = (struct sockaddr *) opt;
- }
- if (findopt(iov, iovlen, "fh", &opt, &args.fhsize) == 0) {
- args.fh = opt;
- }
- if (findopt(iov, iovlen, "hostname", &args.hostname,
- NULL) == 0) {
- }
- if (args.hostname == NULL) {
- errx(1, "Invalid hostname");
- }
-
- newiov = NULL;
- newiovlen = 0;
-
- build_iovec(&newiov, &newiovlen, "nfs_args", &args, sizeof(args));
- copyopt(&newiov, &newiovlen, iov, iovlen, "fstype");
- copyopt(&newiov, &newiovlen, iov, iovlen, "fspath");
- copyopt(&newiov, &newiovlen, iov, iovlen, "errmsg");
-
- return nmount(newiov, newiovlen, 0);
-}
-
-static int
-sec_name_to_num(char *sec)
+sec_name_to_num(const char *sec)
{
if (!strcmp(sec, "krb5"))
return (RPCSEC_GSS_KRB5);
@@ -679,7 +495,7 @@ sec_name_to_num(char *sec)
return (-1);
}
-static char *
+static const char *
sec_num_to_name(int flavor)
{
switch (flavor) {
@@ -863,10 +679,9 @@ nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
struct rpc_err rpcerr;
CLIENT *clp;
struct netconfig *nconf, *nconf_mnt;
- const char *netid, *netid_mnt;
- char *secname;
+ const char *netid, *netid_mnt, *secname;
int doconnect, nfsvers, mntvers, sotype;
- enum clnt_stat stat;
+ enum clnt_stat clntstat;
enum mountmode trymntmode;
sotype = 0;
@@ -910,6 +725,7 @@ nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
tryagain:
if (trymntmode == V4) {
nfsvers = 4;
+ mntvers = 3; /* Workaround for GCC. */
} else if (trymntmode == V2) {
nfsvers = 2;
mntvers = 1;
@@ -969,10 +785,10 @@ tryagain:
try.tv_sec = 10;
try.tv_usec = 0;
- stat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL,
+ clntstat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL,
(xdrproc_t)xdr_void, NULL, try);
- if (stat != RPC_SUCCESS) {
- if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
+ if (clntstat != RPC_SUCCESS) {
+ if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
clnt_destroy(clp);
trymntmode = V2;
goto tryagain;
@@ -981,7 +797,7 @@ tryagain:
snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid,
hostp, spec, clnt_sperror(clp, "NFSPROC_NULL"));
clnt_destroy(clp);
- return (returncode(stat, &rpcerr));
+ return (returncode(clntstat, &rpcerr));
}
clnt_destroy(clp);
@@ -1001,8 +817,10 @@ tryagain:
build_iovec(iov, iovlen, "addr", addr, addrlen);
secname = sec_num_to_name(secflavor);
- if (secname != NULL)
- build_iovec(iov, iovlen, "sec", secname, (size_t)-1);
+ if (secname != NULL) {
+ build_iovec(iov, iovlen, "sec",
+ __DECONST(void *, secname), (size_t)-1);
+ }
build_iovec(iov, iovlen, "nfsv4", NULL, 0);
build_iovec(iov, iovlen, "dirpath", spec, (size_t)-1);
@@ -1022,12 +840,12 @@ tryagain:
clp->cl_auth = authsys_create_default();
nfhret.auth = secflavor;
nfhret.vers = mntvers;
- stat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, spec,
+ clntstat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, spec,
(xdrproc_t)xdr_fh, &nfhret,
try);
auth_destroy(clp->cl_auth);
- if (stat != RPC_SUCCESS) {
- if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
+ if (clntstat != RPC_SUCCESS) {
+ if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
clnt_destroy(clp);
trymntmode = V2;
goto tryagain;
@@ -1036,7 +854,7 @@ tryagain:
snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
hostp, spec, clnt_sperror(clp, "RPCPROG_MNT"));
clnt_destroy(clp);
- return (returncode(stat, &rpcerr));
+ return (returncode(clntstat, &rpcerr));
}
clnt_destroy(clp);
@@ -1062,8 +880,10 @@ tryagain:
build_iovec(iov, iovlen, "addr", addr, addrlen);
build_iovec(iov, iovlen, "fh", fh, fhsize);
secname = sec_num_to_name(nfhret.auth);
- if (secname)
- build_iovec(iov, iovlen, "sec", secname, (size_t)-1);
+ if (secname) {
+ build_iovec(iov, iovlen, "sec",
+ __DECONST(void *, secname), (size_t)-1);
+ }
if (nfsvers == 3)
build_iovec(iov, iovlen, "nfsv3", NULL, 0);
@@ -1075,9 +895,10 @@ tryagain:
* return code.
*/
static enum tryret
-returncode(enum clnt_stat stat, struct rpc_err *rpcerr)
+returncode(enum clnt_stat clntstat, struct rpc_err *rpcerr)
{
- switch (stat) {
+
+ switch (clntstat) {
case RPC_TIMEDOUT:
return (TRYRET_TIMEOUT);
case RPC_PMAPFAILURE:
diff --git a/sbin/newfs_msdos/newfs_msdos.c b/sbin/newfs_msdos/newfs_msdos.c
index 4bfb219..f315d98 100644
--- a/sbin/newfs_msdos/newfs_msdos.c
+++ b/sbin/newfs_msdos/newfs_msdos.c
@@ -689,7 +689,7 @@ main(int argc, char *argv[])
((u_int)tm->tm_hour << 8 |
(u_int)tm->tm_min));
mk4(bsx->exVolumeID, x);
- mklabel(bsx->exVolumeLabel, opt_L ? opt_L : "NO_NAME");
+ mklabel(bsx->exVolumeLabel, opt_L ? opt_L : "NO NAME");
sprintf(buf, "FAT%u", fat);
setstr(bsx->exFileSysType, buf, sizeof(bsx->exFileSysType));
if (!opt_B) {
diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile
index a05efe3..57f82a8 100644
--- a/sbin/ping/Makefile
+++ b/sbin/ping/Makefile
@@ -7,7 +7,7 @@ PROG= ping
MAN= ping.8
BINOWN= root
BINMODE=4555
-WARNS?= 2
+WARNS?= 3
DPADD= ${LIBM}
LDADD= -lm
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
index 283c22b..aeb3014 100644
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -122,7 +122,7 @@ struct tv32 {
};
/* various options */
-int options;
+static int options;
#define F_FLOOD 0x0001
#define F_INTERVAL 0x0002
#define F_NUMERIC 0x0004
@@ -157,52 +157,52 @@ int options;
* to 8192 for complete accuracy...
*/
#define MAX_DUP_CHK (8 * 128)
-int mx_dup_ck = MAX_DUP_CHK;
-char rcvd_tbl[MAX_DUP_CHK / 8];
-
-struct sockaddr_in whereto; /* who to ping */
-int datalen = DEFDATALEN;
-int maxpayload;
-int ssend; /* send socket file descriptor */
-int srecv; /* receive socket file descriptor */
-u_char outpackhdr[IP_MAXPACKET], *outpack;
-char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
-char BSPACE = '\b'; /* characters written for flood */
-char DOT = '.';
-char *hostname;
-char *shostname;
-int ident; /* process id to identify our packets */
-int uid; /* cached uid for micro-optimization */
-u_char icmp_type = ICMP_ECHO;
-u_char icmp_type_rsp = ICMP_ECHOREPLY;
-int phdr_len = 0;
-int send_len;
+static int mx_dup_ck = MAX_DUP_CHK;
+static char rcvd_tbl[MAX_DUP_CHK / 8];
+
+static struct sockaddr_in whereto; /* who to ping */
+static int datalen = DEFDATALEN;
+static int maxpayload;
+static int ssend; /* send socket file descriptor */
+static int srecv; /* receive socket file descriptor */
+static u_char outpackhdr[IP_MAXPACKET], *outpack;
+static char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
+static char BSPACE = '\b'; /* characters written for flood */
+static char DOT = '.';
+static char *hostname;
+static char *shostname;
+static int ident; /* process id to identify our packets */
+static int uid; /* cached uid for micro-optimization */
+static u_char icmp_type = ICMP_ECHO;
+static u_char icmp_type_rsp = ICMP_ECHOREPLY;
+static int phdr_len = 0;
+static int send_len;
/* counters */
-long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
-long npackets; /* max packets to transmit */
-long nreceived; /* # of packets we got back */
-long nrepeats; /* number of duplicates */
-long ntransmitted; /* sequence # for outbound packets = #sent */
-long snpackets; /* max packets to transmit in one sweep */
-long snreceived; /* # of packets we got back in this sweep */
-long sntransmitted; /* # of packets we sent in this sweep */
-int sweepmax; /* max value of payload in sweep */
-int sweepmin = 0; /* start value of payload in sweep */
-int sweepincr = 1; /* payload increment in sweep */
-int interval = 1000; /* interval between packets, ms */
-int waittime = MAXWAIT; /* timeout for each packet */
-long nrcvtimeout = 0; /* # of packets we got back after waittime */
+static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
+static long npackets; /* max packets to transmit */
+static long nreceived; /* # of packets we got back */
+static long nrepeats; /* number of duplicates */
+static long ntransmitted; /* sequence # for outbound packets = #sent */
+static long snpackets; /* max packets to transmit in one sweep */
+static long sntransmitted; /* # of packets we sent in this sweep */
+static int sweepmax; /* max value of payload in sweep */
+static int sweepmin = 0; /* start value of payload in sweep */
+static int sweepincr = 1; /* payload increment in sweep */
+static int interval = 1000; /* interval between packets, ms */
+static int waittime = MAXWAIT; /* timeout for each packet */
+static long nrcvtimeout = 0; /* # of packets we got back after waittime */
/* timing */
-int timing; /* flag to do timing */
-double tmin = 999999999.0; /* minimum round trip time */
-double tmax = 0.0; /* maximum round trip time */
-double tsum = 0.0; /* sum of all times, for doing average */
-double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+static int timing; /* flag to do timing */
+static double tmin = 999999999.0; /* minimum round trip time */
+static double tmax = 0.0; /* maximum round trip time */
+static double tsum = 0.0; /* sum of all times, for doing average */
+static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
-volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */
-volatile sig_atomic_t siginfo_p;
+/* nonzero if we've been told to finish up */
+static volatile sig_atomic_t finish_up;
+static volatile sig_atomic_t siginfo_p;
#ifdef HAVE_LIBCAPSICUM
static cap_channel_t *capdns;
@@ -1150,7 +1150,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
#endif
tp = (const char *)tp + phdr_len;
- if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) {
+ if ((size_t)(cc - ICMP_MINLEN - phdr_len) >=
+ sizeof(tv1)) {
/* Copy to avoid alignment problems: */
memcpy(&tv32, tp, sizeof(tv32));
tv1.tv_sec = ntohl(tv32.tv32_sec);
diff --git a/sbin/ping6/Makefile b/sbin/ping6/Makefile
index 89e7fbe..e40dc6e 100644
--- a/sbin/ping6/Makefile
+++ b/sbin/ping6/Makefile
@@ -4,8 +4,8 @@ PROG= ping6
MAN= ping6.8
CFLAGS+=-DIPSEC -DKAME_SCOPEID -DUSE_RFC2292BIS \
- -DHAVE_POLL_H -DHAVE_ARC4RANDOM
-WARNS?= 2
+ -DHAVE_ARC4RANDOM
+WARNS?= 3
BINOWN= root
BINMODE=4555
diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8
index 60a6980..99111e2 100644
--- a/sbin/ping6/ping6.8
+++ b/sbin/ping6/ping6.8
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 5, 2013
+.Dd September 22, 2014
.Dt PING6 8
.Os
.Sh NAME
@@ -65,6 +65,12 @@ packets to network hosts
.Op Fl i Ar wait
.Ek
.Bk -words
+.Op Fl x Ar waittime
+.Ek
+.Bk -words
+.Op Fl X Ar timeout
+.Ek
+.Bk -words
.Op Fl l Ar preload
.Ek
.Bk -words
@@ -191,6 +197,15 @@ The default is to wait for one second between each packet.
This option is incompatible with the
.Fl f
option.
+.It Fl x Ar waittime
+Time in milliseconds to wait for a reply for each packet sent.
+If a reply arrives later,
+the packet is not printed as replied,
+but considered as replied when calculating statistics.
+.It Fl X Ar timeout
+Specify a timeout,
+in seconds,
+before ping exits regardless of how many packets have been received.
.It Fl l Ar preload
If
.Ar preload
diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c
index b963de1..fa314f6 100644
--- a/sbin/ping6/ping6.c
+++ b/sbin/ping6/ping6.c
@@ -125,10 +125,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
#ifdef IPSEC
#include <netipsec/ah.h>
@@ -154,6 +152,8 @@ struct tv32 {
#define DEFDATALEN ICMP6ECHOTMLEN
#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
#define NROUTES 9 /* number of record route slots */
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
@@ -190,6 +190,7 @@ struct tv32 {
#define F_MISSED 0x800000
#define F_DONTFRAG 0x1000000
#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
+#define F_WAITTIME 0x2000000
u_int options;
#define IN6LEN sizeof(struct in6_addr)
@@ -204,108 +205,96 @@ u_int options;
* to 8192 for complete accuracy...
*/
#define MAX_DUP_CHK (8 * 8192)
-int mx_dup_ck = MAX_DUP_CHK;
-char rcvd_tbl[MAX_DUP_CHK / 8];
-
-struct addrinfo *res = NULL;
-struct sockaddr_in6 dst; /* who to ping6 */
-struct sockaddr_in6 src; /* src addr of this packet */
-socklen_t srclen;
-int datalen = DEFDATALEN;
-int s; /* socket file descriptor */
-u_char outpack[MAXPACKETLEN];
-char BSPACE = '\b'; /* characters written for flood */
-char BBELL = '\a'; /* characters written for AUDIBLE */
-char DOT = '.';
-char *hostname;
-int ident; /* process id to identify our packets */
-u_int8_t nonce[8]; /* nonce field for node information */
-int hoplimit = -1; /* hoplimit */
-int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */
-u_char *packet = NULL;
-#ifdef HAVE_POLL_H
-struct pollfd fdmaskp[1];
-#else
-fd_set *fdmaskp = NULL;
-int fdmasks;
-#endif
+static int mx_dup_ck = MAX_DUP_CHK;
+static char rcvd_tbl[MAX_DUP_CHK / 8];
+
+static struct sockaddr_in6 dst; /* who to ping6 */
+static struct sockaddr_in6 src; /* src addr of this packet */
+static socklen_t srclen;
+static size_t datalen = DEFDATALEN;
+static int s; /* socket file descriptor */
+static u_char outpack[MAXPACKETLEN];
+static char BSPACE = '\b'; /* characters written for flood */
+static char BBELL = '\a'; /* characters written for AUDIBLE */
+static char DOT = '.';
+static char *hostname;
+static int ident; /* process id to identify our packets */
+static u_int8_t nonce[8]; /* nonce field for node information */
+static int hoplimit = -1; /* hoplimit */
+static u_char *packet = NULL;
/* counters */
-long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
-long npackets; /* max packets to transmit */
-long nreceived; /* # of packets we got back */
-long nrepeats; /* number of duplicates */
-long ntransmitted; /* sequence # for outbound packets = #sent */
-struct timeval interval = {1, 0}; /* interval between packets */
+static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
+static long npackets; /* max packets to transmit */
+static long nreceived; /* # of packets we got back */
+static long nrepeats; /* number of duplicates */
+static long ntransmitted; /* sequence # for outbound packets = #sent */
+static int interval = 1000; /* interval between packets in ms */
+static int waittime = MAXWAIT; /* timeout for each packet */
+static long nrcvtimeout = 0; /* # of packets we got back after waittime */
/* timing */
-int timing; /* flag to do timing */
-double tmin = 999999999.0; /* minimum round trip time */
-double tmax = 0.0; /* maximum round trip time */
-double tsum = 0.0; /* sum of all times, for doing average */
-double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+static int timing; /* flag to do timing */
+static double tmin = 999999999.0; /* minimum round trip time */
+static double tmax = 0.0; /* maximum round trip time */
+static double tsum = 0.0; /* sum of all times, for doing average */
+static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
/* for node addresses */
-u_short naflags;
+static u_short naflags;
/* for ancillary data(advanced API) */
-struct msghdr smsghdr;
-struct iovec smsgiov;
-char *scmsg = 0;
+static struct msghdr smsghdr;
+static struct iovec smsgiov;
+static char *scmsg = 0;
-volatile sig_atomic_t seenalrm;
-volatile sig_atomic_t seenint;
+static volatile sig_atomic_t seenint;
#ifdef SIGINFO
-volatile sig_atomic_t seeninfo;
+static volatile sig_atomic_t seeninfo;
#endif
int main(int, char *[]);
-void fill(char *, char *);
-int get_hoplim(struct msghdr *);
-int get_pathmtu(struct msghdr *);
-struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
-void onsignal(int);
-void retransmit(void);
-void onint(int);
-size_t pingerlen(void);
-int pinger(void);
-const char *pr_addr(struct sockaddr *, int);
-void pr_icmph(struct icmp6_hdr *, u_char *);
-void pr_iph(struct ip6_hdr *);
-void pr_suptypes(struct icmp6_nodeinfo *, size_t);
-void pr_nodeaddr(struct icmp6_nodeinfo *, int);
-int myechoreply(const struct icmp6_hdr *);
-int mynireply(const struct icmp6_nodeinfo *);
-char *dnsdecode(const u_char **, const u_char *, const u_char *,
- char *, size_t);
-void pr_pack(u_char *, int, struct msghdr *);
-void pr_exthdrs(struct msghdr *);
-void pr_ip6opt(void *, size_t);
-void pr_rthdr(void *, size_t);
-int pr_bitrange(u_int32_t, int, int);
-void pr_retip(struct ip6_hdr *, u_char *);
-void summary(void);
-void tvsub(struct timeval *, struct timeval *);
-int setpolicy(int, char *);
-char *nigroup(char *, int);
-void usage(void);
+static void fill(char *, char *);
+static int get_hoplim(struct msghdr *);
+static int get_pathmtu(struct msghdr *);
+static struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
+static void onsignal(int);
+static void onint(int);
+static size_t pingerlen(void);
+static int pinger(void);
+static const char *pr_addr(struct sockaddr *, int);
+static void pr_icmph(struct icmp6_hdr *, u_char *);
+static void pr_iph(struct ip6_hdr *);
+static void pr_suptypes(struct icmp6_nodeinfo *, size_t);
+static void pr_nodeaddr(struct icmp6_nodeinfo *, int);
+static int myechoreply(const struct icmp6_hdr *);
+static int mynireply(const struct icmp6_nodeinfo *);
+static char *dnsdecode(const u_char **, const u_char *, const u_char *,
+ char *, size_t);
+static void pr_pack(u_char *, int, struct msghdr *);
+static void pr_exthdrs(struct msghdr *);
+static void pr_ip6opt(void *, size_t);
+static void pr_rthdr(void *, size_t);
+static int pr_bitrange(u_int32_t, int, int);
+static void pr_retip(struct ip6_hdr *, u_char *);
+static void summary(void);
+static void tvsub(struct timeval *, struct timeval *);
+static int setpolicy(int, char *);
+static char *nigroup(char *, int);
+static void usage(void);
int
main(int argc, char *argv[])
{
- struct itimerval itimer;
- struct sockaddr_in6 from;
+ struct timeval last, intvl;
+ struct sockaddr_in6 from, *sin6;
#ifndef HAVE_ARC4RANDOM
struct timeval seed;
#endif
-#ifdef HAVE_POLL_H
- int timeout;
-#else
- struct timeval timeout, *tv;
-#endif
- struct addrinfo hints;
+ struct addrinfo hints, *res;
+ struct sigaction si_sa;
int cc, i;
- int ch, hold, packlen, preload, optval, ret_ga;
+ int almost_done, ch, hold, packlen, preload, optval, error;
int nig_oldmcprefix = -1;
u_char *datap;
char *e, *target, *ifname = NULL, *gateway = NULL;
@@ -326,7 +315,8 @@ main(int argc, char *argv[])
char *policy_in = NULL;
char *policy_out = NULL;
#endif
- double intval;
+ double t;
+ u_long alarmtimeout;
size_t rthlen;
#ifdef IPV6_USE_MIN_MTU
int mflag = 0;
@@ -336,7 +326,7 @@ main(int argc, char *argv[])
memset(&smsghdr, 0, sizeof(smsghdr));
memset(&smsgiov, 0, sizeof(smsgiov));
- preload = 0;
+ alarmtimeout = preload = 0;
datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
#ifndef IPSEC
#define ADDOPTS
@@ -348,7 +338,7 @@ main(int argc, char *argv[])
#endif /*IPSEC_POLICY_IPSEC*/
#endif
while ((ch = getopt(argc, argv,
- "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwW" ADDOPTS)) != -1) {
+ "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwWx:X:" ADDOPTS)) != -1) {
#undef ADDOPTS
switch (ch) {
case 'a':
@@ -399,9 +389,9 @@ main(int argc, char *argv[])
errno = 0;
e = NULL;
lsockbufsize = strtoul(optarg, &e, 10);
- sockbufsize = lsockbufsize;
+ sockbufsize = (int)lsockbufsize;
if (errno || !*optarg || *e ||
- sockbufsize != lsockbufsize)
+ lsockbufsize > INT_MAX)
errx(1, "invalid socket buffer size");
#else
errx(1,
@@ -450,22 +440,22 @@ main(int argc, char *argv[])
#endif
break;
case 'i': /* wait between sending packets */
- intval = strtod(optarg, &e);
+ t = strtod(optarg, &e);
if (*optarg == '\0' || *e != '\0')
errx(1, "illegal timing interval %s", optarg);
- if (intval < 1 && getuid()) {
+ if (t < 1 && getuid()) {
errx(1, "%s: only root may use interval < 1s",
strerror(EPERM));
}
- interval.tv_sec = (long)intval;
- interval.tv_usec =
- (long)((intval - interval.tv_sec) * 1000000);
- if (interval.tv_sec < 0)
+ intvl.tv_sec = (long)t;
+ intvl.tv_usec =
+ (long)((t - intvl.tv_sec) * 1000000);
+ if (intvl.tv_sec < 0)
errx(1, "illegal timing interval %s", optarg);
/* less than 1/hz does not make sense */
- if (interval.tv_sec == 0 && interval.tv_usec < 1) {
+ if (intvl.tv_sec == 0 && intvl.tv_usec < 1) {
warnx("too small interval, raised to .000001");
- interval.tv_usec = 1;
+ intvl.tv_usec = 1;
}
options |= F_INTERVAL;
break;
@@ -516,10 +506,10 @@ main(int argc, char *argv[])
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
- ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
- if (ret_ga) {
+ error = getaddrinfo(optarg, NULL, &hints, &res);
+ if (error) {
errx(1, "invalid source address: %s",
- gai_strerror(ret_ga));
+ gai_strerror(error));
}
/*
* res->ai_family must be AF_INET6 and res->ai_addrlen
@@ -556,6 +546,24 @@ main(int argc, char *argv[])
options &= ~F_NOUSERDATA;
options |= F_FQDNOLD;
break;
+ case 'x':
+ t = strtod(optarg, &e);
+ if (*e || e == optarg || t > (double)INT_MAX)
+ err(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_WAITTIME;
+ waittime = (int)t;
+ break;
+ case 'X':
+ alarmtimeout = strtoul(optarg, &e, 0);
+ if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((int)alarmtimeout);
+ break;
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
case 'P':
@@ -622,9 +630,9 @@ main(int argc, char *argv[])
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
- ret_ga = getaddrinfo(target, NULL, &hints, &res);
- if (ret_ga)
- errx(1, "%s", gai_strerror(ret_ga));
+ error = getaddrinfo(target, NULL, &hints, &res);
+ if (error)
+ errx(1, "%s", gai_strerror(error));
if (res->ai_canonname)
hostname = res->ai_canonname;
else
@@ -647,28 +655,25 @@ main(int argc, char *argv[])
/* set the gateway (next hop) if specified */
if (gateway) {
- struct addrinfo ghints, *gres;
- int error;
-
- memset(&ghints, 0, sizeof(ghints));
- ghints.ai_family = AF_INET6;
- ghints.ai_socktype = SOCK_RAW;
- ghints.ai_protocol = IPPROTO_ICMPV6;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
- error = getaddrinfo(gateway, NULL, &hints, &gres);
+ error = getaddrinfo(gateway, NULL, &hints, &res);
if (error) {
errx(1, "getaddrinfo for the gateway %s: %s",
gateway, gai_strerror(error));
}
- if (gres->ai_next && (options & F_VERBOSE))
+ if (res->ai_next && (options & F_VERBOSE))
warnx("gateway resolves to multiple addresses");
if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
- gres->ai_addr, gres->ai_addrlen)) {
+ res->ai_addr, res->ai_addrlen)) {
err(1, "setsockopt(IPV6_NEXTHOP)");
}
- freeaddrinfo(gres);
+ freeaddrinfo(res);
}
/*
@@ -745,7 +750,7 @@ main(int argc, char *argv[])
*((int *)&nonce[i]) = rand();
#else
memset(nonce, 0, sizeof(nonce));
- for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t))
+ for (i = 0; i < (int)sizeof(nonce); i += sizeof(u_int32_t))
*((u_int32_t *)&nonce[i]) = arc4random();
#endif
optval = 1;
@@ -898,7 +903,7 @@ main(int argc, char *argv[])
}
if (argc > 1) { /* some intermediate addrs are specified */
- int hops, error;
+ int hops;
#ifdef USE_RFC2292BIS
int rthdrlen;
#endif
@@ -920,26 +925,25 @@ main(int argc, char *argv[])
#endif /* USE_RFC2292BIS */
for (hops = 0; hops < argc - 1; hops++) {
- struct addrinfo *iaip;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
if ((error = getaddrinfo(argv[hops], NULL, &hints,
- &iaip)))
+ &res)))
errx(1, "%s", gai_strerror(error));
- if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
+ if (res->ai_addr->sa_family != AF_INET6)
errx(1,
"bad addr family of an intermediate addr");
-
+ sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
#ifdef USE_RFC2292BIS
- if (inet6_rth_add(rthdr,
- &(SIN6(iaip->ai_addr))->sin6_addr))
+ if (inet6_rth_add(rthdr, &sin6->sin6_addr))
errx(1, "can't add an intermediate node");
#else /* old advanced API */
- if (inet6_rthdr_add(scmsgp,
- &(SIN6(iaip->ai_addr))->sin6_addr,
+ if (inet6_rthdr_add(scmsg, &sin6->sin6_addr,
IPV6_RTHDR_LOOSE))
errx(1, "can't add an intermediate node");
#endif /* USE_RFC2292BIS */
- freeaddrinfo(iaip);
+ freeaddrinfo(res);
}
#ifndef USE_RFC2292BIS
@@ -1004,7 +1008,7 @@ main(int argc, char *argv[])
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
if (sockbufsize) {
- if (datalen > sockbufsize)
+ if (datalen > (size_t)sockbufsize)
warnx("you need -b to increase socket buffer size");
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
sizeof(sockbufsize)) < 0)
@@ -1055,58 +1059,50 @@ main(int argc, char *argv[])
printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
- while (preload--) /* Fire off them quickies. */
- (void)pinger();
-
- (void)signal(SIGINT, onsignal);
-#ifdef SIGINFO
- (void)signal(SIGINFO, onsignal);
-#endif
-
- if ((options & F_FLOOD) == 0) {
- (void)signal(SIGALRM, onsignal);
- itimer.it_interval = interval;
- itimer.it_value = interval;
- (void)setitimer(ITIMER_REAL, &itimer, NULL);
- if (ntransmitted == 0)
- retransmit();
+ if (preload == 0)
+ pinger();
+ else {
+ if (npackets != 0 && preload > npackets)
+ preload = npackets;
+ while (preload--)
+ pinger();
}
-
-#ifndef HAVE_POLL_H
- fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
- if ((fdmaskp = malloc(fdmasks)) == NULL)
- err(1, "malloc");
-#endif
-
- seenalrm = seenint = 0;
+ gettimeofday(&last, NULL);
+
+ sigemptyset(&si_sa.sa_mask);
+ si_sa.sa_flags = 0;
+ si_sa.sa_handler = onsignal;
+ if (sigaction(SIGINT, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGINT");
+ seenint = 0;
#ifdef SIGINFO
+ if (sigaction(SIGINFO, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGINFO");
seeninfo = 0;
#endif
+ if (alarmtimeout > 0) {
+ if (sigaction(SIGALRM, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGALRM");
+ }
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else if ((options & F_INTERVAL) == 0) {
+ intvl.tv_sec = interval / 1000;
+ intvl.tv_usec = interval % 1000 * 1000;
+ }
- for (;;) {
+ almost_done = 0;
+ while (seenint == 0) {
+ struct timeval now, timeout;
struct msghdr m;
struct iovec iov[2];
+ fd_set rfds;
+ int n;
/* signal handling */
- if (seenalrm) {
- /* last packet sent, timeout reached? */
- if (npackets && ntransmitted >= npackets) {
- struct timeval zerotime = {0, 0};
- itimer.it_value = zerotime;
- itimer.it_interval = zerotime;
- (void)setitimer(ITIMER_REAL, &itimer, NULL);
- seenalrm = 0; /* clear flag */
- continue;
- }
- retransmit();
- seenalrm = 0;
- continue;
- }
- if (seenint) {
+ if (seenint)
onint(SIGINT);
- seenint = 0;
- continue;
- }
#ifdef SIGINFO
if (seeninfo) {
summary();
@@ -1114,93 +1110,106 @@ main(int argc, char *argv[])
continue;
}
#endif
-
- if (options & F_FLOOD) {
- (void)pinger();
-#ifdef HAVE_POLL_H
- timeout = 10;
-#else
- timeout.tv_sec = 0;
- timeout.tv_usec = 10000;
- tv = &timeout;
-#endif
- } else {
-#ifdef HAVE_POLL_H
- timeout = INFTIM;
-#else
- tv = NULL;
-#endif
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+ timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+ while (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
}
-#ifdef HAVE_POLL_H
- fdmaskp[0].fd = s;
- fdmaskp[0].events = POLLIN;
- cc = poll(fdmaskp, 1, timeout);
-#else
- memset(fdmaskp, 0, fdmasks);
- FD_SET(s, fdmaskp);
- cc = select(s + 1, fdmaskp, NULL, NULL, tv);
-#endif
- if (cc < 0) {
- if (errno != EINTR) {
-#ifdef HAVE_POLL_H
- warn("poll");
-#else
- warn("select");
-#endif
- sleep(1);
- }
- continue;
- } else if (cc == 0)
- continue;
+ while (timeout.tv_usec > 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ if (n < 0)
+ continue; /* EINTR */
+ if (n == 1) {
+ m.msg_name = (caddr_t)&from;
+ m.msg_namelen = sizeof(from);
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = (caddr_t)packet;
+ iov[0].iov_len = packlen;
+ m.msg_iov = iov;
+ m.msg_iovlen = 1;
+ memset(cm, 0, CONTROLLEN);
+ m.msg_control = (void *)cm;
+ m.msg_controllen = CONTROLLEN;
+
+ cc = recvmsg(s, &m, 0);
+ if (cc < 0) {
+ if (errno != EINTR) {
+ warn("recvmsg");
+ sleep(1);
+ }
+ continue;
+ } else if (cc == 0) {
+ int mtu;
- m.msg_name = (caddr_t)&from;
- m.msg_namelen = sizeof(from);
- memset(&iov, 0, sizeof(iov));
- iov[0].iov_base = (caddr_t)packet;
- iov[0].iov_len = packlen;
- m.msg_iov = iov;
- m.msg_iovlen = 1;
- memset(cm, 0, CONTROLLEN);
- m.msg_control = (void *)cm;
- m.msg_controllen = CONTROLLEN;
-
- cc = recvmsg(s, &m, 0);
- if (cc < 0) {
- if (errno != EINTR) {
- warn("recvmsg");
- sleep(1);
+ /*
+ * receive control messages only. Process the
+ * exceptions (currently the only possibility is
+ * a path MTU notification.)
+ */
+ if ((mtu = get_pathmtu(&m)) > 0) {
+ if ((options & F_VERBOSE) != 0) {
+ printf("new path MTU (%d) is "
+ "notified\n", mtu);
+ }
+ }
+ continue;
+ } else {
+ /*
+ * an ICMPv6 message (probably an echoreply)
+ * arrived.
+ */
+ pr_pack(packet, cc, &m);
}
- continue;
- } else if (cc == 0) {
- int mtu;
-
+ if (((options & F_ONCE) != 0 && nreceived > 0) ||
+ (npackets > 0 && nreceived >= npackets))
+ break;
+ }
+ if (n == 0 || (options & F_FLOOD)) {
+ if (npackets == 0 || ntransmitted < npackets)
+ pinger();
+ else {
+ if (almost_done)
+ break;
+ almost_done = 1;
/*
- * receive control messages only. Process the
- * exceptions (currently the only possibility is
- * a path MTU notification.)
+ * If we're not transmitting any more packets,
+ * change the timer to wait two round-trip times
+ * if we've received any packets or (waittime)
+ * milliseconds if we haven't.
*/
- if ((mtu = get_pathmtu(&m)) > 0) {
- if ((options & F_VERBOSE) != 0) {
- printf("new path MTU (%d) is "
- "notified\n", mtu);
+ intvl.tv_usec = 0;
+ if (nreceived) {
+ intvl.tv_sec = 2 * tmax / 1000;
+ if (intvl.tv_sec == 0)
+ intvl.tv_sec = 1;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
}
}
- continue;
- } else {
- /*
- * an ICMPv6 message (probably an echoreply) arrived.
- */
- pr_pack(packet, cc, &m);
- }
- if (((options & F_ONCE) != 0 && nreceived > 0) ||
- (npackets > 0 && nreceived >= npackets))
- break;
- if (ntransmitted - nreceived - 1 > nmissedmax) {
- nmissedmax = ntransmitted - nreceived - 1;
- if (options & F_MISSED)
- (void)write(STDOUT_FILENO, &BBELL, 1);
+ gettimeofday(&last, NULL);
+ if (ntransmitted - nreceived - 1 > nmissedmax) {
+ nmissedmax = ntransmitted - nreceived - 1;
+ if (options & F_MISSED)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ }
}
}
+ sigemptyset(&si_sa.sa_mask);
+ si_sa.sa_flags = 0;
+ si_sa.sa_handler = SIG_IGN;
+ sigaction(SIGINT, &si_sa, 0);
+ sigaction(SIGALRM, &si_sa, 0);
summary();
if (res != NULL)
@@ -1209,23 +1218,16 @@ main(int argc, char *argv[])
if(packet != NULL)
free(packet);
-#ifndef HAVE_POLL_H
- if(fdmaskp != NULL)
- free(fdmaskp);
-#endif
-
exit(nreceived == 0 ? 2 : 0);
}
-void
+static void
onsignal(int sig)
{
switch (sig) {
- case SIGALRM:
- seenalrm++;
- break;
case SIGINT:
+ case SIGALRM:
seenint++;
break;
#ifdef SIGINFO
@@ -1237,38 +1239,6 @@ onsignal(int sig)
}
/*
- * retransmit --
- * This routine transmits another ping6.
- */
-void
-retransmit(void)
-{
- struct itimerval itimer;
-
- if (pinger() == 0)
- return;
-
- /*
- * If we're not transmitting any more packets, change the timer
- * to wait two round-trip times if we've received any packets or
- * ten seconds if we haven't.
- */
-#define MAXWAIT 10
- if (nreceived) {
- itimer.it_value.tv_sec = 2 * tmax / 1000;
- if (itimer.it_value.tv_sec == 0)
- itimer.it_value.tv_sec = 1;
- } else
- itimer.it_value.tv_sec = MAXWAIT;
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = 0;
- itimer.it_value.tv_usec = 0;
-
- (void)signal(SIGALRM, onsignal);
- (void)setitimer(ITIMER_REAL, &itimer, NULL);
-}
-
-/*
* pinger --
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
* will be added on by the kernel. The ID field is our UNIX process ID,
@@ -1276,7 +1246,7 @@ retransmit(void)
* of the data portion are used to hold a UNIX "timeval" struct in VAX
* byte-order, to compute the round-trip time.
*/
-size_t
+static size_t
pingerlen(void)
{
size_t l;
@@ -1295,7 +1265,7 @@ pingerlen(void)
return l;
}
-int
+static int
pinger(void)
{
struct icmp6_hdr *icp;
@@ -1410,7 +1380,7 @@ pinger(void)
return(0);
}
-int
+static int
myechoreply(const struct icmp6_hdr *icp)
{
if (ntohs(icp->icmp6_id) == ident)
@@ -1419,7 +1389,7 @@ myechoreply(const struct icmp6_hdr *icp)
return 0;
}
-int
+static int
mynireply(const struct icmp6_nodeinfo *nip)
{
if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
@@ -1430,7 +1400,7 @@ mynireply(const struct icmp6_nodeinfo *nip)
return 0;
}
-char *
+static char *
dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
size_t bufsiz)
/*base for compressed name*/
@@ -1474,7 +1444,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
while (i-- > 0 && cp < ep) {
l = snprintf(cresult, sizeof(cresult),
isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
- if (l >= sizeof(cresult) || l < 0)
+ if ((size_t)l >= sizeof(cresult) || l < 0)
return NULL;
if (strlcat(buf, cresult, bufsiz) >= bufsiz)
return NULL; /*result overrun*/
@@ -1497,7 +1467,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
* which arrive ('tis only fair). This permits multiple copies of this
* program to be run without having intermingled output (or statistics!).
*/
-void
+static void
pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
{
#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
@@ -1529,7 +1499,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
}
from = (struct sockaddr *)mhdr->msg_name;
fromlen = mhdr->msg_namelen;
- if (cc < sizeof(struct icmp6_hdr)) {
+ if (cc < (int)sizeof(struct icmp6_hdr)) {
if (options & F_VERBOSE)
warnx("packet too short (%d bytes) from %s", cc,
pr_addr(from, fromlen));
@@ -1581,6 +1551,11 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
if (options & F_QUIET)
return;
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
if (options & F_FLOOD)
(void)write(STDOUT_FILENO, &BSPACE, 1);
else {
@@ -1778,7 +1753,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
#undef safeputc
}
-void
+static void
pr_exthdrs(struct msghdr *mhdr)
{
ssize_t bufsize;
@@ -1816,7 +1791,7 @@ pr_exthdrs(struct msghdr *mhdr)
}
#ifdef USE_RFC2292BIS
-void
+static void
pr_ip6opt(void *extbuf, size_t bufsize)
{
struct ip6_hbh *ext;
@@ -1879,7 +1854,7 @@ pr_ip6opt(void *extbuf, size_t bufsize)
}
#else /* !USE_RFC2292BIS */
/* ARGSUSED */
-void
+static void
pr_ip6opt(void *extbuf, size_t bufsize __unused)
{
putchar('\n');
@@ -1888,7 +1863,7 @@ pr_ip6opt(void *extbuf, size_t bufsize __unused)
#endif /* USE_RFC2292BIS */
#ifdef USE_RFC2292BIS
-void
+static void
pr_rthdr(void *extbuf, size_t bufsize)
{
struct in6_addr *in6;
@@ -1945,7 +1920,7 @@ pr_rthdr(void *extbuf, size_t bufsize)
#else /* !USE_RFC2292BIS */
/* ARGSUSED */
-void
+static void
pr_rthdr(void *extbuf, size_t bufsize __unused)
{
putchar('\n');
@@ -1953,7 +1928,7 @@ pr_rthdr(void *extbuf, size_t bufsize __unused)
}
#endif /* USE_RFC2292BIS */
-int
+static int
pr_bitrange(u_int32_t v, int soff, int ii)
{
int off;
@@ -1999,7 +1974,7 @@ pr_bitrange(u_int32_t v, int soff, int ii)
return ii;
}
-void
+static void
pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
/* ni->qtype must be SUPTYPES */
{
@@ -2065,7 +2040,7 @@ pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
}
}
-void
+static void
pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
/* ni->qtype must be NODEADDR */
{
@@ -2131,7 +2106,7 @@ pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
}
}
-int
+static int
get_hoplim(struct msghdr *mhdr)
{
struct cmsghdr *cm;
@@ -2150,7 +2125,7 @@ get_hoplim(struct msghdr *mhdr)
return(-1);
}
-struct in6_pktinfo *
+static struct in6_pktinfo *
get_rcvpktinfo(struct msghdr *mhdr)
{
struct cmsghdr *cm;
@@ -2169,7 +2144,7 @@ get_rcvpktinfo(struct msghdr *mhdr)
return(NULL);
}
-int
+static int
get_pathmtu(struct msghdr *mhdr)
{
#ifdef IPV6_RECVPATHMTU
@@ -2229,7 +2204,7 @@ get_pathmtu(struct msghdr *mhdr)
* Subtract 2 timeval structs: out = out - in. Out is assumed to
* be >= in.
*/
-void
+static void
tvsub(struct timeval *out, struct timeval *in)
{
if ((out->tv_usec -= in->tv_usec) < 0) {
@@ -2244,34 +2219,22 @@ tvsub(struct timeval *out, struct timeval *in)
* SIGINT handler.
*/
/* ARGSUSED */
-void
+static void
onint(int notused __unused)
{
- summary();
-
- if (res != NULL)
- freeaddrinfo(res);
-
- if(packet != NULL)
- free(packet);
-
-#ifndef HAVE_POLL_H
- if(fdmaskp != NULL)
- free(fdmaskp);
-#endif
-
- (void)signal(SIGINT, SIG_DFL);
- (void)kill(getpid(), SIGINT);
-
- /* NOTREACHED */
- exit(1);
+ /*
+ * When doing reverse DNS lookups, the seenint flag might not
+ * be noticed for a while. Just exit if we get a second SIGINT.
+ */
+ if ((options & F_HOSTNAME) && seenint != 0)
+ _exit(nreceived ? 0 : 2);
}
/*
* summary --
* Print out statistics.
*/
-void
+static void
summary(void)
{
@@ -2288,6 +2251,8 @@ summary(void)
((((double)ntransmitted - nreceived) * 100.0) /
ntransmitted));
}
+ if (nrcvtimeout)
+ printf(", %ld packets out of wait time", nrcvtimeout);
(void)putchar('\n');
if (nreceived && timing) {
/* Only display average to microseconds */
@@ -2319,7 +2284,7 @@ static const char *nircode[] = {
* pr_icmph --
* Print a descriptive string about an ICMP header.
*/
-void
+static void
pr_icmph(struct icmp6_hdr *icp, u_char *end)
{
char ntop_buf[INET6_ADDRSTRLEN];
@@ -2549,7 +2514,7 @@ pr_icmph(struct icmp6_hdr *icp, u_char *end)
* pr_iph --
* Print an IP6 header.
*/
-void
+static void
pr_iph(struct ip6_hdr *ip6)
{
u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
@@ -2577,7 +2542,7 @@ pr_iph(struct ip6_hdr *ip6)
* Return an ascii host address as a dotted quad and optionally with
* a hostname.
*/
-const char *
+static const char *
pr_addr(struct sockaddr *addr, int addrlen)
{
static char buf[NI_MAXHOST];
@@ -2596,13 +2561,13 @@ pr_addr(struct sockaddr *addr, int addrlen)
* pr_retip --
* Dump some info on a returned (via ICMPv6) IPv6 packet.
*/
-void
+static void
pr_retip(struct ip6_hdr *ip6, u_char *end)
{
u_char *cp = (u_char *)ip6, nh;
int hlen;
- if (end - (u_char *)ip6 < sizeof(*ip6)) {
+ if ((size_t)(end - (u_char *)ip6) < sizeof(*ip6)) {
printf("IP6");
goto trunc;
}
@@ -2676,7 +2641,7 @@ pr_retip(struct ip6_hdr *ip6, u_char *end)
return;
}
-void
+static void
fill(char *bp, char *patp)
{
int ii, jj, kk;
@@ -2695,7 +2660,7 @@ fill(char *bp, char *patp)
/* xxx */
if (ii > 0)
for (kk = 0;
- kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
+ (size_t)kk <= MAXDATALEN - 8 + sizeof(struct tv32) + ii;
kk += ii)
for (jj = 0; jj < ii; ++jj)
bp[jj + kk] = pat[jj];
@@ -2709,7 +2674,7 @@ fill(char *bp, char *patp)
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
-int
+static int
setpolicy(int so __unused, char *policy)
{
char *buf;
@@ -2730,7 +2695,7 @@ setpolicy(int so __unused, char *policy)
#endif
#endif
-char *
+static char *
nigroup(char *name, int nig_oldmcprefix)
{
char *p;
@@ -2789,7 +2754,7 @@ nigroup(char *name, int nig_oldmcprefix)
return strdup(hbuf);
}
-void
+static void
usage(void)
{
(void)fprintf(stderr,
@@ -2813,6 +2778,7 @@ usage(void)
#endif
"\n"
" [-p pattern] [-S sourceaddr] [-s packetsize] "
- "[hops ...] host\n");
+ "[-x waittime]\n"
+ " [-X timeout] [hops ...] host\n");
exit(1);
}
diff --git a/sbin/rcorder/Makefile b/sbin/rcorder/Makefile
index dc48b4c..b71aa4b 100644
--- a/sbin/rcorder/Makefile
+++ b/sbin/rcorder/Makefile
@@ -14,8 +14,6 @@ CFLAGS+= -DORDER -I.
SRCS+= util.h
CLEANFILES+= util.h
-NO_PIE= yes
-
util.h:
ln -sf ${.CURDIR}/../../lib/libutil/libutil.h ${.TARGET}
diff --git a/sbin/reboot/boot_i386.8 b/sbin/reboot/boot_i386.8
index d860423..690dfcd 100644
--- a/sbin/reboot/boot_i386.8
+++ b/sbin/reboot/boot_i386.8
@@ -36,7 +36,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 1, 2013
+.Dd November 14, 2014
.Dt BOOT 8 i386
.Os
.Sh NAME
@@ -56,6 +56,11 @@ Some BIOSes allow
you to change this default sequence, and may also include a CD-ROM
drive as a boot device.
.Pp
+Some newer PCs boot using UEFI firmware, not BIOS.
+That process is described
+in
+.Xr uefi 8 .
+.Pp
By default, a three-stage bootstrap is employed, and control is
automatically passed from the boot blocks (bootstrap stages one and
two) to a separate third-stage bootstrap program,
@@ -355,7 +360,8 @@ requirement has not been adhered to.
.Xr loader 8 ,
.Xr nextboot 8 ,
.Xr reboot 8 ,
-.Xr shutdown 8
+.Xr shutdown 8 ,
+.Xr uefi 8
.Sh BUGS
The bsdlabel format used by this version of
.Bx
diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c
index 4f34549..225fe32 100644
--- a/sbin/restore/tape.c
+++ b/sbin/restore/tape.c
@@ -260,9 +260,11 @@ setup(void)
fssize = TP_BSIZE;
if (stbuf.st_blksize >= TP_BSIZE && stbuf.st_blksize <= MAXBSIZE)
fssize = stbuf.st_blksize;
- if (((fssize - 1) & fssize) != 0) {
- fprintf(stderr, "bad block size %ld\n", fssize);
- done(1);
+ if (((TP_BSIZE - 1) & stbuf.st_blksize) != 0) {
+ fprintf(stderr, "Warning: filesystem with non-multiple-of-%d "
+ "blocksize (%d);\n", TP_BSIZE, stbuf.st_blksize);
+ fssize = roundup(fssize, TP_BSIZE);
+ fprintf(stderr, "\twriting using blocksize %ld\n", fssize);
}
if (spcl.c_volume != 1) {
fprintf(stderr, "Tape is not volume 1 of the dump\n");
diff --git a/sbin/route/keywords b/sbin/route/keywords
index 8b64be2..82edc46 100644
--- a/sbin/route/keywords
+++ b/sbin/route/keywords
@@ -40,7 +40,6 @@ osi
prefixlen
proto1
proto2
-proto3
proxy
recvpipe
reject
diff --git a/sbin/route/route.8 b/sbin/route/route.8
index 000fbe9..5e6f78b 100644
--- a/sbin/route/route.8
+++ b/sbin/route/route.8
@@ -28,7 +28,7 @@
.\" @(#)route.8 8.3 (Berkeley) 3/19/94
.\" $FreeBSD$
.\"
-.Dd January 11, 2014
+.Dd November 11, 2014
.Dt ROUTE 8
.Os
.Sh NAME
@@ -315,7 +315,6 @@ by indicating the following corresponding modifiers:
-blackhole RTF_BLACKHOLE - silently discard pkts (during updates)
-proto1 RTF_PROTO1 - set protocol specific routing flag #1
-proto2 RTF_PROTO2 - set protocol specific routing flag #2
--proto3 RTF_PROTO3 - set protocol specific routing flag #3
.Ed
.Pp
The optional modifiers
diff --git a/sbin/route/route.c b/sbin/route/route.c
index 9b3bb95..53ec298 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -847,9 +847,6 @@ newroute(int argc, char **argv)
case K_PROTO2:
flags |= RTF_PROTO2;
break;
- case K_PROTO3:
- flags |= RTF_PROTO3;
- break;
case K_PROXY:
nrflags |= F_PROXY;
break;
@@ -1533,9 +1530,19 @@ rtmsg(int cmd, int flags, int fib)
if (debugonly)
return (0);
if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
- if (errno == EPERM)
+ switch (errno) {
+ case EPERM:
err(1, "writing to routing socket");
- warn("writing to routing socket");
+ break;
+ case ESRCH:
+ warnx("route has not been found");
+ break;
+ case EEXIST:
+ /* Handled by newroute() */
+ break;
+ default:
+ warn("writing to routing socket");
+ }
return (-1);
}
if (cmd == RTM_GET) {
@@ -1580,7 +1587,7 @@ static const char routeflags[] =
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
- "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
+ "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
static const char ifnetflags[] =
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
diff --git a/sbin/routed/defs.h b/sbin/routed/defs.h
index c42cd80..a31d6f5 100644
--- a/sbin/routed/defs.h
+++ b/sbin/routed/defs.h
@@ -462,6 +462,7 @@ extern int ridhosts; /* 1=reduce host routes */
extern int mhome; /* 1=want multi-homed host route */
extern int advertise_mhome; /* 1=must continue advertising it */
extern int auth_ok; /* 1=ignore auth if we do not care */
+extern int insecure; /* Reply to special queries or not */
extern struct timeval clk; /* system clock's idea of time */
extern struct timeval epoch; /* system clock when started */
diff --git a/sbin/routed/input.c b/sbin/routed/input.c
index 8f8eefc..901c4f3 100644
--- a/sbin/routed/input.c
+++ b/sbin/routed/input.c
@@ -289,8 +289,19 @@ input(struct sockaddr_in *from, /* received from this IP address */
* with all we know.
*/
if (from->sin_port != htons(RIP_PORT)) {
- supply(from, aifp, OUT_QUERY, 0,
- rip->rip_vers, ap != 0);
+ /*
+ * insecure: query from non-router node
+ * > 1: allow from distant node
+ * > 0: allow from neighbor node
+ * == 0: deny
+ */
+ if ((aifp != NULL && insecure > 0) ||
+ (aifp == NULL && insecure > 1))
+ supply(from, aifp, OUT_QUERY, 0,
+ rip->rip_vers, ap != 0);
+ else
+ trace_pkt("Warning: "
+ "possible attack detected");
return;
}
diff --git a/sbin/routed/main.c b/sbin/routed/main.c
index 1658d2e..5ebd7ec 100644
--- a/sbin/routed/main.c
+++ b/sbin/routed/main.c
@@ -68,6 +68,7 @@ int ridhosts; /* 1=reduce host routes */
int mhome; /* 1=want multi-homed host route */
int advertise_mhome; /* 1=must continue advertising it */
int auth_ok = 1; /* 1=ignore auth if we do not care */
+int insecure; /* Reply to special queries or not */
struct timeval epoch; /* when started */
struct timeval clk;
@@ -136,8 +137,11 @@ main(int argc,
(void)gethostname(myname, sizeof(myname)-1);
(void)gethost(myname, &myaddr);
- while ((n = getopt(argc, argv, "sqdghmAtvT:F:P:")) != -1) {
+ while ((n = getopt(argc, argv, "isqdghmAtvT:F:P:")) != -1) {
switch (n) {
+ case 'i':
+ insecure++;
+ break;
case 's':
supplier = 1;
supplier_set = 1;
diff --git a/sbin/routed/output.c b/sbin/routed/output.c
index 53eb4a5..c2ed468 100644
--- a/sbin/routed/output.c
+++ b/sbin/routed/output.c
@@ -673,8 +673,6 @@ supply(struct sockaddr_in *dst,
struct rt_entry *rt;
int def_metric;
- assert(ifp != NULL);
-
ws.state = 0;
ws.gen_limit = 1024;
diff --git a/sbin/routed/routed.8 b/sbin/routed/routed.8
index 2f8a021..ca5250b 100644
--- a/sbin/routed/routed.8
+++ b/sbin/routed/routed.8
@@ -30,7 +30,7 @@
.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
-.Dd June 1, 1996
+.Dd August 26, 2014
.Dt ROUTED 8
.Os
.Sh NAME
@@ -39,7 +39,7 @@
.Nd network RIP and router discovery routing daemon
.Sh SYNOPSIS
.Nm
-.Op Fl sqdghmpAtv
+.Op Fl isqdghmpAtv
.Op Fl T Ar tracefile
.Oo
.Fl F
@@ -250,6 +250,20 @@ to infer the netmask used by the remote system when RIPv1 is used.
.Pp
The following options are available:
.Bl -tag -width indent
+.It Fl i
+allow
+.Nm
+to accept a RIP request from non-router node.
+When specified once,
+.Nm
+replies to a route information query from neighbor nodes.
+When specified twice,
+it replies to a query from remote nodes in addition.
+.Xr rtquery 8
+utility can be used to send a request.
+.Pp
+This feature is disabled by default because of a risk of reflection attack
+though it is useful for debugging purpose.
.It Fl s
force
.Nm
diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c
index 0f1d41e..7a5fc4c 100644
--- a/sbin/savecore/savecore.c
+++ b/sbin/savecore/savecore.c
@@ -151,7 +151,10 @@ getbounds(void) {
}
if (fgets(buf, sizeof buf, fp) == NULL) {
- syslog(LOG_WARNING, "unable to read from bounds, using 0");
+ if (feof(fp))
+ syslog(LOG_WARNING, "bounds file is empty, using 0");
+ else
+ syslog(LOG_WARNING, "bounds file: %s", strerror(errno));
fclose(fp);
return (ret);
}
@@ -160,6 +163,7 @@ getbounds(void) {
ret = (int)strtol(buf, NULL, 10);
if (ret == 0 && (errno == EINVAL || errno == ERANGE))
syslog(LOG_WARNING, "invalid value found in bounds, using 0");
+ fclose(fp);
return (ret);
}
diff --git a/sbin/shutdown/Makefile b/sbin/shutdown/Makefile
index a6ecb93..905d1bc 100644
--- a/sbin/shutdown/Makefile
+++ b/sbin/shutdown/Makefile
@@ -8,6 +8,6 @@ MLINKS= shutdown.8 poweroff.8
BINOWN= root
BINGRP= operator
-BINMODE=4550
+BINMODE=4554
.include <bsd.prog.mk>
diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c
index 5c6086d..033c40a 100644
--- a/sbin/swapon/swapon.c
+++ b/sbin/swapon/swapon.c
@@ -172,15 +172,8 @@ main(int argc, char **argv)
continue;
if (strstr(fsp->fs_mntops, "noauto") != NULL)
continue;
- /*
- * Forcibly enable "late" option when file= is
- * specified. This is because mounting file
- * systems with rw option is typically
- * required to make the backing store ready.
- */
if (which_prog != SWAPOFF &&
- (strstr(fsp->fs_mntops, "late") != NULL ||
- strstr(fsp->fs_mntops, "file=") != NULL) &&
+ strstr(fsp->fs_mntops, "late") &&
late == 0)
continue;
swfile = swap_on_off(fsp->fs_spec, 1,
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c
index 1359645..a6ea9f9 100644
--- a/sbin/sysctl/sysctl.c
+++ b/sbin/sysctl/sysctl.c
@@ -48,6 +48,16 @@ static const char rcsid[] =
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
+#ifdef __amd64__
+#include <sys/efi.h>
+#include <machine/metadata.h>
+#endif
+
+#if defined(__amd64__) || defined(__i386__)
+#include <machine/pc/bios.h>
+#endif
+
+#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
@@ -69,9 +79,33 @@ static int parsefile(const char *);
static int parse(const char *, int);
static int show_var(int *, int);
static int sysctl_all(int *oid, int len);
-static int name2oid(char *, int *);
+static int name2oid(const char *, int *);
-static int set_IK(const char *, int *);
+static int strIKtoi(const char *, char **);
+
+static int ctl_sign[CTLTYPE+1] = {
+ [CTLTYPE_INT] = 1,
+ [CTLTYPE_LONG] = 1,
+ [CTLTYPE_S64] = 1,
+};
+
+static int ctl_size[CTLTYPE+1] = {
+ [CTLTYPE_INT] = sizeof(int),
+ [CTLTYPE_UINT] = sizeof(u_int),
+ [CTLTYPE_LONG] = sizeof(long),
+ [CTLTYPE_ULONG] = sizeof(u_long),
+ [CTLTYPE_S64] = sizeof(int64_t),
+ [CTLTYPE_U64] = sizeof(uint64_t),
+};
+
+static const char *ctl_typename[CTLTYPE+1] = {
+ [CTLTYPE_INT] = "integer",
+ [CTLTYPE_UINT] = "unsigned integer",
+ [CTLTYPE_LONG] = "long integer",
+ [CTLTYPE_ULONG] = "unsigned long",
+ [CTLTYPE_S64] = "int64_t",
+ [CTLTYPE_U64] = "uint64_t",
+};
static void
usage(void)
@@ -182,7 +216,8 @@ static int
parse(const char *string, int lineno)
{
int len, i, j;
- void *newval = 0;
+ const void *newval;
+ const char *newvalstr = NULL;
int intval;
unsigned int uintval;
long longval;
@@ -191,7 +226,7 @@ parse(const char *string, int lineno)
int64_t i64val;
uint64_t u64val;
int mib[CTL_MAXNAME];
- char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ], line[BUFSIZ];
+ char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ];
u_int kind;
if (lineno)
@@ -221,7 +256,7 @@ parse(const char *string, int lineno)
cp[strlen(cp) - 1] = '\0';
cp++;
}
- newval = cp;
+ newvalstr = cp;
newsize = strlen(cp);
}
len = name2oid(bufp, mib);
@@ -245,7 +280,7 @@ parse(const char *string, int lineno)
exit(1);
}
- if (newval == NULL || dflag) {
+ if (newvalstr == NULL || dflag) {
if ((kind & CTLTYPE) == CTLTYPE_NODE) {
if (dflag) {
i = show_var(mib, len);
@@ -273,97 +308,77 @@ parse(const char *string, int lineno)
return (1);
}
- if ((kind & CTLTYPE) == CTLTYPE_INT ||
- (kind & CTLTYPE) == CTLTYPE_UINT ||
- (kind & CTLTYPE) == CTLTYPE_LONG ||
- (kind & CTLTYPE) == CTLTYPE_ULONG ||
- (kind & CTLTYPE) == CTLTYPE_S64 ||
- (kind & CTLTYPE) == CTLTYPE_U64) {
- if (strlen(newval) == 0) {
+ switch (kind & CTLTYPE) {
+ case CTLTYPE_INT:
+ case CTLTYPE_UINT:
+ case CTLTYPE_LONG:
+ case CTLTYPE_ULONG:
+ case CTLTYPE_S64:
+ case CTLTYPE_U64:
+ if (strlen(newvalstr) == 0) {
warnx("empty numeric value");
return (1);
}
+ /* FALLTHROUGH */
+ case CTLTYPE_STRING:
+ break;
+ default:
+ warnx("oid '%s' is type %d,"
+ " cannot set that%s", bufp,
+ kind & CTLTYPE, line);
+ return (1);
}
+ errno = 0;
+
switch (kind & CTLTYPE) {
case CTLTYPE_INT:
- if (strcmp(fmt, "IK") == 0) {
- if (!set_IK(newval, &intval)) {
- warnx("invalid value '%s'%s",
- (char *)newval, line);
- return (1);
- }
- } else {
- intval = (int)strtol(newval, &endptr,
+ if (strcmp(fmt, "IK") == 0)
+ intval = strIKtoi(newvalstr, &endptr);
+ else
+ intval = (int)strtol(newvalstr, &endptr,
0);
- if (endptr == newval || *endptr != '\0') {
- warnx("invalid integer '%s'%s",
- (char *)newval, line);
- return (1);
- }
- }
newval = &intval;
newsize = sizeof(intval);
break;
case CTLTYPE_UINT:
- uintval = (int) strtoul(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0') {
- warnx("invalid unsigned integer '%s'%s",
- (char *)newval, line);
- return (1);
- }
+ uintval = (int) strtoul(newvalstr, &endptr, 0);
newval = &uintval;
newsize = sizeof(uintval);
break;
case CTLTYPE_LONG:
- longval = strtol(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0') {
- warnx("invalid long integer '%s'%s",
- (char *)newval, line);
- return (1);
- }
+ longval = strtol(newvalstr, &endptr, 0);
newval = &longval;
newsize = sizeof(longval);
break;
case CTLTYPE_ULONG:
- ulongval = strtoul(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0') {
- warnx("invalid unsigned long integer"
- " '%s'%s", (char *)newval, line);
- return (1);
- }
+ ulongval = strtoul(newvalstr, &endptr, 0);
newval = &ulongval;
newsize = sizeof(ulongval);
break;
case CTLTYPE_STRING:
+ newval = newvalstr;
break;
case CTLTYPE_S64:
- i64val = strtoimax(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0') {
- warnx("invalid int64_t '%s'%s",
- (char *)newval, line);
- return (1);
- }
+ i64val = strtoimax(newvalstr, &endptr, 0);
newval = &i64val;
newsize = sizeof(i64val);
break;
case CTLTYPE_U64:
- u64val = strtoumax(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0') {
- warnx("invalid uint64_t '%s'%s",
- (char *)newval, line);
- return (1);
- }
+ u64val = strtoumax(newvalstr, &endptr, 0);
newval = &u64val;
newsize = sizeof(u64val);
break;
- case CTLTYPE_OPAQUE:
- /* FALLTHROUGH */
default:
- warnx("oid '%s' is type %d,"
- " cannot set that%s", bufp,
- kind & CTLTYPE, line);
- return (1);
+ /* NOTREACHED */
+ abort();
+ }
+
+ if (errno != 0 || endptr == newvalstr ||
+ (endptr != NULL && *endptr != '\0')) {
+ warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE],
+ newvalstr, line);
+ return (1);
}
i = show_var(mib, len);
@@ -454,12 +469,12 @@ parsefile(const char *filename)
/* These functions will dump out various interesting structures. */
static int
-S_clockinfo(int l2, void *p)
+S_clockinfo(size_t l2, void *p)
{
struct clockinfo *ci = (struct clockinfo*)p;
if (l2 != sizeof(*ci)) {
- warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
+ warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
return (1);
}
printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
@@ -469,12 +484,12 @@ S_clockinfo(int l2, void *p)
}
static int
-S_loadavg(int l2, void *p)
+S_loadavg(size_t l2, void *p)
{
struct loadavg *tv = (struct loadavg*)p;
if (l2 != sizeof(*tv)) {
- warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
+ warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
return (1);
}
printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
@@ -485,14 +500,14 @@ S_loadavg(int l2, void *p)
}
static int
-S_timeval(int l2, void *p)
+S_timeval(size_t l2, void *p)
{
struct timeval *tv = (struct timeval*)p;
time_t tv_sec;
char *p1, *p2;
if (l2 != sizeof(*tv)) {
- warnx("S_timeval %d != %zu", l2, sizeof(*tv));
+ warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
return (1);
}
printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
@@ -509,13 +524,13 @@ S_timeval(int l2, void *p)
}
static int
-S_vmtotal(int l2, void *p)
+S_vmtotal(size_t l2, void *p)
{
struct vmtotal *v = (struct vmtotal *)p;
int pageKilo = getpagesize() / 1024;
if (l2 != sizeof(*v)) {
- warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
+ warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
return (1);
}
@@ -536,36 +551,147 @@ S_vmtotal(int l2, void *p)
v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
- printf("Free Memory:\t%dK\n", v->t_free * pageKilo);
+ printf("Free Memory:\t%dK", v->t_free * pageKilo);
return (0);
}
+#ifdef __amd64__
+#define efi_next_descriptor(ptr, size) \
+ ((struct efi_md *)(((uint8_t *) ptr) + size))
+
static int
-set_IK(const char *str, int *val)
+S_efi_map(size_t l2, void *p)
{
+ struct efi_map_header *efihdr;
+ struct efi_md *map;
+ const char *type;
+ size_t efisz;
+ int ndesc, i;
+
+ static const char *types[] = {
+ "Reserved",
+ "LoaderCode",
+ "LoaderData",
+ "BootServicesCode",
+ "BootServicesData",
+ "RuntimeServicesCode",
+ "RuntimeServicesData",
+ "ConventionalMemory",
+ "UnusableMemory",
+ "ACPIReclaimMemory",
+ "ACPIMemoryNVS",
+ "MemoryMappedIO",
+ "MemoryMappedIOPortSpace",
+ "PalCode"
+ };
+
+ /*
+ * Memory map data provided by UEFI via the GetMemoryMap
+ * Boot Services API.
+ */
+ if (l2 < sizeof(*efihdr)) {
+ warnx("S_efi_map length less than header");
+ return (1);
+ }
+ efihdr = p;
+ efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
+ map = (struct efi_md *)((uint8_t *)efihdr + efisz);
+
+ if (efihdr->descriptor_size == 0)
+ return (0);
+ if (l2 != efisz + efihdr->memory_size) {
+ warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
+ efihdr->memory_size);
+ return (1);
+ }
+ ndesc = efihdr->memory_size / efihdr->descriptor_size;
+
+ printf("\n%23s %12s %12s %8s %4s",
+ "Type", "Physical", "Virtual", "#Pages", "Attr");
+
+ for (i = 0; i < ndesc; i++,
+ map = efi_next_descriptor(map, efihdr->descriptor_size)) {
+ if (map->md_type <= EFI_MD_TYPE_PALCODE)
+ type = types[map->md_type];
+ else
+ type = "<INVALID>";
+ printf("\n%23s %012lx %12p %08lx ", type, map->md_phys,
+ map->md_virt, map->md_pages);
+ if (map->md_attr & EFI_MD_ATTR_UC)
+ printf("UC ");
+ if (map->md_attr & EFI_MD_ATTR_WC)
+ printf("WC ");
+ if (map->md_attr & EFI_MD_ATTR_WT)
+ printf("WT ");
+ if (map->md_attr & EFI_MD_ATTR_WB)
+ printf("WB ");
+ if (map->md_attr & EFI_MD_ATTR_UCE)
+ printf("UCE ");
+ if (map->md_attr & EFI_MD_ATTR_WP)
+ printf("WP ");
+ if (map->md_attr & EFI_MD_ATTR_RP)
+ printf("RP ");
+ if (map->md_attr & EFI_MD_ATTR_XP)
+ printf("XP ");
+ if (map->md_attr & EFI_MD_ATTR_RT)
+ printf("RUNTIME");
+ }
+ return (0);
+}
+#endif
+
+#if defined(__amd64__) || defined(__i386__)
+static int
+S_bios_smap_xattr(size_t l2, void *p)
+{
+ struct bios_smap_xattr *smap, *end;
+
+ if (l2 % sizeof(*smap) != 0) {
+ warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
+ sizeof(*smap));
+ return (1);
+ }
+
+ end = (struct bios_smap_xattr *)((char *)p + l2);
+ for (smap = p; smap < end; smap++)
+ printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
+ smap->type, smap->xattr, (uintmax_t)smap->base,
+ (uintmax_t)smap->length);
+ return (0);
+}
+#endif
+
+static int
+strIKtoi(const char *str, char **endptrp)
+{
+ int kelv;
float temp;
- int len, kelv;
+ size_t len;
const char *p;
- char *endptr;
- if ((len = strlen(str)) == 0)
- return (0);
+ assert(errno == 0);
+
+ len = strlen(str);
+ /* caller already checked this */
+ assert(len > 0);
+
p = &str[len - 1];
if (*p == 'C' || *p == 'F') {
- temp = strtof(str, &endptr);
- if (endptr == str || endptr != p)
- return (0);
- if (*p == 'F')
- temp = (temp - 32) * 5 / 9;
- kelv = temp * 10 + 2732;
+ temp = strtof(str, endptrp);
+ if (*endptrp != str && *endptrp == p && errno != 0) {
+ if (*p == 'F')
+ temp = (temp - 32) * 5 / 9;
+ return (temp * 10 + 2732);
+ }
} else {
- kelv = (int)strtol(str, &endptr, 10);
- if (endptr == str || *endptr != '\0')
- return (0);
+ kelv = (int)strtol(str, endptrp, 10);
+ if (*endptrp != str && *endptrp == p && errno != 0)
+ return (kelv);
}
- *val = kelv;
- return (1);
+
+ errno = ERANGE;
+ return (0);
}
/*
@@ -578,7 +704,7 @@ set_IK(const char *str, int *val)
*/
static int
-name2oid(char *name, int *oidp)
+name2oid(const char *name, int *oidp)
{
int oid[2];
int i;
@@ -620,21 +746,6 @@ oidfmt(int *oid, int len, char *fmt, u_int *kind)
return (0);
}
-static int ctl_sign[CTLTYPE+1] = {
- [CTLTYPE_INT] = 1,
- [CTLTYPE_LONG] = 1,
- [CTLTYPE_S64] = 1,
-};
-
-static int ctl_size[CTLTYPE+1] = {
- [CTLTYPE_INT] = sizeof(int),
- [CTLTYPE_UINT] = sizeof(u_int),
- [CTLTYPE_LONG] = sizeof(long),
- [CTLTYPE_ULONG] = sizeof(u_long),
- [CTLTYPE_S64] = sizeof(int64_t),
- [CTLTYPE_U64] = sizeof(int64_t),
-};
-
/*
* This formats and outputs the value of one variable
*
@@ -655,7 +766,7 @@ show_var(int *oid, int nlen)
size_t intlen;
size_t j, len;
u_int kind;
- int (*func)(int, void *);
+ int (*func)(size_t, void *);
/* Silence GCC. */
umv = mv = intlen = 0;
@@ -793,6 +904,14 @@ show_var(int *oid, int nlen)
func = S_loadavg;
else if (strcmp(fmt, "S,vmtotal") == 0)
func = S_vmtotal;
+#ifdef __amd64__
+ else if (strcmp(fmt, "S,efi_map_header") == 0)
+ func = S_efi_map;
+#endif
+#if defined(__amd64__) || defined(__i386__)
+ else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
+ func = S_bios_smap_xattr;
+#endif
else
func = NULL;
if (func) {
diff --git a/sbin/umount/umount.c b/sbin/umount/umount.c
index f2e02f2..521bbc8 100644
--- a/sbin/umount/umount.c
+++ b/sbin/umount/umount.c
@@ -394,7 +394,7 @@ umountfs(struct statfs *sfs)
* has been unmounted.
*/
if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
- clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp");
+ clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS3, "udp");
if (clp == NULL) {
warnx("%s: %s", hostp,
clnt_spcreateerror("MOUNTPROG"));
OpenPOWER on IntegriCloud