Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144533794
D3779.1775293847.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D3779.1775293847.diff
View Options
Index: sys/net/pfvar.h
===================================================================
--- sys/net/pfvar.h
+++ sys/net/pfvar.h
@@ -1552,6 +1552,8 @@
extern void pf_print_flags(u_int8_t);
extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t,
u_int8_t);
+extern u_int16_t pf_proto_cksum_fixup(struct mbuf *, u_int16_t,
+ u_int16_t, u_int16_t, u_int8_t);
VNET_DECLARE(struct ifnet *, sync_ifp);
#define V_sync_ifp VNET(sync_ifp);
@@ -1581,6 +1583,9 @@
void *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *,
sa_family_t);
void pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t);
+void pf_change_proto_a(struct mbuf *, void *, u_int16_t *, u_int32_t,
+ u_int8_t);
+void pf_change_tcp_a(struct mbuf *, void *, u_int16_t *, u_int32_t);
void pf_send_deferred_syn(struct pf_state *);
int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *,
struct pf_addr *, sa_family_t);
Index: sys/netpfil/pf/pf.c
===================================================================
--- sys/netpfil/pf/pf.c
+++ sys/netpfil/pf/pf.c
@@ -202,7 +202,7 @@
static void pf_add_threshold(struct pf_threshold *);
static int pf_check_threshold(struct pf_threshold *);
-static void pf_change_ap(struct pf_addr *, u_int16_t *,
+static void pf_change_ap(struct mbuf *, struct pf_addr *, u_int16_t *,
u_int16_t *, u_int16_t *, struct pf_addr *,
u_int16_t, u_int8_t, sa_family_t);
static int pf_modulate_sack(struct mbuf *, int, struct pf_pdesc *,
@@ -1991,6 +1991,22 @@
}
}
+/**
+ * Checksum updates are a little complicated because the checksum in the TCP/UDP
+ * header isn't always a full checksum. In some cases (i.e. output) it's a
+ * pseudo-header checksum, which is a partial checksum over src/dst IP
+ * addresses, protocol number and length.
+ *
+ * That means we have the following cases:
+ * * Input or forwarding: we don't have TSO, the checksum fields are full
+ * checksums, we need to update the checksum whenever we change anything.
+ * * Output (i.e. the checksum is a pseudo-header checksum):
+ * x The field being updated is src/dst address or affects the length of
+ * the packet. We need to update the pseudo-header checksum (note that this
+ * checksum is not ones' complement).
+ * x Some other field is being modified (e.g. src/dst port numbers): We
+ * don't have to update anything.
+ **/
u_int16_t
pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
{
@@ -2006,9 +2022,20 @@
return (l);
}
+u_int16_t
+pf_proto_cksum_fixup(struct mbuf *m, u_int16_t cksum, u_int16_t old,
+ u_int16_t new, u_int8_t udp)
+{
+ if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6))
+ return (cksum);
+
+ return (pf_cksum_fixup(cksum, old, new, udp));
+}
+
static void
-pf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
- struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
+pf_change_ap(struct mbuf *m, struct pf_addr *a, u_int16_t *p, u_int16_t *ic,
+ u_int16_t *pc, struct pf_addr *an, u_int16_t pn, u_int8_t u,
+ sa_family_t af)
{
struct pf_addr ao;
u_int16_t po = *p;
@@ -2016,6 +2043,9 @@
PF_ACPY(&ao, a, af);
PF_ACPY(a, an, af);
+ if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6))
+ *pc = ~*pc;
+
*p = pn;
switch (af) {
@@ -2025,17 +2055,19 @@
ao.addr16[0], an->addr16[0], 0),
ao.addr16[1], an->addr16[1], 0);
*p = pn;
- *pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
+
+ *pc = pf_cksum_fixup(pf_cksum_fixup(*pc,
ao.addr16[0], an->addr16[0], u),
- ao.addr16[1], an->addr16[1], u),
- po, pn, u);
+ ao.addr16[1], an->addr16[1], u);
+
+ *pc = pf_proto_cksum_fixup(m, *pc, po, pn, u);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
- pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
+ pf_cksum_fixup(pf_cksum_fixup(*pc,
ao.addr16[0], an->addr16[0], u),
ao.addr16[1], an->addr16[1], u),
ao.addr16[2], an->addr16[2], u),
@@ -2043,13 +2075,20 @@
ao.addr16[4], an->addr16[4], u),
ao.addr16[5], an->addr16[5], u),
ao.addr16[6], an->addr16[6], u),
- ao.addr16[7], an->addr16[7], u),
- po, pn, u);
+ ao.addr16[7], an->addr16[7], u);
+
+ *pc = pf_proto_cksum_fixup(m, *pc, po, pn, u);
break;
#endif /* INET6 */
}
-}
+ if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA |
+ CSUM_DELAY_DATA_IPV6)) {
+ *pc = ~*pc;
+ if (! *pc)
+ *pc = 0xffff;
+ }
+}
/* Changes a u_int32_t. Uses a void * so there are no align restrictions */
void
@@ -2063,6 +2102,19 @@
ao % 65536, an % 65536, u);
}
+void
+pf_change_proto_a(struct mbuf *m, void *a, u_int16_t *c, u_int32_t an, u_int8_t udp)
+{
+ u_int32_t ao;
+
+ memcpy(&ao, a, sizeof(ao));
+ memcpy(a, &an, sizeof(u_int32_t));
+
+ *c = pf_proto_cksum_fixup(m,
+ pf_proto_cksum_fixup(m, *c, ao / 65536, an / 65536, udp),
+ ao % 65536, an % 65536, udp);
+}
+
#ifdef INET6
static void
pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
@@ -2208,12 +2260,10 @@
for (i = 2; i + TCPOLEN_SACK <= olen;
i += TCPOLEN_SACK) {
memcpy(&sack, &opt[i], sizeof(sack));
- pf_change_a(&sack.start, &th->th_sum,
- htonl(ntohl(sack.start) -
- dst->seqdiff), 0);
- pf_change_a(&sack.end, &th->th_sum,
- htonl(ntohl(sack.end) -
- dst->seqdiff), 0);
+ pf_change_proto_a(m, &sack.start, &th->th_sum,
+ htonl(ntohl(sack.start) - dst->seqdiff), 0);
+ pf_change_proto_a(m, &sack.end, &th->th_sum,
+ htonl(ntohl(sack.end) - dst->seqdiff), 0);
memcpy(&opt[i], &sack, sizeof(sack));
}
copyback = 1;
@@ -3117,7 +3167,7 @@
if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) ||
nk->port[pd->sidx] != sport) {
- pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
+ pf_change_ap(m, saddr, &th->th_sport, pd->ip_sum,
&th->th_sum, &nk->addr[pd->sidx],
nk->port[pd->sidx], 0, af);
pd->sport = &th->th_sport;
@@ -3126,7 +3176,7 @@
if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) ||
nk->port[pd->didx] != dport) {
- pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
+ pf_change_ap(m, daddr, &th->th_dport, pd->ip_sum,
&th->th_sum, &nk->addr[pd->didx],
nk->port[pd->didx], 0, af);
dport = th->th_dport;
@@ -3140,7 +3190,7 @@
if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) ||
nk->port[pd->sidx] != sport) {
- pf_change_ap(saddr, &pd->hdr.udp->uh_sport,
+ 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);
@@ -3150,7 +3200,7 @@
if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) ||
nk->port[pd->didx] != dport) {
- pf_change_ap(daddr, &pd->hdr.udp->uh_dport,
+ 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);
@@ -3502,7 +3552,7 @@
if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) ==
0)
s->src.seqdiff = 1;
- pf_change_a(&th->th_seq, &th->th_sum,
+ pf_change_proto_a(m, &th->th_seq, &th->th_sum,
htonl(s->src.seqlo + s->src.seqdiff), 0);
*rewrite = 1;
} else
@@ -3826,9 +3876,9 @@
while ((src->seqdiff = arc4random() - seq) == 0)
;
ack = ntohl(th->th_ack) - dst->seqdiff;
- pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
+ pf_change_proto_a(m, &th->th_seq, &th->th_sum, htonl(seq +
src->seqdiff), 0);
- pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
+ pf_change_proto_a(m, &th->th_ack, &th->th_sum, htonl(ack), 0);
*copyback = 1;
} else {
ack = ntohl(th->th_ack);
@@ -3878,9 +3928,9 @@
ack = ntohl(th->th_ack) - dst->seqdiff;
if (src->seqdiff) {
/* Modulate sequence numbers */
- pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
+ pf_change_proto_a(m, &th->th_seq, &th->th_sum, htonl(seq +
src->seqdiff), 0);
- pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
+ pf_change_proto_a(m, &th->th_ack, &th->th_sum, htonl(ack), 0);
*copyback = 1;
}
end = seq + pd->p_len;
@@ -4334,14 +4384,14 @@
if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) ||
nk->port[pd->sidx] != th->th_sport)
- pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
- &th->th_sum, &nk->addr[pd->sidx],
+ pf_change_ap(m, pd->src, &th->th_sport,
+ pd->ip_sum, &th->th_sum, &nk->addr[pd->sidx],
nk->port[pd->sidx], 0, pd->af);
if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) ||
nk->port[pd->didx] != th->th_dport)
- pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
- &th->th_sum, &nk->addr[pd->didx],
+ pf_change_ap(m, pd->dst, &th->th_dport,
+ pd->ip_sum, &th->th_sum, &nk->addr[pd->didx],
nk->port[pd->didx], 0, pd->af);
copyback = 1;
}
@@ -4405,13 +4455,13 @@
if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) ||
nk->port[pd->sidx] != uh->uh_sport)
- pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
+ pf_change_ap(m, pd->src, &uh->uh_sport, pd->ip_sum,
&uh->uh_sum, &nk->addr[pd->sidx],
nk->port[pd->sidx], 1, pd->af);
if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) ||
nk->port[pd->didx] != uh->uh_dport)
- pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
+ pf_change_ap(m, pd->dst, &uh->uh_dport, pd->ip_sum,
&uh->uh_sum, &nk->addr[pd->didx],
nk->port[pd->didx], 1, pd->af);
m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
Index: sys/netpfil/pf/pf_ioctl.c
===================================================================
--- sys/netpfil/pf/pf_ioctl.c
+++ sys/netpfil/pf/pf_ioctl.c
@@ -3566,12 +3566,6 @@
{
int chk;
- /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
- if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- in_delayed_cksum(*m);
- (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- }
-
chk = pf_test(PF_OUT, ifp, m, inp);
if (chk && *m) {
m_freem(*m);
@@ -3610,13 +3604,6 @@
{
int chk;
- /* We need a proper CSUM before we start (s. OpenBSD ip_output) */
- if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
- in6_delayed_cksum(*m,
- (*m)->m_pkthdr.len - sizeof(struct ip6_hdr),
- sizeof(struct ip6_hdr));
- (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
- }
CURVNET_SET(ifp->if_vnet);
chk = pf_test6(PF_OUT, ifp, m, inp);
CURVNET_RESTORE();
Index: sys/netpfil/pf/pf_norm.c
===================================================================
--- sys/netpfil/pf/pf_norm.c
+++ sys/netpfil/pf/pf_norm.c
@@ -1215,13 +1215,14 @@
th->th_x2 = 0;
nv = *(u_int16_t *)(&th->th_ack + 1);
- th->th_sum = pf_cksum_fixup(th->th_sum, ov, nv, 0);
+ th->th_sum = pf_proto_cksum_fixup(m, th->th_sum, ov, nv, 0);
rewrite = 1;
}
/* Remove urgent pointer, if TH_URG is not set */
if (!(flags & TH_URG) && th->th_urp) {
- th->th_sum = pf_cksum_fixup(th->th_sum, th->th_urp, 0, 0);
+ th->th_sum = pf_proto_cksum_fixup(m, th->th_sum, th->th_urp,
+ 0, 0);
th->th_urp = 0;
rewrite = 1;
}
@@ -1422,7 +1423,7 @@
(src->scrub->pfss_flags &
PFSS_TIMESTAMP)) {
tsval = ntohl(tsval);
- pf_change_a(&opt[2],
+ pf_change_proto_a(m, &opt[2],
&th->th_sum,
htonl(tsval +
src->scrub->pfss_ts_mod),
@@ -1438,7 +1439,7 @@
PFSS_TIMESTAMP)) {
tsecr = ntohl(tsecr)
- dst->scrub->pfss_ts_mod;
- pf_change_a(&opt[6],
+ pf_change_proto_a(m, &opt[6],
&th->th_sum, htonl(tsecr),
0);
copyback = 1;
@@ -1765,8 +1766,8 @@
case TCPOPT_MAXSEG:
mss = (u_int16_t *)(optp + 2);
if ((ntohs(*mss)) > r->max_mss) {
- th->th_sum = pf_cksum_fixup(th->th_sum,
- *mss, htons(r->max_mss), 0);
+ th->th_sum = pf_proto_cksum_fixup(m,
+ th->th_sum, *mss, htons(r->max_mss), 0);
*mss = htons(r->max_mss);
rewrite = 1;
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 4, 9:10 AM (6 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28258566
Default Alt Text
D3779.1775293847.diff (11 KB)
Attached To
Mode
D3779: pf: Fix TSO issues
Attached
Detach File
Event Timeline
Log In to Comment