vBulletin Search Engine Optimization
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| Hello tech@, first posting here so please don't laugh too hard. My idea was to have pf automatically purge addresses from specified tables after period of time from the insertion has gone by. The patch is bare minimum but functional - adds the option "expire timeout", (timeout parameter in seconds) to pf.conf table definitions. After reading the source for quite some time and at the same time writing this stuff, I can't quite decide on many things about the implementation. If you see this is a bad thing to do to/in the kernel, please let me know.. There are probably many flaws in the code and many more aspects I have overlooked (probably some interference with something I haven't stumbled upon in the source yet?). I'd appreciate some answers/pointers to where to look at on these: - timeouts (as state expiry and my original plan for 3.6 worked) vs. pfpurge thread? - locking in the thread, do I need to rw_enter_write to safely delete kentries with pfr_unroute_kentry() and pfr_destroy_kentry() - is this even the correct method for removing addresses from tables or should I use "higher" level functions? Or lower? - cpu and memory implications: is it OK to add 4 bytes per table? I see the structures are not used that much. This could build up in high traffic/DoS situation, up to probably not-very-many k? The purge "algorithm" surely is stupid, thinking about adding another time_second stamp in pfr_ktable describing the next timeout and just testing that before iterating every kentry in ktable, etc. The problem with these is that development happens on a very low-end setup so I don't reach wire speed anyways, but this would need to be working in a real-world carp'ed fw setup to be installed soon. Routing between fastethernet LANs where wire speed would be desirable. - IOCTL - what's going on here? I've chosen not to update as it seems I don't need to. But anyways I would like to do this right. - many more ideas and todos that I'm only thinking about yet, not knowing if all this code is just bad bs and pointless.. -blank diff for 3.8-current follows Index: src/sbin/pfctl/parse.y ================================================== ================= RCS file: /cvs/src/sbin/pfctl/parse.y,v retrieving revision 1.494 diff -u -r1.494 parse.y --- src/sbin/pfctl/parse.y 2005/11/17 20:52:39 1.494 +++ src/sbin/pfctl/parse.y 2005/11/19 20:30:55 @@ -235,6 +235,7 @@ struct table_opts { int flags; int init_addr; + int expire; struct node_tinithead init_nodes; } table_opts; @@ -411,6 +412,7 @@ %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH %token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE +%token EXPIRE %token <v.string> STRING %token <v.i> PORTBINARY %type <v.interface> interface if_list if_item_not if_item @@ -1026,11 +1028,17 @@ free($3); YYERROR; } - if (pf->loadopt & PFCTL_FLAG_TABLE) + if (pf->loadopt & PFCTL_FLAG_TABLE) { + if ($5.expire && ($5.flags & PFR_TFLAG_CONST)) { + yyerror("const tables can't expire"); + free($3); + YYERROR; + } if (process_tabledef($3, &$5)) { free($3); YYERROR; } + } free($3); for (ti = SIMPLEQ_FIRST(&$5.init_nodes); ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { @@ -1119,6 +1127,13 @@ entries); table_opts.init_addr = 1; } + | EXPIRE number { + if ($2<1) { + printf("minimum table expire time is 1\n"); + YYERROR; + } + table_opts.expire = $2; + } ; altqif : ALTQ interface queue_opts QUEUE qassign { @@ -3859,7 +3874,7 @@ print_tabledef(name, opts->flags, opts->init_addr, &opts->init_nodes); if (!(pf->opts & PF_OPT_NOACTION) && - pfctl_define_table(name, opts->flags, opts->init_addr, + pfctl_define_table(name, opts->flags, opts->expire, opts->init_addr, pf->anchor, &ab, pf->tticket)) { yyerror("cannot define table %s: %s", name, pfr_strerror(errno)); @@ -4583,6 +4598,7 @@ { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, + { "expire", EXPIRE}, { "fastroute", FASTROUTE}, { "file", FILENAME}, { "fingerprints", FINGERPRINTS}, Index: src/sbin/pfctl/pfctl_optimize.c ================================================== ================= RCS file: /cvs/src/sbin/pfctl/pfctl_optimize.c,v retrieving revision 1.9 diff -u -r1.9 pfctl_optimize.c --- src/sbin/pfctl/pfctl_optimize.c 2005/06/13 20:17:26 1.9 +++ src/sbin/pfctl/pfctl_optimize.c 2005/11/19 20:30:58 @@ -1283,7 +1283,7 @@ tablenum++; - if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, pf->anchor, + if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 0, 1, pf->anchor, tbl->pt_buf, pf->tticket)) { warn("failed to create table %s", tbl->pt_name); return (1); Index: src/sbin/pfctl/pfctl_parser.h ================================================== ================= RCS file: /cvs/src/sbin/pfctl/pfctl_parser.h,v retrieving revision 1.83 diff -u -r1.83 pfctl_parser.h --- src/sbin/pfctl/pfctl_parser.h 2005/11/17 20:52:39 1.83 +++ src/sbin/pfctl/pfctl_parser.h 2005/11/19 20:30:58 @@ -219,8 +219,8 @@ void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *, int, struct node_queue_opt *); -int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *, - u_int32_t); +int pfctl_define_table(char *, int, int, int, const char *, + struct pfr_buffer *, u_int32_t); void pfctl_clear_fingerprints(int, int); int pfctl_file_fingerprints(int, int, const char *); Index: src/sbin/pfctl/pfctl_table.c ================================================== ================= RCS file: /cvs/src/sbin/pfctl/pfctl_table.c,v retrieving revision 1.64 diff -u -r1.64 pfctl_table.c --- src/sbin/pfctl/pfctl_table.c 2005/08/17 14:54:59 1.64 +++ src/sbin/pfctl/pfctl_table.c 2005/11/19 20:30:58 @@ -338,6 +338,8 @@ ta->pfrt_name); if (ta->pfrt_anchor[0]) printf("\t%s", ta->pfrt_anchor); + if (ta->pfrt_expire) + printf("\texpire=%d", ta->pfrt_expire); puts(""); } else puts(ta->pfrt_name); @@ -454,8 +456,8 @@ } int -pfctl_define_table(char *name, int flags, int addrs, const char *anchor, - struct pfr_buffer *ab, u_int32_t ticket) +pfctl_define_table(char *name, int flags, int expire, int addrs, + const char *anchor, struct pfr_buffer *ab, u_int32_t ticket) { struct pfr_table tbl; @@ -465,6 +467,7 @@ sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) errx(1, "pfctl_define_table: strlcpy"); tbl.pfrt_flags = flags; + tbl.pfrt_expire = expire; return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0); Index: src/sys/net/pf.c ================================================== ================= RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.508 diff -u -r1.508 pf.c --- src/sys/net/pf.c 2005/11/14 09:18:55 1.508 +++ src/sys/net/pf.c 2005/11/19 20:31:39 @@ -877,6 +877,7 @@ if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { pf_purge_expired_fragments(); pf_purge_expired_src_nodes(0); + pfr_purge_expired_kentries(); nloops = 0; } Index: src/sys/net/pf_table.c ================================================== ================= RCS file: /cvs/src/sys/net/pf_table.c,v retrieving revision 1.67 diff -u -r1.67 pf_table.c --- src/sys/net/pf_table.c 2005/08/02 12:40:42 1.67 +++ src/sys/net/pf_table.c 2005/11/19 20:31:44 @@ -897,6 +897,32 @@ } void +pfr_purge_expired_kentries(void) +{ + struct pfr_ktable *p; + struct pfr_kentryworkq workq; + struct pfr_kentry *pa,*pb; + int n = 0; + + RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) { + if (!p->pfrkt_expire) + continue; + if (!(p->pfrkt_flags & (PFR_TFLAG_ACTIVE & !PFR_TFLAG_CONST))) + continue; + pfr_enqueue_addrs(p, &workq, NULL, 0); + for (pa = SLIST_FIRST(&workq); pa != NULL; pa = pb) { + pb = SLIST_NEXT(pa, pfrke_workq); + if ((pa->pfrke_tzero+p->pfrkt_expire) < time_second) { + pfr_unroute_kentry(p, pa); + pfr_destroy_kentry(pa); + n++; + } + } + p->pfrkt_cnt -= n; + } +} + +void pfr_clean_node_mask(struct pfr_ktable *kt, struct pfr_kentryworkq *workq) { @@ -1902,6 +1928,7 @@ return (NULL); } kt->pfrkt_tzero = tzero; + kt->pfrkt_expire = tbl->pfrt_expire; return (kt); } Index: src/sys/net/pfvar.h ================================================== ================= RCS file: /cvs/src/sys/net/pfvar.h,v retrieving revision 1.233 diff -u -r1.233 pfvar.h --- src/sys/net/pfvar.h 2005/11/04 08:24:15 1.233 +++ src/sys/net/pfvar.h 2005/11/19 20:31:46 @@ -784,6 +784,7 @@ char pfrt_anchor[MAXPATHLEN]; char pfrt_name[PF_TABLE_NAME_SIZE]; u_int32_t pfrt_flags; + u_int32_t pfrt_expire; u_int8_t pfrt_fback; }; @@ -858,6 +859,7 @@ struct pf_ruleset *pfrkt_rs; long pfrkt_larg; int pfrkt_nflags; + long pfrkt_expire; }; #define pfrkt_t pfrkt_ts.pfrts_t #define pfrkt_name pfrkt_t.pfrt_name @@ -1535,6 +1537,7 @@ int pfr_set_tflags(struct pfr_table *, int, int, int, int *, int *, int); int pfr_clr_addrs(struct pfr_table *, int *, int); int pfr_insert_kentry(struct pfr_ktable *, struct pfr_addr *, long); +void pfr_purge_expired_kentries(void); int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, |