diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 003bb7cea7e..63e5ad474bb 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -702,7 +702,8 @@ int getsourcefilter(int, uint32_t, struct sockaddr *, socklen_t, #define IPCTL_FASTFORWARDING 14 /* use fast IP forwarding code */ #define IPCTL_KEEPFAITH 15 /* FAITH IPv4->IPv6 translater ctl */ #define IPCTL_GIF_TTL 16 /* default TTL for gif encap packet */ -#define IPCTL_MAXID 17 +#define IPCTL_IPSEC_INUSE 17 +#define IPCTL_MAXID 18 #endif /* __BSD_VISIBLE */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index dea8bee182b..a574754adcd 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -97,6 +97,11 @@ SYSCTL_VNET_INT(_net_inet_ip, IPCTL_FORWARDING, forwarding, CTLFLAG_RW, &VNET_NAME(ipforwarding), 0, "Enable IP forwarding between interfaces"); +VNET_DEFINE(int, ipipsec_in_use); +SYSCTL_VNET_INT(_net_inet_ip, IPCTL_IPSEC_INUSE, ipsec_in_use, CTLFLAG_RW, + &VNET_NAME(ipipsec_in_use), 0, + "Enable IPSec processing of packets"); + static VNET_DEFINE(int, ipsendredirects) = 1; /* XXX */ #define V_ipsendredirects VNET(ipsendredirects) SYSCTL_VNET_INT(_net_inet_ip, IPCTL_SENDREDIRECTS, redirect, CTLFLAG_RW, @@ -468,7 +473,7 @@ tooshort: /* * Bypass packet filtering for packets previously handled by IPsec. */ - if (ip_ipsec_filtertunnel(m)) + if (V_ipipsec_in_use && ip_ipsec_filtertunnel(m)) goto passin; #endif /* IPSEC */ @@ -675,7 +680,7 @@ passin: m_freem(m); } else { #ifdef IPSEC - if (ip_ipsec_fwd(m)) + if (V_ipipsec_in_use && ip_ipsec_fwd(m)) goto bad; #endif /* IPSEC */ ip_forward(m, dchg); @@ -722,7 +727,7 @@ ours: * note that we do not visit this with protocols with pcb layer * code - like udp/tcp/raw ip. */ - if (ip_ipsec_input(m)) + if (V_ipipsec_in_use && ip_ipsec_input(m)) goto bad; #endif /* IPSEC */ @@ -1519,7 +1524,8 @@ ip_forward(struct mbuf *m, int srcrt) * If IPsec is configured for this path, * override any possibly mtu value set by ip_output. */ - mtu = ip_ipsec_mtu(mcopy, mtu); + if (V_ipipsec_in_use) + mtu = ip_ipsec_mtu(mcopy, mtu); #endif /* IPSEC */ /* * If the MTU was set before make sure we are below the diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 9da46499fc0..a3ab3d7f99c 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -481,18 +481,20 @@ again: sendit: #ifdef IPSEC - switch(ip_ipsec_output(&m, inp, &flags, &error)) { - case 1: - goto bad; - case -1: - goto done; - case 0: - default: - break; /* Continue with packet processing. */ + if (V_ipipsec_in_use) { + switch(ip_ipsec_output(&m, inp, &flags, &error)) { + case 1: + goto bad; + case -1: + goto done; + case 0: + default: + break; /* Continue with packet processing. */ + } + /* Update variables that are affected by ipsec4_output(). */ + ip = mtod(m, struct ip *); + hlen = ip->ip_hl << 2; } - /* Update variables that are affected by ipsec4_output(). */ - ip = mtod(m, struct ip *); - hlen = ip->ip_hl << 2; #endif /* IPSEC */ /* Jump over all PFIL processing if hooks are not active. */ diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index b2251acfd0b..de088498abe 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -176,6 +176,7 @@ struct sockopt; VNET_DECLARE(u_short, ip_id); /* ip packet ctr, for ids */ VNET_DECLARE(int, ip_defttl); /* default IP ttl */ VNET_DECLARE(int, ipforwarding); /* ip forwarding */ +VNET_DECLARE(int, ipipsec_in_use); #ifdef IPSTEALTH VNET_DECLARE(int, ipstealth); /* stealth forwarding */ #endif @@ -191,6 +192,7 @@ extern struct pr_usrreqs rip_usrreqs; #define V_ip_id VNET(ip_id) #define V_ip_defttl VNET(ip_defttl) #define V_ipforwarding VNET(ipforwarding) +#define V_ipipsec_in_use VNET(ipipsec_in_use) #ifdef IPSTEALTH #define V_ipstealth VNET(ipstealth) #endif diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 7d09696a309..48a231c3e02 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -133,6 +133,7 @@ static struct netisr_handler ip6_nh = { .nh_policy = NETISR_POLICY_FLOW, }; +VNET_DECLARE(int, ipipsec_in_use); VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch); #define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) @@ -1000,6 +1001,7 @@ passin: } #ifdef IPSEC + if (V_ipipsec_in_use) { /* * enforce IPsec policy checking if we are seeing last header. * note that we do not visit this with protocols with pcb layer @@ -1007,6 +1009,7 @@ passin: */ if (ip6_ipsec_input(m, nxt)) goto bad; + } #endif /* IPSEC */ /* diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index b1d27d4f667..b9161abf00d 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -147,6 +147,7 @@ static int ip6_getpmtu(struct route_in6 *, struct route_in6 *, struct ifnet *, struct in6_addr *, u_long *, int *, u_int); static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int); +VNET_DECLARE(int, ipipsec_in_use); /* * Make an extension header from option data. hp is the source, and @@ -294,33 +295,35 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, } #ifdef IPSEC - /* - * IPSec checking which handles several cases. - * FAST IPSEC: We re-injected the packet. - */ - switch(ip6_ipsec_output(&m, inp, &flags, &error, &ifp, &sp)) - { - case 1: /* Bad packet */ - goto freehdrs; - case -1: /* Do IPSec */ - needipsec = 1; + if (V_ipipsec_in_use) { /* - * Do delayed checksums now, as we may send before returning. + * IPSec checking which handles several cases. + * FAST IPSEC: We re-injected the packet. */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { - plen = m->m_pkthdr.len - sizeof(*ip6); - in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr)); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; - } + switch(ip6_ipsec_output(&m, inp, &flags, &error, &ifp, &sp)) + { + case 1: /* Bad packet */ + goto freehdrs; + case -1: /* Do IPSec */ + needipsec = 1; + /* + * Do delayed checksums now, as we may send before returning. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { + plen = m->m_pkthdr.len - sizeof(*ip6); + in6_delayed_cksum(m, plen, sizeof(struct ip6_hdr)); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; + } #ifdef SCTP - if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { - sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); - m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; - } + if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { + sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); + m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; + } #endif - case 0: /* No IPSec */ - default: - break; + case 0: /* No IPSec */ + default: + break; + } } #endif /* IPSEC */ @@ -421,67 +424,69 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, IPPROTO_ROUTING); #ifdef IPSEC - if (!needipsec) - goto skip_ipsec2; + if (V_ipipsec_in_use) { + if (!needipsec) + goto skip_ipsec2; - /* - * pointers after IPsec headers are not valid any more. - * other pointers need a great care too. - * (IPsec routines should not mangle mbufs prior to AH/ESP) - */ - exthdrs.ip6e_dest2 = NULL; - - if (exthdrs.ip6e_rthdr) { - rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); - segleft_org = rh->ip6r_segleft; - rh->ip6r_segleft = 0; - } - - bzero(&state, sizeof(state)); - state.m = m; - error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, - &needipsectun); - m = state.m; - if (error == EJUSTRETURN) { /* - * We had a SP with a level of 'use' and no SA. We - * will just continue to process the packet without - * IPsec processing. + * pointers after IPsec headers are not valid any more. + * other pointers need a great care too. + * (IPsec routines should not mangle mbufs prior to AH/ESP) */ - ; - } else if (error) { - /* mbuf is already reclaimed in ipsec6_output_trans. */ - m = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("[%s:%d] (ipsec): error code %d\n", - __func__, __LINE__, error); - /* FALLTHROUGH */ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; + exthdrs.ip6e_dest2 = NULL; + + if (exthdrs.ip6e_rthdr) { + rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); + segleft_org = rh->ip6r_segleft; + rh->ip6r_segleft = 0; + } + + bzero(&state, sizeof(state)); + state.m = m; + error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, + &needipsectun); + m = state.m; + if (error == EJUSTRETURN) { + /* + * We had a SP with a level of 'use' and no SA. We + * will just continue to process the packet without + * IPsec processing. + */ + ; + } else if (error) { + /* mbuf is already reclaimed in ipsec6_output_trans. */ + m = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("[%s:%d] (ipsec): error code %d\n", + __func__, __LINE__, error); + /* FALLTHROUGH */ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; + } + goto bad; + } else if (!needipsectun) { + /* + * In the FAST IPSec case we have already + * re-injected the packet and it has been freed + * by the ipsec_done() function. So, just clean + * up after ourselves. + */ + m = NULL; + goto done; + } + if (exthdrs.ip6e_rthdr) { + /* ah6_output doesn't modify mbuf chain */ + rh->ip6r_segleft = segleft_org; } - goto bad; - } else if (!needipsectun) { - /* - * In the FAST IPSec case we have already - * re-injected the packet and it has been freed - * by the ipsec_done() function. So, just clean - * up after ourselves. - */ - m = NULL; - goto done; - } - if (exthdrs.ip6e_rthdr) { - /* ah6_output doesn't modify mbuf chain */ - rh->ip6r_segleft = segleft_org; } skip_ipsec2:; #endif /* IPSEC */ @@ -552,73 +557,75 @@ again: } #ifdef IPSEC - /* - * We may re-inject packets into the stack here. - */ - if (needipsec && needipsectun) { - struct ipsec_output_state state; - + if (V_ipipsec_in_use) { /* - * All the extension headers will become inaccessible - * (since they can be encrypted). - * Don't panic, we need no more updates to extension headers - * on inner IPv6 packet (since they are now encapsulated). - * - * IPv6 [ESP|AH] IPv6 [extension headers] payload + * We may re-inject packets into the stack here. */ - bzero(&exthdrs, sizeof(exthdrs)); - exthdrs.ip6e_ip6 = m; + if (needipsec && needipsectun) { + struct ipsec_output_state state; - bzero(&state, sizeof(state)); - state.m = m; - state.ro = (struct route *)ro; - state.dst = (struct sockaddr *)dst; - - error = ipsec6_output_tunnel(&state, sp, flags); - - m = state.m; - ro = (struct route_in6 *)state.ro; - dst = (struct sockaddr_in6 *)state.dst; - if (error == EJUSTRETURN) { /* - * We had a SP with a level of 'use' and no SA. We - * will just continue to process the packet without - * IPsec processing. + * All the extension headers will become inaccessible + * (since they can be encrypted). + * Don't panic, we need no more updates to extension headers + * on inner IPv6 packet (since they are now encapsulated). + * + * IPv6 [ESP|AH] IPv6 [extension headers] payload */ - ; - } else if (error) { - /* mbuf is already reclaimed in ipsec6_output_tunnel. */ - m0 = m = NULL; - m = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("[%s:%d] (ipsec): error code %d\n", - __func__, __LINE__, error); - /* FALLTHROUGH */ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; + bzero(&exthdrs, sizeof(exthdrs)); + exthdrs.ip6e_ip6 = m; + + bzero(&state, sizeof(state)); + state.m = m; + state.ro = (struct route *)ro; + state.dst = (struct sockaddr *)dst; + + error = ipsec6_output_tunnel(&state, sp, flags); + + m = state.m; + ro = (struct route_in6 *)state.ro; + dst = (struct sockaddr_in6 *)state.dst; + if (error == EJUSTRETURN) { + /* + * We had a SP with a level of 'use' and no SA. We + * will just continue to process the packet without + * IPsec processing. + */ + ; + } else if (error) { + /* mbuf is already reclaimed in ipsec6_output_tunnel. */ + m0 = m = NULL; + m = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("[%s:%d] (ipsec): error code %d\n", + __func__, __LINE__, error); + /* FALLTHROUGH */ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; + } + goto bad; + } else { + /* + * In the FAST IPSec case we have already + * re-injected the packet and it has been freed + * by the ipsec_done() function. So, just clean + * up after ourselves. + */ + m = NULL; + goto done; } - goto bad; - } else { - /* - * In the FAST IPSec case we have already - * re-injected the packet and it has been freed - * by the ipsec_done() function. So, just clean - * up after ourselves. - */ - m = NULL; - goto done; - } - exthdrs.ip6e_ip6 = m; + exthdrs.ip6e_ip6 = m; + } } #endif /* IPSEC */ diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 70e487ea2e2..7e5e8708f75 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -314,6 +314,7 @@ VNET_DECLARE(int, ip6_v6only); #define V_ip6_rr_prune VNET(ip6_rr_prune) #define V_ip6_mcast_pmtu VNET(ip6_mcast_pmtu) #define V_ip6_v6only VNET(ip6_v6only) +#define V_ipipsec_in_use VNET(ipipsec_in_use) VNET_DECLARE(struct socket *, ip6_mrouter); /* multicast routing daemon */ VNET_DECLARE(int, ip6_sendredirects); /* send IP redirects when forwarding? */