UDP Unicast from external device

65 views Asked by At

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?

0

There are 0 answers