milanHrabos
milanHrabos

Reputation: 1965

How to get local address the kernel assign to a UDP socket with connect()?

Reading the https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551, chapter

8.14 Determining Outgoing Interface with UDP

A connected UDP socket can also be used to determine the outgoing interface that will be used to a particular destination. This is because of a side effect of the connect function when applied to a UDP socket: The kernel chooses the local IP address (assuming the process has not already called bind to explicitly assign this). This local IP address is chosen by searching the routing table for the destination IP address, and then using the primary IP address for the resulting interface.

If I try to run the example (udpcli01.c):

#define BSIZE 256
#define SERV_PORT 9877

typedef struct sockaddr SA;

//argv[1] = ip address
int main(int argc, char **argv)
{
    int sockfd;
    socklen_t servlen, clilen;
    struct sockaddr_in cliaddr, servaddr;
    char ip[BSIZE];

    if (argc < 2)
    {
        die("usage: %s <ip>\n", argv[0]);
    }

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    servlen = sizeof(servaddr);
    memset(&servaddr, 0, servlen);
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    connect(sockfd, (SA *)&servaddr, servlen);

    clilen = sizeof(clilen);
    if (getsockname(sockfd, (SA *)&cliaddr, &clilen) < 0)
    {
        perror("getsockname");
    }

    inet_ntop(AF_INET, &cliaddr, ip, BSIZE);
    printf("address %s:%hd\n", ip, cliaddr.sin_port);
}

Now If i run the server in one terminal (which address INADDR_ANY and port 9877), and then run the client above:

terminal 1:
$ ./udpserv01

terminal 2:
$ #I will try localhost first
$ ./udpcli01 127.0.0.1
address 2.0.178.211:-11342
$ #did not work, now my host ip 10.0.0.11
$ ./udpcli01 10.0.0.11
address 2.0.193.86:22209

I always get some garbage even if the client is prior to printing its address and port, connected to server, which is listening. If i was trying to print server address and port, then it would work (that is, it would print 127.0.0.1:9877 and 10.0.0.11:9877 respectively -> I have already tried). So I know the inet_ntop is working correctly and also getting the port number. So where is issue in the client? Does the kernel really assigns address and port upon connect() according to the book? If so then why my example prints random garbage?

uname -a:
Linux Shepherd 5.8.0-36-generic #40-Ubuntu SMP Tue Jan 5 21:54:35 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Upvotes: 2

Views: 1020

Answers (1)

dbush
dbush

Reputation: 225007

You're passing the address of a struct sockaddr_in to the inet_ntop function. For an AF_INET socket it expects a pointer to a struct in_addr.

So instead of this:

inet_ntop(AF_INET, &cliaddr, ip, BSIZE);

You want this:

inet_ntop(AF_INET, &cliaddr.sin_addr, ip, BSIZE);

Also, be sure to call ntohs on the sin_port member before you print it to get the proper value, and use %d instead of %hd:

printf("address %s:%d\n", ip, ntohs(cliaddr.sin_port));

And clilen is not initialized properly:

clilen = sizeof(clilen);

It should be:

clilen = sizeof(cliaddr);

Upvotes: 2

Related Questions