The Linux Socket Filter: Sniffing Bytes over the Network

A feature added to the kernel with the 2.2 release, this LSF can be programmed to let the kernel decide to which packets access should be granted. Here's how.
Promiscuous vs. Nonpromiscuous Mode

The PF_PACKET family allows an application to retrieve data packets as they are received at the network card level, but still does not allow it to read packets that are not addressed to its host. As we have seen before, this is due to the network card discarding all the packets that do not contain its own MAC address—an operation mode called nonpromiscuous, which basically means that each network card is minding its own business and reading only the frames directed to it. There are three exceptions to this rule: a frame whose destination MAC address is the special broadcast address (FF:FF:FF:FF:FF:FF) will be picked up by any card; a frame whose destination MAC address is a multicast address will be picked up by cards that have multicast reception enabled and a card that has been set in promiscuous mode will pick up all the packets it sees.

The last case is, of course, the most interesting one for our purposes. To set a network card to promiscuous mode, all we have to do is issue a particular ioctl() call to an open socket on that card. Since this is a potentially security-threatening operation, the call is only allowed for the root user. Supposing that “sock” contains an already open socket, the following instructions will do the trick:

strncpy(ethreq.ifr_name,"eth0",IFNAMSIZ);
ioctl(sock, SIOCGIFFLAGS, &ethreq);
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, &ethreq);

(where ethreq is an ifreq structure, defined in /usr/include/net/if.h). The first ioctl reads the current value of the Ethernet card flags; the flags are then ORed with IFF_PROMISC, which enables promiscuous mode and are written back to the card with the second ioctl.

Let's see it in a more complete example (see Listing 2 at ftp://ftp.linuxjournal.com/pub/lj/listings/issue86/). If you compile and run it as root on a machine connected to a LAN, you will be able to see all the packets flowing on the cable, even if they are not for your host. This is because your network card is now working in promiscuous mode. You can easily check it out by giving the ifconfig command and observing the third line in the output.

Note that if your LAN uses Ethernet switches instead of hubs, you will see only packets flowing in the switch's branch you belong to. This is due to the way switches work, and there is very little you can do about it (except for deceiving the switch with MAC address-spoofing, which is outside the scope of this article). For more information on hubs and switches, please have a look at the articles cited in the Resources section.

The Linux Packet Filter

All our sniffing problems seem to be solved right now, but there is still one important thing to consider: if you actually tried the example in Listing 2, and if your LAN serves even a modest amount of traffic (a couple of Windows hosts will be enough to waste some bandwidth with a good number of NETBIOS packets), you will have noticed our sniffer prints out too much data. As network traffic increases, the sniffer will start losing packets since the PC will not be able to process them quickly enough.

The solution to this problem is to filter the packets you receive, and print out information only on those you are interested in. One idea would be to insert an “if statement” in the sniffer's source; this would help polish the output of the sniffer, but it would not be very efficient in terms of performance. The kernel would still pull up all the packets flowing on the network, thus wasting processing time, and the sniffer would still examine each packet header to decide whether to print out the related data or not.

The optimal solution to this problem is to put the filter as early as possible in the packet-processing chain (it starts at the network driver level and ends at the application level, see Figure 3). The Linux kernel allows us to put a filter, called an LPF, directly inside the PF_PACKET protocol-processing routines, which are run shortly after the network card reception interrupt has been served. The filter decides which packets shall be relayed to the application and which ones should be discarded.

Figure 3. Packet-Processing Chain

In order to be as flexible as possible, and not to limit the programmer to a set of predefined conditions, the packet-filtering engine is actually implemented as a state machine running a user-defined program. The program is written in a specific pseudo-machine code language called BPF (for Berkeley packet filter), inspired by an old paper written by Steve McCanne and Van Jacobson (see Resources). BPF actually looks like a real assembly language with a couple of registers and a few instructions to load and store values, perform arithmetic operations and conditionally branch.

The filter code is run on each packet to be examined, and the memory space into which the BPF processor operates are the bytes containing the packet data. The result of the filter is an integer number that specifies how many bytes of the packet (if any) the socket should pass to the application level. This is a further advantage, since often you are interested in just the first few bytes of a packet, and you can spare processing time by avoiding copying the excess ones.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

only sniff or discard too

xandi's picture

hi,

nice article. i like the simplicity of it. However, I am wondering whether this technique can be used to create firewalls ? can i discard packets based on the criteria that I choose. Libpcap won't help because it creates a copy of the packet so the packet does reach where it is intended.

thanks

In both listing1 and

pepox's picture

