2012-08-29 158 views
5

我正在用混合模式下的原始套接字编写程序,我需要原始套接字不嗅探我发送的数据包。我只需要通过以太网rx线(而不是tx线)读取数据。这可能吗?原始套接字混杂模式不嗅探我写什么

非常感谢。

+1

你在使用什么操作系统? – Eloff

+0

我正在使用linux。 –

+0

你是否在同一台机器上发送和嗅探?这是一个问题。你需要2台机器。 – Matt

回答

6

解决方法是查看读取的数据包,如果它是PACKET_OUTGOING。使用此选项,您可以区分放入以太网tx线的数据包和从rx线读取的数据包。

打开混杂模式的Socket:

char* i = "eth0"; 
int fd; 
struct ifreq ifr; 
struct sockaddr_ll interfaceAddr; 
struct packet_mreq mreq; 

if ((fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) < 0) 
    return -1; 

memset(&interfaceAddr,0,sizeof(interfaceAddr)); 
memset(&ifr,0,sizeof(ifr)); 
memset(&mreq,0,sizeof(mreq)); 

memcpy(&ifr.ifr_name,i,IFNAMSIZ); 
ioctl(fd,SIOCGIFINDEX,&ifr); 

interfaceAddr.sll_ifindex = ifr.ifr_ifindex; 
interfaceAddr.sll_family = AF_PACKET; 

if (bind(fd, (struct sockaddr *)&interfaceAddr,sizeof(interfaceAddr)) < 0) 
    return -2; 


mreq.mr_ifindex = ifr.ifr_ifindex; 
mreq.mr_type = PACKET_MR_PROMISC; 
mreq.mr_alen = 6; 

if (setsockopt(fd,SOL_PACKET,PACKET_ADD_MEMBERSHIP, 
    (void*)&mreq,(socklen_t)sizeof(mreq)) < 0) 
     return -3; 
//... 

和阅读。现在,我们可以区分Rx和Tx以太网线:

unsigned char buf[1500]; 
struct sockaddr_ll addr; 
socklen_t addr_len = sizeof(addr); 
n = recvfrom(fd, buf, 2000, 0, (struct sockaddr*)&addr, &addr_len); 
if (n <= 0) 
{ 
    //Error reading 
} 
else if (addr.sll_pkttype == PACKET_OUTGOING) 
{ 
    //The read data are not writing by me. 
    //Use only this data to copy in the other network. 
} 

就这些了。使用它我不会读取我写的数据。当我将网络1帧复制到网络2并将网络2帧复制到网络1时,我避免了循环。

0

您可以轻松筛选来自您的IP地址的内容,并将它们从您的列表中排除。

+0

我们有两个网络和一台带有两个以太网设备(eth0和eth1)的PC。第一个连接到第一个网络,第二个连接到第二个网络。我们喜欢在2级建立软件桥;在混杂模式下使用原始套接字,我们读取网络1的所有流量并将其复制到网络2中,反之亦然。所有它完成无限循环,因为我们复制到网络1的帧复制到网络2并复制到网络1 ...我们不需要嗅探我们写入的帧,并且这些帧在第2层(带有mac)和来自任何机器都是完整的联系。 –

+0

难道你不能简单地在MAC层做你的过滤吗?查看MAC地址并跳过您发送的那些MAC地址并不难。我错过了什么? – kmort

+0

该软件用于通过无线链接在网络和网络之间建立桥梁。我在网络1中读取的数据包通过无线电链接发送到其他计算机(UDP连接中的数据包),解包并写入网络2(反之亦然)。因此,我不能使用linux桥接功能:-(我相信... ... –

3

你需要创建一个对应于传入数据包的BPF(BSD分组过滤器)过滤器:

/* To obtain the BPF filter corresponding to incoming traffic: 
* sudo tcpdump -dd -i eth0 dst host YOUR_IP_ADDRESS and not src host YOUR_IP_ADDRESS 
* The filter given below is what i get on my local machine (192.168.1.7): 
* sudo tcpdump -dd -i eth0 dst host 192.168.1.7 and not src host 192.168.1.7 
*/ 
struct sock_filter incoming_filter[] = {  
    { 0x28, 0, 0, 0x0000000c }, 
    { 0x15, 0, 4, 0x00000800 }, 
    { 0x20, 0, 0, 0x0000001e }, 
    { 0x15, 0, 9, 0xc0a80107 }, 
    { 0x20, 0, 0, 0x0000001a }, 
    { 0x15, 7, 6, 0xc0a80107 }, 
    { 0x15, 1, 0, 0x00000806 }, 
    { 0x15, 0, 5, 0x00008035 }, 
    { 0x20, 0, 0, 0x00000026 }, 
    { 0x15, 0, 3, 0xc0a80107 }, 
    { 0x20, 0, 0, 0x0000001c }, 
    { 0x15, 1, 0, 0xc0a80107 }, 
    { 0x6, 0, 0, 0x0000ffff }, 
    { 0x6, 0, 0, 0x00000000 }, 
}; 

int s; 
struct sockaddr_ll sock_address; 
struct sock_fprog prog; 

/* Init the program filter */ 
prog.len = 14; 
prog.filter = incoming_filter; 

然后你的原始套接字,并绑定与...:

/* Create the raw socket */ 
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 
if (s < 0) 
{ 
    /* Error handling */ 
} 

/* Build our socket */ 
sock_address.sll_family = AF_PACKET; 
sock_address.sll_protocol = htons(ETH_P_IP); 
sock_address.sll_ifindex = if_nametoindex(your_interface_name); 

/* Bind */ 
if (bind(s, (struct sockaddr*)&sock_address, sizeof(sock_address)) < 0) 
{ 
    /* Error handling */ 
} 

/* Apply the filter */ 
if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) 
{ 
    /* Error handling */ 
} 

/* Infinite listen loop */ 
while (1) 
{ 

    /* Handle received packet */ 
} 

编辑:如果你想过滤MAC地址,很简单,像这样生成你的过滤器(我在这里使用我的Mac地址):

sudo tcpdump -dd -i eth0 ether dst 00:0f:b0:68:0f:92 and not ether src 00:0f:b0:68:0f:92 
{ 0x20, 0, 0, 0x00000002 }, 
{ 0x15, 0, 7, 0xb0680f92 }, 
{ 0x28, 0, 0, 0x00000000 }, 
{ 0x15, 0, 5, 0x0000000f }, 
{ 0x20, 0, 0, 0x00000008 }, 
{ 0x15, 0, 2, 0xb0680f92 }, 
{ 0x28, 0, 0, 0x00000006 }, 
{ 0x15, 1, 0, 0x0000000f }, 
{ 0x6, 0, 0, 0x0000ffff }, 
{ 0x6, 0, 0, 0x00000000 }, 
+0

我们正在使用MAC地址在第2层工作,我们没有IP地址。 –

+0

@JoséMaríaB:好吧,这不会改变任何事情!只需按照您的主机Mac地址进行过滤,看看我的编辑 – TOC

+0

非常感谢。在这种情况下使用PACKET_OUTGOING解决方案更为容易(Merci beaucoup。Je pense que c'est plus facileàutiliser la solution PACKET_OUTGOING pour ce cas :-)) –

0

不幸的是,Linux不提供任何选项来指定未接收原始套接字的传出数据包。

如果允许重建Linux内核,我建议只用packet_socket_type.patch修补内核。

并且在用户程序中,您可以指定想要接收哪种类型的数据包。

int mask=0; 
mask = PACKET_MASK_ANY & ~(1<<PACKET_OUTGOING) & ~(1 << PACKET_LOOPBACK); 
setsockopt(raw_sock, SOL_PACKET, PACKET_RECV_TYPE, &mask, sizeof(mask)); 

IMO,这是真正解决问题的解决方案。