imll
imll

Reputation: 341

Comparing ipv4 address of interface and source address of packet (libpcap)

I'm using a modification of the C code in https://www.tcpdump.org/sniffex.c to print information on TCP packets passing through an interface, using libpcap.

This is a sample of the callback code I'm trying to use to check if the received packet has the source field equal to the IP address of the current interface (so to only analyse outgoing packets). It is a rather extensive program, so I decided to just include the problematic part:

// retrieve IP address of interface    
char * dev_name = "eth0";
struct ifreq ifr;
int fd;
char *dev_ip;

fd = socket(AF_INET, SOCK_DGRAM, 0);

// type of address to retrieve (IPv4)
ifr.ifr_addr.sa_family = AF_INET;

// copy the interface name in the ifreq structure
strncpy(ifr.ifr_name , dev_name , IFNAMSIZ-1);

ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);

dev_ip = inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr);

printf("IPv4 address: %s\n", dev_ip);
printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src));

if (strcmp(dev_ip,inet_ntoa(ip->ip_src)) == 0)
    printf("EQUAL!\n");

However, as you can see in the following screenshot, even if the source IP (inet_ntoa) and the IP address of the interface (IPv4 address) are different, their values are always equal according to the program.

Output of program

What could the problem be?

Upvotes: 0

Views: 236

Answers (1)

ottomeister
ottomeister

Reputation: 5808

inet_ntoa returns a pointer to a string that has been constructed in static memory that is internal to inet_ntoa. It re-uses that same static memory every time it is called. When you do this:

    dev_ip = inet_ntoa(...);

dev_ip is set to point to that internal static buffer. At that point the static buffer contains a string that represents the interface address, so your:

    printf("IPv4 address: %s\n", dev_ip);

shows the expected result. But then you do this:

    printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src));

and that overwrites inet_ntoa's internal buffer with a string representing the packet's address.

But remember that dev_ip is still pointing to that internal buffer. So when you do this:

    if (strcmp(dev_ip,inet_ntoa(ip->ip_src)) == 0)

(which BTW unnecessarily overwrites the internal buffer again with the packet's address, which was already there) the two arguments that are passed to strcmp are both pointers to inet_nota's internal buffer, and therefore strcmp will always find that the target strings match -- because both arguments are pointing to the same string.

To fix, either make a local copy of the string generated by inet_ntoa immediately after you call it, by copying into a local buffer or by doing something like:

    dev_ip = strdup(inet_ntoa(...));

(and remember to free(dev_ip) when you no longer need that string) or, even better, use the thread-safe variant of inet_ntoa called inet_ntoa_r if your platform has that function. inet_ntoa_r does not use (and re-use) an internal buffer. It requires its caller to provide the buffer where the string will be placed.

Upvotes: 1

Related Questions