pf: store L4 headers in pf_pdesc

Rather than pointers to the headers store full copies. This brings us
slightly closer to what OpenBSD does, and also makes more sense than
storing pointers to stack variable copies of the headers.

Reviewed by:	donner, scottl
MFC after:	1 week
Sponsored by:	Rubicon Communications, LLC ("Netgate")
Differential Revision:	https://reviews.freebsd.org/D30719
This commit is contained in:
Kristof Provost 2021-06-04 10:52:07 +02:00
parent 8b5f4e692b
commit d38630f619
4 changed files with 95 additions and 110 deletions

View File

@ -51,6 +51,13 @@
#include <net/radix.h>
#include <netinet/in.h>
#ifdef _KERNEL
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#endif
#include <netpfil/pf/pf.h>
#include <netpfil/pf/pf_altq.h>
@ -907,14 +914,14 @@ struct pf_pdesc {
gid_t gid;
} lookup;
u_int64_t tot_len; /* Make Mickey money */
union {
struct tcphdr *tcp;
struct udphdr *udp;
struct icmp *icmp;
union pf_headers {
struct tcphdr tcp;
struct udphdr udp;
struct icmp icmp;
#ifdef INET6
struct icmp6_hdr *icmp6;
struct icmp6_hdr icmp6;
#endif /* INET6 */
void *any;
char any[0];
} hdr;
struct pf_krule *nat_rule; /* nat/rdr rule applied to packet */

View File

@ -3113,17 +3113,13 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd, struct mbuf *m)
switch (pd->proto) {
case IPPROTO_TCP:
if (pd->hdr.tcp == NULL)
return (-1);
sport = pd->hdr.tcp->th_sport;
dport = pd->hdr.tcp->th_dport;
sport = pd->hdr.tcp.th_sport;
dport = pd->hdr.tcp.th_dport;
pi = &V_tcbinfo;
break;
case IPPROTO_UDP:
if (pd->hdr.udp == NULL)
return (-1);
sport = pd->hdr.udp->uh_sport;
dport = pd->hdr.udp->uh_dport;
sport = pd->hdr.udp.uh_sport;
dport = pd->hdr.udp.uh_dport;
pi = &V_udbinfo;
break;
default:
@ -3313,8 +3309,8 @@ pf_tcp_iss(struct pf_pdesc *pd)
ctx = V_pf_tcp_secret_ctx;
MD5Update(&ctx, (char *)&pd->hdr.tcp->th_sport, sizeof(u_short));
MD5Update(&ctx, (char *)&pd->hdr.tcp->th_dport, sizeof(u_short));
MD5Update(&ctx, (char *)&pd->hdr.tcp.th_sport, sizeof(u_short));
MD5Update(&ctx, (char *)&pd->hdr.tcp.th_dport, sizeof(u_short));
if (pd->af == AF_INET6) {
MD5Update(&ctx, (char *)&pd->src->v6, sizeof(struct in6_addr));
MD5Update(&ctx, (char *)&pd->dst->v6, sizeof(struct in6_addr));
@ -3342,7 +3338,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_state **sm, int direction,
struct pf_krule *r, *a = NULL;
struct pf_kruleset *ruleset = NULL;
struct pf_ksrc_node *nsn = NULL;
struct tcphdr *th = pd->hdr.tcp;
struct tcphdr *th = &pd->hdr.tcp;
struct pf_state_key *sk = NULL, *nk = NULL;
u_short reason;
int rewrite = 0, hdrlen = 0;
@ -3371,18 +3367,18 @@ pf_test_rule(struct pf_krule **rm, struct pf_state **sm, int direction,
hdrlen = sizeof(*th);
break;
case IPPROTO_UDP:
sport = pd->hdr.udp->uh_sport;
dport = pd->hdr.udp->uh_dport;
hdrlen = sizeof(*pd->hdr.udp);
sport = pd->hdr.udp.uh_sport;
dport = pd->hdr.udp.uh_dport;
hdrlen = sizeof(pd->hdr.udp);
break;
#ifdef INET
case IPPROTO_ICMP:
if (pd->af != AF_INET)
break;
sport = dport = pd->hdr.icmp->icmp_id;
hdrlen = sizeof(*pd->hdr.icmp);
icmptype = pd->hdr.icmp->icmp_type;
icmpcode = pd->hdr.icmp->icmp_code;
sport = dport = pd->hdr.icmp.icmp_id;
hdrlen = sizeof(pd->hdr.icmp);
icmptype = pd->hdr.icmp.icmp_type;
icmpcode = pd->hdr.icmp.icmp_code;
if (icmptype == ICMP_UNREACH ||
icmptype == ICMP_SOURCEQUENCH ||
@ -3396,10 +3392,10 @@ pf_test_rule(struct pf_krule **rm, struct pf_state **sm, int direction,
case IPPROTO_ICMPV6:
if (af != AF_INET6)
break;
sport = dport = pd->hdr.icmp6->icmp6_id;
hdrlen = sizeof(*pd->hdr.icmp6);
icmptype = pd->hdr.icmp6->icmp6_type;
icmpcode = pd->hdr.icmp6->icmp6_code;
sport = dport = pd->hdr.icmp6.icmp6_id;
hdrlen = sizeof(pd->hdr.icmp6);
icmptype = pd->hdr.icmp6.icmp6_type;
icmpcode = pd->hdr.icmp6.icmp6_code;
if (icmptype == ICMP6_DST_UNREACH ||
icmptype == ICMP6_PACKET_TOO_BIG ||
@ -3449,27 +3445,27 @@ pf_test_rule(struct pf_krule **rm, struct pf_state **sm, int direction,
rewrite++;
break;
case IPPROTO_UDP:
bproto_sum = pd->hdr.udp->uh_sum;
pd->proto_sum = &pd->hdr.udp->uh_sum;
bproto_sum = pd->hdr.udp.uh_sum;
pd->proto_sum = &pd->hdr.udp.uh_sum;
if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) ||
nk->port[pd->sidx] != sport) {
pf_change_ap(m, saddr, &pd->hdr.udp->uh_sport,
pd->ip_sum, &pd->hdr.udp->uh_sum,
pf_change_ap(m, saddr, &pd->hdr.udp.uh_sport,
pd->ip_sum, &pd->hdr.udp.uh_sum,
&nk->addr[pd->sidx],
nk->port[pd->sidx], 1, af);
sport = pd->hdr.udp->uh_sport;
pd->sport = &pd->hdr.udp->uh_sport;
sport = pd->hdr.udp.uh_sport;
pd->sport = &pd->hdr.udp.uh_sport;
}
if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) ||
nk->port[pd->didx] != dport) {
pf_change_ap(m, daddr, &pd->hdr.udp->uh_dport,
pd->ip_sum, &pd->hdr.udp->uh_sum,
pf_change_ap(m, daddr, &pd->hdr.udp.uh_dport,
pd->ip_sum, &pd->hdr.udp.uh_sum,
&nk->addr[pd->didx],
nk->port[pd->didx], 1, af);
dport = pd->hdr.udp->uh_dport;
pd->dport = &pd->hdr.udp->uh_dport;
dport = pd->hdr.udp.uh_dport;
pd->dport = &pd->hdr.udp.uh_dport;
}
rewrite++;
break;
@ -3484,25 +3480,25 @@ pf_test_rule(struct pf_krule **rm, struct pf_state **sm, int direction,
pf_change_a(&daddr->v4.s_addr, pd->ip_sum,
nk->addr[pd->didx].v4.s_addr, 0);
if (nk->port[1] != pd->hdr.icmp->icmp_id) {
pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
pd->hdr.icmp->icmp_cksum, sport,
if (nk->port[1] != pd->hdr.icmp.icmp_id) {
pd->hdr.icmp.icmp_cksum = pf_cksum_fixup(
pd->hdr.icmp.icmp_cksum, sport,
nk->port[1], 0);
pd->hdr.icmp->icmp_id = nk->port[1];
pd->sport = &pd->hdr.icmp->icmp_id;
pd->hdr.icmp.icmp_id = nk->port[1];
pd->sport = &pd->hdr.icmp.icmp_id;
}
m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp);
m_copyback(m, off, ICMP_MINLEN, (caddr_t)&pd->hdr.icmp);
break;
#endif /* INET */
#ifdef INET6
case IPPROTO_ICMPV6:
nk->port[0] = nk->port[1];
if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6))
pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
pf_change_a6(saddr, &pd->hdr.icmp6.icmp6_cksum,
&nk->addr[pd->sidx], 0);
if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6))
pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
pf_change_a6(daddr, &pd->hdr.icmp6.icmp6_cksum,
&nk->addr[pd->didx], 0);
rewrite++;
break;
@ -3713,7 +3709,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
{
struct pf_state *s = NULL;
struct pf_ksrc_node *sn = NULL;
struct tcphdr *th = pd->hdr.tcp;
struct tcphdr *th = &pd->hdr.tcp;
u_int16_t mss = V_tcp_mssdflt;
u_short reason;
@ -4066,7 +4062,7 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst,
struct pf_state **state, struct pfi_kkif *kif, struct mbuf *m, int off,
struct pf_pdesc *pd, u_short *reason, int *copyback)
{
struct tcphdr *th = pd->hdr.tcp;
struct tcphdr *th = &pd->hdr.tcp;
u_int16_t win = ntohs(th->th_win);
u_int32_t ack, end, seq, orig_seq;
u_int8_t sws, dws;
@ -4392,7 +4388,7 @@ static int
pf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst,
struct pf_state **state, struct pf_pdesc *pd, u_short *reason)
{
struct tcphdr *th = pd->hdr.tcp;
struct tcphdr *th = &pd->hdr.tcp;
if (th->th_flags & TH_SYN)
if (src->state < TCPS_SYN_SENT)
@ -4465,7 +4461,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kkif *kif,
u_short *reason)
{
struct pf_state_key_cmp key;
struct tcphdr *th = pd->hdr.tcp;
struct tcphdr *th = &pd->hdr.tcp;
int copyback = 0;
struct pf_state_peer *src, *dst;
struct pf_state_key *sk;
@ -4633,7 +4629,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kkif *kif,
{
struct pf_state_peer *src, *dst;
struct pf_state_key_cmp key;
struct udphdr *uh = pd->hdr.udp;
struct udphdr *uh = &pd->hdr.udp;
bzero(&key, sizeof(key));
key.af = pd->af;
@ -4708,10 +4704,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
switch (pd->proto) {
#ifdef INET
case IPPROTO_ICMP:
icmptype = pd->hdr.icmp->icmp_type;
icmpcode = pd->hdr.icmp->icmp_code;
icmpid = pd->hdr.icmp->icmp_id;
icmpsum = &pd->hdr.icmp->icmp_cksum;
icmptype = pd->hdr.icmp.icmp_type;
icmpcode = pd->hdr.icmp.icmp_code;
icmpid = pd->hdr.icmp.icmp_id;
icmpsum = &pd->hdr.icmp.icmp_cksum;
if (icmptype == ICMP_UNREACH ||
icmptype == ICMP_SOURCEQUENCH ||
@ -4723,10 +4719,10 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
#endif /* INET */
#ifdef INET6
case IPPROTO_ICMPV6:
icmptype = pd->hdr.icmp6->icmp6_type;
icmpcode = pd->hdr.icmp6->icmp6_code;
icmpid = pd->hdr.icmp6->icmp6_id;
icmpsum = &pd->hdr.icmp6->icmp6_cksum;
icmptype = pd->hdr.icmp6.icmp6_type;
icmpcode = pd->hdr.icmp6.icmp6_code;
icmpid = pd->hdr.icmp6.icmp6_id;
icmpsum = &pd->hdr.icmp6.icmp6_cksum;
if (icmptype == ICMP6_DST_UNREACH ||
icmptype == ICMP6_PACKET_TOO_BIG ||
@ -4778,17 +4774,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
nk->addr[pd->didx].v4.s_addr, 0);
if (nk->port[0] !=
pd->hdr.icmp->icmp_id) {
pd->hdr.icmp->icmp_cksum =
pd->hdr.icmp.icmp_id) {
pd->hdr.icmp.icmp_cksum =
pf_cksum_fixup(
pd->hdr.icmp->icmp_cksum, icmpid,
pd->hdr.icmp.icmp_cksum, icmpid,
nk->port[pd->sidx], 0);
pd->hdr.icmp->icmp_id =
pd->hdr.icmp.icmp_id =
nk->port[pd->sidx];
}
m_copyback(m, off, ICMP_MINLEN,
(caddr_t )pd->hdr.icmp);
(caddr_t )&pd->hdr.icmp);
break;
#endif /* INET */
#ifdef INET6
@ -4796,17 +4792,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
if (PF_ANEQ(pd->src,
&nk->addr[pd->sidx], AF_INET6))
pf_change_a6(saddr,
&pd->hdr.icmp6->icmp6_cksum,
&pd->hdr.icmp6.icmp6_cksum,
&nk->addr[pd->sidx], 0);
if (PF_ANEQ(pd->dst,
&nk->addr[pd->didx], AF_INET6))
pf_change_a6(daddr,
&pd->hdr.icmp6->icmp6_cksum,
&pd->hdr.icmp6.icmp6_cksum,
&nk->addr[pd->didx], 0);
m_copyback(m, off, sizeof(struct icmp6_hdr),
(caddr_t )pd->hdr.icmp6);
(caddr_t )&pd->hdr.icmp6);
break;
#endif /* INET6 */
}
@ -5049,7 +5045,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
(caddr_t )pd->hdr.icmp);
(caddr_t )&pd->hdr.icmp);
m_copyback(m, ipoff2, sizeof(h2),
(caddr_t )&h2);
break;
@ -5058,7 +5054,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
(caddr_t )pd->hdr.icmp6);
(caddr_t )&pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
(caddr_t )&h2_6);
break;
@ -5118,7 +5114,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
(caddr_t )pd->hdr.icmp);
(caddr_t )&pd->hdr.icmp);
m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
break;
#endif /* INET */
@ -5126,7 +5122,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
(caddr_t )pd->hdr.icmp6);
(caddr_t )&pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
(caddr_t )&h2_6);
break;
@ -5181,7 +5177,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET);
m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp);
m_copyback(m, off, ICMP_MINLEN, (caddr_t)&pd->hdr.icmp);
m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
m_copyback(m, off2, ICMP_MINLEN, (caddr_t)&iih);
}
@ -5234,7 +5230,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
pd->ip_sum, 0, AF_INET6);
m_copyback(m, off, sizeof(struct icmp6_hdr),
(caddr_t)pd->hdr.icmp6);
(caddr_t)&pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6), (caddr_t)&h2_6);
m_copyback(m, off2, sizeof(struct icmp6_hdr),
(caddr_t)&iih);
@ -5276,7 +5272,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
(caddr_t)pd->hdr.icmp);
(caddr_t)&pd->hdr.icmp);
m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2);
break;
#endif /* INET */
@ -5284,7 +5280,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kkif *kif,
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
(caddr_t )pd->hdr.icmp6);
(caddr_t )&pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
(caddr_t )&h2_6);
break;
@ -6033,16 +6029,13 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *
switch (h->ip_p) {
case IPPROTO_TCP: {
struct tcphdr th;
pd.hdr.tcp = &th;
if (!pf_pull_hdr(m, off, &th, sizeof(th),
if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp),
&action, &reason, AF_INET)) {
log = action != PF_PASS;
goto done;
}
pd.p_len = pd.tot_len - off - (th.th_off << 2);
if ((th.th_flags & TH_ACK) && pd.p_len == 0)
pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2);
if ((pd.hdr.tcp.th_flags & TH_ACK) && pd.p_len == 0)
pqid = 1;
action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
if (action == PF_DROP)
@ -6062,17 +6055,14 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *
}
case IPPROTO_UDP: {
struct udphdr uh;
pd.hdr.udp = &uh;
if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp),
&action, &reason, AF_INET)) {
log = action != PF_PASS;
goto done;
}
if (uh.uh_dport == 0 ||
ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
if (pd.hdr.udp.uh_dport == 0 ||
ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_SHORT);
goto done;
@ -6091,10 +6081,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *
}
case IPPROTO_ICMP: {
struct icmp ih;
pd.hdr.icmp = &ih;
if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN,
&action, &reason, AF_INET)) {
log = action != PF_PASS;
goto done;
@ -6479,15 +6466,12 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
switch (pd.proto) {
case IPPROTO_TCP: {
struct tcphdr th;
pd.hdr.tcp = &th;
if (!pf_pull_hdr(m, off, &th, sizeof(th),
if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp),
&action, &reason, AF_INET6)) {
log = action != PF_PASS;
goto done;
}
pd.p_len = pd.tot_len - off - (th.th_off << 2);
pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2);
action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
if (action == PF_DROP)
goto done;
@ -6506,17 +6490,14 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
}
case IPPROTO_UDP: {
struct udphdr uh;
pd.hdr.udp = &uh;
if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp),
&action, &reason, AF_INET6)) {
log = action != PF_PASS;
goto done;
}
if (uh.uh_dport == 0 ||
ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
if (pd.hdr.udp.uh_dport == 0 ||
ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off ||
ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_SHORT);
goto done;
@ -6542,10 +6523,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
}
case IPPROTO_ICMPV6: {
struct icmp6_hdr ih;
pd.hdr.icmp6 = &ih;
if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
if (!pf_pull_hdr(m, off, &pd.hdr.icmp6, sizeof(pd.hdr.icmp6),
&action, &reason, AF_INET6)) {
log = action != PF_PASS;
goto done;

View File

@ -182,7 +182,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = TAILQ_NEXT(r, entries);
else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
off, pd->hdr.tcp), r->os_fingerprint)))
off, &pd->hdr.tcp), r->os_fingerprint)))
r = TAILQ_NEXT(r, entries);
else {
if (r->tag)

View File

@ -1326,7 +1326,7 @@ pf_normalize_tcp(int dir, struct pfi_kkif *kif, struct mbuf *m, int ipoff,
int off, void *h, struct pf_pdesc *pd)
{
struct pf_krule *r, *rm = NULL;
struct tcphdr *th = pd->hdr.tcp;
struct tcphdr *th = &pd->hdr.tcp;
int rewrite = 0;
u_short reason;
u_int8_t flags;