summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-04 23:20:22 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-04 23:20:22 +0000
commit2b2f59eda8c608d272708986fc8d2c0183eb8dd4 (patch)
treedbda7dc76dd4d65f22ff652cdc8a1f0f1858f533 /sys
parentc4bfe6718e0319e5b13ff515c6cc82e59856a8a1 (diff)
Address independence, IPv6 support, and the -local flag in ipsecadm is
no longer needed.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/ip_esp_new.c8
-rw-r--r--sys/netinet/ip_ipsp.c121
-rw-r--r--sys/netinet/ip_ipsp.h60
-rw-r--r--sys/netinet/ip_output.c567
4 files changed, 421 insertions, 335 deletions
diff --git a/sys/netinet/ip_esp_new.c b/sys/netinet/ip_esp_new.c
index 2f37fea483d..0c5c4e5d8ad 100644
--- a/sys/netinet/ip_esp_new.c
+++ b/sys/netinet/ip_esp_new.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp_new.c,v 1.47 1999/10/29 02:10:01 angelos Exp $ */
+/* $OpenBSD: ip_esp_new.c,v 1.48 1999/12/04 23:20:21 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -36,8 +36,7 @@
*/
/*
- * Based on draft-ietf-ipsec-esp-v2-00.txt and
- * draft-ietf-ipsec-ciph-{des,3des}-{derived,expiv}-00.txt
+ * RFC 2406.
*/
#include <sys/param.h>
@@ -261,6 +260,9 @@ esp_new_input(struct mbuf *m, struct tdb *tdb)
u_int32_t btsx;
union authctx ctx;
u_char buf[AH_ALEN_MAX], buf2[AH_ALEN_MAX];
+#if INET6
+ struct ipv6 *ipv6, ipv6o;
+#endif /* INET6 */
blks = espx->blocksize;
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
index 500e4042b04..eda5bd4b8f3 100644
--- a/sys/netinet/ip_ipsp.c
+++ b/sys/netinet/ip_ipsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.c,v 1.55 1999/11/04 11:20:05 ho Exp $ */
+/* $OpenBSD: ip_ipsp.c,v 1.56 1999/12/04 23:20:21 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -202,6 +202,7 @@ get_sa_require(struct inpcb *inp)
* in that case use dst.
*/
+/* XXX Make IPv6 compliant */
int
check_ipsec_policy(struct inpcb *inp, u_int32_t daddr)
{
@@ -285,9 +286,16 @@ check_ipsec_policy(struct inpcb *inp, u_int32_t daddr)
/* If necessary try to notify keymanagement three times */
while (i < 3)
{
- /* XXX address */
- DPRINTF(("ipsec: send SA request (%d), remote ip: %s, SA type: %d\n",
- i + 1, inet_ntoa4(dst->sen_ip_dst), sa_require));
+ switch (dst->sen_type)
+ {
+ case SENT_IPSP:
+ DPRINTF(("ipsec: send SA request (%d), remote IPv4 address: %s, SA type: %d\n", i + 1, inet_ntoa4(dst->sen_ip_dst), sa_require));
+ break;
+
+ case SENT_IPSP6:
+ DPRINTF(("ipsec: send SA request (%d), remote IPv6 address: %s, SA type: %d\n", i + 1, inet6_ntoa4(dst->sen_ip6_dst), sa_require));
+ break;
+ }
/* Send notify */
/* XXX PF_KEYv2 Notify */
@@ -326,6 +334,7 @@ check_ipsec_policy(struct inpcb *inp, u_int32_t daddr)
* Add an inpcb to the list of inpcb which reference this tdb directly.
*/
+/* XXX Make IPv6 compliant */
void
tdb_add_inp(struct tdb *tdb, struct inpcb *inp)
{
@@ -1049,29 +1058,70 @@ tdb_delete(struct tdb *tdbp, int delchain, int expflags)
bzero(&encapdst, sizeof(struct sockaddr_encap));
bzero(&encapnetmask, sizeof(struct sockaddr_encap));
- encapdst.sen_len = SENT_IP4_LEN;
encapdst.sen_family = PF_KEY;
- encapdst.sen_type = SENT_IP4;
- encapdst.sen_ip_src = tdbp->tdb_flow->flow_src.sin.sin_addr;
- encapdst.sen_ip_dst = tdbp->tdb_flow->flow_dst.sin.sin_addr;
- encapdst.sen_proto = tdbp->tdb_flow->flow_proto;
- encapdst.sen_sport = tdbp->tdb_flow->flow_src.sin.sin_port;
- encapdst.sen_dport = tdbp->tdb_flow->flow_dst.sin.sin_port;
-
- encapnetmask.sen_len = SENT_IP4_LEN;
encapnetmask.sen_family = PF_KEY;
- encapnetmask.sen_type = SENT_IP4;
- encapnetmask.sen_ip_src = tdbp->tdb_flow->flow_srcmask.sin.sin_addr;
- encapnetmask.sen_ip_dst = tdbp->tdb_flow->flow_dstmask.sin.sin_addr;
-
- if (tdbp->tdb_flow->flow_proto)
- {
- encapnetmask.sen_proto = 0xff;
- if (tdbp->tdb_flow->flow_src.sin.sin_port)
- encapnetmask.sen_sport = 0xffff;
- if (tdbp->tdb_flow->flow_dst.sin.sin_port)
- encapnetmask.sen_dport = 0xffff;
- }
+
+ switch (tdbp->tdb_flow->flow_src.sa.sa_family)
+ {
+ case AF_INET:
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_type = SENT_IP4;
+ encapdst.sen_ip_src = tdbp->tdb_flow->flow_src.sin.sin_addr;
+ encapdst.sen_ip_dst = tdbp->tdb_flow->flow_dst.sin.sin_addr;
+ encapdst.sen_proto = tdbp->tdb_flow->flow_proto;
+ encapdst.sen_sport = tdbp->tdb_flow->flow_src.sin.sin_port;
+ encapdst.sen_dport = tdbp->tdb_flow->flow_dst.sin.sin_port;
+
+ encapnetmask.sen_ip_src = tdbp->tdb_flow->flow_srcmask.sin.sin_addr;
+ encapnetmask.sen_ip_dst = tdbp->tdb_flow->flow_dstmask.sin.sin_addr;
+
+ /* Mask transport protocol and ports if applicable */
+ if (tdbp->tdb_flow->flow_proto)
+ {
+ encapnetmask.sen_proto = 0xff;
+ if (tdbp->tdb_flow->flow_src.sin.sin_port)
+ encapnetmask.sen_sport = 0xffff;
+ if (tdbp->tdb_flow->flow_dst.sin.sin_port)
+ encapnetmask.sen_dport = 0xffff;
+ }
+ break;
+
+#if INET6
+ case AF_INET6:
+ encapdst.sen_len = SENT_IP6_LEN;
+ encapdst.sen_type = SENT_IP6;
+ encapdst.sen_ip6_src = tdbp->tdb_flow->flow_src.sin6.sin6_addr;
+ encapdst.sen_ip6_dst = tdbp->tdb_flow->flow_dst.sin6.sin6_addr;
+ encapdst.sen_ip6_proto = tdbp->tdb_flow->flow_proto;
+ encapdst.sen_ip6_sport = tdbp->tdb_flow->flow_src.sin6.sin6_port;
+ encapdst.sen_ip6_dport = tdbp->tdb_flow->flow_dst.sin6.sin6_port;
+
+ encapnetmask.sen_ip6_src = tdbp->tdb_flow->flow_srcmask.sin6.sin6_addr;
+ encapnetmask.sen_ip6_dst = tdbp->tdb_flow->flow_dstmask.sin6.sin6_addr;
+
+ /* Mask transport protocol and ports if applicable */
+ if (tdbp->tdb_flow->flow_proto)
+ {
+ encapnetmask.sen_ip6_proto = 0xff;
+ if (tdbp->tdb_flow->flow_src.sin6.sin6_port)
+ encapnetmask.sen_ip6_sport = 0xffff;
+ if (tdbp->tdb_flow->flow_dst.sin6.sin6_port)
+ encapnetmask.sen_ip6_dport = 0xffff;
+ }
+ break;
+#endif /* INET6 */
+
+ default:
+#ifdef DIAGNOSTIC
+ panic("tdb_delete(): SA %s/%08x/%d has flow of unknown type %d", ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi), tdbp->tdb_sproto, tdbp->tdb_flow->flow_src.sa.sa_family);
+#endif /* DIAGNOSTIC */
+ delete_flow(tdbp->tdb_flow, tdbp);
+ continue;
+ }
+
+ /* Always the same type for address and netmask */
+ encapnetmask.sen_len = encapdst.sen_len;
+ encapnetmask.sen_type = encapdst.sen_type;
rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
(struct sockaddr *) 0,
@@ -1396,7 +1446,7 @@ ipsp_kern(int off, char **bufp, int len)
char *
inet_ntoa4(struct in_addr ina)
{
- static char buf[4][4 * sizeof "123"];
+ static char buf[4][4 * sizeof "123" + 4];
unsigned char *ucp = (unsigned char *) &ina;
static int i = 3;
@@ -1406,6 +1456,22 @@ inet_ntoa4(struct in_addr ina)
return (buf[i]);
}
+#if INET6
+char *
+inet6_ntoa4(struct in6_addr ina)
+{
+ static char buf[4][8 * sizeof "abcd" + 8];
+ unsigned char *ucp = (unsigned char *) &ina;
+ static int i = 3;
+
+ i = (i + 1) % 4;
+ sprintf(buf[i], "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
+ ucp[4] & 0xff, ucp[5] & 0xff, ucp[6] & 0xff, ucp[7] & 0xff);
+ return (buf[i]);
+}
+#endif /* INET6 */
+
char *
ipsp_address(union sockaddr_union sa)
{
@@ -1415,7 +1481,8 @@ ipsp_address(union sockaddr_union sa)
return inet_ntoa4(sa.sin.sin_addr);
#if INET6
- /* XXX Add AF_INET6 support here */
+ case AF_INET6:
+ return inet_ntoa6(sa.sin6.s6_addr);
#endif /* INET6 */
default:
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 62c6ad8b1a6..b3a06d3d7cc 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.46 1999/10/29 05:20:46 angelos Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.47 1999/12/04 23:20:21 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -123,6 +123,16 @@ struct sockaddr_encap
u_int8_t Filler[3];
} Sip4;
+ struct /* SENT_IP6 */
+ {
+ struct in6_addr Src;
+ struct in6_addr Dst;
+ u_int16_t Sport;
+ u_int16_t Dport;
+ u_int8_t Proto;
+ u_int8_t Filler[3];
+ } Sip6;
+
struct /* SENT_IPSP */
{
struct in_addr Dst;
@@ -130,18 +140,34 @@ struct sockaddr_encap
u_int8_t Sproto;
u_int8_t Filler[7];
} Sipsp;
+
+ struct /* SENT_IPSP6 */
+ {
+ struct in6_addr Dst;
+ u_int32_t Spi;
+ u_int8_t Sproto;
+ u_int8_t Filler[7];
+ } Sipsp6;
} Sen;
};
-#define sen_data Sen.Data
-#define sen_ip_src Sen.Sip4.Src
-#define sen_ip_dst Sen.Sip4.Dst
-#define sen_proto Sen.Sip4.Proto
-#define sen_sport Sen.Sip4.Sport
-#define sen_dport Sen.Sip4.Dport
-#define sen_ipsp_dst Sen.Sipsp.Dst
-#define sen_ipsp_spi Sen.Sipsp.Spi
-#define sen_ipsp_sproto Sen.Sipsp.Sproto
+#define sen_data Sen.Data
+#define sen_ip_src Sen.Sip4.Src
+#define sen_ip_dst Sen.Sip4.Dst
+#define sen_proto Sen.Sip4.Proto
+#define sen_sport Sen.Sip4.Sport
+#define sen_dport Sen.Sip4.Dport
+#define sen_ip6_src Sen.Sip6.Src
+#define sen_ip6_dst Sen.Sip6.Dst
+#define sen_ip6_proto Sen.Sip6.Proto
+#define sen_ip6_sport Sen.Sip6.Sport
+#define sen_ip6_dport Sen.Sip6.Dport
+#define sen_ipsp_dst Sen.Sipsp.Dst
+#define sen_ipsp_spi Sen.Sipsp.Spi
+#define sen_ipsp_sproto Sen.Sipsp.Sproto
+#define sen_ipsp6_dst Sen.Sipsp6.Dst
+#define sen_ipsp6_spi Sen.Sipsp6.Spi
+#define sen_ipsp6_sproto Sen.Sipsp6.Sproto
/*
* The "type" is really part of the address as far as the routing
@@ -152,7 +178,9 @@ struct sockaddr_encap
*/
#define SENT_IP4 0x0001 /* data is two struct in_addr */
-#define SENT_IPSP 0x0002 /* data as in IP4 plus SPI */
+#define SENT_IPSP 0x0002 /* data as in IP4/6 plus SPI */
+#define SENT_IP6 0x0004
+#define SENT_IPSP6 0x0008
/*
* SENT_HDRLEN is the length of the "header"
@@ -165,8 +193,13 @@ struct sockaddr_encap
#define SENT_IP4_SRCOFF (0)
#define SENT_IP4_DSTOFF (sizeof (struct in_addr))
+#define SENT_IP6_SRCOFF (0)
+#define SENT_IP6_DSTOFF (sizeof (struct in6_addr))
+
#define SENT_IP4_LEN 20
#define SENT_IPSP_LEN 20
+#define SENT_IP6_LEN 44
+#define SENT_IPSP6_LEN 32
#define NOTIFY_SOFT_EXPIRE 0 /* Soft expiration of SA */
#define NOTIFY_HARD_EXPIRE 1 /* Hard expiration of SA */
@@ -434,6 +467,11 @@ extern struct xformsw xformsw[], *xformswNXFORMSW;
/* Misc. */
extern char *inet_ntoa4(struct in_addr);
+
+#if INET6
+extern char *inet6_ntoa4(struct in6_addr);
+#endif /* INET6 */
+
extern char *ipsp_address(union sockaddr_union);
/* TDB management routines */
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 277a0608ed9..ea4b083e0db 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.52 1999/11/04 11:21:14 ho Exp $ */
+/* $OpenBSD: ip_output.c,v 1.53 1999/12/04 23:20:21 angelos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -129,6 +129,12 @@ ip_output(m0, va_alist)
struct udphdr *udp;
struct tcphdr *tcp;
struct inpcb *inp;
+
+ struct route_enc re0, *re = &re0;
+ struct sockaddr_encap *ddst, *gw;
+ u_int8_t sa_require, sa_have = 0;
+ struct tdb *tdb, *t;
+ int s;
#endif
va_start(ap, m0);
@@ -166,21 +172,187 @@ ip_output(m0, va_alist)
hlen = ip->ip_hl << 2;
}
+ /*
+ * Route packet.
+ */
+ if (ro == 0) {
+ ro = &iproute;
+ bzero((caddr_t)ro, sizeof (*ro));
+ }
+ dst = satosin(&ro->ro_dst);
+ /*
+ * If there is a cached route,
+ * check that it is to the same destination
+ * and is still up. If not, free it and try again.
+ */
+ if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
+ dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ if (ro->ro_rt == 0) {
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = ip->ip_dst;
+ }
+ /*
+ * If routing to interface only,
+ * short circuit routing lookup.
+ */
+ if (flags & IP_ROUTETOIF) {
+ if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
+ (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
+ ipstat.ips_noroute++;
+ error = ENETUNREACH;
+ goto bad;
+ }
+ ifp = ia->ia_ifp;
+ ip->ip_ttl = 1;
+ } else {
+ if (ro->ro_rt == 0)
+ rtalloc(ro);
+ if (ro->ro_rt == 0) {
+ ipstat.ips_noroute++;
+ error = EHOSTUNREACH;
+ goto bad;
+ }
+ ia = ifatoia(ro->ro_rt->rt_ifa);
+ ifp = ro->ro_rt->rt_ifp;
+ ro->ro_rt->rt_use++;
+ if (ro->ro_rt->rt_flags & RTF_GATEWAY)
+ dst = satosin(ro->ro_rt->rt_gateway);
+ }
+ if (IN_MULTICAST(ip->ip_dst.s_addr)) {
+ struct in_multi *inm;
+
+ m->m_flags |= M_MCAST;
+ /*
+ * IP destination address is multicast. Make sure "dst"
+ * still points to the address in "ro". (It may have been
+ * changed to point to a gateway address, above.)
+ */
+ dst = satosin(&ro->ro_dst);
+ /*
+ * See if the caller provided any multicast options
+ */
+ if (imo != NULL) {
+ ip->ip_ttl = imo->imo_multicast_ttl;
+ if (imo->imo_multicast_ifp != NULL)
+ ifp = imo->imo_multicast_ifp;
+ } else
+ ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
+ /*
+ * Confirm that the outgoing interface supports multicast.
+ */
+ if ((ifp->if_flags & IFF_MULTICAST) == 0) {
+ ipstat.ips_noroute++;
+ error = ENETUNREACH;
+ goto bad;
+ }
+ /*
+ * If source address not specified yet, use address
+ * of outgoing interface.
+ */
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ register struct in_ifaddr *ia;
+
+ for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next)
+ if (ia->ia_ifp == ifp) {
+ ip->ip_src = ia->ia_addr.sin_addr;
+ break;
+ }
+ }
+
+ IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
+ if (inm != NULL &&
+ (imo == NULL || imo->imo_multicast_loop)) {
+ /*
+ * If we belong to the destination multicast group
+ * on the outgoing interface, and the caller did not
+ * forbid loopback, loop back a copy.
+ */
+ ip_mloopback(ifp, m, dst);
+ }
+#ifdef MROUTING
+ else {
+ /*
+ * If we are acting as a multicast router, perform
+ * multicast forwarding as if the packet had just
+ * arrived on the interface to which we are about
+ * to send. The multicast forwarding function
+ * recursively calls this function, using the
+ * IP_FORWARDING flag to prevent infinite recursion.
+ *
+ * Multicasts that are looped back by ip_mloopback(),
+ * above, will be forwarded by the ip_input() routine,
+ * if necessary.
+ */
+ extern struct socket *ip_mrouter;
+
+ if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
+ if (ip_mforward(m, ifp) != 0) {
+ m_freem(m);
+ goto done;
+ }
+ }
+ }
+#endif
+ /*
+ * Multicasts with a time-to-live of zero may be looped-
+ * back, above, but must not be transmitted on a network.
+ * Also, multicasts addressed to the loopback interface
+ * are not sent -- the above call to ip_mloopback() will
+ * loop back a copy if this host actually belongs to the
+ * destination group on the loopback interface.
+ */
+ if (ip->ip_ttl == 0 || (ifp->if_flags & IFF_LOOPBACK) != 0) {
+ m_freem(m);
+ goto done;
+ }
+
+ goto sendit;
+ }
+#ifndef notdef
+ /*
+ * If source address not specified yet, use address
+ * of outgoing interface.
+ */
+ if (ip->ip_src.s_addr == INADDR_ANY)
+ ip->ip_src = ia->ia_addr.sin_addr;
+#endif
+ /*
+ * Look for broadcast address and
+ * and verify user is allowed to send
+ * such a packet.
+ */
+ if (in_broadcast(dst->sin_addr, ifp)) {
+ if ((ifp->if_flags & IFF_BROADCAST) == 0) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ if ((flags & IP_ALLOWBROADCAST) == 0) {
+ error = EACCES;
+ goto bad;
+ }
+ /* don't allow broadcast messages to be fragmented */
+ if ((u_int16_t)ip->ip_len > ifp->if_mtu) {
+ error = EMSGSIZE;
+ goto bad;
+ }
+ m->m_flags |= M_BCAST;
+ } else
+ m->m_flags &= ~M_BCAST;
+
+sendit:
#ifdef IPSEC
/*
- * Check if the packet needs encapsulation
+ * Check if the packet needs encapsulation.
*/
if (!(flags & IP_ENCAPSULATED) &&
(inp == NULL ||
inp->inp_seclevel[SL_AUTH] != IPSEC_LEVEL_BYPASS ||
inp->inp_seclevel[SL_ESP_TRANS] != IPSEC_LEVEL_BYPASS ||
inp->inp_seclevel[SL_ESP_NETWORK] != IPSEC_LEVEL_BYPASS)) {
- struct route_enc re0, *re = &re0;
- struct sockaddr_encap *ddst, *gw;
- struct tdb *tdb, *t;
- int s;
- u_int8_t sa_require, sa_have = 0;
-
if (inp == NULL)
sa_require = get_sa_require(inp);
else
@@ -193,10 +365,13 @@ ip_output(m0, va_alist)
* lower the level, and udp_output calls us in splnet().
*/
s = splnet();
- /* Check if there was a bound outgoing SA */
+
+ /*
+ * Check if there was an outgoing SA bound to the flow
+ * from a transport protocol.
+ */
if (inp && inp->inp_tdb &&
- (inp->inp_tdb->tdb_dst.sin.sin_addr.s_addr ==
- INADDR_ANY ||
+ (inp->inp_tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY ||
!bcmp(&inp->inp_tdb->tdb_dst.sin.sin_addr,
&ip->ip_dst, sizeof(ip->ip_dst)))) {
tdb = inp->inp_tdb;
@@ -257,7 +432,8 @@ ip_output(m0, va_alist)
/*
* There might be a specific route, that tells us to avoid
* doing IPsec; this is useful for specific routes that we
- * don't want to have IPsec applied on.
+ * don't want to have IPsec applied on, like the key
+ * management ports.
*/
if ((gw != NULL) && (gw->sen_ipsp_dst.s_addr == 0) &&
@@ -266,7 +442,9 @@ ip_output(m0, va_alist)
goto no_encap;
}
- if (gw == NULL || gw->sen_type != SENT_IPSP) {
+ /* Sanity check */
+ if (gw == NULL || ((gw->sen_type != SENT_IPSP) &&
+ (gw->sen_type != SENT_IPSP6))) {
splx(s);
DPRINTF(("ip_output(): no gw or gw data not IPSP\n"));
@@ -277,50 +455,6 @@ ip_output(m0, va_alist)
goto done;
}
- /*
- * For VPNs a route with a reserved SPI of 0 is used to
- * indicate the need for an SA when none is established.
- */
- if (ntohl(gw->sen_ipsp_spi) == SPI_LOCAL_USE) {
- bzero(&sunion, sizeof(sunion));
- sunion.sin.sin_family = AF_INET;
- sunion.sin.sin_len = sizeof(struct sockaddr_in);
- sunion.sin.sin_addr = gw->sen_ipsp_dst;
- tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
- gw->sen_ipsp_sproto);
-
- if (tdb)
- {
- if (tdb->tdb_authalgxform)
- sa_require = NOTIFY_SATYPE_AUTH;
- if (tdb->tdb_encalgxform)
- sa_require |= NOTIFY_SATYPE_CONF;
- if (tdb->tdb_flags & TDBF_TUNNELING)
- sa_require |= NOTIFY_SATYPE_TUNNEL;
- }
- else /* No TDB found */
- {
- /*
- * XXX We should construct a TDB from system
- * default (which should be tunable via sysctl).
- * For now, drop packet and ignore SPD entry.
- */
- splx(s);
- goto no_encap;
- }
-
- /* PF_KEYv2 notification message */
- if (tdb->tdb_satype != SADB_X_SATYPE_BYPASS)
- pfkeyv2_acquire(tdb, 0); /* XXX Check for errors */
-
- splx(s);
-
- /*
- * When sa_require is set, the packet will be dropped
- * at no_encap.
- */
- goto no_encap;
- }
/*
* At this point we have an IPSP "gateway" (tunnel) spec.
@@ -330,13 +464,63 @@ ip_output(m0, va_alist)
* to the appropriate transformation.
*/
bzero(&sunion, sizeof(sunion));
- sunion.sin.sin_family = AF_INET;
- sunion.sin.sin_len = sizeof(struct sockaddr_in);
- sunion.sin.sin_addr = gw->sen_ipsp_dst;
+
+ if (gw->sen_type == SENT_IPSP) {
+ sunion.sin.sin_family = AF_INET;
+ sunion.sin.sin_len = sizeof(struct sockaddr_in);
+ sunion.sin.sin_addr = gw->sen_ipsp_dst;
+ }
+#if INET6
+ else {
+ sunion.sin6.sin6_family = AF_INET6;
+ sunion.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sunion.sin6.sin6_addr = gw->sen_ipsp6_dst;
+ }
+#endif /* INET6 */
+
tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
gw->sen_ipsp_sproto);
- have_tdb:
+ /*
+ * For VPNs a route with a reserved SPI is used to
+ * indicate the need for an SA when none is established.
+ */
+ if (((ntohl(gw->sen_ipsp_spi) == SPI_LOCAL_USE) &&
+ (gw->sen_type == SENT_IPSP)) ||
+ ((ntohl(gw->sen_ipsp6_spi) == SPI_LOCAL_USE) &&
+ (gw->sen_type == SENT_IPSP6))) {
+ if (tdb == NULL) {
+ /*
+ * XXX We should construct a TDB from system
+ * default (which should be tunable via sysctl).
+ * For now, drop packet and ignore SPD entry.
+ */
+ splx(s);
+ goto no_encap;
+ }
+ else {
+ if (tdb->tdb_authalgxform)
+ sa_require = NOTIFY_SATYPE_AUTH;
+ if (tdb->tdb_encalgxform)
+ sa_require |= NOTIFY_SATYPE_CONF;
+ if (tdb->tdb_flags & TDBF_TUNNELING)
+ sa_require |= NOTIFY_SATYPE_TUNNEL;
+ }
+
+ /* PF_KEYv2 notification message */
+ if (tdb && tdb->tdb_satype != SADB_X_SATYPE_BYPASS)
+ pfkeyv2_acquire(tdb, 0); /* XXX Check for errors */
+
+ splx(s);
+
+ /*
+ * When sa_require is set, the packet will be dropped
+ * at no_encap.
+ */
+ goto no_encap;
+ }
+
+ have_tdb:
ip->ip_len = htons((u_short)ip->ip_len);
ip->ip_off = htons((u_short)ip->ip_off);
@@ -353,7 +537,12 @@ ip_output(m0, va_alist)
if (tdb == NULL) {
splx(s);
- DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto));
+ if (gw->sen_type == SENT_IPSP)
+ DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto));
+#if INET6
+ else
+ DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto));
+#endif /* INET6 */
if (re->re_rt)
RTFREE(re->re_rt);
@@ -374,53 +563,6 @@ ip_output(m0, va_alist)
goto done;
}
- /* Fix the ip_src field if necessary */
- if (ip->ip_src.s_addr == INADDR_ANY) {
- if (tdb && tdb->tdb_src.sin.sin_addr.s_addr != 0 &&
- tdb->tdb_src.sa.sa_family == AF_INET)
- ip->ip_src = tdb->tdb_src.sin.sin_addr;
- else
- {
- if (ro == 0) {
- ro = &iproute;
- bzero((caddr_t)ro, sizeof (*ro));
- }
-
- dst = satosin(&ro->ro_dst);
-
- /*
- * If there is a cached route,
- * check that it is to the same destination
- * and is still up. If not, free it and try again.
- */
- if (ro->ro_rt &&
- ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
- dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
- RTFREE(ro->ro_rt);
- ro->ro_rt = (struct rtentry *)0;
- }
-
- if (ro->ro_rt == 0) {
- dst->sin_family = AF_INET;
- dst->sin_len = sizeof(*dst);
- dst->sin_addr = ip->ip_dst;
- rtalloc(ro);
- }
-
- if (ro->ro_rt == 0) {
- splx(s);
- ipstat.ips_noroute++;
- error = EHOSTUNREACH;
- m_freem(m);
- goto done;
- }
-
- ia = ifatoia(ro->ro_rt->rt_ifa);
- ro->ro_rt->rt_use++;
- ip->ip_src = ia->ia_addr.sin_addr;
- }
- }
-
while (tdb && tdb->tdb_xform) {
/* Check if the SPI is invalid */
if (tdb->tdb_flags & TDBF_INVALID) {
@@ -432,27 +574,35 @@ ip_output(m0, va_alist)
return ENXIO;
}
+ /* Sanity check */
+ if (tdb->tdb_dst.sa.sa_family != AF_INET) {
+ splx(s);
+ DPRINTF(("ip_output(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
+ m_freem(m);
+ if (re->re_rt)
+ RTFREE(re->re_rt);
+ return ENXIO;
+ }
+
/* Register first use, setup expiration timer */
if (tdb->tdb_first_use == 0) {
tdb->tdb_first_use = time.tv_sec;
tdb_expiration(tdb, TDBEXP_TIMEOUT);
}
-
- /* Check for tunneling */
- if (((tdb->tdb_dst.sin.sin_addr.s_addr !=
- INADDR_ANY &&
- tdb->tdb_dst.sin.sin_addr.s_addr !=
- ip->ip_dst.s_addr) ||
- (tdb->tdb_flags & TDBF_TUNNELING)) &&
- (tdb->tdb_xform->xf_type != XF_IP4))
- {
- DPRINTF(("ip_output(): tunneling\n"));
+ /* Check for tunneling */
+ if (((tdb->tdb_dst.sa.sa_family == AF_INET) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr !=
+ INADDR_ANY) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr !=
+ ip->ip_dst.s_addr)) ||
+ ((tdb->tdb_flags & TDBF_TUNNELING) &&
+ (tdb->tdb_xform->xf_type != XF_IP4))) {
/*
* Fix checksum here, AH and ESP fix the
* checksum in their output routines.
*/
- ip->ip_sum = in_cksum(m, hlen);
+ ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
error = ipe4_output(m, tdb, &mp);
if (mp == NULL)
error = EFAULT;
@@ -472,9 +622,10 @@ ip_output(m0, va_alist)
* output routines.
*/
ip = mtod(m, struct ip *);
- ip->ip_sum = in_cksum(m, hlen);
+ ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
}
+
error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp);
if (!error && mp == NULL)
error = EFAULT;
@@ -507,7 +658,7 @@ ip_output(m0, va_alist)
NTOHS(ip->ip_len);
NTOHS(ip->ip_off);
return ip_output(m, NULL, NULL,
- IP_ENCAPSULATED | IP_RAWOUTPUT, NULL, NULL);
+ IP_ENCAPSULATED | IP_RAWOUTPUT, NULL, NULL);
no_encap:
/* This is for possible future use, don't move or delete */
@@ -522,178 +673,6 @@ no_encap:
}
#endif /* IPSEC */
- /*
- * Route packet.
- */
- if (ro == 0) {
- ro = &iproute;
- bzero((caddr_t)ro, sizeof (*ro));
- }
- dst = satosin(&ro->ro_dst);
- /*
- * If there is a cached route,
- * check that it is to the same destination
- * and is still up. If not, free it and try again.
- */
- if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
- dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
- RTFREE(ro->ro_rt);
- ro->ro_rt = (struct rtentry *)0;
- }
- if (ro->ro_rt == 0) {
- dst->sin_family = AF_INET;
- dst->sin_len = sizeof(*dst);
- dst->sin_addr = ip->ip_dst;
- }
- /*
- * If routing to interface only,
- * short circuit routing lookup.
- */
- if (flags & IP_ROUTETOIF) {
- if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
- (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
- ipstat.ips_noroute++;
- error = ENETUNREACH;
- goto bad;
- }
- ifp = ia->ia_ifp;
- ip->ip_ttl = 1;
- } else {
- if (ro->ro_rt == 0)
- rtalloc(ro);
- if (ro->ro_rt == 0) {
- ipstat.ips_noroute++;
- error = EHOSTUNREACH;
- goto bad;
- }
- ia = ifatoia(ro->ro_rt->rt_ifa);
- ifp = ro->ro_rt->rt_ifp;
- ro->ro_rt->rt_use++;
- if (ro->ro_rt->rt_flags & RTF_GATEWAY)
- dst = satosin(ro->ro_rt->rt_gateway);
- }
- if (IN_MULTICAST(ip->ip_dst.s_addr)) {
- struct in_multi *inm;
-
- m->m_flags |= M_MCAST;
- /*
- * IP destination address is multicast. Make sure "dst"
- * still points to the address in "ro". (It may have been
- * changed to point to a gateway address, above.)
- */
- dst = satosin(&ro->ro_dst);
- /*
- * See if the caller provided any multicast options
- */
- if (imo != NULL) {
- ip->ip_ttl = imo->imo_multicast_ttl;
- if (imo->imo_multicast_ifp != NULL)
- ifp = imo->imo_multicast_ifp;
- } else
- ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
- /*
- * Confirm that the outgoing interface supports multicast.
- */
- if ((ifp->if_flags & IFF_MULTICAST) == 0) {
- ipstat.ips_noroute++;
- error = ENETUNREACH;
- goto bad;
- }
- /*
- * If source address not specified yet, use address
- * of outgoing interface.
- */
- if (ip->ip_src.s_addr == INADDR_ANY) {
- register struct in_ifaddr *ia;
-
- for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next)
- if (ia->ia_ifp == ifp) {
- ip->ip_src = ia->ia_addr.sin_addr;
- break;
- }
- }
-
- IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
- if (inm != NULL &&
- (imo == NULL || imo->imo_multicast_loop)) {
- /*
- * If we belong to the destination multicast group
- * on the outgoing interface, and the caller did not
- * forbid loopback, loop back a copy.
- */
- ip_mloopback(ifp, m, dst);
- }
-#ifdef MROUTING
- else {
- /*
- * If we are acting as a multicast router, perform
- * multicast forwarding as if the packet had just
- * arrived on the interface to which we are about
- * to send. The multicast forwarding function
- * recursively calls this function, using the
- * IP_FORWARDING flag to prevent infinite recursion.
- *
- * Multicasts that are looped back by ip_mloopback(),
- * above, will be forwarded by the ip_input() routine,
- * if necessary.
- */
- extern struct socket *ip_mrouter;
-
- if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
- if (ip_mforward(m, ifp) != 0) {
- m_freem(m);
- goto done;
- }
- }
- }
-#endif
- /*
- * Multicasts with a time-to-live of zero may be looped-
- * back, above, but must not be transmitted on a network.
- * Also, multicasts addressed to the loopback interface
- * are not sent -- the above call to ip_mloopback() will
- * loop back a copy if this host actually belongs to the
- * destination group on the loopback interface.
- */
- if (ip->ip_ttl == 0 || (ifp->if_flags & IFF_LOOPBACK) != 0) {
- m_freem(m);
- goto done;
- }
-
- goto sendit;
- }
-#ifndef notdef
- /*
- * If source address not specified yet, use address
- * of outgoing interface.
- */
- if (ip->ip_src.s_addr == INADDR_ANY)
- ip->ip_src = ia->ia_addr.sin_addr;
-#endif
- /*
- * Look for broadcast address and
- * and verify user is allowed to send
- * such a packet.
- */
- if (in_broadcast(dst->sin_addr, ifp)) {
- if ((ifp->if_flags & IFF_BROADCAST) == 0) {
- error = EADDRNOTAVAIL;
- goto bad;
- }
- if ((flags & IP_ALLOWBROADCAST) == 0) {
- error = EACCES;
- goto bad;
- }
- /* don't allow broadcast messages to be fragmented */
- if ((u_int16_t)ip->ip_len > ifp->if_mtu) {
- error = EMSGSIZE;
- goto bad;
- }
- m->m_flags |= M_BCAST;
- } else
- m->m_flags &= ~M_BCAST;
-
-sendit:
#if defined(IPFILTER) || defined(IPFILTER_LKM)
/*
* looks like most checking has been done now...do a filter check