简体   繁体   English

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

[英]Unable to bind raw socket to interface

I'm struggling to bind raw socket to interface, my goal to implement simple packet sniffer. 我正在努力将原始套接字绑定到接口,我的目标是实现简单的数据包嗅探器。 Already dedicated hours searching the web and went through references, part of them listed at bottom. 已经专门的时间搜索网络并浏览了参考文献,其中一部分列在底部。

I'm able to open socket, no error on bind , but when stripping Ethernet header and observing IP header I see that catched loopback (127.0.0.1) and other, undesired, ethX ifaces traffic. 我能够打开套接字, 绑定没有错误, 但是当剥离以太网报头并观察IP报头时,我看到捕获的环回(127.0.0.1)和其他不受欢迎的ethX ifaces流量。

One of conclusions is setsockopt can NOT be used in my case, here is my code snippets : 其中一个结论是在我的情况下不能使用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);

Thanks in advance ! 提前谢谢

References : 参考文献:

  1. http://man7.org/linux/man-pages/man7/packet.7.html http://man7.org/linux/man-pages/man7/packet.7.html
  2. http://man7.org/linux/man-pages/man2/bind.2.html http://man7.org/linux/man-pages/man2/bind.2.html
  3. Raw socket with device bind using setsockopt() system is not working in Fedora core 6(2.6.18-1.2798.fc6) 使用setsockopt()系统的设备绑定的原始套接字在Fedora core 6(2.6.18-1.2798.fc6)中不起作用
  4. how to bind raw socket to specific interface 如何将原始套接字绑定到特定接口

Edit-1 : Thanks a lot for dedicating your time for reply, I'm quite lost and frustrated from endless search for solution. 编辑-1:非常感谢您花时间回复,我对无休止的搜索解决方案感到非常失落和沮丧。

  1. I'm restricted to my own implementation , thus unable to use libcap nor others. 我仅限于自己的实现 ,因此无法使用libcap或其他人。
  2. Interface index returned from ioctl call SIOCGIFINDEX is 3 in my case and is identical to sll.sll_ifindex value. 在我的情况下,从ioctl调用SIOCGIFINDEX返回的接口索引是3,并且与sll.sll_ifindex值相同。 Assuming I can rely on "ip link show" - my eth1 index is indeed 3. 假设我可以依赖“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 } 

If you want to write a packet sniffer, I strongly suggest you use libpcap which is designed for the purpose. 如果你想写一个数据包嗅探器,我强烈建议你使用专为此目的设计的libpcap This will make sure the filtering (as to which packets you want) are done using Berkeley Packet Filter (BPF) before they even get to user land. 这将确保在使用伯克利数据包过滤器(BPF)之前进行过滤(关于您想要的数据包),然后再进入用户登陆状态。

Your last link is about raw sockets, ie IPPROTO_RAW . 你的最后一个链接是关于原始套接字,即IPPROTO_RAW These sockets bind using the setsockopt and SO_BINDTODEVICE . 这些套接字使用setsockoptSO_BINDTODEVICE绑定。 From the man page for raw : raw的手册页:

A raw socket can be bound to a specific local address using the bind(2) call. 可以使用bind(2)调用将原始套接字绑定到特定的本地地址。 If it isn't bound, all packets with the specified IP protocol are received. 如果未绑定,则接收具有指定IP协议的所有数据包。 In addition, a RAW socket can be bound to a specific network device using SO_BINDTODEVICE; 此外,可以使用SO_BINDTODEVICE将RAW套接字绑定到特定网络设备; see socket(7). 见socket(7)。

An IPPROTO_RAW socket is send only. IPPROTO_RAW套接字仅发送。 If you really want to receive all IP packets, use a packet(7) socket with the ETH_P_IP protocol. 如果您确实想要接收所有IP数据包,请使用带有ETH_P_IP协议的数据包(7)套接字。 Note that packet sockets don't reassemble IP fragments, unlike raw sockets. 请注意,与原始套接字不同,数据包套接字不会重新组合IP分片。