In both listing1 and listing2 when i run them i only see "reply" packets, the "request" packets are ignored..

for example:

i run in a console:
zxc@zxc-l:~$ ping -c1 192.168.1.1

while in another was running:
zxc@zxc-l:~$ sudo ./listing2 (or listing1 it's the same output)
----------
98 bytes read
Source MAC address: 00:af:bc:xx:xx:xx
Destination MAC address: 00:1a:2b:xx:xx:xx
Source host 192.168.1.1
Dest host 192.168.1.213
Source,Dest ports 0,10327
Layer-4 protocol 1
----------

However if i do the same with tcpdump, i get this:
zxc@zxc-l:~$ sudo tcpdump -i eth1 -ntUl
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
IP 192.168.1.213 > 192.168.1.1: ICMP echo request, id 44322, seq 1, length 64
IP 192.168.1.1 > 192.168.1.213: ICMP echo reply, id 44322, seq 1, length 64

In one word, with your examples i can only see reply packets, in fact always my output is:
Dest host 192.168.1.213 (my computers ip).

So my question is, if there is a way to "sniff" both reply packets and also request packets over the network...

Hoping to receive answer...

Thank you very much....

Question...

Abelardo Rodríguez-Trilla's picture

Hi Gianluca

Excelent article!. I'm writting from Venezuela, and I wanted to know how do I sniff packets without using the PF_PACKET family. I ask you this because I need to do that without root permissions. Thanks

Great work !

John Kallmer's picture

Really great tutorial !

I also found video tutorials on sniffing at www.security-freak.net . started by a Vivek Ramachandran, they are quite elaborate in coverage and literally spoon feed topics like sniffing, packet injection etc.

Might help ...take a look !

Some changed in list of include files

andyS1976's picture

Without changes for last C programm compillator gives
warning: implicit declaration of function ‘htons’

If this code changed for C++ programm
(replace exit(X) on return X ) the compiller giver error:
‘htons’ was not declared in this scope

So to improve code include files list might be as follow:
#include
#include
#include
#include
// add this header
#include
#include
#include
#include
// changed #include on
#include
#include
#include
#include
#include

Andy

some problem with formating

andyS1976's picture


#include < stdio.h >
#include < string.h >
#include < errno.h >
#include < unistd.h >
// add this header
#include < asm/types.h >
#include < sys/socket.h >
#include < sys/types.h >
#include < netinet/in.h >
// changed #include < linux/in.h > on
#include < netinet/in.h >
#include < linux/if_ether.h >
#include < net/if.h >
#include < linux/filter.h >
#include < sys/ioctl.h >

Setting promiscuous mode

Anonymous's picture

Great article!
I'd just like to point out that you should not use ioctl() for setting the promiscuous mode. If you do, you're responsible for disabling the promiscuous mode after you're done. Unfortunately, you have no way of knowing if another socket also requested the promiscuous mode while your code was running. Thus, resetting the Ethernet flags to the original value could mess things up.

Instead, you should use setsockopt() with SOL_PACKET, PACKET_ADD_MEMBERSHIP and have PACKET_MR_PROMISC as the argument. This way the kernel will track the promiscuous mode usage and turn it off automatically.

Thanks for the simple way of explanation

Rajesh George's picture

Your article made concept so simple. Thanks

thanx

Jagannath's picture

hi,

your document "sniffing bytes over network" is very nice, you have written very clearly so, that we can uderstand. i am a student of master in networking, doing project on filters.

thanking you for your good, nice,and easy to understand document

Regards,
Juxs

Hi Dude....Thu purush naji

Anonymous's picture

Hi Dude....

Thu purush nahi ho.... Maha purush ho..... Sniff sniff sniff and do the right thing for vx180.... Good luck

Re: Kernel Korner: The Linux Socket Filter: Sniffing Bytes over

Anonymous's picture

thanks much for this informative article on a poorly documented subject. this tied together a lot of the bits and pieces i've been sifting through. i'd advise anyone seeking to learn more about creating your own filters to keep this article + source in one hand and the Van Jacobsen/McCanne paper in the other. - britney_spears@hotpop.com

Sniffing Bytes over the Serial port

bahrian's picture

ACtually i m bit new with the socket programming stuff..Actually wat i want to read the bytes from the socket using read () subroutine (I am using Fedora Envionment)but when i exc the program; it stops at the same position where i defined the read sub routine and does not giving me anything..could u plz comment on this..thx in advance.

Thanx a lot for your

Pradeep Reddy's picture

Thanx a lot for your informative article.

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix