0

I have a embedded linux device that listens for UDP packets. The device has two ethernet interfaces so the packets can be retrieved on both interfaces. On certain UDP messages/packets I have to do do something specific for the interface that it was received on. So I need to detect which interface received the packet.

I have found posts and examples on Stackoverflow showing how to extract the destination IP from IP_PKTINFO. This works fine if I test the interfaces one by one. With both interfaces connected and receiving the destination IP is the same.

I have noticed that the ifindex is not the same, but I don't understand why the ipi_spec_dst is the same when I clearly receive a packet on two different interfaces with two different IPs.

C/C++ Code responsible for extracting the destination IP:

    ssize_t byteCount=recvmsg(f_socket, &message, 0);
    if (byteCount==-1) {
        printf("%s",strerror(errno));
    }

    for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&message); 
         cmsg != NULL; 
         cmsg = CMSG_NXTHDR(&message, cmsg)) 
    {
        if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO) continue;
        struct in_pktinfo *pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
        char* destAddr = (char*) calloc(4, sizeof(char));
        destAddr = inet_ntoa(pi->ipi_spec_dst);
        std::cout << destAddr << " " << std::to_string(pi->ipi_ifindex) << std::endl;
    }

Output eth0 connected:

172.20.55.9 4
172.20.55.9 4
172.20.55.9 4
...

Output eth0 connected:

200.0.0.101 6
200.0.0.101 6
200.0.0.101 6
...

Output eth0 and eth1 connected:

172.20.55.9 6
172.20.55.9 4
172.20.55.9 6
172.20.55.9 4
...

Expected output:

200.0.0.101 6
172.20.55.9 4
200.0.0.101 6
172.20.55.9 4
...

First of all, I'm not sure if this is expected or not, I do not think it is, but I might have not understood the documentation correctly.

I can supply more code if needed.

Code taken from:

  1. Getting the destination address of UDP packet
  2. Get destination address of a received UDP packet


Any and all help is greatly appreciated. Thank you.

-aln

too honest for this site
  • 12,050
  • 4
  • 30
  • 52

2 Answers2

1

I Think there is a problem in the lines:

char* destAddr = (char*) calloc(4, sizeof(char));
destAddr = inet_ntoa(pi->ipi_spec_dst);
std::cout << destAddr << " " << std::to_string(pi->ipi_ifindex) << std::endl;

Two problems:

  • You should use ipi_addr instead of ipi_spec_dst (see man 7 ip)
  • You do not need the calloc stuff (which is

    • not big enough,
    • not correctly initialized,
    • not freed.)

You could simplify it by :

printf("%s %d\n", inet_ntoa(pi->ipi_addr), pi->ipi_ifindex);

Thus, to resume, your loop could look like:

for (   struct cmsghdr *cmsg = CMSG_FIRSTHDR(&message); 
        cmsg != NULL; 
        cmsg = CMSG_NXTHDR(&message, cmsg)) 
{
    if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO) 
        continue;

    struct in_pktinfo *pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
    printf("%s %d\n", inet_ntoa(pi->ipi_addr), pi->ipi_ifindex);
}
Mathieu
  • 8,840
  • 7
  • 32
  • 45
  • ipi_addr returns "255.255.255.255", which is right, because its a broadcast message and not a direct one. Either way thank you for clearing up the calloc thing, it was just a copy paste and I'm new to c/c++. – André Nicolaysen Sep 17 '18 at 12:50
  • @AndréNicolaysen Ok, so in that case, you could use `recvfrom` and use the two last parameters? – Mathieu Sep 17 '18 at 12:59
  • `recvfrom` gives me the `src_addr` which is the address where the packet came from. `pi->ipi_spec_dest` is supposed to give me the local address which the packet was received on. Which it does, but it is wrong if I connect both my interfaces at the same time. – André Nicolaysen Sep 17 '18 at 13:05
  • It seems that what you want to do is difficult: https://stackoverflow.com/q/25070649/1212012 – Mathieu Sep 17 '18 at 13:17
  • 1
    It seems so. Thank you for finding it. I will have to try some of that stuff out. This is a weird issue, because the `ifindex` is correct every time. – André Nicolaysen Sep 17 '18 at 14:16
  • @AndréNicolaysen: Use `ifindex`. It exactly meets your requirement "I need to detect which interface received the packet." – Ben Voigt Sep 17 '18 at 14:55
  • @BenVoigt Looks like it's the easiest solution at the moment, I will update my post tomorrow. – André Nicolaysen Sep 17 '18 at 16:38
0

I solved this problem by using ifindex to get the interface name which I then used to execute the interface specific code.