summaryrefslogtreecommitdiff
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c182
1 files changed, 181 insertions, 1 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 2b31d8dd9f2..0bfe9cce3f7 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.6 1996/07/29 02:34:31 downsj Exp $ */
+/* $OpenBSD: ip_output.c,v 1.7 1997/02/20 01:08:06 deraadt Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -61,6 +61,13 @@
#include <machine/stdarg.h>
+#ifdef IPSEC
+#include <net/encap.h>
+#include <netinet/ip_ipsp.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#endif
+
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
static void ip_mloopback
__P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
@@ -96,6 +103,11 @@ ip_output(m0, va_alist)
int flags;
struct ip_moptions *imo;
va_list ap;
+#ifdef IPSEC
+ struct mbuf *mp;
+ struct udphdr *udp;
+ struct tcphdr *tcp;
+#endif
va_start(ap, m0);
opt = va_arg(ap, struct mbuf *);
@@ -127,6 +139,174 @@ ip_output(m0, va_alist)
} else {
hlen = ip->ip_hl << 2;
}
+
+#ifdef IPSEC
+ /*
+ * Check if the packet needs encapsulation
+ */
+ if (!(flags & IP_ENCAPSULATED)) {
+ struct route_enc {
+ struct rtentry *re_rt;
+ struct sockaddr_encap re_dst;
+ } re0, *re = &re0;
+ struct sockaddr_encap *dst, *gw;
+ struct tdb *tdb;
+
+ bzero((caddr_t)re, sizeof (*re));
+ dst = (struct sockaddr_encap *)&re->re_dst;
+ dst->sen_family = AF_ENCAP;
+ dst->sen_len = SENT_IP4_LEN;
+ dst->sen_type = SENT_IP4;
+ dst->sen_ip_src = ip->ip_src;
+ dst->sen_ip_dst = ip->ip_dst;
+ dst->sen_proto = ip->ip_p;
+
+ if ((m->m_len < hlen + 2*sizeof(u_int16_t)) &&
+ ((m = m_pullup(m, hlen + 2*sizeof(u_int16_t))) == 0))
+ goto bad;
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP:
+ udp = (struct udphdr *) (mtod(m, u_char *) + hlen);
+ dst->sen_sport = ntohs(udp->uh_sport);
+ dst->sen_dport = ntohs(udp->uh_dport);
+ break;
+ case IPPROTO_UDP:
+ tcp = (struct tcphdr *) (mtod(m, u_char *) + hlen);
+ dst->sen_sport = ntohs(tcp->th_sport);
+ dst->sen_dport = ntohs(tcp->th_dport);
+ break;
+ default:
+ dst->sen_sport = 0;
+ dst->sen_dport = 0;
+ }
+ rtalloc((struct route *)re);
+ if (re->re_rt == NULL)
+ goto no_encap;
+
+ gw = (struct sockaddr_encap *)(re->re_rt->rt_gateway);
+ if (gw == NULL || gw->sen_type != SENT_IPSP) {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: no gw or gw data not IPSP\n");
+#endif ENCDEBUG
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return EHOSTUNREACH;
+ }
+
+ ifp = re->re_rt->rt_ifp;
+
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ struct sockaddr_encap *sen;
+ struct sockaddr_in *sinp;
+
+ if (ifp->if_addrlist.tqh_first)
+ sen = (struct sockaddr_encap *)
+ ifp->if_addrlist.tqh_first->ifa_addr;
+ else {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: interface %s has no default address\n",
+ ifp->if_xname);
+#endif ENCDEBUG
+ return ENXIO;
+ }
+
+ if (sen->sen_family != AF_ENCAP) {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: %s does not have AF_ENCAP address\n",
+ ifp->if_xname);
+#endif ENCDEBUG
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return EHOSTDOWN;
+ }
+
+ if (sen->sen_type != SENT_DEFIF) {
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: %s does not have SENT_DEFIF address\n",
+ ifp->if_xname);
+#endif ENCDEBUG
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return EHOSTDOWN;
+ }
+ sinp = (struct sockaddr_in *)&(sen->sen_dfl);
+ ip->ip_src = sinp->sin_addr;
+ }
+
+ if (hlen > sizeof (struct ip)) { /* XXX IPOPT */
+ ip_stripoptions(m, (struct mbuf *)0);
+ hlen = sizeof (struct ip);
+ }
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: encapsulating %x->%x through %x->%x\n",
+ ip->ip_src.s_addr, ip->ip_dst.s_addr,
+ gw->sen_ipsp_src, gw->sen_ipsp_dst);
+#endif
+ ip->ip_len = htons((u_short)ip->ip_len);
+ ip->ip_off = htons((u_short)ip->ip_off);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, hlen);
+
+ /*
+ * At this point we have an IPSP "gateway" (tunnel) spec.
+ * Use the destination of the tunnel and the SPI to
+ * look up the necessary Tunnel Control Block. Look it up,
+ * and then pass it, along with the packet and the gw,
+ * to the appropriate transformation.
+ */
+
+ tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, gw->sen_ipsp_dst);
+
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: tdb=0x%x, tdb->tdb_xform=0x%x, tdb->tdb_xform->xf_output=%x\n", tdb, tdb->tdb_xform, tdb->tdb_xform->xf_output);
+#endif ENCDEBUG
+
+ while (tdb && tdb->tdb_xform) {
+ m0 = NULL;
+#ifdef ENCDEBUG
+ if (encdebug)
+ printf("ip_output: calling %s\n",
+ tdb->tdb_xform->xf_name);
+#endif ENCDEBUG
+ error = (*(tdb->tdb_xform->xf_output))(m, gw, tdb, &mp);
+ if (mp == NULL)
+ error = EFAULT;
+ if (error) {
+ RTFREE(re->re_rt);
+ return error;
+ }
+ tdb = tdb->tdb_onext;
+ m = mp;
+ }
+
+ /*
+ * At this point, mp is pointing to an mbuf chain with the
+ * processed packet. Call ourselves recursively, but
+ * bypass the encap code.
+ */
+
+ RTFREE(re->re_rt);
+
+ ip = mtod(m, struct ip *);
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+
+ return ip_output(m, NULL, NULL, IP_ENCAPSULATED | IP_RAWOUTPUT, NULL);
+
+no_encap:
+ if (re->re_rt)
+ RTFREE(re->re_rt);
+ }
+#endif IPSEC
+
/*
* Route packet.
*/