those freaking code pathes for stateless are annoying as hell and tend
to be buggy since everybody does stateful anyway...
so here's the deal: always get us a state back when we actually pass
the packet, but don't link it into the state table. late in pf_test
throw it away if we want stateless. makes things easier and allows for
some future simplifications (yes, i marked some in this diff to not
forget)
speaking of forgetting: anakin main tree
Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.713
diff -u -p -r1.713 pf.c
--- pf.c 24 Sep 2010 02:28:10 -0000 1.713
+++ pf.c 24 Sep 2010 08:52:38 -0000
@@ -1200,7 +1200,7 @@ pf_free_state(struct pf_state *cur)
if (pfsync_state_in_use(cur))
return;
#endif
- KASSERT(cur->timeout == PFTM_UNLINKED);
+ KASSERT(cur->timeout == PFTM_UNLINKED || cur->key[PF_SK_STACK] == NULL);
if (--cur->rule.ptr->states_cur <= 0 &&
cur->rule.ptr->src_nodes <= 0)
pf_rm_rule(NULL, cur->rule.ptr);
@@ -1215,8 +1215,10 @@ pf_free_state(struct pf_state *cur)
pool_put(&pf_rule_item_pl, ri);
}
pf_normalize_tcp_cleanup(cur);
- pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
- TAILQ_REMOVE(&state_list, cur, entry_list);
+ if (cur->key[PF_SK_STACK] != NULL) {
+ pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
+ TAILQ_REMOVE(&state_list, cur, entry_list);
+ }
if (cur->tag)
pf_tag_unref(cur->tag);
pool_put(&pf_state_pl, cur);
@@ -2789,7 +2791,7 @@ pf_test_rule(struct pf_rule **rm, struct
int tag = -1;
int asd = 0;
int match = 0;
- int state_icmp = 0, icmp_dir, multi;
+ int state_icmp = 0, icmp_dir, multi, action;
u_int16_t virtual_type, virtual_id;
u_int8_t icmptype = 0, icmpcode = 0;
@@ -3033,46 +3035,37 @@ pf_test_rule(struct pf_rule **rm, struct
if (r->action == PF_DROP)
goto cleanup;
- if (pf_tag_packet(m, tag, act.rtableid)) {
+ if (pf_tag_packet(m, tag, act.rtableid)) { /* XXX kill */
REASON_SET(&reason, PFRES_MEMORY);
goto cleanup;
}
- if (act.rtableid >= 0 &&
+ if (act.rtableid >= 0 && /* XXX kill */
rtable_l2(act.rtableid) != pd->rdomain)
pd->destchg = 1;
+ if (state_icmp || !r->keep_state)
+ act.fake_state = 1;
+ if (!act.fake_state && r->rule_flag & PFRULE_SRCTRACK &&
+ pf_insert_src_node(&sns[PF_SN_NONE], r, PF_SN_NONE, pd->af,
+ pd->src, NULL, 0) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
+ goto cleanup;
+ }
- if (!state_icmp && r->keep_state) {
- int action;
-
- if (r->rule_flag & PFRULE_SRCTRACK &&
- pf_insert_src_node(&sns[PF_SN_NONE], r, PF_SN_NONE, pd->af,
- pd->src, NULL, 0) != 0) {
- REASON_SET(&reason, PFRES_SRCLIMIT);
- goto cleanup;
- }
-
- action = pf_create_state(r, a, pd, &skw, &sks, m, off,
- &rewrite, kif, sm, tag, hdrlen, &rules, &act, sns);
-
- if (action != PF_PASS)
+ if ((action = pf_create_state(r, a, pd, &skw, &sks, m, off, &rewrite,
+ kif, sm, tag, hdrlen, &rules, &act, sns)) != PF_PASS)
return (action);
- if (sks != skw) {
- struct pf_state_key *sk;
+ /* XXX do the rewrite in pf_test */
+ if (!act.fake_state && sks != skw) {
+ struct pf_state_key *sk;
- if (pd->dir == PF_IN)
- sk = sks;
- else
- sk = skw;
- rewrite += pf_translate(pd,
- &sk->addr[pd->sidx], sk->port[pd->sidx],
- &sk->addr[pd->didx], sk->port[pd->didx],
- virtual_type, icmp_dir, m);
- }
- } else {
- while ((ri = SLIST_FIRST(&rules))) {
- SLIST_REMOVE_HEAD(&rules, entry);
- pool_put(&pf_rule_item_pl, ri);
- }
+ if (pd->dir == PF_IN)
+ sk = sks;
+ else
+ sk = skw;
+ rewrite += pf_translate(pd,
+ &sk->addr[pd->sidx], sk->port[pd->sidx],
+ &sk->addr[pd->didx], sk->port[pd->didx],
+ virtual_type, icmp_dir, m);
}
/* copy back packet headers if we performed NAT operations */
@@ -3080,8 +3073,8 @@ pf_test_rule(struct pf_rule **rm, struct
m_copyback(m, off, hdrlen, pd->hdr.any, M_NOWAIT);
#if NPFSYNC > 0
- if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) &&
- direction == PF_OUT && pfsync_up()) {
+ if (!act.fake_state && *sm != NULL && direction == PF_OUT &&
+ pfsync_up() && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC)) {
/*
* We want the state created, but we dont
* want to send this in case a partner
@@ -3222,6 +3215,11 @@ pf_create_state(struct pf_rule *r, struc
}
s->direction = pd->dir;
+ if (act->fake_state) {
+ *sm = s;
+ return (PF_PASS);
+ }
+
if (pf_state_key_setup(pd, skw, sks, act->rtableid)) {
REASON_SET(&reason, PFRES_MEMORY);
goto csfailed;
@@ -5826,16 +5824,17 @@ int
pf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
struct ether_header *eh)
{
- struct pfi_kif *kif;
- u_short action, reason = 0, pflog = 0;
struct mbuf *m = *m0;
struct ip *h;
+ struct pfi_kif *kif;
+ struct pf_divert *divert;
struct pf_rule *a = NULL, *r = &pf_default_rule;
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, hdrlen;
u_int32_t qid, pqid = 0;
+ u_short action, reason = 0, pflog = 0;
if (!pf_status.running)
return (PF_PASS);
@@ -5919,11 +5918,8 @@ pf_test(int dir, struct ifnet *ifp, stru
action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ipintrq, hdrlen);
- if (s) {
- if (s->max_mss)
- pf_normalize_mss(m, off, &pd, s->max_mss);
- } else if (r->max_mss)
- pf_normalize_mss(m, off, &pd, r->max_mss);
+ if (s && s->max_mss)
+ pf_normalize_mss(m, off, &pd, s->max_mss);
break;
}
@@ -5982,69 +5978,57 @@ pf_test(int dir, struct ifnet *ifp, stru
}
done:
- if (action == PF_PASS && h->ip_hl > 5 &&
- !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_IPOPTIONS);
- pflog |= PF_LOG_FORCE;
- DPFPRINTF(LOG_NOTICE,
- "pf: dropping packet with ip options");
- }
-
- if (s) {
+ if (action == PF_PASS) {
+ if (h->ip_hl > 5 && !(s->state_flags & PFSTATE_ALLOWOPTS)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ pflog |= PF_LOG_FORCE;
+ DPFPRINTF(LOG_NOTICE,
+ "pf: dropping packet with ip options");
+ }
pf_scrub_ip(&m, s->state_flags, s->min_ttl, s->set_tos);
pf_tag_packet(m, s->tag, s->rtableid[pd.didx]);
if (pqid || (pd.tos & IPTOS_LOWDELAY))
qid = s->pqid;
else
qid = s->qid;
- } else {
- pf_scrub_ip(&m, r->scrub_flags, r->min_ttl, r->set_tos);
- if (pqid || (pd.tos & IPTOS_LOWDELAY))
- qid = r->pqid;
- else
- qid = r->qid;
- }
- if (dir == PF_IN && s && s->key[PF_SK_STACK])
- m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK];
+ if (dir == PF_IN && s->key[PF_SK_STACK])
+ m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK];
#ifdef ALTQ
- if (action == PF_PASS && qid) {
- m->m_pkthdr.pf.qid = qid;
- m->m_pkthdr.pf.hdr = h; /* hints for ecn */
- }
+ if (qid) {
+ m->m_pkthdr.pf.qid = qid;
+ m->m_pkthdr.pf.hdr = h; /* hints for ecn */
+ }
#endif /* ALTQ */
- /*
- * connections redirected to loopback should not match sockets
- * bound specifically to loopback due to security implications,
- * see tcp_input() and in_pcblookup_listen().
- */
- if (pd.destchg &&
- (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
- m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
- /* We need to redo the route lookup on outgoing routes. */
- if (pd.destchg && dir == PF_OUT)
- m->m_pkthdr.pf.flags |= PF_TAG_REROUTE;
-
- if (dir == PF_IN && action == PF_PASS && r->divert.port) {
- struct pf_divert *divert;
-
- if ((divert = pf_get_divert(m))) {
- m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED;
- divert->port = r->divert.port;
- divert->addr.ipv4 = r->divert.addr.v4;
+ /*
+ * connections redirected to loopback should not match sockets
+ * bound specifically to loopback due to security implications,
+ * see tcp_input() and in_pcblookup_listen().
+ */
+ if (pd.destchg && (ntohl(pd.dst->v4.s_addr) >>
+ IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+ m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
+ /* We need to redo the route lookup on outgoing routes. */
+ if (pd.destchg && dir == PF_OUT)
+ m->m_pkthdr.pf.flags |= PF_TAG_REROUTE;
+
+ if (dir == PF_IN && r->divert.port) {
+ if ((divert = pf_get_divert(m))) {
+ m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED;
+ divert->port = r->divert.port;
+ divert->addr.ipv4 = r->divert.addr.v4;
+ }
}
- }
-
- if (action == PF_PASS && r->divert_packet.port) {
- struct pf_divert *divert;
- if ((divert = pf_get_divert(m)))
- divert->port = r->divert_packet.port;
-
- action = PF_DIVERT;
+ if (r->divert_packet.port) {
+ struct pf_divert *divert;
+ if ((divert = pf_get_divert(m)))
+ divert->port = r->divert_packet.port;
+ action = PF_DIVERT;
+ }
}
if (pflog) {
@@ -6053,16 +6037,19 @@ done:
if (pflog & PF_LOG_FORCE || r->log & PF_LOG_ALL)
PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a,
ruleset, &pd);
- if (s) {
- SLIST_FOREACH(ri, &s->match_rules, entry)
- if (ri->r->log & PF_LOG_ALL)
- PFLOG_PACKET(kif, h, m, AF_INET, dir,
- reason, ri->r, a, ruleset, &pd);
- }
+ SLIST_FOREACH(ri, &s->match_rules, entry)
+ if (ri->r->log & PF_LOG_ALL)
+ PFLOG_PACKET(kif, h, m, AF_INET, dir,
+ reason, ri->r, a, ruleset, &pd);
}
pf_counters_inc(dir, action, &pd, kif, s, r, a);
+ if (s && s->key[PF_SK_STACK] == NULL) {
+ pf_free_state(s);
+ s = NULL;
+ }
+
switch (action) {
case PF_SYNPROXY_DROP:
m_freem(*m0);
@@ -6091,15 +6078,16 @@ int
pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
struct ether_header *eh)
{
- struct pfi_kif *kif;
- u_short action, reason = 0, pflog = 0;
struct mbuf *m = *m0, *n = NULL;
struct ip6_hdr *h;
+ struct pfi_kif *kif;
+ struct pf_divert *divert;
struct pf_rule *a = NULL, *r = &pf_default_rule;
struct pf_state *s = NULL;
struct pf_ruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, hdrlen;
+ u_short action, reason = 0, pflog = 0;
if (!pf_status.running)
return (PF_PASS);
@@ -6188,12 +6176,8 @@ pf_test6(int dir, struct ifnet *ifp, str
action = pf_test_rule(&r, &s, dir, kif,
m, off, h, &pd, &a, &ruleset, &ip6intrq, hdrlen);
- if (s) {
- if (s->max_mss)
- pf_normalize_mss(m, off, &pd, s->max_mss);
- } else if (r->max_mss)
- pf_normalize_mss(m, off, &pd, r->max_mss);
-
+ if (s && s->max_mss)
+ pf_normalize_mss(m, off, &pd, s->max_mss);
break;
}
@@ -6257,62 +6241,54 @@ done:
n = NULL;
}
- /* handle dangerous IPv6 extension headers. */
- if (action == PF_PASS && pd.rh_cnt &&
- !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
- action = PF_DROP;
- REASON_SET(&reason, PFRES_IPOPTIONS);
- pflog |= PF_LOG_FORCE;
- DPFPRINTF(LOG_NOTICE,
- "pf: dropping packet with dangerous v6 headers");
- }
-
- if (s)
+ if (action == PF_PASS) {
+ /* handle dangerous IPv6 extension headers. */
+ if (action == PF_PASS && pd.rh_cnt &&
+ !(s->state_flags & PFSTATE_ALLOWOPTS)) {
+ action = PF_DROP;
+ REASON_SET(&reason, PFRES_IPOPTIONS);
+ pflog |= PF_LOG_FORCE;
+ DPFPRINTF(LOG_NOTICE,
+ "pf: dropping packet with dangerous v6 headers");
+ }
pf_scrub_ip6(&m, s->min_ttl);
- else
- pf_scrub_ip6(&m, r->min_ttl);
+ if (s->tag)
+ pf_tag_packet(m, s->tag, s->rtableid[pd.didx]);
- if (s && s->tag)
- pf_tag_packet(m, s ? s->tag : 0, s->rtableid[pd.didx]);
-
- if (dir == PF_IN && s && s->key[PF_SK_STACK])
- m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK];
+ if (dir == PF_IN && s->key[PF_SK_STACK])
+ m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK];
#ifdef ALTQ
- if (action == PF_PASS && s && s->qid) {
- if (pd.tos & IPTOS_LOWDELAY)
- m->m_pkthdr.pf.qid = s->pqid;
- else
- m->m_pkthdr.pf.qid = s->qid;
- /* add hints for ecn */
- m->m_pkthdr.pf.hdr = h;
- }
+ if (s->qid) {
+ if (pd.tos & IPTOS_LOWDELAY)
+ m->m_pkthdr.pf.qid = s->pqid;
+ else
+ m->m_pkthdr.pf.qid = s->qid;
+ /* add hints for ecn */
+ m->m_pkthdr.pf.hdr = h;
+ }
#endif /* ALTQ */
- if (pd.destchg &&
- IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
- m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
- /* We need to redo the route lookup on outgoing routes. */
- if (pd.destchg && dir == PF_OUT)
- m->m_pkthdr.pf.flags |= PF_TAG_REROUTE;
-
- if (dir == PF_IN && action == PF_PASS && r->divert.port) {
- struct pf_divert *divert;
-
- if ((divert = pf_get_divert(m))) {
- m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED;
- divert->port = r->divert.port;
- divert->addr.ipv6 = r->divert.addr.v6;
+ if (pd.destchg &&
+ IN6_IS_ADDR_LOOPBACK(&pd.dst->v6))
+ m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST;
+ /* We need to redo the route lookup on outgoing routes. */
+ if (pd.destchg && dir == PF_OUT)
+ m->m_pkthdr.pf.flags |= PF_TAG_REROUTE;
+
+ if (dir == PF_IN && r->divert.port) {
+ if ((divert = pf_get_divert(m))) {
+ m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED;
+ divert->port = r->divert.port;
+ divert->addr.ipv6 = r->divert.addr.v6;
+ }
}
- }
-
- if (action == PF_PASS && r->divert_packet.port) {
- struct pf_divert *divert;
-
- if ((divert = pf_get_divert(m)))
- divert->port = r->divert_packet.port;
- action = PF_DIVERT;
+ if (r->divert_packet.port) {
+ if ((divert = pf_get_divert(m)))
+ divert->port = r->divert_packet.port;
+ action = PF_DIVERT;
+ }
}
if (pflog) {
@@ -6321,15 +6297,18 @@ done:
if (pflog & PF_LOG_FORCE || r->log & PF_LOG_ALL)
PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a,
ruleset, &pd);
- if (s) {
- SLIST_FOREACH(ri, &s->match_rules, entry)
- if (ri->r->log & PF_LOG_ALL)
- PFLOG_PACKET(kif, h, m, AF_INET6, dir,
- reason, ri->r, a, ruleset, &pd);
- }
+ SLIST_FOREACH(ri, &s->match_rules, entry)
+ if (ri->r->log & PF_LOG_ALL)
+ PFLOG_PACKET(kif, h, m, AF_INET6, dir,
+ reason, ri->r, a, ruleset, &pd);
}
pf_counters_inc(dir, action, &pd, kif, s, r, a);
+
+ if (s && s->key[PF_SK_STACK] == NULL) {
+ pf_free_state(s);
+ s = NULL;
+ }
switch (action) {
case PF_SYNPROXY_DROP:
Index: pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.315
diff -u -p -r1.315 pfvar.h
--- pfvar.h 22 Sep 2010 05:58:29 -0000 1.315
+++ pfvar.h 24 Sep 2010 08:52:38 -0000
@@ -527,7 +527,7 @@ struct pf_rule_actions {
u_int8_t log;
u_int8_t set_tos;
u_int8_t min_ttl;
- u_int8_t pad[1];
+ u_int8_t fake_state;
u_int16_t flags;
};