summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/pfctl/parse.y110
-rw-r--r--sbin/pfctl/pfctl.c7
-rw-r--r--sbin/pfctl/pfctl_parser.c26
-rw-r--r--sbin/pfctl/pfctl_parser.h9
-rw-r--r--share/man/man5/pf.conf.530
-rw-r--r--sys/net/pf.c43
-rw-r--r--sys/net/pfvar.h3
7 files changed, 180 insertions, 48 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 4bf9bc08cdd..e6f88352269 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.80 2002/06/08 01:00:23 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.81 2002/06/08 07:58:07 dhartmei Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -103,6 +103,19 @@ struct node_icmp {
struct node_icmp *next;
};
+struct node_state_opt {
+ enum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 };
+ int type;
+ union {
+ u_int32_t max_states;
+ struct {
+ int number;
+ u_int32_t seconds;
+ } timeout;
+ } data;
+ struct node_state_opt *next;
+};
+
struct peer {
struct node_host *host;
struct node_port *port;
@@ -158,6 +171,7 @@ typedef struct {
struct node_port *port;
struct node_uid *uid;
struct node_gid *gid;
+ struct node_state_opt *state_opt;
struct peer peer;
struct {
struct peer src, dst;
@@ -173,10 +187,8 @@ typedef struct {
struct range rport;
} *redirection;
struct {
- int action;
- struct {
- u_int32_t max_states;
- } options;
+ int action;
+ struct node_state_opt *options;
} keep_state;
} v;
int lineno;
@@ -208,7 +220,8 @@ typedef struct {
%type <v.route> route
%type <v.redirection> redirection
%type <v.string> label
-%type <v.keep_state> keep keep_opts
+%type <v.keep_state> keep
+%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
%%
ruleset : /* empty */
@@ -237,6 +250,7 @@ pfrule : action dir log quick interface route af proto fromto
maxmss allowopts label
{
struct pf_rule r;
+ struct node_state_opt *o;
if (natmode) {
yyerror("filter rule not permitted in nat mode");
@@ -260,7 +274,33 @@ pfrule : action dir log quick interface route af proto fromto
r.flagset = $12.b2;
r.keep_state = $14.action;
- r.max_states = $14.options.max_states;
+ o = $14.options;
+ while (o) {
+ struct node_state_opt *p = o;
+
+ switch (o->type) {
+ case PF_STATE_OPT_MAX:
+ if (r.max_states) {
+ yyerror("state option 'max' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.max_states = o->data.max_states;
+ break;
+ case PF_STATE_OPT_TIMEOUT:
+ if (r.timeout[o->data.timeout.number]) {
+ yyerror("state timeout %s "
+ "multiple definitions",
+ pf_timeouts[o->data.
+ timeout.number].name);
+ YYERROR;
+ }
+ r.timeout[o->data.timeout.number] =
+ o->data.timeout.seconds;
+ }
+ o = o->next;
+ free(p);
+ }
if ($15)
r.rule_flag |= PFRULE_FRAGMENT;
@@ -974,23 +1014,61 @@ icmp6type : STRING {
;
keep : /* empty */ { $$.action = 0; }
- | KEEP STATE keep_opts {
+ | KEEP STATE state_opt_spec {
$$.action = PF_STATE_NORMAL;
- $$.options = $3.options;
+ $$.options = $3;
}
- | MODULATE STATE keep_opts {
+ | MODULATE STATE state_opt_spec {
$$.action = PF_STATE_MODULATE;
- $$.options = $3.options;
+ $$.options = $3;
+ }
+ ;
+
+state_opt_spec : /* empty */ { $$ = NULL; }
+ | '(' state_opt_list ')' { $$ = $2; }
+ ;
+
+state_opt_list : state_opt_item { $$ = $1; }
+ | state_opt_list ',' state_opt_item {
+ $$ = $1;
+ while ($1->next)
+ $1 = $1->next;
+ $1->next = $3;
}
;
-keep_opts : /* empty */ { $$.options.max_states = 0; }
- | '(' MAXIMUM NUMBER ')' {
- if ($3 <= 0) {
- yyerror("illegal keep states max value %d", $3);
+state_opt_item : MAXIMUM NUMBER {
+ if ($2 <= 0) {
+ yyerror("illegal states max value %d", $2);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX;
+ $$->data.max_states = $2;
+ $$->next = NULL;
+ }
+ | STRING NUMBER {
+ int i;
+
+ for (i = 0; pf_timeouts[i].name &&
+ strcmp(pf_timeouts[i].name, $1); ++i);
+ if (!pf_timeouts[i].name) {
+ yyerror("illegal timeout name %s", $1);
YYERROR;
}
- $$.options.max_states = $3;
+ if ($2 < 0) {
+ yyerror("illegal timeout value %d", $2);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_TIMEOUT;
+ $$->data.timeout.number = pf_timeouts[i].timeout;
+ $$->data.timeout.seconds = $2;
+ $$->next = NULL;
}
;
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index b08b13261c2..9a31c58dea2 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.69 2002/06/07 21:25:35 dhartmei Exp $ */
+/* $OpenBSD: pfctl.c,v 1.70 2002/06/08 07:58:07 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -92,10 +92,7 @@ char *state_kill[2];
char *infile;
-static const struct {
- const char *name;
- int timeout;
-} pf_timeouts[] = {
+const struct pf_timeout pf_timeouts[] = {
{ "tcp.first", PFTM_TCP_FIRST_PACKET },
{ "tcp.opening", PFTM_TCP_OPENING },
{ "tcp.established", PFTM_TCP_ESTABLISHED },
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index fab149fb866..a11f13a42f8 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.79 2002/06/07 22:53:45 pb Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.80 2002/06/08 07:58:07 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -530,6 +530,8 @@ print_status(struct pf_status *s)
void
print_rule(struct pf_rule *r)
{
+ int i, opts;
+
printf("@%d ", r->nr);
if (r->action == PF_PASS)
printf("pass ");
@@ -685,8 +687,28 @@ print_rule(struct pf_rule *r)
printf("keep state ");
else if (r->keep_state == PF_STATE_MODULATE)
printf("modulate state ");
+ opts = 0;
if (r->max_states)
- printf("(max %u) ", r->max_states);
+ opts = 1;
+ for (i = 0; !opts && i < PFTM_MAX; ++i)
+ if (r->timeout[i])
+ opts = 1;
+ if (opts) {
+ printf("(");
+ if (r->max_states) {
+ printf("max %u", r->max_states);
+ opts = 0;
+ }
+ for (i = 0; i < PFTM_MAX; ++i)
+ if (r->timeout[i]) {
+ if (!opts)
+ printf(", ");
+ opts = 0;
+ printf("%s %u", pf_timeouts[i].name,
+ r->timeout[i]);
+ }
+ printf(") ");
+ }
if (r->rule_flag & PFRULE_FRAGMENT)
printf("fragment ");
if (r->rule_flag & PFRULE_NODF)
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index e3773439cd8..807b0a18764 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.18 2002/06/07 19:33:03 henning Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.19 2002/06/08 07:58:07 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -86,4 +86,11 @@ struct icmptypeent *geticmptypebyname(char *, u_int8_t);
struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t);
struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t);
+struct pf_timeout {
+ const char *name;
+ int timeout;
+};
+
+extern const struct pf_timeout pf_timeouts[];
+
#endif /* _PFCTL_PARSER_H_ */
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 9f80e07e141..a0c636c6f49 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pf.conf.5,v 1.51 2002/06/08 04:36:18 henning Exp $
+.\" $OpenBSD: pf.conf.5,v 1.52 2002/06/08 07:58:07 dhartmei Exp $
.\"
.\" Copyright (c) 2001, Daniel Hartmeier
.\" All rights reserved.
@@ -53,7 +53,7 @@ rule = action ( "in" | "out" )
hosts
[ user ] [ group ] [ flags ]
[ icmp-type | ipv6-icmp-type ]
- [ ( "keep" | "modulate" ) "state" [ "(" "max" number ")" ] ]
+ [ ( "keep" | "modulate" ) "state" [ "(" state-opts ")" ] ]
[ "fragment" ] [ "no-df" ] [ "min-ttl" number ]
[ "max-mss" number ] [ "allow-opts" ]
[ "label" string ] .
@@ -101,6 +101,9 @@ icmp-type-code = ( icmp-type-name | icmp-type-number )
[ "code" ( icmp-code-name | icmp-code-number ) ] .
icmp-list = icmp-type-code [ "," icmp-list ] .
+state-opts = state-opt [ "," state-opts ] .
+state-opt = ( "max" number ) | ( timeout number ) .
+
.Ed
.Sh FILTER RULES
Filter rules are typically manipulated using
@@ -490,11 +493,6 @@ see
.Xr nat.conf 5
.Pc
implicitly create state for connections.
-.Pp
-The "(max <number>)" option can be used to limit the number of concurrent
-states a rule can create to the specified maximum.
-When this limit is reached, further packets matching the rule that would
-create state are dropped, until existing states time out.
.Sh STATE MODULATION
Much of the security derived from TCP is attributable to how well the
initial sequence numbers (ISNs) are chosen.
@@ -540,6 +538,24 @@ The sudden withdrawl
of the modulation will appear to each side of the connection that its
peer has suddenly shifted its sequence by a random amount. Neither side
will be able to recover and the connection will stall then eventually close.
+.Sh STATE OPTIONS
+Both "keep state" and "modulate state" support the following options:
+.Bl -tag -width timeout_seconds -compact
+.It Em max number
+Limits the number of concurrent states the rule may create.
+When this limit is reached, further packets matching the rule that would
+create state are dropped, until existing states time out.
+.It Em timeout seconds
+Changes the timeout values used for states created by this rule.
+For a list of all valid timeout names, see
+.Xr pf.conf 5 .
+.El
+.Pp
+Multiple options can be specified, separated by commas:
+.Bd -literal
+ pass in proto tcp from any to any port www flags S/SA \\
+ keep state (max 100, tcp.established 60, tcp.closing 5)
+.Ed
.Sh NORMALIZATION
Packet normalization is invoked via the
.Pa scrub
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 5600ecf8000..253f1069921 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.219 2002/06/07 22:53:37 pb Exp $ */
+/* $OpenBSD: pf.c,v 1.220 2002/06/08 07:58:06 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -277,7 +277,8 @@ int pf_socket_lookup(uid_t *, gid_t *, int, int, int,
(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
(s)->lan.port != (s)->gwy.port
-
+#define TIMEOUT(r,i) \
+ (((r) && (r)->timeout[(i)]) ? (r)->timeout[(i)] : *pftm_timeouts[(i)])
static __inline int pf_state_compare(struct pf_tree_node *,
struct pf_tree_node *);
@@ -3246,7 +3247,7 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp,
s->src.state = TCPS_SYN_SENT;
s->dst.state = TCPS_CLOSED;
s->creation = time.tv_sec;
- s->expire = s->creation + pftm_tcp_first_packet;
+ s->expire = s->creation + TIMEOUT(*rm, PFTM_TCP_FIRST_PACKET);
s->packets = 1;
s->bytes = pd->tot_len;
if (pf_insert_state(s)) {
@@ -3482,7 +3483,7 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
s->dst.max_win = 0;
s->dst.state = 0;
s->creation = time.tv_sec;
- s->expire = s->creation + pftm_udp_first_packet;
+ s->expire = s->creation + TIMEOUT(*rm, PFTM_UDP_FIRST_PACKET);
s->packets = 1;
s->bytes = pd->tot_len;
if (pf_insert_state(s)) {
@@ -3744,7 +3745,7 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
s->dst.max_win = 0;
s->dst.state = 0;
s->creation = time.tv_sec;
- s->expire = s->creation + pftm_icmp_first_packet;
+ s->expire = s->creation + TIMEOUT(*rm, PFTM_ICMP_FIRST_PACKET);
s->packets = 1;
s->bytes = pd->tot_len;
if (pf_insert_state(s)) {
@@ -3952,7 +3953,7 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
s->dst.max_win = 0;
s->dst.state = 0;
s->creation = time.tv_sec;
- s->expire = s->creation + pftm_other_first_packet;
+ s->expire = s->creation + TIMEOUT(*rm, PFTM_OTHER_FIRST_PACKET);
s->packets = 1;
s->bytes = pd->tot_len;
if (pf_insert_state(s)) {
@@ -4184,18 +4185,23 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
/* update expire time */
if (src->state >= TCPS_FIN_WAIT_2 &&
dst->state >= TCPS_FIN_WAIT_2)
- (*state)->expire = time.tv_sec + pftm_tcp_closed;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_TCP_CLOSED);
else if (src->state >= TCPS_FIN_WAIT_2 ||
dst->state >= TCPS_FIN_WAIT_2)
- (*state)->expire = time.tv_sec + pftm_tcp_fin_wait;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_TCP_FIN_WAIT);
else if (src->state >= TCPS_CLOSING ||
dst->state >= TCPS_CLOSING)
- (*state)->expire = time.tv_sec + pftm_tcp_closing;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_TCP_CLOSING);
else if (src->state < TCPS_ESTABLISHED ||
dst->state < TCPS_ESTABLISHED)
- (*state)->expire = time.tv_sec + pftm_tcp_opening;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_TCP_OPENING);
else
- (*state)->expire = time.tv_sec + pftm_tcp_established;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_TCP_ESTABLISHED);
/* Fall through to PASS packet */
@@ -4349,9 +4355,11 @@ pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp,
/* update expire time */
if (src->state == 2 && dst->state == 2)
- (*state)->expire = time.tv_sec + pftm_udp_multiple;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_UDP_MULTIPLE);
else
- (*state)->expire = time.tv_sec + pftm_udp_single;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_UDP_SINGLE);
/* translate source/destination address, if necessary */
if (STATE_TRANSLATE(*state)) {
@@ -4436,7 +4444,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
(*state)->packets++;
(*state)->bytes += pd->tot_len;
- (*state)->expire = time.tv_sec + pftm_icmp_error_reply;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_ICMP_ERROR_REPLY);
/* translate source/destination address, if needed */
if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) {
@@ -4889,9 +4898,11 @@ pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp,
/* update expire time */
if (src->state == 2 && dst->state == 2)
- (*state)->expire = time.tv_sec + pftm_other_multiple;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_OTHER_MULTIPLE);
else
- (*state)->expire = time.tv_sec + pftm_other_single;
+ (*state)->expire = time.tv_sec +
+ TIMEOUT((*state)->rule.ptr, PFTM_OTHER_SINGLE);
/* translate source/destination address, if necessary */
if (STATE_TRANSLATE(*state)) {
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 087cedf8947..99602cbf14e 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.77 2002/06/07 23:06:21 henning Exp $ */
+/* $OpenBSD: pfvar.h,v 1.78 2002/06/08 07:58:06 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -232,6 +232,7 @@ struct pf_rule {
struct pf_rule *skip[PF_SKIP_COUNT];
#define PF_RULE_LABEL_SIZE 64
char label[PF_RULE_LABEL_SIZE];
+ u_int32_t timeout[PFTM_MAX];
struct pf_addr rt_addr;
char ifname[IFNAMSIZ];
char rt_ifname[IFNAMSIZ];