Thus your last link is not relevant, and you are correct to use the normal bind() call. 因此,您的上一个链接不相关,并且您使用正常的bind()调用是正确的。

If you are determined not to use libpcap I suggest first you print out the value of sll.sll_ifindex . 如果您决定不使用libpcap我建议您首先打印出sll.sll_ifindex的值。 I'm betting it's zero (all interfaces). 我认为它是零(所有接口)。 You have not shown us the source for get_iface_index , but I suspect the bug might be there. 你还没有向我们展示get_iface_index的来源,但我怀疑这个bug可能就在那里。

Another thing you should try is to compare strace(1) output from your code and that from the standard tcpdump(8) based on libpcap , though the latter might use the Linux PACKET_RX_RING extension. 您应该尝试的另一件事是比较代码中的strace(1)输出和基于libpcap的标准tcpdump(8)的输出,尽管后者可能使用Linux PACKET_RX_RING扩展。

This is how my own sniffer runs under strace(1) . 这就是我自己的嗅探器在strace(1)下运行的方式。 Seems like my code is essentially identical to yours. 好像我的代码与你的代码完全相同。

socket(PF_PACKET, SOCK_RAW, 768)        = 3
ioctl(3, SIOCGIFINDEX, {ifr_name="eth1", ifr_index=3}) = 0
bind(3, {sa_family=AF_PACKET, proto=0000, if3, pkttype=PACKET_HOST, addr(0)={0, }, 20) = 0
recvfrom(3, "\377\377\377\377\377\377\0\17S\f\365\254\10\6\0\1\10\0\6\4\0\1\0\17S\f\365\254\n\312\233\2"..., 65535, 0, {sa_family=AF_PACKET, proto=0x806, if3, pkttype=PACKET_BROADCAST, addr(6)={1, 000f530cf5ac}, [18]) = 56
...
recvfrom(3, "\0\17S\f\365\254\254\26-o\244\325\10\6\0\1\10\0\6\4\0\2\254\26-o\244\325\n\312\233\5"..., 65535, 0, {sa_family=AF_PACKET, proto=0x806, if3, pkttype=PACKET_OUTGOING, addr(6)={1, ac162d6fa4d5}, [18]) = 42
...
recvfrom(3, "\254\26-o\244\325\0\17S\f\365\254\10\0E\0\0T\0\0@\0@\1\357\r\n\312\233\2\n\312"..., 65535, 0, {sa_family=AF_PACKET, proto=0x800, if3, pkttype=PACKET_HOST, addr(6)={1, 000f530cf5ac}, [18]) = 98
...
recvfrom(3, "\0\17S\f\365\254\254\26-o\244\325\10\0E\0\0Tq\235\0\0@\1\275p\n\312\233\5\n\312"..., 65535, 0, {sa_family=AF_PACKET, proto=0x800, if3, pkttype=PACKET_OUTGOING, addr(6)={1, ac162d6fa4d5}, [18]) = 98

Note the "pkttype" ( sll.sll_pkttype ) field in the strace(1) output. 注意strace(1)输出中的“pkttype”( sll.sll_pkttype )字段。 You might as well check 你不妨检查一下

Environment 环境

$ strace -V
strace -- version 4.5.20
$ uname -a
Linux kaidev01 3.2.0-57-generic #87-Ubuntu SMP Tue Nov 12 21:35:10 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ ip l show dev eth1                      
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether ac:16:2d:6f:a4:d5 brd ff:ff:ff:ff:ff:ff

One minor issue with your code: you should define saddr_size as a socklen_t variable from the first place rather than resorting to pointer typecast which can be dangerous. 你的代码的一个小问题:你应该从第一个位置将saddr_size定义为socklen_t变量,而不是诉诸指针类型转换,这可能是危险的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM