* 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) {