? 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 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 + +#ifndef lint +__RCSID("$NetBSD: parse.y$"); +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 STRING +%type 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 + +#ifndef lint +__RCSID("$NetBSD: pfs.c$"); +#endif + +#include +#include +#include +#include + +#include +#include +#define TCPSTATES +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 | -r |\n" + " [ -W | -R ]\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 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 + +#ifndef lint +__RCSID("$NetBSD: token.l$"); +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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)