The branch main has been updated by glebius:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=70703aa922b41faedfd72211633884bb580ceeac

commit 70703aa922b41faedfd72211633884bb580ceeac
Author:     acazuc <aca...@acazuc.fr>
AuthorDate: 2025-03-03 13:21:15 +0000
Commit:     Gleb Smirnoff <gleb...@freebsd.org>
CommitDate: 2025-03-04 16:45:32 +0000

    netinet: allow per protocol random IP id control, single out IPSEC
    
    A globally enabled random IP id generation maybe useful in most IP
    contexts, but it may be unnecessary in the case of IPsec encapsulated
    packets because IPsec can be configured to use anti-replay windows.
    
    This commit adds a new net.inet.ipsec.random_id sysctl to control whether
    or not IPsec packets should use random IP id generation.
    
    Rest of the protocols/modules are still controlled by the global
    net.inet.ip.random_id, but can be easily augmented with a knob.
    
    Reviewed by:            glebius
    Sponsored by:           Stormshield
    Differential Revision:  https://reviews.freebsd.org/D49164
---
 share/man/man4/ipsec.4                   |  6 +++++-
 sys/netinet/ip_carp.c                    |  4 ++--
 sys/netinet/ip_gre.c                     |  2 +-
 sys/netinet/ip_id.c                      | 22 +++++++++++-----------
 sys/netinet/ip_mroute.c                  |  2 +-
 sys/netinet/ip_output.c                  |  2 +-
 sys/netinet/ip_var.h                     |  4 +++-
 sys/netinet/raw_ip.c                     |  2 +-
 sys/netinet/sctp_output.c                |  4 ++--
 sys/netipsec/ipsec.c                     |  4 ++++
 sys/netipsec/ipsec.h                     |  3 +++
 sys/netipsec/ipsec_output.c              |  2 +-
 sys/netpfil/ipfilter/netinet/fil.c       |  2 +-
 sys/netpfil/ipfilter/netinet/ip_nat.c    |  4 ++--
 sys/netpfil/ipfw/nat64/nat64_translate.c |  4 ++--
 sys/netpfil/pf/if_pfsync.c               |  2 +-
 sys/netpfil/pf/pf.c                      |  4 ++--
 sys/netpfil/pf/pf_norm.c                 |  2 +-
 18 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/share/man/man4/ipsec.4 b/share/man/man4/ipsec.4
index 96a10dfb7700..9fd6207c2f14 100644
--- a/share/man/man4/ipsec.4
+++ b/share/man/man4/ipsec.4
@@ -27,7 +27,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 6, 2017
+.Dd March 4, 2025
 .Dt IPSEC 4
 .Os
 .Sh NAME
@@ -239,6 +239,7 @@ for tweaking the kernel's IPsec behavior:
 .It "net.inet.ipsec.debug      integer yes"
 .It "net.inet.ipsec.natt_cksum_policy  integer yes"
 .It "net.inet.ipsec.check_policy_history       integer yes"
+.It "net.inet.ipsec.random_id          integer yes"
 .It "net.inet6.ipsec6.ecn      integer yes"
 .It "net.inet6.ipsec6.debug    integer yes"
 .El
@@ -298,6 +299,9 @@ have been decrypted and authenticated.
 If this variable is set to a non-zero value, each packet handled by IPsec
 is checked against the history of IPsec security associations.
 The IPsec security protocol, mode, and SA addresses must match.
