10fb6ad5ae/*-
20fb6ad5ae * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
30fb6ad5ae * All rights reserved.
40fb6ad5ae *
50fb6ad5ae * Redistribution and use in source and binary forms, with or without
60fb6ad5ae * modification, are permitted provided that the following conditions
70fb6ad5ae * are met:
80fb6ad5ae *
90fb6ad5ae * 1. Redistributions of source code must retain the above copyright
100fb6ad5ae *    notice, this list of conditions and the following disclaimer.
110fb6ad5ae * 2. Redistributions in binary form must reproduce the above copyright
120fb6ad5ae *    notice, this list of conditions and the following disclaimer in the
130fb6ad5ae *    documentation and/or other materials provided with the distribution.
140fb6ad5ae *
150fb6ad5ae * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
160fb6ad5ae * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
170fb6ad5ae * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
180fb6ad5ae * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
190fb6ad5ae * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
200fb6ad5ae * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
210fb6ad5ae * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
220fb6ad5ae * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
230fb6ad5ae * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
240fb6ad5ae * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
250fb6ad5ae */
260fb6ad5ae
270fb6ad5ae#include <sys/cdefs.h>
280fb6ad5ae__FBSDID("$FreeBSD$");
290fb6ad5ae
300fb6ad5ae#include "opt_inet.h"
310fb6ad5ae#include "opt_inet6.h"
320fb6ad5ae#include "opt_ipsec.h"
330fb6ad5ae
340fb6ad5ae#include <sys/param.h>
350fb6ad5ae#include <sys/systm.h>
360fb6ad5ae#include <sys/kernel.h>
370fb6ad5ae#include <sys/lock.h>
380fb6ad5ae#include <sys/malloc.h>
390fb6ad5ae#include <sys/mbuf.h>
400fb6ad5ae#include <sys/priv.h>
410fb6ad5ae#include <sys/socket.h>
420fb6ad5ae#include <sys/sockopt.h>
430fb6ad5ae#include <sys/syslog.h>
440fb6ad5ae#include <sys/proc.h>
450fb6ad5ae
460fb6ad5ae#include <netinet/in.h>
470fb6ad5ae#include <netinet/in_pcb.h>
480fb6ad5ae
490fb6ad5ae#include <netipsec/ipsec.h>
500fb6ad5ae#include <netipsec/ipsec6.h>
510fb6ad5ae#include <netipsec/ipsec_support.h>
520fb6ad5ae#include <netipsec/key.h>
530fb6ad5ae#include <netipsec/key_debug.h>
540fb6ad5ae
550fb6ad5aeMALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
560fb6ad5ae
570fb6ad5aestatic void
580fb6ad5aeipsec_setsockaddrs_inpcb(struct inpcb *inp, union sockaddr_union *src,
590fb6ad5ae    union sockaddr_union *dst, u_int dir)
600fb6ad5ae{
610fb6ad5ae
620fb6ad5ae#ifdef INET6
630fb6ad5ae	if (inp->inp_vflag & INP_IPV6) {
640fb6ad5ae		struct sockaddr_in6 *sin6;
650fb6ad5ae
660fb6ad5ae		bzero(&src->sin6, sizeof(src->sin6));
670fb6ad5ae		bzero(&dst->sin6, sizeof(dst->sin6));
680fb6ad5ae		src->sin6.sin6_family = AF_INET6;
690fb6ad5ae		src->sin6.sin6_len = sizeof(struct sockaddr_in6);
700fb6ad5ae		dst->sin6.sin6_family = AF_INET6;
710fb6ad5ae		dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
720fb6ad5ae
730fb6ad5ae		if (dir == IPSEC_DIR_OUTBOUND)
740fb6ad5ae			sin6 = &src->sin6;
750fb6ad5ae		else
760fb6ad5ae			sin6 = &dst->sin6;
770fb6ad5ae		sin6->sin6_addr = inp->in6p_laddr;
780fb6ad5ae		sin6->sin6_port = inp->inp_lport;
790fb6ad5ae		if (IN6_IS_SCOPE_LINKLOCAL(&inp->in6p_laddr)) {
800fb6ad5ae			/* XXXAE: use in6p_zoneid */
810fb6ad5ae			sin6->sin6_addr.s6_addr16[1] = 0;
820fb6ad5ae			sin6->sin6_scope_id = ntohs(
830fb6ad5ae			    inp->in6p_laddr.s6_addr16[1]);
840fb6ad5ae		}
850fb6ad5ae
860fb6ad5ae		if (dir == IPSEC_DIR_OUTBOUND)
870fb6ad5ae			sin6 = &dst->sin6;
880fb6ad5ae		else
890fb6ad5ae			sin6 = &src->sin6;
900fb6ad5ae		sin6->sin6_addr = inp->in6p_faddr;
910fb6ad5ae		sin6->sin6_port = inp->inp_fport;
920fb6ad5ae		if (IN6_IS_SCOPE_LINKLOCAL(&inp->in6p_faddr)) {
930fb6ad5ae			/* XXXAE: use in6p_zoneid */
940fb6ad5ae			sin6->sin6_addr.s6_addr16[1] = 0;
950fb6ad5ae			sin6->sin6_scope_id = ntohs(
960fb6ad5ae			    inp->in6p_faddr.s6_addr16[1]);
970fb6ad5ae		}
980fb6ad5ae	}
990fb6ad5ae#endif
1000fb6ad5ae#ifdef INET
1010fb6ad5ae	if (inp->inp_vflag & INP_IPV4) {
1020fb6ad5ae		struct sockaddr_in *sin;
1030fb6ad5ae
1040fb6ad5ae		bzero(&src->sin, sizeof(src->sin));
1050fb6ad5ae		bzero(&dst->sin, sizeof(dst->sin));
1060fb6ad5ae		src->sin.sin_family = AF_INET;
1070fb6ad5ae		src->sin.sin_len = sizeof(struct sockaddr_in);
1080fb6ad5ae		dst->sin.sin_family = AF_INET;
1090fb6ad5ae		dst->sin.sin_len = sizeof(struct sockaddr_in);
1100fb6ad5ae
1110fb6ad5ae		if (dir == IPSEC_DIR_OUTBOUND)
1120fb6ad5ae			sin = &src->sin;
1130fb6ad5ae		else
1140fb6ad5ae			sin = &dst->sin;
1150fb6ad5ae		sin->sin_addr = inp->inp_laddr;
1160fb6ad5ae		sin->sin_port = inp->inp_lport;
1170fb6ad5ae
1180fb6ad5ae		if (dir == IPSEC_DIR_OUTBOUND)
1190fb6ad5ae			sin = &dst->sin;
1200fb6ad5ae		else
1210fb6ad5ae			sin = &src->sin;
1220fb6ad5ae		sin->sin_addr = inp->inp_faddr;
1230fb6ad5ae		sin->sin_port = inp->inp_fport;
1240fb6ad5ae	}
1250fb6ad5ae#endif
1260fb6ad5ae}
1270fb6ad5ae
1280fb6ad5aevoid
1290fb6ad5aeipsec_setspidx_inpcb(struct inpcb *inp, struct secpolicyindex *spidx,
1300fb6ad5ae    u_int dir)
1310fb6ad5ae{
1320fb6ad5ae
1330fb6ad5ae	ipsec_setsockaddrs_inpcb(inp, &spidx->src, &spidx->dst, dir);
1340fb6ad5ae#ifdef INET6
1350fb6ad5ae	if (inp->inp_vflag & INP_IPV6) {
1360fb6ad5ae		spidx->prefs = sizeof(struct in6_addr) << 3;
1370fb6ad5ae		spidx->prefd = sizeof(struct in6_addr) << 3;
1380fb6ad5ae	}
1390fb6ad5ae#endif
1400fb6ad5ae#ifdef INET
1410fb6ad5ae	if (inp->inp_vflag & INP_IPV4) {
142