无法将原始套接字绑定到接口

Vla*_*lad 5 c sockets linux bind raw-sockets

我正在努力将原始套接字绑定到接口,我的目标是实现简单的数据包嗅探器.已经专门的时间搜索网络并浏览了参考文献,其中一部分列在底部.

我能够打开套接字,绑定没有错误,但是当剥离以太网报头并观察IP报头时,我看到捕获的环回(127.0.0.1)和其他不受欢迎的ethX ifaces流量.

其中一个结论是在我的情况下不能使用setsockopt,这是我的代码片段:

struct sockaddr_ll sll;
int raw_sock;

raw_sock = socket( PF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
// also tried with AF_PACKET

bzero(&sll , sizeof(sll));

sll.sll_family = PF_PACKET; 
// also tried with AF_PACKET
sll.sll_ifindex =get_iface_index(raw_sock,"eth1");
// returns valid ifr.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
if((bind(raw_sock , (struct sockaddr *)&sll , sizeof(sll))) ==-1)
{
    perror("bind: ");
    exit(-1);
}

saddr_size = (sizeof sll);
data_size = recvfrom(raw_sock , buffer_ptr, 65536, 0 , &sll , (socklen_t*)&saddr_size);
Run Code Online (Sandbox Code Playgroud)

提前谢谢!

参考文献:

  1. http://man7.org/linux/man-pages/man7/packet.7.html
  2. http://man7.org/linux/man-pages/man2/bind.2.html
  3. 使用setsockopt()系统的设备绑定的原始套接字在Fedora core 6(2.6.18-1.2798.fc6)中不起作用
  4. 如何将原始套接字绑定到特定接口

编辑-1:非常感谢您花时间回复,我对无休止的搜索解决方案感到非常失落和沮丧.

  1. 我仅限于自己的实现,因此无法使用libcap或其他人.
  2. 在我的情况下,从ioctl调用SIOCGIFINDEX返回的接口索引是3,并且与sll.sll_ifindex值相同.假设我可以依赖"ip link show" - 我的eth1索引确实是3.

    int get_iface_index(int socket,char *iface_name){
    struct ifreq ifr;
    char ifname[IFNAMSIZ]="eth1"; 
    // Ugly hard coded, will be changed
    memset(&ifr, 0, sizeof(struct ifreq));
    strncpy((char *)ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0){
            perror("ioctl: ");
            return -1;
    }
    return ifr.ifr_ifindex;
    // Always success here 2 for eth0, 3 for eth1
    }
    
    Run Code Online (Sandbox Code Playgroud)

abl*_*igh 2

如果您想编写一个数据包嗅探器,我强烈建议您使用libpcap为此目的而设计的。这将确保在数据包到达用户区域之前使用伯克利数据包过滤器 (BPF) 完成过滤(关于您想要的数据包)。

您的最后一个链接是关于原始套接字的,即IPPROTO_RAW。这些套接字使用setsockopt和进行绑定SO_BINDTODEVICE。从手册页raw

可以使用bind(2)调用将原始套接字绑定到特定的本地地址。如果不绑定,则接收所有具有指定 IP 协议的数据包。另外,可以使用SO_BINDTODEVICE将RAW套接字绑定到特定的网络设备;请参见套接字(7)。

IPPROTO_RAW 套接字仅用于发送。如果您确实想要接收所有 IP 数据包,请使用带有 ETH_P_IP 协议的 packet(7) 套接字。请注意,与原始套接字不同,数据包套接字不会重新组装 IP 片段。

因此,您的最后一个链接不相关,并且您使用正常bind()调用是正确的。

如果您决定不使用,libpcap我建议您首先打印出 的值sll.sll_ifindex。我打赌它是零(所有接口)。您还没有向我们展示 的来源get_iface_index,但我怀疑可能存在该错误。