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