[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: PF & stream size



* Ed White <[email protected]> [19.01.2004 16:14]:
> I would like to know if there is any plan to limit the number of bytes
> a TCP connection can transfer. The idea is to drop/close the
> connection after $SIZE bytes have been transferred. 
This is a first cut at this idea. It implements a per-state traffic
limit like this:
    pass in proto tcp from any to any port = 25 \
        flags S/SA keep state (bytes 100000)
This could be easily extended to per-rule or per-source-ip limits. I
just didn't want to invent too many keywords.
Opinions? Ideas?
Index: sys/net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.418
diff -p -u -r1.418 pf.c
--- sys/net/pf.c	6 Jan 2004 20:24:33 -0000	1.418
+++ sys/net/pf.c	21 Jan 2004 15:54:19 -0000
@@ -5469,6 +5469,12 @@ done:
 		REASON_SET(&reason, PFRES_MEMORY);
 	}
 
+	if (r->max_bytes && (s->bytes[0] + s->bytes[1] >= r->max_bytes)) {
+		s->timeout = PFTM_PURGE;
+		action = PF_DROP;
+		REASON_SET(&reason, PFRES_MAXBYTES);
+	}
+
 	if (log)
 		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
 
Index: sys/net/pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.180
diff -p -u -r1.180 pfvar.h
--- sys/net/pfvar.h	31 Dec 2003 11:18:25 -0000	1.180
+++ sys/net/pfvar.h	21 Jan 2004 15:54:19 -0000
@@ -484,6 +484,7 @@ struct pf_rule {
 	u_int32_t		 timeout[PFTM_MAX];
 	u_int32_t		 states;
 	u_int32_t		 max_states;
+	u_int64_t		 max_bytes;
 	u_int32_t		 src_nodes;
 	u_int32_t		 max_src_nodes;
 	u_int32_t		 max_src_states;
@@ -859,7 +860,8 @@ struct pf_pdesc {
 #define PFRES_SHORT	3		/* Dropping short packet */
 #define PFRES_NORM	4		/* Dropping by normalizer */
 #define PFRES_MEMORY	5		/* Dropped due to lacking mem */
-#define PFRES_MAX	6		/* total+1 */
+#define PFRES_MAXBYTES	6		/* Dropped due to bytes limit */
+#define PFRES_MAX	7		/* total+1 */
 
 #define PFRES_NAMES { \
 	"match", \
@@ -868,6 +870,7 @@ struct pf_pdesc {
 	"short", \
 	"normalize", \
 	"memory", \
+	"bytes", \
 	NULL \
 }
 
Index: sbin/pfctl/parse.y
===================================================================
RCS file: /cvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.436
diff -p -u -r1.436 parse.y
--- sbin/pfctl/parse.y	5 Jan 2004 22:04:24 -0000	1.436
+++ sbin/pfctl/parse.y	21 Jan 2004 15:53:57 -0000
@@ -117,12 +117,13 @@ struct node_icmp {
 
 enum	{ PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
 	  PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_NODES,
-	  PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT };
+	  PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_BYTES };
 
 struct node_state_opt {
 	int			 type;
 	union {
 		u_int32_t	 max_states;
+		u_int64_t	 max_bytes;
 		u_int32_t	 max_src_states;
 		u_int32_t	 max_src_nodes;
 		u_int8_t	 src_track;
@@ -399,7 +400,7 @@ typedef struct {
 %token	QUEUE PRIORITY QLIMIT
 %token	LOAD
 %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
-%token	TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY
+%token	TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY BYTES
 %token	<v.string>		STRING
 %token	<v.i>			PORTBINARY
 %type	<v.interface>		interface if_list if_item_not if_item
@@ -1465,6 +1466,14 @@ pfrule		: action dir logquick interface 
 					}
 					r.max_states = o->data.max_states;
 					break;
+				case PF_STATE_OPT_BYTES:
+					if (r.max_bytes) {
+						yyerror("state option 'bytes' "
+						    "multiple definitions");
+						YYERROR;
+					}
+					r.max_bytes = o->data.max_bytes;
+					break;
 				case PF_STATE_OPT_NOSYNC:
 					if (r.rule_flag & PFRULE_NOSYNC) {
 						yyerror("state option 'sync' "
@@ -2571,6 +2580,15 @@ state_opt_item	: MAXIMUM number		{
 			$$->next = NULL;
 			$$->tail = $$;
 		}
+		| BYTES number		{
+			$$ = calloc(1, sizeof(struct node_state_opt));
+			if ($$ == NULL)
+				err(1, "state_opt_item: calloc");
+			$$->type = PF_STATE_OPT_BYTES;
+			$$->data.max_bytes = $2;
+			$$->next = NULL;
+			$$->tail = $$;
+		}
 		| NOSYNC				{
 			$$ = calloc(1, sizeof(struct node_state_opt));
 			if ($$ == NULL)
@@ -4131,6 +4149,7 @@ lookup(char *s)
 		{ "bitmask",		BITMASK},
 		{ "block",		BLOCK},
 		{ "block-policy",	BLOCKPOLICY},
+		{ "bytes",		BYTES},
 		{ "cbq",		CBQ},
 		{ "code",		CODE},
 		{ "crop",		FRAGCROP},
Index: sbin/pfctl/pfctl_parser.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v
retrieving revision 1.187
diff -p -u -r1.187 pfctl_parser.c
--- sbin/pfctl/pfctl_parser.c	31 Dec 2003 22:14:41 -0000	1.187
+++ sbin/pfctl/pfctl_parser.c	21 Jan 2004 15:53:57 -0000
@@ -776,7 +776,7 @@ print_rule(struct pf_rule *r, int verbos
 	else if (r->keep_state == PF_STATE_SYNPROXY)
 		printf(" synproxy state");
 	opts = 0;
-	if (r->max_states || r->max_src_nodes || r->max_src_states)
+	if (r->max_states || r->max_src_nodes || r->max_src_states || r->max_bytes)
 		opts = 1;
 	if (r->rule_flag & PFRULE_NOSYNC)
 		opts = 1;
@@ -791,6 +791,12 @@ print_rule(struct pf_rule *r, int verbos
 		printf(" (");
 		if (r->max_states) {
 			printf("max %u", r->max_states);
+			opts = 0;
+		}
+		if (r->max_bytes) {
+			if (!opts)
+				printf(", ");
+			printf("bytes %llu", r->max_bytes);
 			opts = 0;
 		}
 		if (r->rule_flag & PFRULE_NOSYNC) {