summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>1998-05-24 23:03:48 +0000
committerNiels Provos <provos@cvs.openbsd.org>1998-05-24 23:03:48 +0000
commita6b1b0e75d58e4fa759283326d95d026943cd065 (patch)
tree56e89aaea9294afe11f40ccbd6d22666f7e5391b
parenta4217d09968d0696cb8e86961cf55dea433cc1c0 (diff)
allow SAs with non-specified source address
-rw-r--r--sys/netinet/ip_output.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index bf09aadbe69..2f248b3e51f 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.29 1998/05/24 14:14:00 provos Exp $ */
+/* $OpenBSD: ip_output.c,v 1.30 1998/05/24 23:03:47 provos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -168,7 +168,7 @@ ip_output(m0, va_alist)
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 *dst, *gw;
+ struct sockaddr_encap *ddst, *gw;
struct tdb *tdb;
u_int8_t sa_require, sa_have = 0;
@@ -178,13 +178,13 @@ ip_output(m0, va_alist)
sa_require = inp->inp_secrequire;
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;
+ ddst = (struct sockaddr_encap *) &re->re_dst;
+ ddst->sen_family = AF_ENCAP;
+ ddst->sen_len = SENT_IP4_LEN;
+ ddst->sen_type = SENT_IP4;
+ ddst->sen_ip_src = ip->ip_src;
+ ddst->sen_ip_dst = ip->ip_dst;
+ ddst->sen_proto = ip->ip_p;
switch (ip->ip_p) {
case IPPROTO_UDP:
@@ -195,8 +195,8 @@ ip_output(m0, va_alist)
ip = mtod(m, struct ip *);
}
udp = (struct udphdr *) (mtod(m, u_char *) + hlen);
- dst->sen_sport = ntohs(udp->uh_sport);
- dst->sen_dport = ntohs(udp->uh_dport);
+ ddst->sen_sport = ntohs(udp->uh_sport);
+ ddst->sen_dport = ntohs(udp->uh_dport);
break;
case IPPROTO_TCP:
@@ -207,13 +207,13 @@ ip_output(m0, va_alist)
ip = mtod(m, struct ip *);
}
tcp = (struct tcphdr *) (mtod(m, u_char *) + hlen);
- dst->sen_sport = ntohs(tcp->th_sport);
- dst->sen_dport = ntohs(tcp->th_dport);
+ ddst->sen_sport = ntohs(tcp->th_sport);
+ ddst->sen_dport = ntohs(tcp->th_dport);
break;
default:
- dst->sen_sport = 0;
- dst->sen_dport = 0;
+ ddst->sen_sport = 0;
+ ddst->sen_dport = 0;
}
rtalloc((struct route *) re);
@@ -295,8 +295,48 @@ ip_output(m0, va_alist)
#endif ENCDEBUG
/* Fix the ip_src field if necessary */
- if ((ip->ip_src.s_addr == INADDR_ANY) && tdb)
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ if (tdb && tdb->tdb_src.s_addr != 0) /* Provided */
ip->ip_src = tdb->tdb_src;
+ 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) {
+ ipstat.ips_noroute++;
+ error = EHOSTUNREACH;
+ goto bad;
+ }
+
+ ia = ifatoia(ro->ro_rt->rt_ifa);
+ ro->ro_rt->rt_use++;
+ ip->ip_src = ia->ia_addr.sin_addr;
+ }
+ }
/* Now fix the checksum */
ip->ip_sum = in_cksum(m, hlen);