Index: sys/netinet/in_pcb.c =================================================================== --- sys/netinet/in_pcb.c (revision 193931) +++ sys/netinet/in_pcb.c (working copy) @@ -597,10 +597,34 @@ in_pcbconnect_setup(struct inpcb *inp, struct sock faddr = satosin(&TAILQ_FIRST( &in_ifaddrhead)->ia_broadaddr)->sin_addr; } +#ifdef FAST_IPSEC if (laddr.s_addr == INADDR_ANY) { + struct ifaddr *ifa; + struct sockaddr_in *sin; struct route sro; bzero(&sro, sizeof(sro)); + + sin = (struct sockaddr_in *)&sro.ro_dst; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_addr.s_addr = key_find_src(&faddr.s_addr); + + /* + * If there is an IPsec tunnel with a destination matching faddr, + * try to use source address for the tunnel. + */ + ifa = ifa_ifwithnet(sintosa(sin)); + if (ifa != NULL) { + sin = IA_SIN(ifatoia(ifa)); + laddr.s_addr = sin->sin_addr.s_addr; + } + } +#endif + if (laddr.s_addr == INADDR_ANY) { + struct route sro; + + bzero(&sro, sizeof(sro)); ia = (struct in_ifaddr *)0; /* * If route is known our src addr is taken from the i/f, Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c (revision 193931) +++ sys/netinet/ip_output.c (working copy) @@ -138,6 +138,8 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct struct secpolicy *sp = NULL; struct tdb_ident *tdbi; struct m_tag *mtag; + struct sockaddr_in sin; + struct ifaddr *ifa; int s; #endif /* FAST_IPSEC */ @@ -179,6 +181,17 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct hlen = ip->ip_hl << 2; } +#ifdef FAST_IPSEC + if (ip->ip_src.s_addr == INADDR_ANY) { + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = key_find_src(&ip->ip_dst.s_addr); + ifa = ifa_ifwithnet(sintosa(&sin)); + if (ifa != NULL) + ip->ip_src = IA_SIN(ifatoia(ifa))->sin_addr; + } +#endif + dst = (struct sockaddr_in *)&ro->ro_dst; again: /* Index: sys/i386/conf/GENERIC =================================================================== --- sys/i386/conf/GENERIC (revision 193931) +++ sys/i386/conf/GENERIC (working copy) @@ -24,6 +24,9 @@ cpu I586_CPU cpu I686_CPU ident GENERIC +options FAST_IPSEC #new IPsec (cannot define w/ IPSEC) +device crypto + # To statically compile in device wiring instead of /boot/device.hints #hints "GENERIC.hints" # Default places to look for devices. Index: sys/netipsec/key.c =================================================================== --- sys/netipsec/key.c (revision 193931) +++ sys/netipsec/key.c (working copy) @@ -742,6 +742,39 @@ done: return sp; } +in_addr_t +key_find_src(const in_addr_t *dst) +{ + struct secpolicy *sp; + in_addr_t src = INADDR_ANY; + + SPTREE_LOCK(); + LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) { + + if (sp->state == IPSEC_SPSTATE_DEAD) + continue; + + if (sp->spidx.dir != IPSEC_DIR_OUTBOUND) + continue; + + if (sp->spidx.dst.sa.sa_family != AF_INET) + continue; + + if (key_bbcmp(&sp->spidx.dst.sin.sin_addr.s_addr, dst, sp->spidx.prefd)) + break; + } + + if (sp) { + /* sanity check */ + KEY_CHKSPDIR(sp->spidx.dir, IPSEC_DIR_OUTBOUND, __func__); + + src = sp->spidx.src.sin.sin_addr.s_addr; + } + SPTREE_UNLOCK(); + + return (src); +} + /* * allocating an SA entry for an *OUTBOUND* packet. * checking each request entries in SP, and acquire an SA if need. Index: sys/netipsec/key.h =================================================================== --- sys/netipsec/key.h (revision 193931) +++ sys/netipsec/key.h (working copy) @@ -100,6 +100,8 @@ extern void key_sa_recordxfer __P((struct secasvar extern void key_sa_routechange __P((struct sockaddr *)); extern void key_sa_stir_iv __P((struct secasvar *)); +extern in_addr_t key_find_src(const in_addr_t *dst); + #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_IPSEC_SA); MALLOC_DECLARE(M_IPSEC_SAH);