views:

1331

answers:

4

Does anyone know how to read from a promiscuous (or sniffing) device in C? I know that you need to have root access to do it, but I was wondering if anyone knew what functions were necessary to do this (normal sockets wouldn't seem to make sense here)? I want to write a real-time analysis tool for wireless traffic.

A: 

Why wouldn't you use something like WireShark?

It is open source, so at least you could learn a few things from it if you don't want to just use it.

Geoffrey Chetwood
I'm not sure if WireShark can capture the full wireless packet. I think its configured for regular MAC not wireless MAC. I need to be able to look at traffic from multiple essids.
ajbl
Again, I would start by looking through the wireshark source code.
Geoffrey Chetwood
WireShark does not work with wireless cards on Windows (full stop).
leppie
+2  A: 

You could use the pcap library (see http://www.tcpdump.org/pcap.htm) which is also used by tcpdump and Wireshark.

oliver
+6  A: 

On Linux you use a PF_PACKET socket to read data from a raw device, such as an ethernet interface running in promiscuous mode:

s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))

This will send copies of every packet received up to your socket. It is quite likely that you don't really want every packet, though. The kernel can perform a first level of filtering using BPF, the Berkeley Packet Filter. BPF is essentially a stack-based virtual machine: it handles a small set of instructions such as:

    ldh = load halfword (from packet)
    jeq = jump if equal
    ret = return with exit code
BPF's exit code tells the kernel whether to copy the packet to the socket or not. It is possible to write relatively small BPF programs directly, using setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ...bpf program buffer...).

For anything reasonably complex, you really want to use libpcap. BPF is limited in what it can do, in particular in the number of instructions it can execute per packet. libpcap will take care of splitting a complex filter up into two pieces, with the kernel performing a first level of filtering and the more-capable user-space code dropping the packets it didn't actually want to receive.

libpcap also abstracts the kernel interface out of your application code. Linux and BSD use similar APIs, but Solaris requires DLPI and Windows uses something else.

DGentry
Thanks for the answer!
ajbl
+1  A: 

I once had to listen on raw ethernet frames and ended up creating a wrapper for this. By calling the function with the device name, ex eth0 i got a socket in return that was in promiscuous mode. What you need to do is to create a raw socket and then put it into promiscuous mode. Here is how i did it. int raw_init (char *device)

{

struct ifreq ifr;
int raw_socket;
int ifindex;

memset (&ifr, 0, sizeof (struct ifreq));
memset (&saddr, 0, sizeof (struct sockaddr_ll));

/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
  printf ("ERROR: Could not open socket, Got #?\n");
  exit (1);
}

/* Set the device to use */
strcpy (ifr.ifr_name, device);

/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
 perror ("Error: Could not retrive the flags from the device.\n");
 exit (1);
}

/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
  perror ("Error: Could not set flag IFF_PROMISC");
  exit (1);
}
printf ("Entering promiscuous mode\n");

/* Configure the device */

if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
   perror ("Error: Error getting the device index.\n");
   exit (1);
}
ifindex = ifr.ifr_ifindex;
saddr.sll_family = AF_PACKET;
saddr.sll_ifindex = ifindex;
saddr.sll_protocol = ETH_P_ALL; /* Now we will get ALL packets */

return raw_socket;

}

Then when you have your socket you can just use select to handle packets as they arrive.