csocketsudprecvfrom

Why does recvfrom() returns wrong address of sender?


This simple UDP client:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define PORT 9877
#define BSIZE 256
#define ADDRSTRLEN 19

static char presentation[ADDRSTRLEN];
char *Inet_ntop(const void *src)
{
    if (inet_ntop(AF_INET, src, presentation, ADDRSTRLEN) == NULL)
    {
        perror("inet_ntop");
    }
    return presentation;
}

int main()
{
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    char recvline[BSIZE], sendline[BSIZE];

    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    //localhost
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    socklen_t servlen = sizeof(servaddr);
    struct sockaddr *replyaddr = malloc(servlen);
    socklen_t replylen;

    while (fgets(sendline, BSIZE, stdin) != NULL)
    {
        sendto(sockfd, sendline, strlen(sendline), 0, (struct sockaddr *)&servaddr, servlen);
        printf("serv addr: %s\n", Inet_ntop(&servaddr));

        //recvfrom() should return address of the host this UDP received datagram from (localhost)
        replylen = servlen;
        ssize_t bytesRead = recvfrom(sockfd, recvline, BSIZE, 0, replyaddr, &replylen);
        printf("reply addr: %s\n", Inet_ntop(replyaddr));

        recvline[bytesRead] = '\0';
        puts(recvline);
    }
}

will send datagram to server (echo server) on 127.0.0.1:9877. The output is

a
serv addr: 2.0.38.149
reply addr: 2.0.38.149
a

b
serv addr: 2.0.38.149
reply addr: 2.0.38.149
b

c
serv addr: 2.0.38.149
reply addr: 2.0.38.149
c

^C

you can see neither the server address passed sendto() (servaddr) nor the address from recvfrom() (replyaddr) is not localhost or 127.0.0.1. what is 2.0.38.149 ??

tcpdump:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
IP 127.0.0.1.40270 > 127.0.0.1.9877: UDP, length 2
IP 127.0.0.1.9877 > 127.0.0.1.40270: UDP, length 2
IP 127.0.0.1.40270 > 127.0.0.1.9877: UDP, length 2
IP 127.0.0.1.9877 > 127.0.0.1.40270: UDP, length 2
IP 127.0.0.1.40270 > 127.0.0.1.9877: UDP, length 2
IP 127.0.0.1.9877 > 127.0.0.1.40270: UDP, length 2
^C
6 packets captured
12 packets received by filter
0 packets dropped by kernel

this is correct, and you can see localhost. So what is 2.0.38.149?

The address 2.0.38.149 is not random. I can compile it and run it multiple time and always get the same address, 2.0.38.149. What is that address?

EDIT, server part:

void dg_echo(int sockfd, struct sockaddr *cliaddr, socklen_t clilen)
{
    ssize_t bytesRead;
    socklen_t len;
    char buf[BSIZE];

    while (1)
    {
        len = clilen;
        bytesRead = Recvfrom(sockfd, buf, BSIZE, 0, cliaddr, &len);

        Sendto(sockfd, buf, bytesRead, 0, cliaddr, len);
    }
}


int main()
{
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;

    sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    Bind(sockfd, (SA *)&servaddr, sizeof(servaddr));

    dg_echo(sockfd, (SA *)&cliaddr, sizeof(cliaddr));
}

Solution

  • You're passing the wrong thing to inet_ntop.

    When the first parameter to inet_ntop is AF_INET, the second parameter should be a pointer to a struct in_addr. What you're passing in is a pointer to a struct sockaddr_in. So the values you're seeing are from the first 4 bytes of the struct sockaddr_in.

    You need to call your wrapper function like this:

    Inet_ntop(&servaddr.sin_addr)