1

I am trying to communicate with an external device using unicast UDP.

SETUP: My machine and the external device are both running versions of Linux. The external device is connected to NIC#2 in my machine, or eno2. The external device is sending unicast packets to port 25000 and IP of my eno2 NIC 192.24.38.1. I have also updated the ARP table on the remote device to add my machines IP and HW address.

WHAT I HAVE DONE: Using the simple code below, I never receive any data.

   int socket_desc;
   struct ifreq ifr;
   struct sockaddr_in server_addr, client_addr;
   char server_message[2000], client_message[2000];
   int client_struct_length = sizeof(client_addr);

   // Clean buffers:
   memset(server_message, '\0', sizeof(server_message));
   memset(client_message, '\0', sizeof(client_message));

   // Create UDP socket:
   socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

   if (socket_desc < 0) {
      printf("Error while creating socket\n");
      return -1;
   }
   printf("Socket created successfully\n");
   if (setsockopt(socket_desc, SOL_SOCKET, SO_BINDTODEVICE, "eno2", strlen("eno2") + 1) < 0)
   {
      std::cout << "Error setting SO_BINDTODEVICE" << std::endl;
      exit(-1);
   }
   
   // Set port and IP:
   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons(25000);
   server_addr.sin_addr.s_addr = inet_addr("192.24.38.1");

   // Bind to the set port and IP:
   if (bind(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
      printf("Couldn't bind to the port\n");
      return -1;
   }
   

   printf("Done with binding\n");

   printf("Listening for incoming messages...\n\n");

   // Receive client's message:
   if (recvfrom(socket_desc, client_message, sizeof(client_message), 0,
      (struct sockaddr*)&client_addr, (socklen_t*)&client_struct_length) < 0) {
      printf("Couldn't receive\n");
      return -1;
   }
   printf("Received message from IP: %s and port: %i\n",
      inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

   printf("Msg from client: %s\n", client_message);

THE ISSUE: The only way I can see these packets is if I put the NIC in promiscuous mode and with the following code:

   struct ifreq ifr;
   struct sockaddr_in servaddr;

   int saddr_size, data_size;
   struct sockaddr saddr;

   thisSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

   if (thisSocket < 0)
   {
      //Print the error with proper message
      perror("Socket Error");
   }

   if (setsockopt(thisSocket, SOL_SOCKET, SO_BINDTODEVICE, "eno2", strlen("eno2") + 1) < 0)
   {
      std::cout << "Error setting SO_BINDTODEVICE" << std::endl;
      exit(-1);
   }

   memset(&ifr, 0, sizeof(ifr));
   strncpy((char*)ifr.ifr_name, "eno2", IFNAMSIZ);
   if ((ioctl(thisSocket, SIOCGIFHWADDR, &ifr)) == -1)
   {
      std::cout << "Error getting Interface hw address!" << std::endl;
      exit(-1);
   }

   timeval timeout;
   timeout.tv_sec = 0;
   timeout.tv_usec = 18000;
   saddr_size = sizeof saddr;
   while (1)
   {
      fd_set fds;
      FD_ZERO(&fds);
      FD_SET(thisSocket, &fds);
      int status = select(thisSocket + 1, &fds, NULL, NULL, &timeout);
      if (status > 0) {
         
         //Receive a packet
         data_size = recvfrom(thisSocket, &RX_Buffer[0], RX_Buffer.size(), 0, &saddr, (socklen_t*)&saddr_size);

         if (data_size < 0)
         {
            std::cout << "Recvfrom error , failed to get packets" << std::endl;
         }
         else {
            //Now process the packet
            ProcessPacket(RX_Buffer, data_size);
         }
      }

   }

This is not ideal because I have to ‘sniff’ all traffic and parse the raw packet IP header to look for the packets I want. There is a lot of multicast traffic that I do not care about. I would like to bind to an address so I only receive packets that are intended for my machine. What am I doing wrong?

m.s.
  • 31
  • 1
  • 3
  • If promiscuous mode makes it work, I don't think 192.24.38.1 is the correct address of the NIC. – Barmar Apr 28 '23 at 22:46
  • Or you didn't update the ARP cache correctly. You shouldn't need to do that manually, ARP works automatically. – Barmar Apr 28 '23 at 22:47
  • This is the data parsed from the IP header when in promiscuous mode - the IP is correct – m.s. Apr 28 '23 at 22:51
  • `***********************IP HEADER************************* |-IP Version : 4 |-IP Header Length : 5 DWORDS or 20 Bytes |-Type Of Service : 0 |-IP Total Length : 272 Bytes(Size of Packet) |-Identification : 21727 |-TTL : 64 |-Protocol : 17 |-Checksum : 17611 |-Source IP : 192.24.34.1 |-Destination IP : 192.24.38.1 ***********************UDP Packet************************* UDP Header |-Source Port : 14510 |-Destination Port : 25000 |-UDP Length : 252 |-UDP Checksum : 11392` – m.s. Apr 28 '23 at 22:51
  • I use ip neigh change to ... to modify the ARP table. I know I did it right because I didn't see these packets until I did that – m.s. Apr 28 '23 at 22:59
  • Something in the destination information must not match the actual configuration of the PC, or it would receive the packet with the normal code. – Barmar Apr 28 '23 at 23:15
  • 1
    Why do you think that means you did it right? Promiscuous mode receives all packets, not just those with the correct destination MAC. Before you updated the ARP cache, the device couldn't send the packets at all. Are the two devices on the same IP subnet? – Barmar Apr 28 '23 at 23:17
  • Yes they are on the same subnet
    Local machine
    ~# ifconfig
    eno2 Link encap:Ethernet HWaddr 00:72:2F:30:6E:C9
    inet addr:192.24.38.1 Bcast:192.24.255.255 Mask:255.255.0.0
    inet6 addr: fe80::280:2fff:fe30:6ec4/64 Scope:Link
    UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1
    Remote Machine
    ~# ifconfig
    eth0 Link encap:Ethernet HWaddr 00:28:12:00:7A:C9
    inet addr:192.24.34.1 Bcast:0.0.0.0 Mask:255.255.0.0
    UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
    – m.s. May 01 '23 at 18:37
  • I wouldn't be here if everything was right. Telling me I am wrong without providing any useful or constructive solutions isn't helpful. – m.s. May 01 '23 at 18:38
  • I don't notice anything obvious with the code. That's why I think your underlying assumptions might be wrong. – Barmar May 01 '23 at 19:27
  • Would it matter if the remote device I am trying to receive packets from is a part of a VLAN? In other words I am trying to receive data from a specific IP that is part of a VLAN inside the remote machine... – m.s. May 01 '23 at 22:15
  • If they're on the same VLAN then that should be transparent to the devices. – Barmar May 02 '23 at 14:57
  • But if you get the data in promiscuous mode, the LAN is probably not an issue. – Barmar May 02 '23 at 14:58

0 Answers0