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.
If the Ethernet address display is not turned on and the NIC is in promiscuous mode, it will – incorrectly -- show that there are no problems on the network. This may lead to network outages. To prevent such issues, it's important to use non-promiscuous mode or turn on the Ethernet address display in tcpdump.
Answer: In a network, promiscuous mode allows a network device to intercept and read each network packet that arrives in its entirety. In an Ethernet local area network ( LAN), promiscuous mode is a mode of operation in which every data packet transmitted can be received and read by a network adapter.
Promiscuous mode is used to monitor(sniff) network traffic. Typically, promiscuous mode is used and implemented by a snoop program that captures all network traffic visible on all configured network adapters on a system.
A network card configuration that passes all traffic received to the network adapter driver and protocol stack. Network analyzers, protocol analyzers, and packet sniffers use promiscuous mode to investigate network traffic and detect potential vulnerabilities.
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.
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 },
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With