On Thu, Mar 17, 2022 at 12:05:16PM -0600, Theo de Raadt wrote:
> This should not be done in applications. The kernel must do it. It means
> the current kernel code is worng.
i think this is the right place for raw ipv4 sockets like what
ping/traceroute uses.
ipv6 looks like it already does the right thing.
Index: raw_ip.c
===================================================================
RCS file: /cvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.123
diff -u -p -r1.123 raw_ip.c
--- raw_ip.c 14 Mar 2022 22:38:43 -0000 1.123
+++ raw_ip.c 19 Mar 2022 03:40:44 -0000
@@ -222,6 +222,7 @@ int
rip_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr,
struct mbuf *control)
{
+ struct sockaddr_in *dst = satosin(dstaddr);
struct ip *ip;
struct inpcb *inp;
int flags, error;
@@ -246,8 +247,8 @@ rip_output(struct mbuf *m, struct socket
ip->ip_off = htons(0);
ip->ip_p = inp->inp_ip.ip_p;
ip->ip_len = htons(m->m_pkthdr.len);
- ip->ip_src = inp->inp_laddr;
- ip->ip_dst = satosin(dstaddr)->sin_addr;
+ ip->ip_src.s_addr = INADDR_ANY;
+ ip->ip_dst = dst->sin_addr;
ip->ip_ttl = inp->inp_ip.ip_ttl ? inp->inp_ip.ip_ttl : MAXTTL;
} else {
if (m->m_pkthdr.len > IP_MAXPACKET) {
@@ -262,11 +263,23 @@ rip_output(struct mbuf *m, struct socket
ip = mtod(m, struct ip *);
if (ip->ip_id == 0)
ip->ip_id = htons(ip_randomid());
+ dst->sin_addr = ip->ip_dst;
/* XXX prevent ip_output from overwriting header fields */
flags |= IP_RAWOUTPUT;
ipstat_inc(ips_rawout);
}
+
+ if (ip->ip_src.s_addr == INADDR_ANY) {
+ struct in_addr *laddr;
+
+ error = in_pcbselsrc(&laddr, dst, inp);
+ if (error != 0)
+ return (error);
+
+ ip->ip_src = *laddr;
+ }
+
#ifdef INET6
/*
* A thought: Even though raw IP shouldn't be able to set IPv6