Recalculate checksum of normalised packet
authorbket <bket@openbsd.org>
Mon, 10 Oct 2022 16:43:12 +0000 (16:43 +0000)
committerbket <bket@openbsd.org>
Mon, 10 Oct 2022 16:43:12 +0000 (16:43 +0000)
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
sys/net/pf_norm.c
sys/net/pfvar.h

index 1b157b8..4c70b08 100644 (file)
@@ -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)
 {
index 76b5821..f04930d 100644 (file)
@@ -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 <provos@citi.umich.edu>
@@ -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);
+       }
 }
index 174eef3..8339863 100644 (file)
@@ -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 *);