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, &current_peer, sizeof(current_peer));
+               }
+       ;
+
+dst_peer
+       : DST peer { 
+                       memcpy(dst_peer, &current_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, &current_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(&current_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