簡體   English   中英

無法將原始套接字綁定到接口

[英]Unable to bind raw socket to interface

我正在努力將原始套接字綁定到接口,我的目標是實現簡單的數據包嗅探器。 已經專門的時間搜索網絡並瀏覽了參考文獻,其中一部分列在底部。

我能夠打開套接字, 綁定沒有錯誤, 但是當剝離以太網報頭並觀察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);

提前謝謝

參考文獻:

  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 } 

如果你想寫一個數據包嗅探器,我強烈建議你使用專為此目的設計的libpcap 這將確保在使用伯克利數據包過濾器(BPF)之前進行過濾(關於您想要的數據包),然后再進入用戶登陸狀態。

你的最后一個鏈接是關於原始套接字,即IPPROTO_RAW 這些套接字使用setsockoptSO_BINDTODEVICE綁定。 raw的手冊頁:

可以使用bind(2)調用將原始套接字綁定到特定的本地地址。 如果未綁定,則接收具有指定IP協議的所有數據包。 此外,可以使用SO_BINDTODEVICE將RAW套接字綁定到特定網絡設備; 見socket(7)。

IPPROTO_RAW套接字僅發送。 如果您確實想要接收所有IP數據包,請使用帶有ETH_P_IP協議的數據包(7)套接字。 請注意,與原始套接字不同,數據包套接字不會重新組合IP分片。

因此,您的上一個鏈接不相關,並且您使用正常的bind()調用是正確的。

如果您決定不使用libpcap我建議您首先打印出sll.sll_ifindex的值。 我認為它是零(所有接口)。 你還沒有向我們展示get_iface_index的來源,但我懷疑這個bug可能就在那里。

您應該嘗試的另一件事是比較代碼中的strace(1)輸出和基於libpcap的標准tcpdump(8)的輸出,盡管后者可能使用Linux PACKET_RX_RING擴展。

這就是我自己的嗅探器在strace(1)下運行的方式。 好像我的代碼與你的代碼完全相同。

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

注意strace(1)輸出中的“pkttype”( sll.sll_pkttype )字段。 你不妨檢查一下

環境

$ 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

你的代碼的一個小問題:你應該從第一個位置將saddr_size定義為socklen_t變量,而不是訴諸指針類型轉換,這可能是危險的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM