diff --git a/share/man/man4/ipsec.4 b/share/man/man4/ipsec.4 index 96a10dfb770..9fd6207c2f1 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 6fde7bd70c6..c01d1bdd8cf 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 c9356edb060..01a6ef4cd67 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 12dd6c8bf97..738b7eceb44 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 e224d2e6daf..d30bd42ec57 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 35aaf85d6a4..9d72300e8b6 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 0f2ed8c43e6..18ca5861a40 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 0d677d954f1..7b6104da540 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 02ad901259f..e4bdb429197 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 8d604a24eee..6bacc68b744 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 f8c5b10e7bd..3acb6a4044f 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 @@ -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 8d8a304e7af..b394ff81d9c 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 c1b49196b71..2a75190a3ec 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 b8a0e7d2075..a13c6129a28 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 2924a9b2d19..393780c969f 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 98a2367b79b..b2aaf3add25 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 349b10c346a..e0b66477254 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 98539be8c6c..fd72fec62a3 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