From 33c43c6d649cb278e929a54ed859d02dd780bf43 Mon Sep 17 00:00:00 2001 From: bket Date: Mon, 10 Oct 2022 16:43:12 +0000 Subject: [PATCH] Recalculate checksum of normalised packet In 2011, henning@ removed fiddling with the ip checksum of normalised packets in r1.131 of sys/net/pf_norm.c. Rationale was that the checksum is always recalculated in all output paths anyway. In 2016, procter@ reintroduced checksum modification to preserve end-to-end checksums in r1.189 of sys/net/pf_norm.c. Likely soomewhere in that timeslot checksum recalculation of normalised packets was broken. With input from bluhm@. OK sashan@, bluhm@ --- sys/net/pf.c | 6 +++--- sys/net/pf_norm.c | 27 ++++++++++++++++++++++----- sys/net/pfvar.h | 4 +++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/sys/net/pf.c b/sys/net/pf.c index 1b157b84ee9..4c70b08571e 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.1140 2022/09/03 19:22:19 bluhm Exp $ */ +/* $OpenBSD: pf.c,v 1.1141 2022/10/10 16:43:12 bket Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -164,7 +164,7 @@ void pf_add_threshold(struct pf_threshold *); int pf_check_threshold(struct pf_threshold *); int pf_check_tcp_cksum(struct mbuf *, int, int, sa_family_t); -static __inline void pf_cksum_fixup(u_int16_t *, u_int16_t, u_int16_t, +__inline void pf_cksum_fixup(u_int16_t *, u_int16_t, u_int16_t, u_int8_t); void pf_cksum_fixup_a(u_int16_t *, const struct pf_addr *, const struct pf_addr *, sa_family_t, u_int8_t); @@ -1937,7 +1937,7 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) * Note: this serves also as a reduction step for at most one add (as the * trailing mod 2^16 prevents further reductions by destroying carries). */ -static __inline void +__inline void pf_cksum_fixup(u_int16_t *cksum, u_int16_t was, u_int16_t now, u_int8_t proto) { diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 76b58213da0..f04930d34c9 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.224 2022/08/22 20:35:39 bluhm Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.225 2022/10/10 16:43:12 bket Exp $ */ /* * Copyright 2001 Niels Provos @@ -1646,14 +1646,21 @@ pf_scrub(struct mbuf *m, u_int16_t flags, sa_family_t af, u_int8_t min_ttl, #ifdef INET6 struct ip6_hdr *h6 = mtod(m, struct ip6_hdr *); #endif /* INET6 */ + u_int16_t old; /* Clear IP_DF if no-df was requested */ - if (flags & PFSTATE_NODF && af == AF_INET && h->ip_off & htons(IP_DF)) + if (flags & PFSTATE_NODF && af == AF_INET && h->ip_off & htons(IP_DF)) { + old = h->ip_off; h->ip_off &= htons(~IP_DF); + pf_cksum_fixup(&h->ip_sum, old, h->ip_off, 0); + } /* Enforce a minimum ttl, may cause endless packet loops */ - if (min_ttl && af == AF_INET && h->ip_ttl < min_ttl) + if (min_ttl && af == AF_INET && h->ip_ttl < min_ttl) { + old = h->ip_ttl; h->ip_ttl = min_ttl; + pf_cksum_fixup(&h->ip_sum, old, h->ip_ttl, 0); + } #ifdef INET6 if (min_ttl && af == AF_INET6 && h6->ip6_hlim < min_ttl) h6->ip6_hlim = min_ttl; @@ -1661,8 +1668,15 @@ pf_scrub(struct mbuf *m, u_int16_t flags, sa_family_t af, u_int8_t min_ttl, /* Enforce tos */ if (flags & PFSTATE_SETTOS) { - if (af == AF_INET) + if (af == AF_INET) { + /* + * ip_tos is 8 bit field at offset 1. Use 16 bit value + * at offset 0. + */ + old = *(u_int16_t *)h; h->ip_tos = tos | (h->ip_tos & IPTOS_ECN_MASK); + pf_cksum_fixup(&h->ip_sum, old, *(u_int16_t *)h, 0); + } #ifdef INET6 if (af == AF_INET6) { /* drugs are unable to explain such idiocy */ @@ -1674,6 +1688,9 @@ pf_scrub(struct mbuf *m, u_int16_t flags, sa_family_t af, u_int8_t min_ttl, /* random-id, but not for fragments */ if (flags & PFSTATE_RANDOMID && af == AF_INET && - !(h->ip_off & ~htons(IP_DF))) + !(h->ip_off & ~htons(IP_DF))) { + old = h->ip_id; h->ip_id = htons(ip_randomid()); + pf_cksum_fixup(&h->ip_sum, old, h->ip_id, 0); + } } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 174eef37fe0..8339863a94a 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.510 2022/09/03 14:57:54 yasuoka Exp $ */ +/* $OpenBSD: pfvar.h,v 1.511 2022/10/10 16:43:12 bket Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -1745,6 +1745,8 @@ extern void pf_print_state(struct pf_state *); extern void pf_print_flags(u_int8_t); extern void pf_addrcpy(struct pf_addr *, struct pf_addr *, sa_family_t); +extern void pf_cksum_fixup(u_int16_t *, u_int16_t, + u_int16_t, u_int8_t); void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); void pf_purge_rule(struct pf_rule *); -- 2.20.1