Index: sys/dist/pf/net/pf.c =================================================================== RCS file: /cvsroot/src/sys/dist/pf/net/pf.c,v retrieving revision 1.36 diff -u -r1.36 pf.c --- sys/dist/pf/net/pf.c 4 Mar 2007 06:02:58 -0000 1.36 +++ sys/dist/pf/net/pf.c 15 May 2007 08:38:21 -0000 @@ -2910,6 +2910,7 @@ if ((r->action == PF_DROP) && ((r->rule_flag & PFRULE_RETURNRST) || + (r->rule_flag & PFRULE_RETURNSYNACK) || (r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { /* undo NAT changes, if they have taken place */ @@ -2925,6 +2926,7 @@ } } if (((r->rule_flag & PFRULE_RETURNRST) || + (r->rule_flag & PFRULE_RETURNSYNACK) || (r->rule_flag & PFRULE_RETURN)) && !(th->th_flags & TH_RST)) { u_int32_t ack = ntohl(th->th_seq) + pd->p_len; @@ -2935,8 +2937,10 @@ ack++; pf_send_tcp(r, af, pd->dst, pd->src, th->th_dport, th->th_sport, - ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + (r->rule_flag & PFRULE_RETURNSYNACK) ? arc4random() : ntohl(th->th_ack), + ack, + (r->rule_flag & PFRULE_RETURNSYNACK) ? TH_SYN|TH_ACK : TH_RST|TH_ACK, + 0, 0, r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); } else if ((af == AF_INET) && r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, r->return_icmp & 255, af, r); @@ -5869,6 +5873,7 @@ struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; + struct pfr_addr pa; int off, dirndx, pqid = 0; if (!pf_status.running || @@ -6098,6 +6103,31 @@ REASON_SET(&reason, PFRES_MEMORY); } + memset(&pa, 0, sizeof(pa)); + pa.pfra_af = AF_INET; + pa.pfra_net = 32; + + switch (r->opert) { + case PF_TOPER_NONE: + break; + case PF_TOPER_ADD_SOURCE: + memcpy(&pa.pfra_ip4addr, &h->ip_src, sizeof(struct in_addr)); + pfr_insert_kentry(r->oper_tbl, &pa, time_second); + break; + case PF_TOPER_DEL_SOURCE: + memcpy(&pa.pfra_ip4addr, &h->ip_src, sizeof(struct in_addr)); + pfr_remove_kentry(r->oper_tbl, &pa); + break; + case PF_TOPER_ADD_DEST: + memcpy(&pa.pfra_ip4addr, &h->ip_dst, sizeof(struct in_addr)); + pfr_insert_kentry(r->oper_tbl, &pa, time_second); + break; + case PF_TOPER_DEL_DEST: + memcpy(&pa.pfra_ip4addr, &h->ip_dst, sizeof(struct in_addr)); + pfr_remove_kentry(r->oper_tbl, &pa); + break; + } + if (log) PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset); Index: sys/dist/pf/net/pf_ioctl.c =================================================================== RCS file: /cvsroot/src/sys/dist/pf/net/pf_ioctl.c,v retrieving revision 1.30 diff -u -r1.30 pf_ioctl.c --- sys/dist/pf/net/pf_ioctl.c 12 Mar 2007 18:18:31 -0000 1.30 +++ sys/dist/pf/net/pf_ioctl.c 15 May 2007 08:38:21 -0000 @@ -723,6 +723,8 @@ pf_tbladdr_remove(&rule->dst.addr); if (rule->overload_tbl) pfr_detach_table(rule->overload_tbl); + if (rule->oper_tbl) + pfr_detach_table(rule->oper_tbl); } TAILQ_REMOVE(rulequeue, rule, entries); rule->entries.tqe_prev = NULL; @@ -748,6 +750,8 @@ pf_tbladdr_remove(&rule->dst.addr); if (rule->overload_tbl) pfr_detach_table(rule->overload_tbl); + if (rule->oper_tbl) + pfr_detach_table(rule->oper_tbl); } pfi_detach_rule(rule->kif); pf_anchor_remove(rule); @@ -1412,6 +1416,15 @@ PFR_TFLAG_ACTIVE; } + if (rule->oper_tblname[0]) { + if ((rule->oper_tbl = pfr_attach_table(ruleset, + rule->oper_tblname)) == NULL) + error = EINVAL; + else + rule->oper_tbl->pfrkt_flags |= + PFR_TFLAG_ACTIVE; + } + pf_mv_pool(&pf_pabuf, &rule->rpool.list); if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || (rule->action == PF_BINAT)) && rule->anchor == NULL) || @@ -1633,6 +1646,15 @@ PFR_TFLAG_ACTIVE; } + if (newrule->oper_tblname[0]) { + if ((newrule->oper_tbl = pfr_attach_table( + ruleset, newrule->oper_tblname)) == NULL) + error = EINVAL; + else + newrule->oper_tbl->pfrkt_flags |= + PFR_TFLAG_ACTIVE; + } + pf_mv_pool(&pf_pabuf, &newrule->rpool.list); if (((((newrule->action == PF_NAT) || (newrule->action == PF_RDR) || Index: sys/dist/pf/net/pf_table.c =================================================================== RCS file: /cvsroot/src/sys/dist/pf/net/pf_table.c,v retrieving revision 1.12 diff -u -r1.12 pf_table.c --- sys/dist/pf/net/pf_table.c 12 Mar 2007 18:18:31 -0000 1.12 +++ sys/dist/pf/net/pf_table.c 15 May 2007 08:38:21 -0000 @@ -921,6 +921,21 @@ pfr_destroy_kentries(workq); } +int +pfr_remove_kentry(struct pfr_ktable *kt, struct pfr_addr *ad) +{ + struct pfr_kentry *p; + struct pfr_kentryworkq wq; + + p = pfr_lookup_addr(kt, ad, 1); + if (p == NULL) + return 0; + SLIST_INIT(&wq); + SLIST_INSERT_HEAD(&wq, p, pfrke_workq); + pfr_remove_kentries(kt, &wq); + return 1; +} + void pfr_clean_node_mask(struct pfr_ktable *kt, struct pfr_kentryworkq *workq) Index: sys/dist/pf/net/pfvar.h =================================================================== RCS file: /cvsroot/src/sys/dist/pf/net/pfvar.h,v retrieving revision 1.14 diff -u -r1.14 pfvar.h --- sys/dist/pf/net/pfvar.h 4 Mar 2007 06:02:59 -0000 1.14 +++ sys/dist/pf/net/pfvar.h 15 May 2007 08:38:21 -0000 @@ -523,6 +523,7 @@ char match_tagname[PF_TAG_NAME_SIZE]; char overload_tblname[PF_TABLE_NAME_SIZE]; + char oper_tblname[PF_TABLE_NAME_SIZE]; TAILQ_ENTRY(pf_rule) entries; struct pf_pool rpool; @@ -593,6 +594,14 @@ #define PF_FLUSH 0x01 #define PF_FLUSH_GLOBAL 0x02 u_int8_t flush; + +#define PF_TOPER_NONE 0 +#define PF_TOPER_ADD_SOURCE 1 +#define PF_TOPER_DEL_SOURCE 2 +#define PF_TOPER_ADD_DEST 3 +#define PF_TOPER_DEL_DEST 4 + u_int8_t opert; + struct pfr_ktable *oper_tbl; }; /* rule flags */ @@ -604,6 +613,7 @@ #define PFRULE_NOSYNC 0x0010 #define PFRULE_SRCTRACK 0x0020 /* track source states */ #define PFRULE_RULESRCTRACK 0x0040 /* per rule */ +#define PFRULE_RETURNSYNACK 0x0080 /* scrub flags */ #define PFRULE_NODF 0x0100 @@ -1530,6 +1540,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); +int pfr_remove_kentry(struct pfr_ktable *, struct pfr_addr *); 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 *, Index: dist/pf/sbin/pfctl/parse.y =================================================================== RCS file: /cvsroot/src/dist/pf/sbin/pfctl/parse.y,v retrieving revision 1.7 diff -u -r1.7 parse.y --- dist/pf/sbin/pfctl/parse.y 27 Sep 2006 15:35:12 -0000 1.7 +++ dist/pf/sbin/pfctl/parse.y 15 May 2007 08:38:21 -0000 @@ -152,6 +152,11 @@ struct node_state_opt *tail; }; +struct node_operule { + u_int8_t opert; + char tblname[PF_TABLE_NAME_SIZE]; +}; + struct peer { struct node_host *host; struct node_port *port; @@ -337,6 +342,7 @@ int b; int t; } range; + struct node_operule *operule; struct node_if *interface; struct node_proto *proto; struct node_icmp *icmp; @@ -397,7 +403,7 @@ %} %token PASS BLOCK SCRUB RETURN IN OS OUT LOG LOGALL QUICK ON FROM TO FLAGS -%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE +%token RETURNRST RETURNICMP RETURNICMP6 RETURNSYNACK PROTO INET INET6 ALL ANY ICMPTYPE %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL %token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE @@ -412,6 +418,7 @@ %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH %token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY ROUTE +%token ADDSRC DELSRC ADDDST DELDST %token STRING %token PORTBINARY %type interface if_list if_item_not if_item @@ -457,6 +464,7 @@ %type table_opts table_opt table_opts_l %type pool_opts pool_opt pool_opts_l %type tagged +%type opertype %% ruleset : /* empty */ @@ -1495,7 +1503,7 @@ ; pfrule : action dir logquick interface route af proto fromto - filter_opts + filter_opts opertype { struct pf_rule r; struct node_state_opt *o; @@ -1524,6 +1532,10 @@ r.return_icmp = $1.w; r.return_icmp6 = $1.w2; break; + case PFRULE_RETURNSYNACK: + r.rule_flag |= PFRULE_RETURNSYNACK; + r.return_ttl = $1.w; + break; } r.direction = $2; r.log = $3.log; @@ -1577,6 +1589,10 @@ } r.tos = $9.tos; + if ($10 && $10->opert) { + r.opert = $10->opert; + strlcpy(r.oper_tblname, $10->tblname, PF_TABLE_NAME_SIZE); + } r.keep_state = $9.keep.action; o = $9.keep.options; while (o) { @@ -1973,6 +1989,20 @@ $$.w = $4; $$.w2 = 0; } + | RETURNSYNACK { + $$.b2 = PFRULE_RETURNSYNACK; + $$.w = 0; + $$.w2 = 0; + } + | RETURNSYNACK '(' TTL number ')' { + if ($4 > 255) { + yyerror("illegal ttl value %d", $4); + YYERROR; + } + $$.b2 = PFRULE_RETURNSYNACK; + $$.w = $4; + $$.w2 = 0; + } | RETURNICMP { $$.b2 = PFRULE_RETURNICMP; $$.w = returnicmpdefault; @@ -2827,6 +2857,34 @@ } ; +opertype : ADDSRC STRING { + $$ = calloc(1, sizeof(struct node_operule)); + strlcpy($$->tblname, $2, PF_TABLE_NAME_SIZE); + $$->opert = PF_TOPER_ADD_SOURCE; + free($2); + } + | ADDDST STRING { + $$ = calloc(1, sizeof(struct node_operule)); + strlcpy($$->tblname, $2, PF_TABLE_NAME_SIZE); + $$->opert = PF_TOPER_ADD_DEST; + free($2); + } + | DELSRC STRING { + $$ = calloc(1, sizeof(struct node_operule)); + strlcpy($$->tblname, $2, PF_TABLE_NAME_SIZE); + $$->opert = PF_TOPER_DEL_SOURCE; + free($2); + } + | DELDST STRING { + $$ = calloc(1, sizeof(struct node_operule)); + strlcpy($$->tblname, $2, PF_TABLE_NAME_SIZE); + $$->opert = PF_TOPER_DEL_DEST; + free($2); + } + | /* empty */ { + $$ = NULL; } + ; + sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } @@ -3787,6 +3845,10 @@ yyerror("return-rst can only be applied to TCP rules"); problems++; } + if (r->rule_flag & PFRULE_RETURNSYNACK && r->proto != IPPROTO_TCP) { + yyerror("return-sa can only be applied to TCP rules"); + problems++; + } if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { yyerror("max-src-nodes requires 'source-track rule'"); problems++; @@ -4575,6 +4637,8 @@ { /* this has to be sorted always */ static const struct keywords keywords[] = { + { "add-dst", ADDDST}, + { "add-src", ADDSRC}, { "all", ALL}, { "allow-opts", ALLOWOPTS}, { "altq", ALTQ}, @@ -4591,6 +4655,8 @@ { "code", CODE}, { "crop", FRAGCROP}, { "debug", DEBUG}, + { "del-dst", DELDST}, + { "del-src", DELSRC}, { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, @@ -4662,6 +4728,7 @@ { "return-icmp", RETURNICMP}, { "return-icmp6", RETURNICMP6}, { "return-rst", RETURNRST}, + { "return-sa", RETURNSYNACK}, { "round-robin", ROUNDROBIN}, { "route", ROUTE}, { "route-to", ROUTETO}, Index: dist/pf/sbin/pfctl/pfctl_parser.c =================================================================== RCS file: /cvsroot/src/dist/pf/sbin/pfctl/pfctl_parser.c,v retrieving revision 1.9 diff -u -r1.9 pfctl_parser.c --- dist/pf/sbin/pfctl/pfctl_parser.c 3 Jul 2006 20:26:19 -0000 1.9 +++ dist/pf/sbin/pfctl/pfctl_parser.c 15 May 2007 08:38:21 -0000 @@ -711,6 +711,11 @@ printf(" return-rst"); else printf(" return-rst(ttl %d)", r->return_ttl); + } else if (r->rule_flag & PFRULE_RETURNSYNACK) { + if (!r->return_ttl) + printf(" return-sa"); + else + printf(" return-sa(ttl %d)", r->return_ttl); } else if (r->rule_flag & PFRULE_RETURNICMP) { const struct icmpcodeent *ic, *ic6; @@ -765,6 +770,24 @@ else printf(" on %s", r->ifname); } + switch (r->opert) { + case PF_TOPER_ADD_SOURCE: + printf(" add-src to <%s>", + r->oper_tblname); + break; + case PF_TOPER_DEL_SOURCE: + printf(" del-src from <%s>", + r->oper_tblname); + break; + case PF_TOPER_ADD_DEST: + printf(" add-dst to <%s>", + r->oper_tblname); + break; + case PF_TOPER_DEL_DEST: + printf(" del-dst from <%s>", + r->oper_tblname); + } + if (r->rt) { if (r->rt == PF_ROUTETO) printf(" route-to");