Linux socket use SO_BINDTODEVICE but with specified IP address

Issue

I got a program which does

    ...
    /* Only rx/tx packets on the interface */
    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
        ...
    }
    ...

for each given ethernet interface and uses UDP.
I want every interface to use the same IP I specified (for example: 50.0.0.1/24).
So that packets coming out from eth0 tell "my source IP is 50.0.0.1"
and packets from eth1 tell the same("source IP: 50.0.0.1").
Both receiving and sending in required.

Is there any way to achieve this?
I’ve tried

    addr.sin_addr.s_addr = inet_addr("50.0.0.1");
    ...
    bind(fd, (struct sockaddr *)&addr, sizeof(addr));

but it won’t work (error: cannot assign IP address) unless I set an unrelated interface’s IP to 50.0.0.1.
After that, the packets coming out say "source IP: 50.0.0.1" but sending packets with "source IP: 50.0.0.X" to the machine (which runs the above program), it will not receive any.

Solution

You can’t bind a socket to an interface and an IP at the same time, only one or the other. If an interface is bound, its IP gets used. If an IP is bound, its interface gets used.

And, you can’t use bind() to set a source IP that does not belong to the bound interface.

On some platforms (Linux, etc), you can use sendmsg() with IP_PKTINFO to specify a source IP for outgoing packets. However, the OS will lookup and use the interface that belongs to the specified IP, which could be different than the bound interface, so this doesn’t address your issue.

So, you will likely have to use a RAW socket and send your UDP packets with a custom IP header, then you can populate that header however you want.

Answered By – Remy Lebeau

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published