? usr.sbin/pf/pfs/.gdbinit
? usr.sbin/pf/pfs/.new.pfs.c
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 17:28:06 -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 17:28:12 -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 17:28:15 -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 17:28:15 -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 17:28:15 -0000
@@ -0,0 +1,503 @@
+/* $NetBSD: parse.y$ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+
+#ifndef lint
+__RCSID("$NetBSD: parse.y$");
+#endif
+
+#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;
+ if (size > sizeof(buf))
+ return false;
+ 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;
+
+ if (size > sizeof(buf))
+ return false;
+ 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;
+ if (size > sizeof(buf))
+ return false;
+ 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 17:28:15 -0000
@@ -0,0 +1,42 @@
+/* $NetBSD: parser.h$ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 _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 17:28:15 -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 17:28:15 -0000
@@ -0,0 +1,575 @@
+/* $NetBSD: pfs.c$ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+
+#ifndef lint
+__RCSID("$NetBSD: pfs.c$");
+#endif
+
+#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 17:28:15 -0000
@@ -0,0 +1,130 @@
+/* $NetBSD: token.l$ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+
+#ifndef lint
+__RCSID("$NetBSD: token.l$");
+#endif
+
+#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 17:28:17 -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 17:28:18 -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 17:28:21 -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)