【问题标题】:Receiving packets via raw socket通过原始套接字接收数据包
【发布时间】:2022-01-01 06:30:39
【问题描述】:

我正在尝试通过原始套接字接收以太网数据包。 但行为并不像预期的那样。

代码在这里。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <net/ethernet.h>
#include <linux/if_packet.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
 
int32_t main(int32_t argc, int8_t *argv[])
{
   int32_t sock;
   int8_t buf[1522];
   int32_t ret;
   int32_t bytes;
 
   sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
   if (sock == -1)
   {
      printf("socket open failed\n");
      return 1;
   }
 
   ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "ens193", (strlen("ens193")+1));
   if (ret == -1)
   {
      printf("interface binding failed\n");
      close(sock);
      return 1;
   }
 
   while(1)
   {
      bytes = recvfrom(sock, buf, 1522, 0, NULL, NULL);
      if (bytes < 0)
      {
         printf("error in recvfrom\n");
         exit;
      }
      printf("bytes = %d\n", bytes);
   }
 
   close(sock);
   return 0;
}

并且执行输出在这里。

# ./a.out
[Nothing happening for a while]
bytes = 60
bytes = 42
bytes = 134
bytes = 118
bytes = 118
bytes = 118
bytes = 118
bytes = 118
bytes = 118
bytes = 66
...
...
...

但我认为接口实际上并没有收到任何数据包。 如果我看到 ifconfig 输出,则 RX 计数没有增加。 是因为我的代码中遗漏了一些东西吗? 如果你有什么好主意,请告诉我!

【问题讨论】:

  • 您似乎正在捕获在指定接口上收到的所有流量,这可能并不总是计入 RX 计数。
  • 你的意思是 ifconfig 不显示通过以太网驱动程序接收的所有数据包的计数吗?
  • 既然你正在捕获htons(ETH_P_ALL),那可能就是这种情况
  • 为什么不用wireshark看看它们是什么?
  • 我认为 htons(ETH_P_ALL) 意味着从设备/驱动程序接收所有以太网帧。 ifconfig 的 RX 计数应该与从设备/驱动程序接收到的以太网帧数匹配。

标签: c linux ethernet raw-sockets


【解决方案1】:

我查看了 tcpdump/libpcap 代码并修改了我的代码,如下所示。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>

/* Return the index of the given device name */
static int32_t iface_to_id(int32_t sk, int8_t *device)
{
   struct ifreq   ifr;
   int32_t  ret;

   memset(&ifr, 0, sizeof(struct ifreq));
   strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));

   ret = ioctl(sk, SIOCGIFINDEX, &ifr);
   if (ret < 0)
   {
      printf("failed to get index\n");
      return -1;
   }

   return ifr.ifr_ifindex;
}

/* Bint the socket to the given device */
static int32_t iface_bind_to_device(int32_t sk, int32_t ifindex, int32_t protocol)
{
   struct sockaddr_ll   sll;
   int32_t ret;

   memset(&sll, 0x0, sizeof(struct sockaddr_ll));
   sll.sll_family    = AF_PACKET;
   sll.sll_ifindex   = ifindex;
   sll.sll_protocol  = protocol;

   ret = bind(sk, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll));
   if (ret == -1)
   {
      return -1;
   }

   return 0;
}

int32_t main(int32_t argc, int8_t *argv[])
{
   int32_t sock;
   int8_t buf[1522];
   int32_t ifindex;
   int32_t ret;
   int32_t bytes;
   struct packet_mreq mr;

   sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
   if (sock == -1)
   {
      printf("socket open failed\n");
      return 1;
   }

   ifindex = iface_to_id(sock, "ens193");
   if (ifindex < 0)
   {
      close(sock);
      return 1;
   }

   ret = iface_bind_to_device(sock, ifindex, htons(ETH_P_ALL));
   if (ret < 0)
   {
      close(sock);
      printf("interface binding error\n");
      return 1;
   }

   while(1)
   {
      bytes = recvfrom(sock, buf, 1522, 0, NULL, NULL);
      if (bytes < 0)
      {
         printf("error in recvfrom\n");
         exit;
      }
      printf("received bytes = %d\n", bytes);
   }

   close(sock);
   return 0;
}

进行这样的更改后,行为符合预期。 如果我向接口 ens193 发送 ping。 然后,我看到如下输出。

# ./a.out
received bytes = 98
received bytes = 98

所以,htons(ETH_P_ALL) 不是问题。 似乎使用“setsockopt 和 SO_BINDTODEVICE”不是正确的方法。 现在,我的问题是 SO_BINDTODEVICE 是什么意思以及何时使用它。

如果有人上面有 cmets,请在此处添加。 我也会研究更多。

【讨论】:

  • SO_BINDTODEVICE 设置socket传输时使用的接口,从而绕过路由。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多