Packet Sniffing Using Raw Sockets in Linux in C

Packet Sniffing using Raw Sockets in Linux in C

You should be using ETH_P_ALL instead of ETH_P_IP as the protocol. ETH_P_IP only listens for incoming IP packets.

how to sniff all ICMP packets using RAW sockets

You are trying to print raw packet data (including headers) as a string. In this case, E which is ascii 0x45 is the first byte of the IP header. The upper 4 bits mean "IPv4" and the lower 4 bits is the IHL (number of 32-bit words in the IP header) which is 5*4 = 20 bytes.

To properly access this data you should use the IP/ICMP header structs provided by linux. I've updated your code a little to illustrate:

# include <unistd.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <string.h>
# include <netinet/in.h>
# include <stdio.h>
# include<stdlib.h>

#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

main(){
int sockfd,retval,n;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
char buf[10000];
int i;

sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0){
perror("sock:");
exit(1);
}
clilen = sizeof(struct sockaddr_in);
while(1){
printf(" before recvfrom\n");
n=recvfrom(sockfd,buf,10000,0,(struct sockaddr *)&cliaddr,&clilen);
printf(" rec'd %d bytes\n",n);

struct iphdr *ip_hdr = (struct iphdr *)buf;

printf("IP header is %d bytes.\n", ip_hdr->ihl*4);

for (i = 0; i < n; i++) {
printf("%02X%s", (uint8_t)buf[i], (i + 1)%16 ? " " : "\n");
}
printf("\n");

struct icmphdr *icmp_hdr = (struct icmphdr *)((char *)ip_hdr + (4 * ip_hdr->ihl));

printf("ICMP msgtype=%d, code=%d", icmp_hdr->type, icmp_hdr->code);
}
}

Now, if I run that and ping 127.0.0.1: you see output like this:

 before recvfrom
rec'd 84 bytes
IP header is 20 bytes.
45 00 00 54 00 00 40 00 40 01 3C A7 7F 00 00 01
7F 00 00 01 08 00 A9 DF 11 66 00 01 9A 77 1A 51
00 00 00 00 BA 1D 0F 00 00 00 00 00 10 11 12 13
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23
24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33
34 35 36 37
ICMP msgtype=8, code=0 before recvfrom
rec'd 84 bytes
IP header is 20 bytes.
45 00 00 54 8D F3 00 00 40 01 EE B3 7F 00 00 01
7F 00 00 01 00 00 B1 DF 11 66 00 01 9A 77 1A 51
00 00 00 00 BA 1D 0F 00 00 00 00 00 10 11 12 13
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23
24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33
34 35 36 37
ICMP msgtype=0, code=0 before recvfrom

Here this shows a msgtype 8 (echo request) and msgtype 0 (echo reply). Beware that when accessing data this way from an array you can run into alignment problems (x86/x64 are happy to handle it for you, but other architectures may not be so generous). I'll leave that as an exercise to the reader ;).

Is it possible to inject on a raw socket while sniffing in promiscous mode?

The short answer is yes. Below is the longer one...

I know that for normal promiscous mode operation of a wireless card, your not suppose to be able to interact with the network

I am not sure where you have got this knowledge from but the above statement is wrong. A promiscuous mode does not restrict what you can do and how you can interact with the network. By default, network interface cards are simply trying to reduce the amount of data they pass to the host for better efficiency. For example, NICs would not pass an Ethernet frame to the host if its destination MAC address does not match the address of the receiving media access controller. The only thing that promiscuous mode does is simply tells the device to pass everything it gets to the host, be that frame addressed for the host or not. In other words, whatever you were able to do with NIC in a normal operation mode, you can still do when it is in promiscuous mode. Plus, NIC does not filter anything for you anymore, so you can receive more (as long as the host can handle the load).

but is it possible to do it with raw sockets?

Yes, it is possible. As long as you have enough privileges, you can send and receive Ethernet frames from user-space using "raw" sockets API. Whether a devices is in promiscuous mode or not does not make any difference.

Also note that these days routers are very smart and they won't forward packets to your host even if you put your host's NIC into promiscuous mode. So in the right network your are not likely to receive anything that in fact is not intended for your host, and promiscuous mode won't make any difference.

If that helps, here is a simple example of exchanging custom packets with an FPGA board connected to the PC over Ethernet. It uses raw socket API and runs in user-space on Linux.

capturing both incoming and outgoing packets using raw socket

I have found this while searching over your problem. I haven't tried this. May be this will work.

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

Retransmitting large packets with raw sockets

Your network card probably has segmentation offload enabled, which means the hardware can re-assemble TCP segments before they reach the OS or your code.

You can check whether that is the case by running ethtool -k.
While transparently capturing TCP traffic and re-transmitting it at such a low level is often more trouble than it is worth(one are often better off doing this at the application layer, terminate the TCP connection and set up a new TCP connection towards your host B), you cannot capture and re-send packets if your network card has messed with the packets. You need to:

  • Turn off generic-segmentation-offload
  • Turn off generic-receive-offload
  • Turn off tcp-segmentation-offload
  • Turn off udp-fragmentation-offload if you are also dealing with UDP
  • Turn off rx-vlan-offload/tx-vlan-offload if your packets are VLAN encapsulated
  • Possibly turn off rx-checksumming and tx-checksumming. It either works if both
    are enabled, or it's broken wrt. RAW sockets if enabled, depending on your
    kernel version and type of network card.

These can be turned on/off with the ethtool -K command, the exact syntax is described in the ethtool manpage.



Related Topics



Leave a reply



Submit