+.It Li ipsec.random_id
+Enables randomization of encapsulated IPv4 packets ID.
+By default, ID randomization is not enabled.
 .El
 .Pp
 Variables under the
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 6fde7bd70c6b..c01d1bdd8cff 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1256,7 +1256,7 @@ carp_send_ad_locked(struct carp_softc *sc)
                ip->ip_ttl = CARP_DFLTTL;
                ip->ip_p = IPPROTO_CARP;
                ip->ip_sum = 0;
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
 
                ifa = carp_best_ifa(AF_INET, sc->sc_carpdev);
                if (ifa != NULL) {
@@ -1395,7 +1395,7 @@ vrrp_send_ad_locked(struct carp_softc *sc)
                ip->ip_ttl = CARP_DFLTTL;
                ip->ip_p = IPPROTO_CARP;
                ip->ip_sum = 0;
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
 
                ifa = carp_best_ifa(AF_INET, sc->sc_carpdev);
                if (ifa != NULL) {
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
index c9356edb0608..01a6ef4cd670 100644
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -534,7 +534,7 @@ in_gre_output(struct mbuf *m, int af, int hlen)
 #ifdef INET6
        case AF_INET6:
                gi->gi_ip.ip_tos = 0; /* XXX */
-               ip_fillid(&gi->gi_ip);
+               ip_fillid(&gi->gi_ip, V_ip_random_id);
                break;
 #endif
        }
diff --git a/sys/netinet/ip_id.c b/sys/netinet/ip_id.c
index 12dd6c8bf972..738b7eceb448 100644
--- a/sys/netinet/ip_id.c
+++ b/sys/netinet/ip_id.c
@@ -97,9 +97,9 @@
  * user wants to, we can turn on random ID generation.
  */
 VNET_DEFINE_STATIC(int, ip_rfc6864) = 1;
-VNET_DEFINE_STATIC(int, ip_do_randomid) = 0;
 #define        V_ip_rfc6864            VNET(ip_rfc6864)
-#define        V_ip_do_randomid        VNET(ip_do_randomid)
+
+VNET_DEFINE(int, ip_random_id) = 0;
 
 /*
  * Random ID state engine.
@@ -126,7 +126,7 @@ VNET_DEFINE_STATIC(struct mtx, ip_id_mtx);
 VNET_DEFINE_STATIC(counter_u64_t, ip_id);
 #define        V_ip_id         VNET(ip_id)
 
-static int     sysctl_ip_randomid(SYSCTL_HANDLER_ARGS);
+static int     sysctl_ip_random_id(SYSCTL_HANDLER_ARGS);
 static int     sysctl_ip_id_change(SYSCTL_HANDLER_ARGS);
 static void    ip_initid(int);
 static uint16_t ip_randomid(void);
@@ -136,7 +136,7 @@ static void ipid_sysuninit(void);
 SYSCTL_DECL(_net_inet_ip);
 SYSCTL_PROC(_net_inet_ip, OID_AUTO, random_id,
     CTLTYPE_INT | CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_MPSAFE,
-    &VNET_NAME(ip_do_randomid), 0, sysctl_ip_randomid, "IU",
+    &VNET_NAME(ip_random_id), 0, sysctl_ip_random_id, "IU",
     "Assign random ip_id values");
 SYSCTL_INT(_net_inet_ip, OID_AUTO, rfc6864, CTLFLAG_VNET | CTLFLAG_RW,
     &VNET_NAME(ip_rfc6864), 0,
@@ -151,22 +151,22 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, random_id_total, 
CTLFLAG_RD | CTLFLAG_VNET,
     &VNET_NAME(random_id_total), 0, "Count of IP IDs created");
 
 static int
-sysctl_ip_randomid(SYSCTL_HANDLER_ARGS)
+sysctl_ip_random_id(SYSCTL_HANDLER_ARGS)
 {
        int error, new;
 
-       new = V_ip_do_randomid;
+       new = V_ip_random_id;
        error = sysctl_handle_int(oidp, &new, 0, req);
        if (error || req->newptr == NULL)
                return (error);
        if (new != 0 && new != 1)
                return (EINVAL);
-       if (new == V_ip_do_randomid)
+       if (new == V_ip_random_id)
                return (0);
-       if (new == 1 && V_ip_do_randomid == 0)
+       if (new == 1 && V_ip_random_id == 0)
                ip_initid(8192);
        /* We don't free memory when turning random ID off, due to race. */
-       V_ip_do_randomid = new;
+       V_ip_random_id = new;
        return (0);
 }
 
@@ -238,7 +238,7 @@ ip_randomid(void)
 }
 
 void
