summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netpfil/pf/pf.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netpfil/pf/pf.c')
-rw-r--r--freebsd/sys/netpfil/pf/pf.c206
1 files changed, 115 insertions, 91 deletions
diff --git a/freebsd/sys/netpfil/pf/pf.c b/freebsd/sys/netpfil/pf/pf.c
index 3cc4ff11..f765350d 100644
--- a/freebsd/sys/netpfil/pf/pf.c
+++ b/freebsd/sys/netpfil/pf/pf.c
@@ -137,7 +137,7 @@ VNET_DEFINE(int, pf_tcp_iss_off);
VNET_DECLARE(int, pf_vnet_active);
#define V_pf_vnet_active VNET(pf_vnet_active)
-static VNET_DEFINE(uint32_t, pf_purge_idx);
+VNET_DEFINE_STATIC(uint32_t, pf_purge_idx);
#define V_pf_purge_idx VNET(pf_purge_idx)
/*
@@ -161,7 +161,7 @@ struct pf_send_entry {
};
STAILQ_HEAD(pf_send_head, pf_send_entry);
-static VNET_DEFINE(struct pf_send_head, pf_sendqueue);
+VNET_DEFINE_STATIC(struct pf_send_head, pf_sendqueue);
#define V_pf_sendqueue VNET(pf_sendqueue)
static struct mtx pf_sendqueue_mtx;
@@ -181,9 +181,9 @@ struct pf_overload_entry {
};
SLIST_HEAD(pf_overload_head, pf_overload_entry);
-static VNET_DEFINE(struct pf_overload_head, pf_overloadqueue);
+VNET_DEFINE_STATIC(struct pf_overload_head, pf_overloadqueue);
#define V_pf_overloadqueue VNET(pf_overloadqueue)
-static VNET_DEFINE(struct task, pf_overloadtask);
+VNET_DEFINE_STATIC(struct task, pf_overloadtask);
#define V_pf_overloadtask VNET(pf_overloadtask)
static struct mtx pf_overloadqueue_mtx;
@@ -197,7 +197,7 @@ struct mtx pf_unlnkdrules_mtx;
MTX_SYSINIT(pf_unlnkdrules_mtx, &pf_unlnkdrules_mtx, "pf unlinked rules",
MTX_DEF);
-static VNET_DEFINE(uma_zone_t, pf_sources_z);
+VNET_DEFINE_STATIC(uma_zone_t, pf_sources_z);
#define V_pf_sources_z VNET(pf_sources_z)
uma_zone_t pf_mtag_z;
VNET_DEFINE(uma_zone_t, pf_state_z);
@@ -297,14 +297,14 @@ static void pf_mtag_free(struct m_tag *);
#ifdef INET
static void pf_route(struct mbuf **, struct pf_rule *, int,
struct ifnet *, struct pf_state *,
- struct pf_pdesc *);
+ struct pf_pdesc *, struct inpcb *);
#endif /* INET */
#ifdef INET6
static void pf_change_a6(struct pf_addr *, u_int16_t *,
struct pf_addr *, u_int8_t);
static void pf_route6(struct mbuf **, struct pf_rule *, int,
struct ifnet *, struct pf_state *,
- struct pf_pdesc *);
+ struct pf_pdesc *, struct inpcb *);
#endif /* INET6 */
int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
@@ -1721,24 +1721,28 @@ pf_purge_expired_states(u_int i, int maxcheck)
while (maxcheck > 0) {
ih = &V_pf_idhash[i];
+
+ /* only take the lock if we expect to do work */
+ if (!LIST_EMPTY(&ih->states)) {
relock:
- PF_HASHROW_LOCK(ih);
- LIST_FOREACH(s, &ih->states, entry) {
- if (pf_state_expires(s) <= time_uptime) {
- V_pf_status.states -=
- pf_unlink_state(s, PF_ENTER_LOCKED);
- goto relock;
+ PF_HASHROW_LOCK(ih);
+ LIST_FOREACH(s, &ih->states, entry) {
+ if (pf_state_expires(s) <= time_uptime) {
+ V_pf_status.states -=
+ pf_unlink_state(s, PF_ENTER_LOCKED);
+ goto relock;
+ }
+ s->rule.ptr->rule_flag |= PFRULE_REFS;
+ if (s->nat_rule.ptr != NULL)
+ s->nat_rule.ptr->rule_flag |= PFRULE_REFS;
+ if (s->anchor.ptr != NULL)
+ s->anchor.ptr->rule_flag |= PFRULE_REFS;
+ s->kif->pfik_flags |= PFI_IFLAG_REFS;
+ if (s->rt_kif)
+ s->rt_kif->pfik_flags |= PFI_IFLAG_REFS;
}
- s->rule.ptr->rule_flag |= PFRULE_REFS;
- if (s->nat_rule.ptr != NULL)
- s->nat_rule.ptr->rule_flag |= PFRULE_REFS;
- if (s->anchor.ptr != NULL)
- s->anchor.ptr->rule_flag |= PFRULE_REFS;
- s->kif->pfik_flags |= PFI_IFLAG_REFS;
- if (s->rt_kif)
- s->rt_kif->pfik_flags |= PFI_IFLAG_REFS;
+ PF_HASHROW_UNLOCK(ih);
}
- PF_HASHROW_UNLOCK(ih);
/* Return when we hit end of hash. */
if (++i > pf_hashmask) {
@@ -2501,6 +2505,81 @@ pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
pf_send(pfse);
}
+static void
+pf_return(struct pf_rule *r, struct pf_rule *nr, struct pf_pdesc *pd,
+ struct pf_state_key *sk, int off, struct mbuf *m, struct tcphdr *th,
+ struct pfi_kif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen,
+ u_short *reason)
+{
+ struct pf_addr * const saddr = pd->src;
+ struct pf_addr * const daddr = pd->dst;
+ sa_family_t af = pd->af;
+
+ /* undo NAT changes, if they have taken place */
+ if (nr != NULL) {
+ PF_ACPY(saddr, &sk->addr[pd->sidx], af);
+ PF_ACPY(daddr, &sk->addr[pd->didx], af);
+ if (pd->sport)
+ *pd->sport = sk->port[pd->sidx];
+ if (pd->dport)
+ *pd->dport = sk->port[pd->didx];
+ if (pd->proto_sum)
+ *pd->proto_sum = bproto_sum;
+ if (pd->ip_sum)
+ *pd->ip_sum = bip_sum;
+ m_copyback(m, off, hdrlen, pd->hdr.any);
+ }
+ if (pd->proto == IPPROTO_TCP &&
+ ((r->rule_flag & PFRULE_RETURNRST) ||
+ (r->rule_flag & PFRULE_RETURN)) &&
+ !(th->th_flags & TH_RST)) {
+ u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
+ int len = 0;
+#ifdef INET
+ struct ip *h4;
+#endif
+#ifdef INET6
+ struct ip6_hdr *h6;
+#endif
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ h4 = mtod(m, struct ip *);
+ len = ntohs(h4->ip_len) - off;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ h6 = mtod(m, struct ip6_hdr *);
+ len = ntohs(h6->ip6_plen) - (off - sizeof(*h6));
+ break;
+#endif
+ }
+
+ if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af))
+ REASON_SET(reason, PFRES_PROTCKSUM);
+ else {
+ if (th->th_flags & TH_SYN)
+ ack++;
+ if (th->th_flags & TH_FIN)
+ ack++;
+ pf_send_tcp(m, 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, kif->pfik_ifp);
+ }
+ } else if (pd->proto != IPPROTO_ICMP && af == AF_INET &&
+ r->return_icmp)
+ pf_send_icmp(m, r->return_icmp >> 8,
+ r->return_icmp & 255, af, r);
+ else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 &&
+ r->return_icmp6)
+ pf_send_icmp(m, r->return_icmp6 >> 8,
+ r->return_icmp6 & 255, af, r);
+}
+
+
static int
pf_ieee8021q_setpcp(struct mbuf *m, u_int8_t prio)
{
@@ -3475,68 +3554,8 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
((r->rule_flag & PFRULE_RETURNRST) ||
(r->rule_flag & PFRULE_RETURNICMP) ||
(r->rule_flag & PFRULE_RETURN))) {
- /* undo NAT changes, if they have taken place */
- if (nr != NULL) {
- PF_ACPY(saddr, &sk->addr[pd->sidx], af);
- PF_ACPY(daddr, &sk->addr[pd->didx], af);
- if (pd->sport)
- *pd->sport = sk->port[pd->sidx];
- if (pd->dport)
- *pd->dport = sk->port[pd->didx];
- if (pd->proto_sum)
- *pd->proto_sum = bproto_sum;
- if (pd->ip_sum)
- *pd->ip_sum = bip_sum;
- m_copyback(m, off, hdrlen, pd->hdr.any);
- }
- if (pd->proto == IPPROTO_TCP &&
- ((r->rule_flag & PFRULE_RETURNRST) ||
- (r->rule_flag & PFRULE_RETURN)) &&
- !(th->th_flags & TH_RST)) {
- u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
- int len = 0;
-#ifdef INET
- struct ip *h4;
-#endif
-#ifdef INET6
- struct ip6_hdr *h6;
-#endif
-
- switch (af) {
-#ifdef INET
- case AF_INET:
- h4 = mtod(m, struct ip *);
- len = ntohs(h4->ip_len) - off;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- h6 = mtod(m, struct ip6_hdr *);
- len = ntohs(h6->ip6_plen) - (off - sizeof(*h6));
- break;
-#endif
- }
-
- if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af))
- REASON_SET(&reason, PFRES_PROTCKSUM);
- else {
- if (th->th_flags & TH_SYN)
- ack++;
- if (th->th_flags & TH_FIN)
- ack++;
- pf_send_tcp(m, 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, kif->pfik_ifp);
- }
- } else if (pd->proto != IPPROTO_ICMP && af == AF_INET &&
- r->return_icmp)
- pf_send_icmp(m, r->return_icmp >> 8,
- r->return_icmp & 255, af, r);
- else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 &&
- r->return_icmp6)
- pf_send_icmp(m, r->return_icmp6 >> 8,
- r->return_icmp6 & 255, af, r);
+ pf_return(r, nr, pd, sk, off, m, th, kif, bproto_sum,
+ bip_sum, hdrlen, &reason);
}
if (r->action == PF_DROP)
@@ -3555,8 +3574,13 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off,
sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum,
hdrlen);
- if (action != PF_PASS)
+ if (action != PF_PASS) {
+ if (action == PF_DROP &&
+ (r->rule_flag & PFRULE_RETURN))
+ pf_return(r, nr, pd, sk, off, m, th, kif,
+ bproto_sum, bip_sum, hdrlen, &reason);
return (action);
+ }
} else {
if (sk != NULL)
uma_zfree(V_pf_state_key_z, sk);
@@ -5454,7 +5478,7 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif,
#ifdef INET
static void
pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
- struct pf_state *s, struct pf_pdesc *pd)
+ struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp)
{
struct mbuf *m0, *m1;
struct sockaddr_in dst;
@@ -5522,7 +5546,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test(PF_OUT, 0, ifp, &m0, NULL) != PF_PASS)
+ if (pf_test(PF_OUT, 0, ifp, &m0, inp) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
@@ -5615,7 +5639,7 @@ bad:
#ifdef INET6
static void
pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
- struct pf_state *s, struct pf_pdesc *pd)
+ struct pf_state *s, struct pf_pdesc *pd, struct inpcb *inp)
{
struct mbuf *m0;
struct sockaddr_in6 dst;
@@ -5684,7 +5708,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
if (oifp != ifp) {
- if (pf_test6(PF_OUT, PFIL_FWD, ifp, &m0, NULL) != PF_PASS)
+ if (pf_test6(PF_OUT, PFIL_FWD, ifp, &m0, inp) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
@@ -6248,7 +6272,7 @@ done:
default:
/* pf_route() returns unlocked. */
if (r->rt) {
- pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
+ pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp);
return (action);
}
break;
@@ -6645,7 +6669,7 @@ done:
default:
/* pf_route6() returns unlocked. */
if (r->rt) {
- pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd);
+ pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp);
return (action);
}
break;