On Sat, Mar 19, 2022 at 12:27:43PM +0100, Claudio Jeker wrote:
> On Sat, Mar 19, 2022 at 10:51:13AM +0000, Stuart Henderson wrote:
> > On 2022/03/19 19:14, David Gwynne wrote:
> > > 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.
> >
> > Given that this turned out so similar to the existing v6 support that
> > I think you didn't notice before writing the v4 version, this looks
> > like the right place indeed :)
> >
> > Works for me, OK
>
> Did someone try this on an ospf router?
> I think our ospfd(8) always includes the source address and uses IP_HDRINCL
> but not sure about other daemons. Are there other raw IP users that expect
> the IP source to be set to the outgoing interface by default?
> Maybe IGMP proxies and routers. E.g. dvmrpd depends on IP_MULTICAST_IF to
> set the source IP address.
>
> Looking at the code I think this will break the IP_MULTICAST_IF case.
> In ip_output() the check is like this:
>
> if ((IN_MULTICAST(ip->ip_dst.s_addr) ||
> (ip->ip_dst.s_addr == INADDR_BROADCAST)) &&
> imo != NULL && (ifp = if_get(imo->imo_ifidx)) != NULL) {
>
> mtu = ifp->if_mtu;
> if (ip->ip_src.s_addr == INADDR_ANY) {
> struct in_ifaddr *ia;
>
> IFP_TO_IA(ifp, ia);
> if (ia != NULL)
> ip->ip_src = ia->ia_addr.sin_addr;
> }
>
> Now raw_ip.c already set ip_src to something so
> if (ip->ip_src.s_addr == INADDR_ANY)
> is never true.
>
> It is possible to skip the in_pcbselsrc() call in rip_output() when
> IN_MULTICAST(ip->ip_dst.s_addr) || (ip->ip_dst.s_addr == INADDR_BROADCAST)
>
> Is that good enough?
Actually in_pcbselsrc() checks the multicast options but only for the
IN_MULTICAST() case. I guess we could add INADDR_BROADCAST handling in
there as well. Seems like a sensible thing todo. Broadcast is just a very
special version of multicast.
Also if this is changed is there still a way to have ip->ip_src ==
INADDR_ANY in ip_output()?
> > > 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
> > >
> >
>
> --
> :wq Claudio
>
--
:wq Claudio