-ip_fillid(struct ip *ip)
+ip_fillid(struct ip *ip, bool do_randomid)
 {
 
        /*
@@ -249,7 +249,7 @@ ip_fillid(struct ip *ip)
         */
        if (V_ip_rfc6864 && (ip->ip_off & htons(IP_DF)) == htons(IP_DF))
                ip->ip_id = 0;
-       else if (V_ip_do_randomid)
+       else if (do_randomid)
                ip->ip_id = ip_randomid();
        else {
                counter_u64_add(V_ip_id, 1);
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index e224d2e6daf5..d30bd42ec578 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -2466,7 +2466,7 @@ pim_register_send_rp(struct ip *ip, struct vif *vifp, 
struct mbuf *mb_copy,
        ip_outer->ip_tos = ip->ip_tos;
        if (ip->ip_off & htons(IP_DF))
                ip_outer->ip_off |= htons(IP_DF);
-       ip_fillid(ip_outer);
+       ip_fillid(ip_outer, V_ip_random_id);
        pimhdr = (struct pim_encap_pimhdr *)((caddr_t)ip_outer
                        + sizeof(pim_encap_iphdr));
        *pimhdr = pim_encap_pimhdr;
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 35aaf85d6a4e..9d72300e8b68 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -368,7 +368,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route 
*ro, int flags,
        if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
                ip->ip_v = IPVERSION;
                ip->ip_hl = hlen >> 2;
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
        } else {
                /* Header already set, fetch hlen from there */
                hlen = ip->ip_hl << 2;
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
index 0f2ed8c43e64..18ca5861a40e 100644
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -204,6 +204,7 @@ extern int  (*legal_vif_num)(int);
 extern u_long  (*ip_mcast_src)(int);
 VNET_DECLARE(int, rsvp_on);
 VNET_DECLARE(int, drop_redirect);
+VNET_DECLARE(int, ip_random_id);
 
 #define        V_ip_id                 VNET(ip_id)
 #define        V_ip_defttl             VNET(ip_defttl)
@@ -216,6 +217,7 @@ VNET_DECLARE(int, drop_redirect);
 #define        V_ip_mrouter            VNET(ip_mrouter)
 #define        V_rsvp_on               VNET(rsvp_on)
 #define        V_drop_redirect         VNET(drop_redirect)
+#define        V_ip_random_id          VNET(ip_random_id)
 
 void   inp_freemoptions(struct ip_moptions *);
 int    inp_getmoptions(struct inpcb *, struct sockopt *);
@@ -235,7 +237,7 @@ struct mbuf *
        ip_reass(struct mbuf *);
 void   ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
            struct mbuf *);
-void   ip_fillid(struct ip *);
+void   ip_fillid(struct ip *, bool);
 int    rip_ctloutput(struct socket *, struct sockopt *);
 int    ipip_input(struct mbuf **, int *, int);
 int    rsvp_input(struct mbuf **, int *, int);
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 0d677d954f11..7b6104da5402 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -601,7 +601,7 @@ rip_send(struct socket *so, int pruflags, struct mbuf *m, 
struct sockaddr *nam,
                 * but we got this limitation from the beginning of history.
                 */
                if (ip->ip_id == 0)
-                       ip_fillid(ip);
+                       ip_fillid(ip, V_ip_random_id);
 
                /*
                 * XXX prevent ip_output from overwriting header fields.
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 02ad901259f4..e4bdb4291972 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -4071,7 +4071,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
                                ip->ip_off = htons(0);
                        }
                        /* FreeBSD has a function for ip_id's */
-                       ip_fillid(ip);
+                       ip_fillid(ip, V_ip_random_id);
 
                        ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl;
                        ip->ip_len = htons(packet_length);
@@ -11197,7 +11197,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct 
sockaddr *dst,
                ip->ip_hl = (sizeof(struct ip) >> 2);
                ip->ip_tos = 0;
                ip->ip_off = htons(IP_DF);
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
                ip->ip_ttl = MODULE_GLOBAL(ip_defttl);
                if (port) {
                        ip->ip_p = IPPROTO_UDP;
diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c
index 8d604a24eeea..6bacc68b7441 100644
--- a/sys/netipsec/ipsec.c
+++ b/sys/netipsec/ipsec.c
@@ -119,6 +119,7 @@ VNET_DEFINE(int, ip4_ah_trans_deflev) = IPSEC_LEVEL_USE;
 VNET_DEFINE(int, ip4_ah_net_deflev) = IPSEC_LEVEL_USE;
 /* ECN ignore(-1)/forbidden(0)/allowed(1) */
 VNET_DEFINE(int, ip4_ipsec_ecn) = 0;
+VNET_DEFINE(int, ip4_ipsec_random_id) = 0;
 
 VNET_DEFINE_STATIC(int, ip4_filtertunnel) = 0;
 #define        V_ip4_filtertunnel VNET(ip4_filtertunnel)
@@ -201,6 +202,9 @@ SYSCTL_INT(_net_inet_ipsec, IPSECCTL_MIN_PMTU, min_pmtu,
 SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, ecn,
        CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_ecn), 0,
        "Explicit Congestion Notification handling.");
+SYSCTL_INT(_net_inet_ipsec, IPSECCTL_RANDOM_ID, random_id,
+       CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip4_ipsec_random_id), 0,
+       "Assign random ip_id values.");
 SYSCTL_INT(_net_inet_ipsec, OID_AUTO, crypto_support,
        CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(crypto_support), 0,
        "Crypto driver selection.");
diff --git a/sys/netipsec/ipsec.h b/sys/netipsec/ipsec.h
index f8c5b10e7bd6..3acb6a4044f1 100644
--- a/sys/netipsec/ipsec.h
+++ b/sys/netipsec/ipsec.h
@@ -260,6 +260,7 @@ struct ipsecstat {
 #define        IPSECCTL_DEBUG                  12
 #define        IPSECCTL_ESP_RANDPAD            13
 #define        IPSECCTL_MIN_PMTU               14
+#define        IPSECCTL_RANDOM_ID              15
 
 #ifdef _KERNEL
 #include <sys/counter.h>
@@ -293,6 +294,7 @@ VNET_DECLARE(int, ip4_ah_net_deflev);
 VNET_DECLARE(int, ip4_ipsec_dfbit);
 VNET_DECLARE(int, ip4_ipsec_min_pmtu);
 VNET_DECLARE(int, ip4_ipsec_ecn);
+VNET_DECLARE(int, ip4_ipsec_random_id);
 VNET_DECLARE(int, crypto_support);
 VNET_DECLARE(int, async_crypto);
 VNET_DECLARE(int, natt_cksum_policy);
@@ -310,6 +312,7 @@ VNET_DECLARE(int, natt_cksum_policy);
 #define        V_ip4_ipsec_dfbit       VNET(ip4_ipsec_dfbit)
 #define        V_ip4_ipsec_min_pmtu    VNET(ip4_ipsec_min_pmtu)
 #define        V_ip4_ipsec_ecn         VNET(ip4_ipsec_ecn)
+#define        V_ip4_ipsec_random_id   VNET(ip4_ipsec_random_id)
 #define        V_crypto_support        VNET(crypto_support)
 #define        V_async_crypto          VNET(async_crypto)
 #define        V_natt_cksum_policy     VNET(natt_cksum_policy)
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c
index 8d8a304e7af4..b394ff81d9c6 100644
--- a/sys/netipsec/ipsec_output.c
+++ b/sys/netipsec/ipsec_output.c
@@ -1200,7 +1200,7 @@ ipsec_encap(struct mbuf **mp, struct secasindex *saidx)
                ip->ip_src = saidx->src.sin.sin_addr;
                ip->ip_dst = saidx->dst.sin.sin_addr;
                ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos);
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip4_ipsec_random_id);
                break;
 #endif /* INET */
 #ifdef INET6
diff --git a/sys/netpfil/ipfilter/netinet/fil.c 
b/sys/netpfil/ipfilter/netinet/fil.c
index c1b49196b712..2a75190a3ec7 100644
--- a/sys/netpfil/ipfilter/netinet/fil.c
+++ b/sys/netpfil/ipfilter/netinet/fil.c
@@ -5952,7 +5952,7 @@ ipf_updateipid(fr_info_t *fin)
                id = (u_short)sum;
                ip->ip_id = htons(id);
        } else {
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
                id = ntohs(ip->ip_id);
                if ((fin->fin_flx & FI_FRAG) != 0)
                        (void) ipf_frag_ipidnew(fin, (u_32_t)id);
diff --git a/sys/netpfil/ipfilter/netinet/ip_nat.c 
b/sys/netpfil/ipfilter/netinet/ip_nat.c
index b8a0e7d2075b..a13c6129a287 100644
--- a/sys/netpfil/ipfilter/netinet/ip_nat.c
+++ b/sys/netpfil/ipfilter/netinet/ip_nat.c
@@ -5117,7 +5117,7 @@ ipf_nat_out(fr_info_t *fin, nat_t *nat, int natadd, 
u_32_t nflags)
                }
 
                ip = MTOD(m, ip_t *);
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
                s2 = ntohs(ip->ip_id);
 
                s1 = ip->ip_len;
