> Am 12.06.2016 um 16:36 schrieb Vincent Gross <[email protected]>:
> 
> 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
> 

It is exactly like you explained it.

Binding to every IP address statically is just a really bad solution and you 
always have to reload the daemon on address changes. None of them watch the 
routing socket for address changes, and it would be very complex to do (and 
also require even more permission and a pledge bits).

As iked, unbound, relayd (udp) and many others would benefit from it, I am all 
for IP_SENDSRCADDR.

Reyk

>> 
>>> 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