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