@@ -5560,7 +5560,7 @@ ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t 
nflags)
                }
 
                ip = MTOD(m, ip_t *);
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
                sum1 = ntohs(ip->ip_len);
                ip->ip_len = ntohs(ip->ip_len);
                ip->ip_len += fin->fin_plen;
diff --git a/sys/netpfil/ipfw/nat64/nat64_translate.c 
b/sys/netpfil/ipfw/nat64/nat64_translate.c
index 2924a9b2d19a..393780c969fe 100644
--- a/sys/netpfil/ipfw/nat64/nat64_translate.c
+++ b/sys/netpfil/ipfw/nat64/nat64_translate.c
@@ -520,7 +520,7 @@ nat64_init_ip4hdr(const struct ip6_hdr *ip6, const struct 
ip6_frag *frag,
                ip->ip_ttl -= IPV6_HLIMDEC;
        ip->ip_sum = 0;
        ip->ip_p = (proto == IPPROTO_ICMPV6) ? IPPROTO_ICMP: proto;
-       ip_fillid(ip);
+       ip_fillid(ip, V_ip_random_id);
        if (frag != NULL) {
                ip->ip_off = htons(ntohs(frag->ip6f_offlg) >> 3);
                if (frag->ip6f_offlg & IP6F_MORE_FRAG)
@@ -845,7 +845,7 @@ nat64_icmp_reflect(struct mbuf *m, uint8_t type,
        oip->ip_len = htons(n->m_pkthdr.len);
        oip->ip_ttl = V_ip_defttl;
        oip->ip_p = IPPROTO_ICMP;
-       ip_fillid(oip);
+       ip_fillid(oip, V_ip_random_id);
        oip->ip_off = htons(IP_DF);
        oip->ip_src = ip->ip_dst;
        oip->ip_dst = ip->ip_src;
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 98a2367b79b0..b2aaf3add25c 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -1900,7 +1900,7 @@ pfsync_sendout(int schedswi, int c)
 
                len -= sizeof(union inet_template) - sizeof(struct ip);
                ip->ip_len = htons(len);
-               ip_fillid(ip);
+               ip_fillid(ip, V_ip_random_id);
                break;
            }
 #endif
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 349b10c346a7..e0b664772544 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -3527,7 +3527,7 @@ pf_translate_af(struct pf_pdesc *pd)
                ip4->ip_hl = hlen >> 2;
                ip4->ip_tos = pd->tos;
                ip4->ip_len = htons(hlen + (pd->tot_len - pd->off));
-               ip_fillid(ip4);
+               ip_fillid(ip4, V_ip_random_id);
                ip4->ip_ttl = pd->ttl;
                ip4->ip_p = pd->proto;
                ip4->ip_src = pd->nsaddr.v4;
@@ -3630,7 +3630,7 @@ pf_change_icmp_af(struct mbuf *m, int off, struct 
pf_pdesc *pd,
                ip4->ip_v = IPVERSION;
                ip4->ip_hl = sizeof(*ip4) >> 2;
                ip4->ip_len = htons(sizeof(*ip4) + pd2->tot_len - olen);
-               ip_fillid(ip4);
+               ip_fillid(ip4, V_ip_random_id);
                ip4->ip_off = htons(IP_DF);
                ip4->ip_ttl = pd2->ttl;
                if (pd2->proto == IPPROTO_ICMPV6)
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 98539be8c6ce..fd72fec62a3b 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -2254,7 +2254,7 @@ pf_scrub(struct pf_pdesc *pd)
            pd->act.flags & PFSTATE_RANDOMID && !(h->ip_off & ~htons(IP_DF))) {
                uint16_t ip_id = h->ip_id;
 
-               ip_fillid(h);
+               ip_fillid(h, V_ip_random_id);
                h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0);
        }
 #endif

Reply via email to