On Sun, 12 Jun 2016 15:29:32 +0200 (CEST)
Mark Kettenis <[email protected]> wrote:

> > Date: Sun, 12 Jun 2016 14:59:55 +0200
> > From: Vincent Gross <[email protected]>
> > 
> > This diff adds support for IP_SENDSRCADDR cmsg on UDP sockets. As
> > for udp6_output(), we check that the source address+port is
> > available only if inp_laddr != *
> > 
> > Ok ?  
> 
> Why do we need this?  cmsg stuff is fragile, so we want the to keep it
> as simple as possible.

In iked.conf(5), you can specify the local and remote addresses to use
for IKEv2 handshake. Let's say I have 192.0.2.1/25 on em0, and
192.0.2.129/25 on em1, and that I have a single udp socket bound to
0.0.0.0. I receive an IKEv2 message on em0, with 192.0.2.129 as
destination address, and a source address reachable only via em0.
If I reply with the receiving socket, in_selectsrc() will pick 192.0.2.1
as the reply source address, and the handshake will abort.

isakmpd(8) work around this by opening one socket per local address.
This means that we must either watch for RTM_NEWADDR and RTM_DELADDR,
or poll using getifaddrs(3), if we want to catch all changes.

This is one example, I remember other developers saying how they
would benefit from this, but I can't find the conversations back :P

> 
> > diff --git a/share/man/man4/ip.4 b/share/man/man4/ip.4
> > index 111432b..154b0d1 100644
> > --- a/share/man/man4/ip.4
> > +++ b/share/man/man4/ip.4
> > @@ -290,6 +290,27 @@ cmsg_len = CMSG_LEN(sizeof(u_int))
> >  cmsg_level = IPPROTO_IP
> >  cmsg_type = IP_RECVRTABLE
> >  .Ed
> > +.Pp
> > +If the
> > +.Dv IP_SENDSRCADDR
> > +option is passed to a
> > +.Xr sendmsg 2
> > +call on a
> > +.Dv SOCK_DGRAM
> > +socket, the address passed along the
> > +.Vt cmsghdr
> > +structure will be used as the source of the outgoing
> > +.Tn UDP
> > +datagram.  The
> > +.Vt cmsghdr
> > +fields for
> > +.Xr sendmsg 2
> > +have the following values:
> > +.Bd -literal -offset indent
> > +cmsg_len = CMSG_LEN(sizeof(struct in_addr))
> > +cmsg_level = IPPROTO_IP
> > +cmsg_type = IP_SENDSRCADDR
> > +.Ed
> >  .Ss "Multicast Options"
> >  .Tn IP
> >  multicasting is supported only on
> > diff --git a/sys/netinet/in.h b/sys/netinet/in.h
> > index adb1b30..bf8c95d 100644
> > --- a/sys/netinet/in.h
> > +++ b/sys/netinet/in.h
> > @@ -307,6 +307,7 @@ struct ip_opts {
> >  #define IP_RECVRTABLE              35   /* bool; receive rdomain
> > w/dgram */ #define IP_IPSECFLOWINFO 36   /* bool; IPsec flow
> > info for dgram */ #define IP_IPDEFTTL               37   /* int;
> > IP TTL system default */ +#define IP_SENDSRCADDR
> > 38   /* struct in_addr; source address to use */ 
> >  #define IP_RTABLE          0x1021  /* int; routing
> > table, see SO_RTABLE */ #define IP_DIVERTFL
> > 0x1022      /* int; divert direction flag opt */ diff --git
> > a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index
> > 1feea11..35675b4 100644 --- a/sys/netinet/udp_usrreq.c
> > +++ b/sys/netinet/udp_usrreq.c
> > @@ -888,6 +888,7 @@ udp_output(struct inpcb *inp, struct mbuf *m,
> > struct mbuf *addr, struct sockaddr_in *sin = NULL;
> >     struct udpiphdr *ui;
> >     u_int32_t ipsecflowinfo = 0;
> > +   struct sockaddr_in src_sin;
> >     int len = m->m_pkthdr.len;
> >     struct in_addr *laddr;
> >     int error = 0;
> > @@ -906,6 +907,8 @@ udp_output(struct inpcb *inp, struct mbuf *m,
> > struct mbuf *addr, goto release;
> >     }
> >  
> > +   memset(&src_sin, 0, sizeof(src_sin));
> > +
> >     if (control) {
> >             u_int clen;
> >             struct cmsghdr *cm;
> > @@ -939,9 +942,16 @@ udp_output(struct inpcb *inp, struct mbuf *m,
> > struct mbuf *addr, cm->cmsg_level == IPPROTO_IP &&
> >                         cm->cmsg_type == IP_IPSECFLOWINFO) {
> >                             ipsecflowinfo = *(u_int32_t
> > *)CMSG_DATA(cm);
> > -                           break;
> > -                   }
> > +                   } else
> >  #endif
> > +                   if (cm->cmsg_len == CMSG_LEN(sizeof(struct
> > in_addr)) &&
> > +                       cm->cmsg_level == IPPROTO_IP &&
> > +                       cm->cmsg_type == IP_SENDSRCADDR) {
> > +                           memcpy(&src_sin.sin_addr,
> > CMSG_DATA(cm),
> > +                               sizeof(struct in_addr));
> > +                           src_sin.sin_family = AF_INET;
> > +                           src_sin.sin_len = sizeof(src_sin);
> > +                   }
> >                     clen -= CMSG_ALIGN(cm->cmsg_len);
> >                     cmsgs += CMSG_ALIGN(cm->cmsg_len);
> >             } while (clen);
> > @@ -980,6 +990,17 @@ udp_output(struct inpcb *inp, struct mbuf *m,
> > struct mbuf *addr, if (error)
> >                             goto release;
> >             }
> > +
> > +           if (src_sin.sin_len > 0 &&
> > +               src_sin.sin_addr.s_addr != INADDR_ANY &&
> > +               src_sin.sin_addr.s_addr !=
> > inp->inp_laddr.s_addr) {
> > +                   src_sin.sin_port = inp->inp_lport;
> > +                   if (inp->inp_laddr.s_addr != INADDR_ANY &&
> > +                       (error =
> > +                       in_pcbaddrisavail(inp, &src_sin, 0,
> > curproc)))
> > +                           goto release;
> > +                   laddr = &src_sin.sin_addr;
> > +           }
> >     } else {
> >             if (inp->inp_faddr.s_addr == INADDR_ANY) {
> >                     error = ENOTCONN;
> > 
> >   
> 

Reply via email to