问题
I am writing a program with a Raw Socket in promiscuous mode and I need the raw socket not sniff the packet I send. I need to read only the data over the ethernet rx wire (not the tx wire). It's posible?
Thanks a lot.
回答1:
The solution is to look in the read packet if it is a PACKET_OUTGOING. Using this option you can diference the packet you put in the ethernet tx wire and the packet you read from the rx wire.
Open the Socket in promiscuous mode:
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;
//...
And read. Now, We can differentiate between the Rx and Tx ethernet wire:
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.
}
And it's all. Using it I don't read the data I write. I avoid the loop when I copy the network 1 frames to network 2 and the network 2 frames to network 1.
回答2:
You need to create the BPF
(BSD Packet Filter) filter that correspond to incoming packets :
/* 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;
And then your RAW socket, and bind and ... :
/* 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 */
}
EDIT : If you want to filter by Mac Address, it's simple, generate your filter like this (I use my Mac address here):
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 },
回答3:
You can easily filter for things that came from you IP address and just exclude them from your list.
回答4:
Sadly, Linux doesn't offer any options to specify not receiving outgoing packets for a raw socket.
If rebuilding the Linux kernel is allowed, I would suggest just patching the kernel with packet_socket_type.patch.
and at the user program, you specify what kind of packet you'd like to receive like this.
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, this is the solution that really solves the problem.
来源:https://stackoverflow.com/questions/12177708/raw-socket-promiscuous-mode-not-sniffing-what-i-write