Date: Thu, 22 Dec 2016 14:18:43 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r310411 - projects/ipsec/sys/netipsec Message-ID: <201612221418.uBMEIhsZ073539@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Thu Dec 22 14:18:43 2016 New Revision: 310411 URL: https://svnweb.freebsd.org/changeset/base/310411 Log: Add IPSEC_OUTPUT() and IPSEC_FORWARD() methods implementation. Modified: projects/ipsec/sys/netipsec/ipsec_output.c Modified: projects/ipsec/sys/netipsec/ipsec_output.c ============================================================================== --- projects/ipsec/sys/netipsec/ipsec_output.c Thu Dec 22 14:17:30 2016 (r310410) +++ projects/ipsec/sys/netipsec/ipsec_output.c Thu Dec 22 14:18:43 2016 (r310411) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +33,7 @@ #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_sctp.h" #include <sys/param.h> #include <sys/systm.h> @@ -67,6 +69,9 @@ #ifdef INET6 #include <netinet/icmp6.h> #endif +#ifdef SCTP +#include <netinet/sctp_crc32.h> +#endif #include <netipsec/ipsec.h> #ifdef INET6 @@ -84,10 +89,6 @@ #include <machine/in_cksum.h> -#ifdef IPSEC_NAT_T -#include <netinet/udp.h> -#endif - #define IPSEC_OSTAT_INC(proto, name) do { \ if ((proto) == IPPROTO_ESP) \ ESPSTAT_INC(esps_##name); \ @@ -293,6 +294,111 @@ ipsec4_process_packet(struct mbuf *m, st return (ipsec4_perform_request(m, sp, 0)); } + +static int +ipsec4_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) +{ + struct secpolicy *sp; + int error, idx; + + /* Lookup for the corresponding outbound security policy */ + sp = ipsec4_checkpolicy(m, inp, &error); + if (sp == NULL) { + if (error == -EINVAL) { + /* Discarded by policy. */ + m_freem(m); + return (EACCES); + } + return (0); /* No IPsec required. */ + } + + if (forwarding) { + /* + * Check that SP has tunnel mode IPsec transform. + * We can't use transport mode when forwarding. + */ + for (idx = 0; idx < sp->tcount; idx++) { + if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL) + break; + } + if (idx == sp->tcount) { + IPSECSTAT_INC(ips_out_inval); + key_freesp(&sp); + m_freem(m); + return (EACCES); + } + } else { + /* + * Do delayed checksums now because we send before + * this is done in the normal processing path. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) { + struct ip *ip = mtod(m, struct ip *); + + sctp_delayed_cksum(m, (uint32_t)(ip->ip_hl << 2)); + m->m_pkthdr.csum_flags &= ~CSUM_SCTP; + } +#endif + } + /* NB: callee frees mbuf and releases reference to SP */ + error = ipsec4_process_packet(m, sp, inp); + 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 and return without error. + */ + return (0); + } + if (error == 0) + return (EINPROGRESS); /* consumed by IPsec */ + return (error); +} + +/* + * IPSEC_OUTPUT() method implementation for IPv4. + * 0 - no IPsec handling needed + * other values - mbuf consumed by IPsec. + */ +int +ipsec4_output(struct mbuf *m, struct inpcb *inp) +{ + + /* + * If the packet is resubmitted to ip_output (e.g. after + * AH, ESP, etc. processing), there will be a tag to bypass + * the lookup and related policy checking. + */ + if (m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL) + return (0); + + return (ipsec4_common_output(m, inp, 0)); +} + +/* + * IPSEC_FORWARD() method implementation for IPv4. + * 0 - no IPsec handling needed + * other values - mbuf consumed by IPsec. + */ +int +ipsec4_forward(struct mbuf *m) +{ + + /* + * Check if this packet has an active inbound SP and needs to be + * dropped instead of forwarded. + */ + if (ipsec4_in_reject(m, NULL) != 0) { + m_freem(m); + return (EACCES); + } + return (ipsec4_common_output(m, NULL, 1)); +} #endif #ifdef INET6 @@ -502,6 +608,117 @@ ipsec6_process_packet(struct mbuf *m, st return (ipsec6_perform_request(m, sp, 0)); } + +static int +ipsec6_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) +{ + struct secpolicy *sp; + int error, idx; + + /* Lookup for the corresponding outbound security policy */ + sp = ipsec6_checkpolicy(m, inp, &error); + if (sp == NULL) { + if (error == -EINVAL) { + /* Discarded by policy. */ + m_freem(m); + return (EACCES); + } + return (0); /* No IPsec required. */ + } + + if (forwarding) { + /* + * Check that SP has tunnel mode IPsec transform. + * We can't use transport mode when forwarding. + * + * RFC2473 says: + * "A tunnel IPv6 packet resulting from the encapsulation of + * an original packet is considered an IPv6 packet originating + * from the tunnel entry-point node." + * So, we don't need MTU checking, after IPsec processing + * we will just fragment it if needed. + */ + for (idx = 0; idx < sp->tcount; idx++) { + if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL) + break; + } + if (idx == sp->tcount) { + IPSEC6STAT_INC(ips_out_inval); + key_freesp(&sp); + m_freem(m); + return (EACCES); + } + } else { + /* + * Do delayed checksums now because we send before + * this is done in the normal processing path. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { + in6_delayed_cksum(m, m->m_pkthdr.len - + sizeof(struct ip6_hdr), 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; + } +#endif + } + /* NB: callee frees mbuf and releases reference to SP */ + error = ipsec6_process_packet(m, sp, inp); + 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 and return without error. + */ + return (0); + } + if (error == 0) + return (EINPROGRESS); /* consumed by IPsec */ + return (error); +} + +/* + * IPSEC_OUTPUT() method implementation for IPv6. + * 0 - no IPsec handling needed + * other values - mbuf consumed by IPsec. + */ +int +ipsec6_output(struct mbuf *m, struct inpcb *inp) +{ + + /* + * If the packet is resubmitted to ip_output (e.g. after + * AH, ESP, etc. processing), there will be a tag to bypass + * the lookup and related policy checking. + */ + if (m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL) + return (0); + + return (ipsec6_common_output(m, inp, 0)); +} + +/* + * IPSEC_FORWARD() method implementation for IPv6. + * 0 - no IPsec handling needed + * other values - mbuf consumed by IPsec. + */ +int +ipsec6_forward(struct mbuf *m) +{ + + /* + * Check if this packet has an active inbound SP and needs to be + * dropped instead of forwarded. + */ + if (ipsec6_in_reject(m, NULL) != 0) { + m_freem(m); + return (EACCES); + } + return (ipsec6_common_output(m, NULL, 1)); +} #endif /* INET6 */ int
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612221418.uBMEIhsZ073539>