2
votes

My application has opened an UDP socket that is bound to INADDR_ANY to listen to packets on all the interfaces my server has. I'm sending out replies through the same socket.

However, while sending a reply from the server, default IP is chosen by the IP layer of linux depending upon which interface is chosen for packet to going out. The IP associated with this interface may not be the destination address with which this UDP server got a query from a client. Thus source IP of the reply from server becomes different from the destination IP with which the query came. The client may be uncomfortable with such a reply.

Following link gives the behavior of INADDR_ANY with UDP: http://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html

How can I change this default behavior and use a particular interface IP in the source address? That is more control on the application code to decide what will be the source address. Also it make sense that source address in the reply be same as the destination address with which the query came.

2
It will be a little more work, but you haven't thought about using raw sockets instead? Then you can change all the fields in the IP and UDP headers as you please.Some programmer dude
@JoachimPileborg I wouldn't recommend using raw sockets for this. You'll have to basically reimplement UDP in your application, select UDP ports to use without the kernel's knowledge (and maybe interfere with its own selection), and you'll need root access.Celada
is there no way I can have a say as to which interface UDP chooses as it's server source address?superbCoder
@superbCoder Of course there is, unless there is some part of your requirement that i misunderstood. Take a look at my answer belowfkl
You must have a very strange routing table if the interface chosen automatically isn't the one the sender sent to.user207421

2 Answers

1
votes

Assuming you have multiple interfaces (one of which has the correct ip) of course you can bind to an interface for outgoing response. Take a look at SO_BINDTODEVICE socket option.

int bind_sock2inf(int sock, char *interface_name)
{
    int status = -1;
    struct ifreq ifr;

    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), interface_name);
    if ( (status = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
                (void *)&ifr, sizeof(ifr))) < 0) {
        log_debug(4, "Failed binding to interface named %s", inf_name);
    }
    else log_debug(3, "Binding to interface %s", inf_name);

    return status;
}

Now your outgoing request should automatically use the ip address attached to this interface. The only down side is that you stop receiving messages on any other interface for this socket.

Possible work arounds are:

  1. Use a separate socket for listening which is not bound to any interface and another one for sending and bind to whatever interface you need before sending.

  2. Bind to interface before sending a message and bind to "" again which clears the previous bind immediately after sending. However, you might loose any packets received during this time frame which your socket was bound to interface say eth0 and packets arrived at eth1.

Also you can simply use bind() for associating a source ip for an outgoing packet.

0
votes

Once a socket is bound to an address you can not bind it again to another address or you will get error EINVAL. But there is another technique described in this post Setting the source IP for a UDP socket