! ! Enhance the historic behaviour of raw sockets and jails in a way ! that we allow all possible jail IPs as source address rather than ! forcing the "primary". While IPv6 naturally has source address ! selection, for legacy IP we do not go through the pain in case ! IP_HDRINCL was not set. People should bind(2) for that. ! ! This will allow ping(|6) -S to work correctly for non-primary ! addresses, for example. ! ! Reported by: (ten 211.ru) ! MFC after: 1 week ! Index: sys/netinet/raw_ip.c =================================================================== --- sys/netinet/raw_ip.c (revision 207153) +++ sys/netinet/raw_ip.c (working copy) @@ -427,11 +427,24 @@ rip_output(struct mbuf *m, struct socket *so, u_lo ip->ip_p = inp->inp_ip_p; ip->ip_len = m->m_pkthdr.len; ip->ip_src = inp->inp_laddr; - error = prison_get_ip4(inp->inp_cred, &ip->ip_src); - if (error != 0) { - INP_RUNLOCK(inp); - m_freem(m); - return (error); + if (jailed(inp->inp_cred)) { + /* + * prison_local_ip4() would be good enough but would + * let a source of INADDR_ANY pass, which we do not + * want to see from jails. We do not go through the + * pain of in_pcbladdr() for raw sockets. + */ + if (ip->ip_src.s_addr == INADDR_ANY) + error = prison_get_ip4(inp->inp_cred, + &ip->ip_src); + else + error = prison_local_ip4(inp->inp_cred, + &ip->ip_src); + if (error != 0) { + INP_RUNLOCK(inp); + m_freem(m); + return (error); + } } ip->ip_dst.s_addr = dst; ip->ip_ttl = inp->inp_ip_ttl; Index: sys/netinet6/raw_ip6.c =================================================================== --- sys/netinet6/raw_ip6.c (revision 207153) +++ sys/netinet6/raw_ip6.c (working copy) @@ -465,7 +465,7 @@ rip6_output(m, va_alist) &oifp, &in6a); if (error) goto bad; - error = prison_get_ip6(in6p->inp_cred, &in6a); + error = prison_check_ip6(in6p->inp_cred, &in6a); if (error != 0) goto bad; ip6->ip6_src = in6a;