tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Review of pfs(8)
Hi,
I would like to integrate pfs(8) into the main tree. pfs is a tool similar as
ipfs(8) but for the pf(4) filtering solution, aka it lets the administrator
dumps the current internal state table of pf, reboot for maintenance, and loads
the saved table into pf, in a tranparent way for users.
I attach the current version of the code in attachment. If there are no comment,
I will push it to main tree next week.
Best regards,
--
Arnaud Degroote
degroote%NetBSD.org@localhost
? usr.sbin/pf/pfs/.gdbinit
? usr.sbin/pf/pfs/.new.pfs.c
? sys/dist/pf/net/.pf_ioctl.c.swp
Index: distrib/sets/lists/base/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/mi,v
retrieving revision 1.860
diff -u -r1.860 mi
--- distrib/sets/lists/base/mi 8 Mar 2010 06:40:06 -0000 1.860
+++ distrib/sets/lists/base/mi 6 Apr 2010 14:12:23 -0000
@@ -271,6 +271,7 @@
./sbin/nologin base-sysutil-root
./sbin/pfctl base-pf-root pf
./sbin/pflogd base-pf-root pf
+./sbin/pfs base-pf-root
pf
./sbin/ping base-netutil-root
./sbin/ping6 base-netutil-root
use_inet6
./sbin/poweroff base-sysutil-root
Index: distrib/sets/lists/man/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.1198
diff -u -r1.1198 mi
--- distrib/sets/lists/man/mi 11 Mar 2010 10:38:36 -0000 1.1198
+++ distrib/sets/lists/man/mi 6 Apr 2010 14:12:29 -0000
@@ -2442,6 +2442,7 @@
./usr/share/man/cat8/peace.0 man-sys-catman .cat
./usr/share/man/cat8/pfctl.0 man-pf-catman pf,.cat
./usr/share/man/cat8/pflogd.0 man-pf-catman pf,.cat
+./usr/share/man/cat8/pfs.0 man-pf-catman
pf,.cat
./usr/share/man/cat8/pfspamd-setup.0 man-obsolete obsolete
./usr/share/man/cat8/pfspamd.0 man-obsolete obsolete
./usr/share/man/cat8/pfspamdb.0 man-obsolete
obsolete
@@ -4865,6 +4866,7 @@
./usr/share/man/html8/peace.html man-sys-htmlman html
./usr/share/man/html8/pfctl.html man-pf-htmlman pf,html
./usr/share/man/html8/pflogd.html man-pf-htmlman pf,html
+./usr/share/man/html8/pfs.html man-pf-htmlman pf,html
./usr/share/man/html8/pickup.html man-postfix-htmlman
postfix,html
./usr/share/man/html8/ping.html man-netutil-htmlman
html
./usr/share/man/html8/ping6.html man-netutil-htmlman
use_inet6,html
@@ -7522,6 +7524,7 @@
./usr/share/man/man8/peace.8 man-sys-man .man
./usr/share/man/man8/pfctl.8 man-pf-man pf,.man
./usr/share/man/man8/pflogd.8 man-pf-man pf,.man
+./usr/share/man/man8/pfs.8 man-pf-man
pf,.man
./usr/share/man/man8/pfspamd-setup.8 man-obsolete obsolete
./usr/share/man/man8/pfspamd.8 man-obsolete obsolete
./usr/share/man/man8/pfspamdb.8 man-obsolete
obsolete
Index: usr.sbin/pf/Makefile
===================================================================
RCS file: /cvsroot/src/usr.sbin/pf/Makefile,v
retrieving revision 1.8
diff -u -r1.8 Makefile
--- usr.sbin/pf/Makefile 18 Jun 2008 09:06:28 -0000 1.8
+++ usr.sbin/pf/Makefile 6 Apr 2010 14:12:31 -0000
@@ -6,6 +6,7 @@
SUBDIR+= ftp-proxy
SUBDIR+= pfctl
SUBDIR+= pflogd
+SUBDIR+= pfs
SUBDIR+= tftp-proxy
SUBDIR+= man
Index: usr.sbin/pf/pfs/Makefile
===================================================================
RCS file: usr.sbin/pf/pfs/Makefile
diff -N usr.sbin/pf/pfs/Makefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.sbin/pf/pfs/Makefile 6 Apr 2010 14:12:31 -0000
@@ -0,0 +1,18 @@
+
+SRCS= pfs.c token.l parse.y
+PROG= pfs
+CPPFLAGS+=-I${NETBSDSRCDIR}/sys/dist/pf
+CPPFLAGS+=-I${.CURDIR}
+WARNS= 4
+
+YHEADER=parse.h
+
+LDADD+= -ll -ly
+DPADD+= ${LIBL} ${LIBY}
+
+BINDIR=/sbin
+
+MAN= pfs.8
+
+
+.include <bsd.prog.mk>
Index: usr.sbin/pf/pfs/parse.y
===================================================================
RCS file: usr.sbin/pf/pfs/parse.y
diff -N usr.sbin/pf/pfs/parse.y
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.sbin/pf/pfs/parse.y 6 Apr 2010 14:12:31 -0000
@@ -0,0 +1,471 @@
+
+%{
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/tcp_fsm.h>
+
+#include "parser.h"
+
+// XXX it is really correct ?
+extern const char * const tcpstates[];
+
+
+struct pfsync_state global_state;
+struct pfsync_state_peer *src_peer, *dst_peer;
+struct pfsync_state_peer current_peer;
+
+static void parse_init(void);
+static void add_state(void);
+static bool get_pfsync_host(const char*, struct pfsync_state_host*,
sa_family_t*);
+static uint8_t retrieve_peer_state(const char*, int);
+static bool retrieve_seq(const char*, struct pfsync_state_peer*);
+static bool strtou32(const char*, uint32_t*);
+
+%}
+
+%union {
+ uintmax_t num;
+ char* str;
+}
+
+%token STATE
+%token IN OUT
+%token ON PROTO
+%token FROM TO USING
+%token ID CID EXPIRE TIMEOUT
+%token SRC DST
+%token SEQ MAX_WIN WSCALE MSS
+%token NOSCRUB SCRUB FLAGS TTL MODE
+%token NUMBER STRING
+
+%type <str> STRING
+%type <num> NUMBER
+%%
+
+states
+ : /* NOTHING */
+ | state states { parse_init(); }
+ ;
+
+state
+ : STATE direction iface proto addrs id cid expire timeout src_peer
dst_peer {
+ add_state();
+ }
+ ;
+
+direction
+ : IN {
+ global_state.direction = PF_IN;
+ src_peer = &global_state.dst;
+ dst_peer = &global_state.src;
+ }
+ | OUT {
+ global_state.direction = PF_OUT;
+ src_peer = &global_state.src;
+ dst_peer = &global_state.dst;
+ }
+ ;
+
+iface
+ : ON STRING {
+ strlcpy(global_state.ifname, $2,
sizeof(global_state.ifname));
+ free($2);
+ }
+ ;
+
+proto
+ : PROTO STRING {
+ struct protoent *p;
+ p = getprotobyname($2);
+ if (p == NULL)
+ yyfatal("Invalid protocol name");
+ global_state.proto = p->p_proto;
+ free($2);
+ }
+ | PROTO NUMBER {
+ // check that the number may be valid proto ?
+ global_state.proto = $2;
+ }
+ ;
+
+addrs
+ : FROM STRING TO STRING {
+ get_pfsync_host($2, &global_state.lan, &global_state.af);
+ get_pfsync_host($4, &global_state.ext, &global_state.af);
+ memcpy(&global_state.gwy, &global_state.lan, sizeof(struct
pfsync_state_host));
+ free($2);
+ free($4);
+ }
+ | FROM STRING TO STRING USING STRING {
+ get_pfsync_host($2, &global_state.lan, &global_state.af);
+ get_pfsync_host($4, &global_state.ext, &global_state.af);
+ get_pfsync_host($6, &global_state.gwy, &global_state.af);
+ free($2);
+ free($4);
+ free($6);
+ }
+ ;
+
+id
+ : ID NUMBER {
+ if ( $2 > UINT64_MAX)
+ yyfatal("id is too big");
+ uint64_t value = (uint64_t)$2;
+ memcpy(global_state.id, &value,
sizeof(global_state.id));
+ }
+ ;
+
+cid
+ : CID NUMBER {
+ if ( $2 > UINT32_MAX)
+ yyfatal("creator id is too big");
+ global_state.creatorid = (uint32_t)$2;
+ }
+ ;
+
+expire
+ : EXPIRE NUMBER {
+ if ( $2 > UINT32_MAX)
+ yyfatal("expire time is too big");
+ global_state.expire = (uint32_t) $2;
+ }
+ ;
+
+timeout
+ : TIMEOUT NUMBER {
+ if ($2 > UINT8_MAX)
+ yyfatal("timeout time is too big");
+ global_state.timeout = (uint8_t) $2;
+ }
+ ;
+
+src_peer
+ : SRC peer {
+ memcpy(src_peer, ¤t_peer, sizeof(current_peer));
+ }
+ ;
+
+dst_peer
+ : DST peer {
+ memcpy(dst_peer, ¤t_peer, sizeof(current_peer));
+ }
+ ;
+
+peer
+ : peer_state scrub
+ | peer_state tcp_options scrub
+ ;
+
+peer_state
+ : STATE STRING {
+ current_peer.state = retrieve_peer_state($2,
global_state.proto);
+ free($2);
+ }
+ | STATE NUMBER {
+ if ( $2 > UINT8_MAX)
+ yyfatal("peer state is too big");
+ current_peer.state = $2;
+ }
+ ;
+
+tcp_options
+ : SEQ seqs MAX_WIN NUMBER WSCALE NUMBER {
+ if ($4 > UINT16_MAX)
+ yyfatal("max_win is too big");
+ current_peer.max_win = $4;
+
+ if ($6 > UINT8_MAX)
+ yyfatal("wscale is too big");
+ current_peer.wscale = $6;
+ }
+ | SEQ seqs MAX_WIN NUMBER WSCALE NUMBER MSS NUMBER {
+ if ($4 > UINT16_MAX)
+ yyfatal("max_win is too big");
+ current_peer.max_win = $4;
+
+ if ($6 > UINT8_MAX)
+ yyfatal("wscale is too big");
+ current_peer.wscale = $6;
+
+ if ($8 > UINT16_MAX)
+ yyfatal("mss is too big");
+ current_peer.mss = $8;
+ }
+ ;
+
+seqs
+ : STRING {
+ if (!retrieve_seq($1, ¤t_peer))
+ yyfatal("invalid seq number");
+
+ free($1);
+ }
+ ;
+
+scrub
+ : NOSCRUB { current_peer.scrub.scrub_flag= 0;}
+ | SCRUB FLAGS NUMBER MODE NUMBER TTL NUMBER {
+ current_peer.scrub.scrub_flag= PFSYNC_SCRUB_FLAG_VALID;
+ if ($3 > UINT16_MAX)
+ yyfatal("scrub flags is too big");
+ current_peer.scrub.pfss_flags = $3;
+
+ if ($5 > UINT32_MAX)
+ yyfatal("scrub mode is too big");
+ current_peer.scrub.pfss_ts_mod = $5;
+
+ if ($7 > UINT8_MAX)
+ yyfatal("scrub ttl is too big");
+ current_peer.scrub.pfss_ttl = $7;
+ }
+ ;
+
+
+%%
+
+static void
+parse_init(void)
+{
+ memset(&global_state, 0, sizeof(global_state));
+ memset(¤t_peer, 0, sizeof(current_peer));
+ src_peer = NULL;
+ dst_peer = NULL;
+}
+
+static bool
+get_pfsync_host(const char* str, struct pfsync_state_host* host, sa_family_t*
af)
+{
+ size_t count_colon, addr_len, port_len;
+ const char* p, *last_colon, *first_bracket, *last_bracket;
+ char buf[48];
+ char buf_port[6];
+
+ if (str == NULL || *str == '\0')
+ return false;
+
+ p = str;
+ last_colon = NULL;
+ count_colon = 0;
+
+ while (*p != '\0') {
+ if (*p == ':') {
+ count_colon++;
+ last_colon = p;
+ }
+ p++;
+ }
+
+ /*
+ * If no colon, it is not an expected addr
+ * If there are more than one colon, we guess that af = AF_INET6
+ */
+
+ if (count_colon == 0)
+ return false;
+
+ if (count_colon == 1)
+ *af = AF_INET;
+ else
+ *af = AF_INET6;
+
+ /*
+ * First bracket must be next character after last colon
+ * Last bracket must be the last character
+ * distance between both must be <= 7
+ */
+
+ if (*(last_colon+1) == '[')
+ first_bracket = last_colon + 1;
+ else
+ return false;
+
+ last_bracket = str + (strlen(str) - 1);
+ if (*last_bracket != ']')
+ return false;
+
+ port_len = last_bracket - first_bracket;
+ if (last_bracket - first_bracket > 7)
+ return false;
+
+ memcpy(buf_port, first_bracket +1, port_len - 1);
+ buf_port[port_len-1]= '\0';
+
+ addr_len = last_colon - str;
+ if (addr_len > sizeof(buf))
+ return false;
+ memcpy(buf, str, addr_len);
+ buf[addr_len] = '\0';
+
+ if (inet_pton(*af, buf, &host->addr) != 1)
+ return false;
+
+ host->port = htons(atoi(buf_port));
+
+ return true;
+}
+
+static uint8_t
+retrieve_peer_state(const char* str, int proto)
+{
+ uint8_t i;
+
+ if (proto == IPPROTO_TCP) {
+ i = 0;
+ while (i < TCP_NSTATES) {
+ if (strcmp(str, tcpstates[i]) == 0)
+ return i;
+ i++;
+ }
+ yyfatal("Invalid peer state");
+
+ } else {
+ if (proto == IPPROTO_UDP) {
+ const char* mystates[] = PFUDPS_NAMES;
+ i = 0;
+
+ while (i < PFUDPS_NSTATES) {
+ if (strcmp(str, mystates[i]) == 0)
+ return i;
+ i++;
+ }
+
+ yyfatal("Invalid peer state");
+ } else {
+ const char *mystates[] = PFOTHERS_NAMES;
+ i = 0;
+
+ while (i < PFOTHERS_NSTATES) {
+ if (strcmp(str, mystates[i]) == 0)
+ return i;
+ i++;
+ }
+
+ yyfatal("Invalid peer state");
+ }
+ }
+ /*NOTREACHED*/
+ return 0;
+}
+
+static bool
+strtou32(const char* str, uint32_t* res)
+{
+ uintmax_t u;
+ errno = 0;
+ u = strtoumax(str, NULL, 10);
+ if (errno == ERANGE && u == UINTMAX_MAX)
+ return false;
+ if (u > UINT32_MAX)
+ return false;
+ *res = (uint32_t) u;
+ return true;
+}
+
+static bool
+retrieve_seq(const char* str, struct pfsync_state_peer* peer)
+{
+ const char* p, *p_colon, *p_comma;
+ char buf[100];
+ size_t size;
+
+ if (str == NULL || *str == '\0')
+ return false;
+
+ if (*str != '[' || *(str+(strlen(str) -1)) != ']')
+ return false;
+
+ p = str;
+ p_colon = NULL;
+ p_comma = NULL;
+ while (*p != '\0') {
+ if (*p == ':') {
+ if (p_colon !=NULL)
+ return false;
+ else
+ p_colon = p;
+ }
+
+ if (*p == ',') {
+ if (p_comma != NULL)
+ return false;
+ else
+ p_comma = p;
+ }
+ p++;
+ }
+
+ size = p_colon - str;
+ memcpy(buf, str+1, size-1);
+ buf[size-1] = '\0';
+
+ if (!strtou32(buf, &peer->seqlo))
+ return false;
+
+
+ if (p_comma == NULL)
+ size = str + strlen(str) - 1 - p_colon;
+ else
+ size = p_comma - p_colon;
+
+ memcpy(buf, p_colon+1, size -1);
+ buf[size-1] = '\0';
+
+ if (!strtou32(buf, &peer->seqhi))
+ return false;
+
+ if (p_comma == NULL) {
+ peer->seqdiff = 0;
+ } else {
+ size = str + strlen(str) - 1 - p_comma;
+ memcpy(buf, p_comma +1, size -1);
+ buf[size-1] = '\0';
+
+ if (!strtou32(buf, &peer->seqdiff))
+ return false;
+ }
+
+ return true;
+}
+
+static void
+add_state(void)
+{
+ int idx;
+
+ if (allocated == 0) {
+ allocated = 5;
+ states->ps_buf = malloc(allocated * sizeof(struct
pfsync_state));
+ if (states->ps_buf == NULL)
+ yyfatal("Not enougth memory");
+ }
+
+ if (allocated == (states->ps_len / sizeof(struct pfsync_state))) {
+ void *buf;
+ allocated = allocated * 2 + 1;
+ buf = realloc(states->ps_buf, allocated * sizeof(struct
pfsync_state));
+ if (buf == NULL) {
+ free(states->ps_buf);
+ yyfatal("Not enougth memory");
+ }
+ states->ps_buf = buf;
+ }
+
+ idx = states->ps_len / sizeof(struct pfsync_state);
+ memcpy(&states->ps_states[idx], &global_state, sizeof(struct
pfsync_state));
+ states->ps_len += sizeof(struct pfsync_state);
+}
+
+
+
Index: usr.sbin/pf/pfs/parser.h
===================================================================
RCS file: usr.sbin/pf/pfs/parser.h
diff -N usr.sbin/pf/pfs/parser.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.sbin/pf/pfs/parser.h 6 Apr 2010 14:12:31 -0000
@@ -0,0 +1,16 @@
+
+#ifndef _PARSER_H_
+#define _PARSER_H_
+
+int yylex(void);
+void yyerror(const char*);
+void yyfatal(const char*);
+int parse(FILE*, struct pfioc_states*);
+int yyparse(void);
+
+int lineno;
+
+struct pfioc_states* states;
+size_t allocated;
+
+#endif /* _PARSER_H_*/
Index: usr.sbin/pf/pfs/pfs.8
===================================================================
RCS file: usr.sbin/pf/pfs/pfs.8
diff -N usr.sbin/pf/pfs/pfs.8
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.sbin/pf/pfs/pfs.8 6 Apr 2010 14:12:31 -0000
@@ -0,0 +1,75 @@
+.Dd July 21, 2009
+.Dt PFS 8
+.Os
+.Sh NAME
+.Nm pfs
+.Nd saves and restores information for NAT and state tables.
+.Sh SYNOPSIS
+.Nm
+.Op Fl v
+.Fl l
+.Nm
+.Op Fl v
+.Fl u
+.Nm
+.Op Fl v
+.Op Fl b
+.Fl w
+.Ar filename
+.Nm
+.Op Fl v
+.Op Fl b
+.Fl r
+.Ar filename
+.Nm
+.Op Fl v
+.Op Fl b
+.Fl R
+.Ar filename
+.Nm
+.Op Fl v
+.Op Fl b
+.Fl W
+.Ar filename
+.Sh DESCRIPTION
+The
+.Nm
+command allows state information created for NAT entries and rules using
+.Pa keep state
+to be locked (modification prevented) and then saved to disk,
+allowing for the system to experience a reboot, followed by the restoration
+of that information, resulting in connections not being interrupted.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl b
+The information are read or stored using binary format. The default format is
+a readable ascii format, similar to
+.Pa pfctl.conf
+syntax.
+.It Fl v
+Provides a verbose description of what's being done.
+.It Fl u
+Unlock state tables in the kernel.
+.It Fl l
+Lock state tables in the kernel.
+.It Fl r
+Read information in from the specified file and load it into the
+kernel. This requires the state tables to have already been locked
+and does not change the lock once complete.
+.It Fl w
+Write information out to the specified file and from the kernel.
+This requires the state tables to have already been locked
+and does not change the lock once complete.
+.It Fl R
+Restores information in from the specified file and load it into the
+kernel. The state tables are locked at the beginning of this operation and
+unlocked once complete.
+.It Fl W
+Write information out to the specified file and from the kernel. The state
+tables are locked at the beginning of this operation and unlocked once
+complete.
+.El
+.Sh FILES
+/dev/pf
+.Sh SEE ALSO
+.Xr pf 4
Index: usr.sbin/pf/pfs/pfs.c
===================================================================
RCS file: usr.sbin/pf/pfs/pfs.c
diff -N usr.sbin/pf/pfs/pfs.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.sbin/pf/pfs/pfs.c 6 Apr 2010 14:12:31 -0000
@@ -0,0 +1,541 @@
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "parser.h"
+
+__dead static void usage(void);
+static int setlock(int, int, int);
+static int get_states(int, int, struct pfioc_states*);
+static int dump_states_binary(int, int, const char*);
+static int restore_states_binary(int, int, const char*);
+static int dump_states_ascii(int, int, const char*);
+static int restore_states_ascii(int, int, const char*);
+static char* print_host(const struct pfsync_state_host *h, sa_family_t, char*,
size_t);
+static void print_peer(const struct pfsync_state_peer *peer, uint8_t, FILE*);
+static int print_states(int, int, FILE*);
+static void display_states(const struct pfioc_states*, int, FILE*);
+static int test_ascii_dump(int, const char*, const char*);
+
+static char pf_device[] = "/dev/pf";
+
+__dead static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage : %s [-v] [-u | -l | -w <filename> | -r
<filename> |\n"
+ " [ -W <filename> | -R <filename>
]\n",
+ getprogname());
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * The state table must be locked before calling this function
+ * Return the number of state in case of success, -1 in case of failure
+ * ps::ps_buf must be freed by user after use (in case of success)
+ */
+static int
+get_states(int fd, int verbose __unused, struct pfioc_states* ps)
+{
+ memset(ps, 0, sizeof(*ps));
+ ps->ps_len = 0;
+ char* inbuf;
+
+ // ask the kernel how much memory we need to allocate
+ if (ioctl(fd, DIOCGETSTATES, ps) == -1) {
+ err(EXIT_FAILURE, "DIOCGETSTATES");
+ }
+
+ /* no state */
+ if (ps->ps_len == 0)
+ return 0;
+
+ inbuf = malloc(ps->ps_len);
+ if (inbuf == NULL)
+ err(EXIT_FAILURE, NULL);
+
+ ps->ps_buf = inbuf;
+
+ // really retrieve the different states
+ if (ioctl(fd, DIOCGETSTATES, ps) == -1) {
+ free(ps->ps_buf);
+ err(EXIT_FAILURE, "DIOCGETSTATES");
+ }
+
+ return (ps->ps_len / sizeof(struct pfsync_state));
+}
+
+static int
+dump_states_binary(int fd, int verbose, const char* filename)
+{
+ int wfd;
+ struct pfioc_states ps;
+ struct pfsync_state *p = NULL;
+ int nb_states;
+ int i;
+ int error = 0;
+ int errno_saved = 0;
+
+ wfd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600);
+ if (wfd == -1)
+ err(EXIT_FAILURE, "Cannot open %s", filename);
+
+ nb_states = get_states(fd, verbose, &ps);
+ if (nb_states <= 0) {
+ close(wfd);
+ return nb_states;
+ }
+
+ /*
+ * In the file, write the number of states, then store the different
states
+ * When we will switch to text format, we probably don't care any more
about the len
+ */
+ if (write(wfd, &nb_states, sizeof(nb_states)) != sizeof(nb_states)) {
+ error = EXIT_FAILURE;
+ errno_saved = errno;
+ goto done;
+ }
+
+ p = ps.ps_states;
+ for (i = 0; i < nb_states; i++) {
+ if (write(wfd, &p[i], sizeof(*p)) != sizeof(*p)) {
+ error = EXIT_FAILURE;
+ errno_saved = errno;
+ goto done;
+ }
+ }
+
+done:
+ free(p);
+ close(wfd);
+ // close can't modify errno
+ if (error) {
+ errno = errno_saved;
+ err(error, NULL);
+ }
+
+ return 0;
+}
+
+static int
+restore_states_binary(int fd, int verbose __unused, const char* filename)
+{
+ int rfd;
+ struct pfioc_states ps;
+ struct pfsync_state *p;
+ int nb_states;
+ int errno_saved = 0;
+ int i;
+
+ rfd = open(filename, O_RDONLY, 0600);
+ if (rfd == -1)
+ err(EXIT_FAILURE, "Cannot open %s", filename);
+
+ if (read(rfd, &nb_states, sizeof(nb_states)) != sizeof(nb_states)) {
+ errno_saved = errno;
+ close(rfd);
+ errno = errno_saved;
+ err(EXIT_FAILURE, NULL);
+ }
+
+ ps.ps_len = nb_states * sizeof(struct pfsync_state);
+ ps.ps_states = malloc(ps.ps_len);
+ if (ps.ps_states == NULL) {
+ errno_saved = errno;
+ close(rfd);
+ errno = errno_saved;
+ err(EXIT_FAILURE, NULL);
+ }
+
+ p = ps.ps_states;
+
+ for (i = 0; i < nb_states; i++) {
+ if (read(rfd, &p[i], sizeof(*p)) != sizeof(*p)) {
+ errno_saved = errno;
+ close(rfd);
+ free(ps.ps_states);
+ errno = errno_saved;
+ err(EXIT_FAILURE, NULL);
+ }
+ }
+
+ if (ioctl(fd, DIOCADDSTATES, &ps) == -1) {
+ errno_saved = errno;
+ close(rfd);
+ free(ps.ps_states);
+ errno = errno_saved;
+ err(EXIT_FAILURE, "DIOCADDSTATES");
+ }
+
+ free(ps.ps_states);
+ close(rfd);
+ return 0;
+}
+
+static char*
+print_host(const struct pfsync_state_host *h, sa_family_t af, char* buf,
+ size_t size_buf)
+{
+ uint16_t port;
+ char buf_addr[48];
+
+ port = ntohs(h->port);
+ if (inet_ntop(af, &(h->addr) , buf_addr, sizeof(buf_addr)) == NULL) {
+ strcpy(buf_addr, "?");
+ }
+
+ snprintf(buf, size_buf, "%s:[%d]", buf_addr, port);
+ return buf;
+}
+
+static void
+print_peer(const struct pfsync_state_peer* peer, uint8_t proto, FILE* f)
+{
+ if (proto == IPPROTO_TCP) {
+ if (peer->state < TCP_NSTATES)
+ fprintf(f, "state %s", tcpstates[peer->state]);
+
+ if (peer->seqdiff != 0)
+ fprintf(f, " seq [%" PRIu32 ":%" PRIu32 ",%" PRIu32"]",
+ peer->seqlo, peer->seqhi,
peer->seqdiff);
+ else
+ fprintf(f, " seq [%" PRIu32 ":%" PRIu32 "]",
+ peer->seqlo, peer->seqhi);
+
+ if (peer->mss != 0)
+ fprintf(f, " max_win %" PRIu16 " mss %" PRIu16 " wscale
%" PRIu8,
+ peer->max_win, peer->mss, peer->wscale);
+ else
+ fprintf(f, " max_win %" PRIu16 " wscale %" PRIu8,
peer->max_win,
+ peer->wscale);
+
+ } else {
+ if (proto == IPPROTO_UDP) {
+ const char *mystates[] = PFUDPS_NAMES;
+ if (peer->state < PFUDPS_NSTATES)
+ fprintf(f, "state %s", mystates[peer->state]);
+ } else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
+ fprintf(f, " state %" PRIu8, peer->state);
+ } else {
+ const char *mystates[] = PFOTHERS_NAMES;
+ if (peer->state < PFOTHERS_NSTATES)
+ fprintf(f, " state %s", mystates[peer->state]);
+ }
+ }
+
+ if (peer->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID) {
+ fprintf(f, " scrub flags %" PRIu16 "ttl %" PRIu8 "mod %"PRIu32,
+ peer->scrub.pfss_flags, peer->scrub.pfss_ttl,
peer->scrub.pfss_ts_mod);
+ } else {
+ fprintf(f, " no-scrub");
+ }
+}
+
+static void
+display_states(const struct pfioc_states *ps, int verbose __unused, FILE* f)
+{
+ struct pfsync_state *p = NULL;
+ struct pfsync_state_peer *src, *dst;
+ struct protoent *proto;
+ int nb_states;
+ int i;
+ uint64_t id;
+
+ p = ps->ps_states;
+ nb_states = ps->ps_len / sizeof(struct pfsync_state);
+
+ for (i = 0; i < nb_states; i++, p++) {
+ fprintf(f, "state %s ", p->direction == PF_OUT ? "out" : "in");
+ fprintf(f, "on %s ", p->ifname);
+
+ if ((proto = getprotobynumber(p->proto)) != NULL)
+ fprintf(f, "proto %s ", proto->p_name);
+ else
+ fprintf(f, "proto %u ", p->proto);
+
+
+ if (PF_ANEQ(&p->lan.addr, &p->gwy.addr, p->af) ||
+ (p->lan.port != p->gwy.port)) {
+
+ char buf1[64], buf2[64], buf3[64];
+ fprintf(f, "from %s to %s using %s",
+ print_host(&p->lan, p->af, buf1,
sizeof(buf1)),
+ print_host(&p->ext, p->af, buf2,
sizeof(buf2)),
+ print_host(&p->gwy, p->af, buf3,
sizeof(buf3)));
+ } else {
+ char buf1[64], buf2[64];
+ fprintf(f, "from %s to %s",
+ print_host(&p->lan, p->af, buf1,
sizeof(buf1)),
+ print_host(&p->ext, p->af, buf2,
sizeof(buf2)));
+ }
+
+ memcpy(&id, p->id, sizeof(p->id));
+ fprintf(f, " id %" PRIu64 " cid %" PRIu32 " expire %" PRIu32 "
timeout %" PRIu8,
+ id , p->creatorid, p->expire, p->timeout);
+
+ if (p->direction == PF_OUT) {
+ src = &p->src;
+ dst = &p->dst;
+ } else {
+ src = &p->dst;
+ dst = &p->src;
+ }
+
+ fprintf(f, " src ");
+ print_peer(src, p->proto, f);
+ fprintf(f, " dst ");
+ print_peer(dst, p->proto, f);
+
+ fprintf(f, "\n");
+ }
+}
+
+static int
+print_states(int fd, int verbose, FILE* f)
+{
+ struct pfioc_states ps;
+ int nb_states;
+
+ nb_states = get_states(fd, verbose, &ps);
+ if (nb_states <= 0) {
+ return nb_states;
+ }
+
+ display_states(&ps, verbose, f);
+
+ free(ps.ps_states);
+ return 0;
+}
+
+static int
+dump_states_ascii(int fd, int verbose, const char* filename)
+{
+ FILE *f;
+
+ if (strcmp(filename, "-") == 0) {
+ f = stdout;
+ } else {
+ f = fopen(filename, "w");
+ if (f == NULL)
+ err(EXIT_FAILURE, "Can't open %s\n", filename);
+ }
+
+ print_states(fd, verbose, f);
+
+ if (f != stdout)
+ fclose(f);
+
+ return 0;
+}
+
+static int
+restore_states_ascii(int fd, int verbose __unused, const char* filename)
+{
+ FILE *f;
+ struct pfioc_states ps;
+ int errno_saved;
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ err(EXIT_FAILURE, "Can't open %s\n", filename);
+
+ parse(f, &ps);
+
+ if (ioctl(fd, DIOCADDSTATES, &ps) == -1) {
+ errno_saved = errno;
+ fclose(f);
+ free(ps.ps_states);
+ errno = errno_saved;
+ err(EXIT_FAILURE, "DIOCADDSTATES");
+ }
+
+ free(ps.ps_states);
+ fclose(f);
+ return 0;
+}
+
+static int
+setlock(int fd, int verbose, int lock)
+{
+ if (verbose)
+ printf("Turning lock %s\n", lock ? "on" : "off");
+
+ if (ioctl(fd, DIOCSETLCK, &lock) == -1)
+ err(EXIT_FAILURE, "DIOCSETLCK");
+
+ return 0;
+}
+
+static int
+test_ascii_dump(int verbose, const char* file1, const char *file2)
+{
+ FILE *f1, *f2;
+ struct pfioc_states ps;
+ int errno_saved;
+
+ f1 = fopen(file1, "r");
+ if (f1 == NULL)
+ err(EXIT_FAILURE, "Can't open %s\n", file1);
+
+
+ f2 = fopen(file2, "w");
+ if (f2 == NULL) {
+ errno_saved = errno;
+ fclose(f2);
+ errno = errno_saved;
+ err(EXIT_FAILURE, "Can't open %s\n", file2);
+ }
+
+ parse(f1, &ps);
+ display_states(&ps, verbose, f2);
+
+ free(ps.ps_states);
+ fclose(f1);
+ fclose(f2);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ setprogname(argv[0]);
+
+ int lock = 0;
+ int set = 0;
+ int dump = 0;
+ int restore = 0;
+ int verbose = 0;
+ int test = 0;
+ bool binary = false;
+ char* filename = NULL;
+ char* filename2 = NULL;
+ int error = 0;
+ int fd;
+ int c;
+
+ while ((c = getopt(argc, argv, "ulvw:r:R:W:bt:o:")) != -1)
+ switch (c) {
+ case 'u' :
+ lock = 0;
+ set = 1;
+ break;
+
+ case 'l' :
+ lock = 1;
+ set = 1;
+ break;
+
+ case 'b':
+ binary = true;
+ break;
+
+ case 'r':
+ restore = 1;
+ filename = optarg;
+ break;
+
+ case 'v':
+ verbose=1;
+ break;
+
+ case 'w':
+ dump=1;
+ filename=optarg;
+ break;
+
+ case 'R':
+ restore = 1;
+ set = 1;
+ filename = optarg;
+ break;
+
+ case 'W':
+ dump = 1;
+ set = 1;
+ filename = optarg;
+ break;
+
+ case 't':
+ test=1;
+ filename = optarg;
+ break;
+
+ case 'o':
+ filename2 = optarg;
+ break;
+
+ case '?' :
+ default:
+ usage();
+ }
+
+ if (set == 0 && dump == 0 && restore == 0 && test == 0)
+ usage();
+
+ if (dump == 1 && restore == 1)
+ usage();
+
+ if (test == 1) {
+ if (filename2 == NULL) {
+ fprintf(stderr, "-o <file> is required when using
-t\n");
+ err(EXIT_FAILURE, NULL);
+ }
+ error = test_ascii_dump(verbose, filename, filename2);
+ } else {
+ fd = open(pf_device, O_RDWR);
+ if (fd == -1)
+ err(EXIT_FAILURE, "Cannot open %s", pf_device);
+
+ if (set != 0 && dump == 0 && restore == 0)
+ error = setlock(fd, verbose, lock);
+
+ if (dump) {
+ if (set)
+ error = setlock(fd, verbose, 1);
+
+ if (binary)
+ error = dump_states_binary(fd, verbose,
filename);
+ else
+ error = dump_states_ascii(fd, verbose,
filename);
+
+ if (set)
+ error = setlock(fd, verbose, 0);
+ }
+
+ if (restore) {
+ if (set)
+ error = setlock(fd, verbose, 1);
+
+ if (binary)
+ error = restore_states_binary(fd, verbose,
filename);
+ else
+ error = restore_states_ascii(fd, verbose,
filename);
+
+ if (set)
+ error = setlock(fd, verbose, 0);
+ }
+
+ close(fd);
+ }
+
+ return error;
+}
Index: usr.sbin/pf/pfs/token.l
===================================================================
RCS file: usr.sbin/pf/pfs/token.l
diff -N usr.sbin/pf/pfs/token.l
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.sbin/pf/pfs/token.l 6 Apr 2010 14:12:31 -0000
@@ -0,0 +1,95 @@
+%{
+#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include "parse.h"
+#include "parser.h"
+
+%}
+
+%option nounput
+
+%%
+
+state { return STATE;}
+on { return ON;}
+out { return OUT;}
+in { return IN;}
+proto { return PROTO;}
+from { return FROM;}
+to { return TO;}
+using { return USING;}
+id { return ID;}
+cid { return CID;}
+expire { return EXPIRE;}
+timeout { return TIMEOUT;}
+src { return SRC;}
+dst { return DST;}
+seq { return SEQ;}
+max_win { return MAX_WIN;}
+wscale { return WSCALE;}
+mss { return MSS;}
+no-scrub { return NOSCRUB;}
+scrub { return SCRUB;}
+flags { return FLAGS;}
+ttl { return TTL;}
+mode { return MODE;}
+[0-9]+ { char *ep;
+ errno = 0;
+ yylval.num = strtoumax(yytext, &ep, 10);
+ if (errno == ERANGE && yylval.num == UINTMAX_MAX)
+ yyfatal("Number out of range");
+ return NUMBER;
+ }
+
+[A-Za-z0-9:\[][A-Za-z0-9\[\]_:%\.-]* { yylval.str = strdup(yytext);
+ if (yylval.str ==
NULL)
+
yyfatal("Not enough memory");
+ return STRING;
+ }
+
+
+\n { lineno ++; }
+
+%%
+
+
+void
+yyfatal(const char *s)
+{
+ yyerror(s);
+ exit(EXIT_FAILURE);
+}
+
+void
+yyerror(const char *s)
+{
+ printf("line %d: %s at [%s]\n", lineno, s, yytext);
+}
+
+
+int
+parse(FILE *fp, struct pfioc_states* s)
+{
+ yyin = fp;
+
+ lineno = 1;
+
+ states = s;
+ allocated = 0;
+ memset(s, 0, sizeof(*s));
+
+ if (yyparse()) {
+ printf("parse failed, line %d.\n", lineno);
+ return(-1);
+ }
+
+ return(0);
+}
Index: sys/dist/pf/net/pf.c
===================================================================
RCS file: /cvsroot/src/sys/dist/pf/net/pf.c,v
retrieving revision 1.61
diff -u -r1.61 pf.c
--- sys/dist/pf/net/pf.c 19 Jan 2010 22:08:00 -0000 1.61
+++ sys/dist/pf/net/pf.c 6 Apr 2010 14:12:34 -0000
@@ -257,6 +257,8 @@
extern struct pool pfr_ktable_pl;
extern struct pool pfr_kentry_pl;
+extern int pf_state_lock;
+
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
{ &pf_state_pl, PFSTATE_HIWAT },
{ &pf_src_tree_pl, PFSNODE_HIWAT },
@@ -267,6 +269,10 @@
#define STATE_LOOKUP() \
do { \
+ if (pf_state_lock) { \
+ *state = NULL; \
+ return (PF_DROP); \
+ }
\
if (direction == PF_IN) \
*state = pf_find_state(kif, &key, PF_EXT_GWY); \
else \
@@ -928,8 +934,9 @@
s = splsoftnet();
/* process a fraction of the state table every second */
- pf_purge_expired_states(1 + (pf_status.states
- / pf_default_rule.timeout[PFTM_INTERVAL]));
+ if (! pf_state_lock)
+ pf_purge_expired_states(1 + (pf_status.states
+ /
pf_default_rule.timeout[PFTM_INTERVAL]));
/* purge other expired types every PFTM_INTERVAL seconds */
if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
@@ -3323,6 +3330,11 @@
a, ruleset, pd);
}
+ if (r->keep_state && pf_state_lock) {
+ REASON_SET(&reason, PFRES_STATELOCKED);
+ return PF_DROP;
+ }
+
if ((r->action == PF_DROP) &&
((r->rule_flag & PFRULE_RETURNRST) ||
(r->rule_flag & PFRULE_RETURNICMP) ||
Index: sys/dist/pf/net/pf_ioctl.c
===================================================================
RCS file: /cvsroot/src/sys/dist/pf/net/pf_ioctl.c,v
retrieving revision 1.37
diff -u -r1.37 pf_ioctl.c
--- sys/dist/pf/net/pf_ioctl.c 3 Oct 2009 00:37:02 -0000 1.37
+++ sys/dist/pf/net/pf_ioctl.c 6 Apr 2010 14:12:34 -0000
@@ -133,6 +133,8 @@
void pf_state_import(struct pfsync_state *,
struct pf_state_key *, struct pf_state *);
+static int pf_state_add(struct pfsync_state*);
+
struct pf_rule pf_default_rule;
#ifdef __NetBSD__
krwlock_t pf_consistency_lock;
@@ -143,6 +145,8 @@
static int pf_altq_running;
#endif
+int pf_state_lock = 0;
+
#define TAGID_MAX 50000
TAILQ_HEAD(pf_tags, pf_tagname) pf_tags =
TAILQ_HEAD_INITIALIZER(pf_tags),
pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
@@ -1016,21 +1020,62 @@
/* copy to state */
memcpy(&s->id, &sp->id, sizeof(sp->id));
s->creatorid = sp->creatorid;
- strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
pf_state_peer_from_pfsync(&sp->src, &s->src);
pf_state_peer_from_pfsync(&sp->dst, &s->dst);
s->rule.ptr = &pf_default_rule;
+ s->rule.ptr->states++;
s->nat_rule.ptr = NULL;
s->anchor.ptr = NULL;
s->rt_kif = NULL;
s->creation = time_second;
+ s->expire = time_second;
+ s->timeout = sp->timeout;
+ if (sp->expire > 0)
+ s->expire -= pf_default_rule.timeout[sp->timeout] - sp->expire;
s->pfsync_time = 0;
s->packets[0] = s->packets[1] = 0;
s->bytes[0] = s->bytes[1] = 0;
}
int
+pf_state_add(struct pfsync_state* sp)
+{
+ struct pf_state *s;
+ struct pf_state_key *sk;
+ struct pfi_kif *kif;
+
+ if (sp->timeout >= PFTM_MAX &&
+ sp->timeout != PFTM_UNTIL_PACKET) {
+ return EINVAL;
+ }
+ s = pool_get(&pf_state_pl, PR_NOWAIT);
+ if (s == NULL) {
+ return ENOMEM;
+ }
+ bzero(s, sizeof(struct pf_state));
+ if ((sk = pf_alloc_state_key(s)) == NULL) {
+ pool_put(&pf_state_pl, s);
+ return ENOMEM;
+ }
+ pf_state_import(sp, sk, s);
+ kif = pfi_kif_get(sp->ifname);
+ if (kif == NULL) {
+ pool_put(&pf_state_pl, s);
+ pool_put(&pf_state_key_pl, sk);
+ return ENOENT;
+ }
+ if (pf_insert_state(kif, s)) {
+ pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+ pool_put(&pf_state_pl, s);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+
+int
pf_setup_pfsync_matching(struct pf_ruleset *rs)
{
MD5_CTX ctx;
@@ -1118,6 +1163,8 @@
case DIOCIGETIFACES:
case DIOCSETIFFLAG:
case DIOCCLRIFFLAG:
+ case DIOCSETLCK:
+ case DIOCADDSTATES:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -1155,6 +1202,7 @@
case DIOCOSFPGET:
case DIOCGETSRCNODES:
case DIOCIGETIFACES:
+ case DIOCSETLCK:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -1165,6 +1213,7 @@
case DIOCRDELADDRS:
case DIOCRSETADDRS:
case DIOCRSETTFLAGS:
+ case DIOCADDSTATES:
if (((struct pfioc_table *)addr)->pfrio_flags &
PFR_FLAG_DUMMY) {
flags |= FWRITE; /* need write lock for dummy */
@@ -1763,42 +1812,39 @@
case DIOCADDSTATE: {
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pfsync_state *sp = (struct pfsync_state *)ps->state;
- struct pf_state *s;
- struct pf_state_key *sk;
- struct pfi_kif *kif;
- if (sp->timeout >= PFTM_MAX &&
- sp->timeout != PFTM_UNTIL_PACKET) {
- error = EINVAL;
- break;
- }
- s = pool_get(&pf_state_pl, PR_NOWAIT);
- if (s == NULL) {
- error = ENOMEM;
- break;
- }
- bzero(s, sizeof(struct pf_state));
- if ((sk = pf_alloc_state_key(s)) == NULL) {
- error = ENOMEM;
- break;
- }
- pf_state_import(sp, sk, s);
- kif = pfi_kif_get(sp->ifname);
- if (kif == NULL) {
- pool_put(&pf_state_pl, s);
- pool_put(&pf_state_key_pl, sk);
- error = ENOENT;
- break;
- }
- if (pf_insert_state(kif, s)) {
- pfi_kif_unref(kif, PFI_KIF_REF_NONE);
- pool_put(&pf_state_pl, s);
- pool_put(&pf_state_key_pl, sk);
- error = ENOMEM;
+ error = pf_state_add(sp);
+ break;
+ }
+
+ case DIOCADDSTATES: {
+ struct pfioc_states *ps = (struct pfioc_states *)addr;
+ struct pfsync_state *p = (struct pfsync_state *)
ps->ps_states;
+ struct pfsync_state *pk;
+ int size = ps->ps_len;
+ int i = 0;
+ error = 0;
+
+ pk = malloc(sizeof(*pk), M_TEMP,M_WAITOK);
+
+ while (error == 0 && i < size)
+ {
+ if (copyin(p, pk, sizeof(struct pfsync_state)))
+ {
+ error = EFAULT;
+ free(pk, M_TEMP);
+ } else {
+ error = pf_state_add(pk);
+ i += sizeof(*p);
+ p++;
+ }
}
+
+ free(pk, M_TEMP);
break;
}
+
case DIOCGETSTATE: {
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pf_state *s;
@@ -3069,6 +3115,11 @@
break;
}
+ case DIOCSETLCK: {
+ pf_state_lock = *(uint32_t*)addr;
+ break;
+ }
+
default:
error = ENODEV;
break;
Index: sys/dist/pf/net/pfvar.h
===================================================================
RCS file: /cvsroot/src/sys/dist/pf/net/pfvar.h,v
retrieving revision 1.17
diff -u -r1.17 pfvar.h
--- sys/dist/pf/net/pfvar.h 28 Jul 2009 18:15:26 -0000 1.17
+++ sys/dist/pf/net/pfvar.h 6 Apr 2010 14:12:35 -0000
@@ -1123,7 +1123,8 @@
#define PFRES_MAXSTATES 12 /* State limit */
#define PFRES_SRCLIMIT 13 /* Source node/conn limit */
#define PFRES_SYNPROXY 14 /* SYN proxy */
-#define PFRES_MAX 15 /* total+1 */
+#define PFRES_STATELOCKED 15 /* state table locked */
+#define PFRES_MAX 16 /* total+1 */
#define PFRES_NAMES { \
"match", \
@@ -1141,6 +1142,7 @@
"state-limit", \
"src-limit", \
"synproxy", \
+ "state-locked", \
NULL \
}
@@ -1493,7 +1495,8 @@
#define DIOCADDRULE _IOWR('D', 4, struct pfioc_rule)
#define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule)
#define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule)
-/* XXX cut 8 - 17 */
+#define DIOCSETLCK _IOWR('D', 8, uint32_t)
+/* XXX cut 9 - 17 */
#define DIOCCLRSTATES _IOWR('D', 18, struct pfioc_state_kill)
#define DIOCGETSTATE _IOWR('D', 19, struct pfioc_state)
#define DIOCSETSTATUSIF _IOWR('D', 20, struct pfioc_if)
@@ -1523,7 +1526,8 @@
#define DIOCGETADDRS _IOWR('D', 53, struct pfioc_pooladdr)
#define DIOCGETADDR _IOWR('D', 54, struct pfioc_pooladdr)
#define DIOCCHANGEADDR _IOWR('D', 55, struct pfioc_pooladdr)
-/* XXX cut 55 - 57 */
+#define DIOCADDSTATES _IOWR('D', 56, struct pfioc_states)
+/* XXX cut 57 - 57 */
#define DIOCGETRULESETS _IOWR('D', 58, struct pfioc_ruleset)
#define DIOCGETRULESET _IOWR('D', 59, struct pfioc_ruleset)
#define DIOCRCLRTABLES _IOWR('D', 60, struct pfioc_table)
Home |
Main Index |
Thread Index |
Old Index