summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/udp_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/udp_usrreq.c')
-rw-r--r--freebsd/sys/netinet/udp_usrreq.c285
1 files changed, 60 insertions, 225 deletions
diff --git a/freebsd/sys/netinet/udp_usrreq.c b/freebsd/sys/netinet/udp_usrreq.c
index 42461ce9..093b7f32 100644
--- a/freebsd/sys/netinet/udp_usrreq.c
+++ b/freebsd/sys/netinet/udp_usrreq.c
@@ -19,7 +19,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -98,10 +98,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/udplite.h>
#include <netinet/in_rss.h>
-#ifdef IPSEC
-#include <netipsec/ipsec.h>
-#include <netipsec/esp.h>
-#endif
+#include <netipsec/ipsec_support.h>
#include <machine/in_cksum.h>
@@ -178,15 +175,6 @@ static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, struct thread *);
#endif
-#ifdef IPSEC
-#ifdef IPSEC_NAT_T
-#define UF_ESPINUDP_ALL (UF_ESPINUDP_NON_IKE|UF_ESPINUDP)
-#ifdef INET
-static struct mbuf *udp4_espdecap(struct inpcb *, struct mbuf *, int);
-#endif
-#endif /* IPSEC_NAT_T */
-#endif /* IPSEC */
-
static void
udp_zone_change(void *tag)
{
@@ -322,7 +310,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
{
struct sockaddr *append_sa;
struct socket *so;
- struct mbuf *opts = NULL;
+ struct mbuf *tmpopts, *opts = NULL;
#ifdef INET6
struct sockaddr_in6 udp_in6;
#endif
@@ -337,7 +325,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
if (up->u_tun_func != NULL) {
in_pcbref(inp);
INP_RUNLOCK(inp);
- (*up->u_tun_func)(n, off, inp, (struct sockaddr *)udp_in,
+ (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0],
up->u_tun_ctx);
INP_RLOCK(inp);
return (in_pcbrele_rlocked(inp));
@@ -345,21 +333,18 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
off += sizeof(struct udphdr);
-#ifdef IPSEC
+#if defined(IPSEC) || defined(IPSEC_SUPPORT)
/* Check AH/ESP integrity. */
- if (ipsec4_in_reject(n, inp)) {
+ if (IPSEC_ENABLED(ipv4) &&
+ IPSEC_CHECK_POLICY(ipv4, n, inp) != 0) {
m_freem(n);
return (0);
}
-#ifdef IPSEC_NAT_T
- up = intoudpcb(inp);
- KASSERT(up != NULL, ("%s: udpcb NULL", __func__));
- if (up->u_flags & UF_ESPINUDP_ALL) { /* IPSec UDP encaps. */
- n = udp4_espdecap(inp, n, off);
- if (n == NULL) /* Consumed. */
- return (0);
+ if (up->u_flags & UF_ESPINUDP) {/* IPSec UDP encaps. */
+ if (IPSEC_ENABLED(ipv4) &&
+ UDPENCAP_INPUT(n, off, AF_INET) != 0)
+ return (0); /* Consumed. */
}
-#endif /* IPSEC_NAT_T */
#endif /* IPSEC */
#ifdef MAC
if (mac_inpcb_check_deliver(inp, n) != 0) {
@@ -376,16 +361,27 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
#endif /* INET6 */
ip_savecontrol(inp, &opts, ip, n);
}
+ if ((inp->inp_vflag & INP_IPV4) && (inp->inp_flags2 & INP_ORIGDSTADDR)) {
+ tmpopts = sbcreatecontrol((caddr_t)&udp_in[1],
+ sizeof(struct sockaddr_in), IP_ORIGDSTADDR, IPPROTO_IP);
+ if (tmpopts) {
+ if (opts) {
+ tmpopts->m_next = opts;
+ opts = tmpopts;
+ } else
+ opts = tmpopts;
+ }
+ }
#ifdef INET6
if (inp->inp_vflag & INP_IPV6) {
bzero(&udp_in6, sizeof(udp_in6));
udp_in6.sin6_len = sizeof(udp_in6);
udp_in6.sin6_family = AF_INET6;
- in6_sin_2_v4mapsin6(udp_in, &udp_in6);
+ in6_sin_2_v4mapsin6(&udp_in[0], &udp_in6);
append_sa = (struct sockaddr *)&udp_in6;
} else
#endif /* INET6 */
- append_sa = (struct sockaddr *)udp_in;
+ append_sa = (struct sockaddr *)&udp_in[0];
m_adj(n, off);
so = inp->inp_socket;
@@ -411,7 +407,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
uint16_t len, ip_len;
struct inpcbinfo *pcbinfo;
struct ip save_ip;
- struct sockaddr_in udp_in;
+ struct sockaddr_in udp_in[2];
struct mbuf *m;
struct m_tag *fwd_tag;
int cscov_partial, iphlen;
@@ -456,11 +452,15 @@ udp_input(struct mbuf **mp, int *offp, int proto)
* Construct sockaddr format source address. Stuff source address
* and datagram in user buffer.
*/
- bzero(&udp_in, sizeof(udp_in));
- udp_in.sin_len = sizeof(udp_in);
- udp_in.sin_family = AF_INET;
- udp_in.sin_port = uh->uh_sport;
- udp_in.sin_addr = ip->ip_src;
+ bzero(&udp_in[0], sizeof(struct sockaddr_in) * 2);
+ udp_in[0].sin_len = sizeof(struct sockaddr_in);
+ udp_in[0].sin_family = AF_INET;
+ udp_in[0].sin_port = uh->uh_sport;
+ udp_in[0].sin_addr = ip->ip_src;
+ udp_in[1].sin_len = sizeof(struct sockaddr_in);
+ udp_in[1].sin_family = AF_INET;
+ udp_in[1].sin_port = uh->uh_dport;
+ udp_in[1].sin_addr = ip->ip_dst;
/*
* Make mbuf data length reflect UDP length. If not enough data to
@@ -589,7 +589,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
blocked = imo_multi_filter(imo, ifp,
(struct sockaddr *)&group,
- (struct sockaddr *)&udp_in);
+ (struct sockaddr *)&udp_in[0]);
if (blocked != MCAST_PASS) {
if (blocked == MCAST_NOTGMEMBER)
IPSTAT_INC(ips_notmember);
@@ -608,7 +608,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
UDP_PROBE(receive, NULL, last, ip,
last, uh);
if (udp_append(last, ip, n, iphlen,
- &udp_in)) {
+ udp_in)) {
goto inp_lost;
}
}
@@ -641,7 +641,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
goto badunlocked;
}
UDP_PROBE(receive, NULL, last, ip, last, uh);
- if (udp_append(last, ip, m, iphlen, &udp_in) == 0)
+ if (udp_append(last, ip, m, iphlen, udp_in) == 0)
INP_RUNLOCK(last);
inp_lost:
INP_INFO_RUNLOCK(pcbinfo);
@@ -688,13 +688,13 @@ udp_input(struct mbuf **mp, int *offp, int proto)
INPLOOKUP_RLOCKPCB, ifp, m);
if (inp == NULL) {
if (udp_log_in_vain) {
- char buf[4*sizeof "123"];
+ char src[INET_ADDRSTRLEN];
+ char dst[INET_ADDRSTRLEN];
- strcpy(buf, inet_ntoa(ip->ip_dst));
log(LOG_INFO,
"Connection attempt to UDP %s:%d from %s:%d\n",
- buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src),
- ntohs(uh->uh_sport));
+ inet_ntoa_r(ip->ip_dst, dst), ntohs(uh->uh_dport),
+ inet_ntoa_r(ip->ip_src, src), ntohs(uh->uh_sport));
}
UDPSTAT_INC(udps_noport);
if (m->m_flags & (M_BCAST | M_MCAST)) {
@@ -731,7 +731,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
}
UDP_PROBE(receive, NULL, inp, ip, inp, uh);
- if (udp_append(inp, ip, m, iphlen, &udp_in) == 0)
+ if (udp_append(inp, ip, m, iphlen, udp_in) == 0)
INP_RUNLOCK(inp);
return (IPPROTO_DONE);
@@ -911,13 +911,7 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
if (inp->inp_gencnt <= gencnt) {
struct xinpcb xi;
- bzero(&xi, sizeof(xi));
- xi.xi_len = sizeof xi;
- /* XXX should avoid extra copy */
- bcopy(inp, &xi.xi_inp, sizeof *inp);
- if (inp->inp_socket)
- sotoxsocket(inp->inp_socket, &xi.xi_socket);
- xi.xi_inp.inp_gencnt = inp->inp_gencnt;
+ in_pcbtoxinpcb(inp, &xi);
INP_RUNLOCK(inp);
error = SYSCTL_OUT(req, &xi, sizeof xi);
} else
@@ -1027,42 +1021,17 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
switch (sopt->sopt_dir) {
case SOPT_SET:
switch (sopt->sopt_name) {
+#if defined(IPSEC) || defined(IPSEC_SUPPORT)
+#ifdef INET
case UDP_ENCAP:
- INP_WUNLOCK(inp);
- error = sooptcopyin(sopt, &optval, sizeof optval,
- sizeof optval);
- if (error)
- break;
- inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
- INP_WLOCK(inp);
-#ifdef IPSEC_NAT_T
- up = intoudpcb(inp);
- KASSERT(up != NULL, ("%s: up == NULL", __func__));
-#endif
- switch (optval) {
- case 0:
- /* Clear all UDP encap. */
-#ifdef IPSEC_NAT_T
- up->u_flags &= ~UF_ESPINUDP_ALL;
-#endif
- break;
-#ifdef IPSEC_NAT_T
- case UDP_ENCAP_ESPINUDP:
- case UDP_ENCAP_ESPINUDP_NON_IKE:
- up->u_flags &= ~UF_ESPINUDP_ALL;
- if (optval == UDP_ENCAP_ESPINUDP)
- up->u_flags |= UF_ESPINUDP;
- else if (optval == UDP_ENCAP_ESPINUDP_NON_IKE)
- up->u_flags |= UF_ESPINUDP_NON_IKE;
- break;
-#endif
- default:
- error = EINVAL;
- break;
+ if (!IPSEC_ENABLED(ipv4)) {
+ INP_WUNLOCK(inp);
+ return (ENOPROTOOPT);
}
- INP_WUNLOCK(inp);
+ error = UDPENCAP_PCBCTL(inp, sopt);
break;
+#endif /* INET */
+#endif /* IPSEC */
case UDPLITE_SEND_CSCOV:
case UDPLITE_RECV_CSCOV:
if (!isudplite) {
@@ -1099,15 +1068,17 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt)
break;
case SOPT_GET:
switch (sopt->sopt_name) {
-#ifdef IPSEC_NAT_T
+#if defined(IPSEC) || defined(IPSEC_SUPPORT)
+#ifdef INET
case UDP_ENCAP:
- up = intoudpcb(inp);
- KASSERT(up != NULL, ("%s: up == NULL", __func__));
- optval = up->u_flags & UF_ESPINUDP_ALL;
- INP_WUNLOCK(inp);
- error = sooptcopyout(sopt, &optval, sizeof optval);
+ if (!IPSEC_ENABLED(ipv4)) {
+ INP_WUNLOCK(inp);
+ return (ENOPROTOOPT);
+ }
+ error = UDPENCAP_PCBCTL(inp, sopt);
break;
-#endif
+#endif /* INET */
+#endif /* IPSEC */
case UDPLITE_SEND_CSCOV:
case UDPLITE_RECV_CSCOV:
if (!isudplite) {
@@ -1590,142 +1561,6 @@ release:
return (error);
}
-
-#if defined(IPSEC) && defined(IPSEC_NAT_T)
-/*
- * Potentially decap ESP in UDP frame. Check for an ESP header
- * and optional marker; if present, strip the UDP header and
- * push the result through IPSec.
- *
- * Returns mbuf to be processed (potentially re-allocated) or
- * NULL if consumed and/or processed.
- */
-static struct mbuf *
-udp4_espdecap(struct inpcb *inp, struct mbuf *m, int off)
-{
- size_t minlen, payload, skip, iphlen;
- caddr_t data;
- struct udpcb *up;
- struct m_tag *tag;
- struct udphdr *udphdr;
- struct ip *ip;
-
- INP_RLOCK_ASSERT(inp);
-
- /*
- * Pull up data so the longest case is contiguous:
- * IP/UDP hdr + non ESP marker + ESP hdr.
- */
- minlen = off + sizeof(uint64_t) + sizeof(struct esp);
- if (minlen > m->m_pkthdr.len)
- minlen = m->m_pkthdr.len;
- if ((m = m_pullup(m, minlen)) == NULL) {
- IPSECSTAT_INC(ips_in_inval);
- return (NULL); /* Bypass caller processing. */
- }
- data = mtod(m, caddr_t); /* Points to ip header. */
- payload = m->m_len - off; /* Size of payload. */
-
- if (payload == 1 && data[off] == '\xff')
- return (m); /* NB: keepalive packet, no decap. */
-
- up = intoudpcb(inp);
- KASSERT(up != NULL, ("%s: udpcb NULL", __func__));
- KASSERT((up->u_flags & UF_ESPINUDP_ALL) != 0,
- ("u_flags 0x%x", up->u_flags));
-
- /*
- * Check that the payload is large enough to hold an
- * ESP header and compute the amount of data to remove.
- *
- * NB: the caller has already done a pullup for us.
- * XXX can we assume alignment and eliminate bcopys?
- */
- if (up->u_flags & UF_ESPINUDP_NON_IKE) {
- /*
- * draft-ietf-ipsec-nat-t-ike-0[01].txt and
- * draft-ietf-ipsec-udp-encaps-(00/)01.txt, ignoring
- * possible AH mode non-IKE marker+non-ESP marker
- * from draft-ietf-ipsec-udp-encaps-00.txt.
- */
- uint64_t marker;
-
- if (payload <= sizeof(uint64_t) + sizeof(struct esp))
- return (m); /* NB: no decap. */
- bcopy(data + off, &marker, sizeof(uint64_t));
- if (marker != 0) /* Non-IKE marker. */
- return (m); /* NB: no decap. */
- skip = sizeof(uint64_t) + sizeof(struct udphdr);
- } else {
- uint32_t spi;
-
- if (payload <= sizeof(struct esp)) {
- IPSECSTAT_INC(ips_in_inval);
- m_freem(m);
- return (NULL); /* Discard. */
- }
- bcopy(data + off, &spi, sizeof(uint32_t));
- if (spi == 0) /* Non-ESP marker. */
- return (m); /* NB: no decap. */
- skip = sizeof(struct udphdr);
- }
-
- /*
- * Setup a PACKET_TAG_IPSEC_NAT_T_PORT tag to remember
- * the UDP ports. This is required if we want to select
- * the right SPD for multiple hosts behind same NAT.
- *
- * NB: ports are maintained in network byte order everywhere
- * in the NAT-T code.
- */
- tag = m_tag_get(PACKET_TAG_IPSEC_NAT_T_PORTS,
- 2 * sizeof(uint16_t), M_NOWAIT);
- if (tag == NULL) {
- IPSECSTAT_INC(ips_in_nomem);
- m_freem(m);
- return (NULL); /* Discard. */
- }
- iphlen = off - sizeof(struct udphdr);
- udphdr = (struct udphdr *)(data + iphlen);
- ((uint16_t *)(tag + 1))[0] = udphdr->uh_sport;
- ((uint16_t *)(tag + 1))[1] = udphdr->uh_dport;
- m_tag_prepend(m, tag);
-
- /*
- * Remove the UDP header (and possibly the non ESP marker)
- * IP header length is iphlen
- * Before:
- * <--- off --->
- * +----+------+-----+
- * | IP | UDP | ESP |
- * +----+------+-----+
- * <-skip->
- * After:
- * +----+-----+
- * | IP | ESP |
- * +----+-----+
- * <-skip->
- */
- ovbcopy(data, data + skip, iphlen);
- m_adj(m, skip);
-
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(ntohs(ip->ip_len) - skip);
- ip->ip_p = IPPROTO_ESP;
-
- /*
- * We cannot yet update the cksums so clear any
- * h/w cksum flags as they are no longer valid.
- */
- if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID)
- m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID|CSUM_PSEUDO_HDR);
-
- (void) ipsec_common_input(m, iphlen, offsetof(struct ip, ip_p),
- AF_INET, ip->ip_p);
- return (NULL); /* NB: consumed, bypass processing. */
-}
-#endif /* defined(IPSEC) && defined(IPSEC_NAT_T) */
-
static void
udp_abort(struct socket *so)
{