diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 022df483f2c0c..a0682b685be79 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -448,7 +448,7 @@ int parseport(char *, struct range *r, int); %} -%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS +%token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS %token RETURNRST RETURNICMP RETURNICMP6 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 SCHEDULE @@ -2625,6 +2625,7 @@ probability : STRING { action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } + | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; } | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } ; @@ -5540,6 +5541,7 @@ lookup(char *s) { "load", LOAD}, { "log", LOG}, { "loginterface", LOGINTERFACE}, + { "match", MATCH}, { "max", MAXIMUM}, { "max-mss", MAXMSS}, { "max-src-conn", MAXSRCCONN}, diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index d17edde19053b..51e1af75020e3 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -692,7 +692,9 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) if (verbose) printf("@%d ", r->nr); - if (r->action > PF_NORDR) + if (r->action == PF_MATCH) + printf("match"); + else if (r->action > PF_NORDR) printf("action(%d)", r->action); else if (anchor_call[0]) { if (anchor_call[0] == '_') { diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 71467227a5dd4..aa8eb595743c9 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -468,6 +468,13 @@ struct pf_osfp_ioctl { int fp_getnum; /* DIOCOSFPGET number */ }; +struct pf_rule_actions { + u_int16_t qid; + u_int16_t pqid; + u_int32_t pdnpipe; + u_int32_t dnpipe; + u_int8_t flags; +}; union pf_rule_ptr { struct pf_rule *ptr; @@ -524,8 +531,8 @@ struct pf_rule { u_int32_t limit; u_int32_t seconds; } max_src_conn_rate; - u_int32_t qid; - u_int32_t pqid; + u_int16_t qid; + u_int16_t pqid; u_int32_t dnpipe; u_int32_t pdnpipe; #define PFRULE_DN_IS_PIPE 0x00000010 @@ -767,6 +774,10 @@ struct pf_state { u_int32_t creation; u_int32_t expire; u_int32_t pfsync_time; + u_int16_t qid; + u_int16_t pqid; + u_int32_t pdnpipe; + u_int32_t dnpipe; u_int16_t tag; u_int8_t log; u_int8_t state_flags; @@ -1138,6 +1149,7 @@ struct pf_pdesc { u_int16_t *sport; u_int16_t *dport; struct pf_mtag *pf_mtag; + struct pf_rule_actions act; u_int32_t p_len; /* total length of payload */ diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 26f18fb005e05..2ee8c3baa361a 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -230,6 +230,8 @@ static int pf_state_key_attach(struct pf_state_key *, static void pf_state_key_detach(struct pf_state *, int); static int pf_state_key_ctor(void *, int, void *, int); static u_int32_t pf_tcp_iss(struct pf_pdesc *); +void pf_rule_to_actions(struct pf_rule *, + struct pf_rule_actions *); static int pf_test_rule(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, struct pf_pdesc *, struct pf_rule **, @@ -2991,6 +2993,21 @@ pf_addr_inc(struct pf_addr *addr, sa_family_t af) } #endif /* INET6 */ +void +pf_rule_to_actions(struct pf_rule *r, struct pf_rule_actions *a) +{ + if (r->qid) + a->qid = r->qid; + if (r->pqid) + a->pqid = r->pqid; + if (r->pdnpipe) + a->pdnpipe = r->pdnpipe; + if (r->dnpipe) + a->dnpipe = r->dnpipe; + if (r->free_flags & PFRULE_DN_IS_PIPE) + a->flags |= PFRULE_DN_IS_PIPE; +} + int pf_socket_lookup(int direction, struct pf_pdesc *pd, struct mbuf *m) { @@ -3503,10 +3520,20 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->rtableid >= 0) rtableid = r->rtableid; if (r->anchor == NULL) { - match = 1; - *rm = r; - *am = a; - *rsm = ruleset; + if (r->action == PF_MATCH) { + r->packets[direction == PF_OUT]++; + r->bytes[direction == PF_OUT] += pd->tot_len; + pf_rule_to_actions(r, &pd->act); + if (r->log) + PFLOG_PACKET(kif, m, af, + direction, PFRES_MATCH, r, + a, ruleset, pd, 1); + } else { + match = 1; + *rm = r; + *am = a; + *rsm = ruleset; + } if ((*rm)->quick) break; r = TAILQ_NEXT(r, entries); @@ -3525,6 +3552,9 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); + /* apply actions for last matching pass/block rule */ + pf_rule_to_actions(r, &pd->act); + if (r->log || (nr != NULL && nr->log)) { if (rewrite) m_copyback(m, off, hdrlen, pd->hdr.any); @@ -3698,6 +3728,11 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, s->state_flags |= PFSTATE_SLOPPY; s->log = r->log & PF_LOG_ALL; s->sync_state = PFSYNC_S_NONE; + s->qid = pd->act.qid; + s->pqid = pd->act.pqid; + s->pdnpipe = pd->act.pdnpipe; + s->dnpipe = pd->act.dnpipe; + s->state_flags |= pd->act.flags; if (nr != NULL) s->log |= nr->log & PF_LOG_ALL; switch (pd->proto) { @@ -3959,10 +3994,20 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, r = TAILQ_NEXT(r, entries); else { if (r->anchor == NULL) { - match = 1; - *rm = r; - *am = a; - *rsm = ruleset; + if (r->action == PF_MATCH) { + r->packets[direction == PF_OUT]++; + r->bytes[direction == PF_OUT] += pd->tot_len; + pf_rule_to_actions(r, &pd->act); + if (r->log) + PFLOG_PACKET(kif, m, af, + direction, PFRES_MATCH, r, + a, ruleset, pd, 1); + } else { + match = 1; + *rm = r; + *am = a; + *rsm = ruleset; + } if ((*rm)->quick) break; r = TAILQ_NEXT(r, entries); @@ -3981,6 +4026,9 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, REASON_SET(&reason, PFRES_MATCH); + /* apply actions for last matching pass/block rule */ + pf_rule_to_actions(r, &pd->act); + if (r->log) PFLOG_PACKET(kif, m, af, direction, reason, r, a, ruleset, pd, 1); @@ -6308,6 +6356,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) M_SETFIB(m, r->rtableid); #ifdef ALTQ + if (s && s->qid) { + pd.act.pqid = s->pqid; + pd.act.qid = s->qid; + } else if (r->qid) { + pd.act.pqid = r->pqid; + pd.act.qid = r->qid; + } if (action == PF_PASS && r->qid) { if (pd.pf_mtag == NULL && ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { @@ -6332,15 +6387,25 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) action = PF_DROP; REASON_SET(&reason, PFRES_MEMORY); } - if (r->dnpipe && ip_dn_io_ptr != NULL && loopedfrom != 1) { - if (dir != r->direction && r->pdnpipe) { - dnflow.rule.info = r->pdnpipe; + if (s && (s->dnpipe || s->pdnpipe)) { + pd.act.dnpipe = s->dnpipe; + pd.act.pdnpipe = s->pdnpipe; + pd.act.flags = s->state_flags; + } else if (r->dnpipe || r->pdnpipe) { + pd.act.dnpipe = r->dnpipe; + pd.act.dnpipe = r->pdnpipe; + pd.act.flags = r->free_flags; + } + + if (pd.act.dnpipe && ip_dn_io_ptr != NULL && loopedfrom != 1) { + if (dir != r->direction && pd.act.pdnpipe) { + dnflow.rule.info = pd.act.pdnpipe; } else if (dir == r->direction) { - dnflow.rule.info = r->dnpipe; + dnflow.rule.info = pd.act.dnpipe; } else goto continueprocessing; - if (r->free_flags & PFRULE_DN_IS_PIPE) + if (pd.act.flags & PFRULE_DN_IS_PIPE) dnflow.rule.info |= IPFW_IS_PIPE; dnflow.f_id.addr_type = 4; /* IPv4 type */ dnflow.f_id.proto = pd.proto; @@ -6835,7 +6900,14 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) M_SETFIB(m, r->rtableid); #ifdef ALTQ - if (action == PF_PASS && r->qid) { + if (s && s->qid) { + pd.act.pqid = s->pqid; + pd.act.qid = s->qid; + } else if (r->qid) { + pd.act.pqid = r->pqid; + pd.act.qid = r->qid; + } + if (action == PF_PASS && pd.act.qid) { if (pd.pf_mtag == NULL && ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { action = PF_DROP; @@ -6844,9 +6916,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) if (s != NULL) pd.pf_mtag->qid_hash = pf_state_hash(s); if (pd.tos & IPTOS_LOWDELAY) - pd.pf_mtag->qid = r->pqid; + pd.pf_mtag->qid = pd.act.pqid; else - pd.pf_mtag->qid = r->qid; + pd.pf_mtag->qid = pd.act.qid; /* Add hints for ecn. */ pd.pf_mtag->hdr = h; } @@ -6858,15 +6930,25 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp) action = PF_DROP; REASON_SET(&reason, PFRES_MEMORY); } - if (r->dnpipe && ip_dn_io_ptr != NULL && loopedfrom != 1) { - if (dir != r->direction && r->pdnpipe) { - dnflow.rule.info = r->pdnpipe; - } else if (dir == r->direction) { - dnflow.rule.info = r->dnpipe; + if (s && (s->dnpipe || s->pdnpipe)) { + pd.act.dnpipe = s->dnpipe; + pd.act.pdnpipe = s->pdnpipe; + pd.act.flags = s->state_flags; + } else if (r->dnpipe || r->pdnpipe) { + pd.act.dnpipe = r->dnpipe; + pd.act.dnpipe = r->pdnpipe; + pd.act.flags = r->free_flags; + } + if ((pd.act.dnpipe || pd.act.pdnpipe) && + ip_dn_io_ptr != NULL && loopedfrom != 1) { + if (dir != r->direction && pd.act.pdnpipe) { + dnflow.rule.info = pd.act.pdnpipe; + } else if (dir == r->direction && pd.act.dnpipe) { + dnflow.rule.info = pd.act.dnpipe; } else goto continueprocessing6; - if (r->free_flags & PFRULE_DN_IS_PIPE) + if (pd.act.flags & PFRULE_DN_IS_PIPE) dnflow.rule.info |= IPFW_IS_PIPE; dnflow.f_id.addr_type = 6; /* IPv4 type */ dnflow.f_id.proto = pd.proto; diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h index ac0e0fb983e2a..16e60eb09101e 100644 --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -45,7 +45,8 @@ enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD }; enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT, - PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER }; + PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER, + PF_MATCH }; enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT, PF_RULESET_BINAT, PF_RULESET_RDR, PF_RULESET_MAX }; enum { PF_OP_NONE, PF_OP_IRG, PF_OP_EQ, PF_OP_NE, PF_OP_LT, diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c index 61da586fbdd93..5bb3be60ff9cc 100644 --- a/sys/netpfil/pf/pf_ruleset.c +++ b/sys/netpfil/pf/pf_ruleset.c @@ -121,6 +121,7 @@ pf_get_ruleset_number(u_int8_t action) return (PF_RULESET_SCRUB); break; case PF_PASS: + case PF_MATCH: case PF_DROP: return (PF_RULESET_FILTER); break;