Back to Home

skbuffer - Linux network buffers ( by Paolo Ardoino < paolo.ardoino@gmail.com > )
skbuff are buffers used by Linux network layers ; its structure is defined in <linux/skbuff.h> .
skbuffs are linked lists as we can easily see :

        /* These two members must be first . */
        struct sk_buff          *next; // Next buffer in list
        struct sk_buff          *prev; // Previous buffer in list


Follows the description of all fields of the structure taken from the header file:

/**     
 *      struct sk_buff - socket buffer
 *      @next: Next buffer in list
 *      @prev: Previous buffer in list
 *      @list: List we are on
 *      @sk: Socket we are owned by
 *      @tstamp: Time we arrived
 *      @dev: Device we arrived on/are leaving by
 *      @input_dev: Device we arrived on
 *      @h: Transport layer header
 *      @nh: Network layer header
 *      @mac: Link layer header 
 *      @dst: destination entry 
 *      @sp: the security path, used for xfrm
 *      @cb: Control buffer. Free for use by every layer. Put private vars here
 *      @len: Length of actual data
 *      @data_len: Data length
 *      @mac_len: Length of link layer header
 *      @csum: Checksum
 *      @local_df: allow local fragmentation
 *      @cloned: Head may be cloned (check refcnt to be sure)
 *      @nohdr: Payload reference only, must not modify header
 *      @pkt_type: Packet class 
 *      @ip_summed: Driver fed us an IP checksum
 *      @priority: Packet queueing priority
 *      @users: User count - see {datagram,tcp}.c
 *      @protocol: Packet protocol from driver
 *      @truesize: Buffer size 
 *      @head: Head of buffer
 *      @data: Data head pointer
 *      @tail: Tail pointer     
 *      @end: End pointer
 *      @destructor: Destruct function
 *      @nfmark: Can be used for communication between hooks
 *      @nfct: Associated connection, if any
 *      @nfctinfo: Relationship of this skb to the connection
 *      @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
 *      @tc_index: Traffic control index
 *      @tc_verd: traffic control verdict
 */ 


Now let's take a look to the functions we need to work with network buffers:
allow_skb() creates and initializes a new ,ready to use , sk_buff .
kfree_skb() releases the buffer .
skb_clone() makes a copy of a skb_buff .
skb_queue_head() add a buffer on the head of the list .
skb_queue_tail() add a buffer on the tail of the list .
skb_unlink() removes a skb_buff from lists , but not releases it .
skb_dequeue() takes the first ( header ) skb_buff . 

Here is a simple kernel module that uses Linux network buffers to show incoming and 
outgoing packets .


/*****************************************************************************/
/* SKB ( Linux Network Buffers ) test on Linux 2.6.x kernels
 * This module will show show all incoming packets
 * and outgoing packets from the local computer
 * To get it working edit #define MYADDR setting
 * the ip of your computer . This is only an example to
 * show how create kernel sniffers or hijacker modules .
 */


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/byteorder/generic.h>

#include <linux/netdevice.h>
#include <linux/skbuff.h>

#include <linux/ip.h>
#include <linux/tcp.h>

#define DEBUG 1

// ip address of the local computer
#define MYADDR "192.168.0.3"

MODULE_AUTHOR("Paolo Ardoino");
MODULE_LICENSE("GPL");
#define MODNAME "SKBTEST"

unsigned long fromaddr;
unsigned short int fromport;
struct packet_type myskb;

// my_addr convert an ip address string from standard dot notation
// to an unsigned long
static unsigned long my_addr(char *ip)
{
  unsigned long tmp;
  unsigned int val;
  int ctr;

  tmp = 0;
  for (ctr = 0; ctr < 4; ctr++) {
    tmp <<= 8;
    if(*ip != '\0') {
      val = 0;
      while (*ip != '\0' && *ip != '.') {
        val *= 10;
        val += *ip - '0';
        ip++;
      }
      tmp |= val;
      if (*ip != '\0') {
        ip++;
      }
    }
  }
  return htonl(tmp);
}

// my_ntoa convers an unsigned long ( Internet host address )
// given in network byte order to a string in standard dot notation
static char *my_ntoa(unsigned long addr)
{
  static char buff[18];
  char *p;
  
  p = (char *) &addr;
  sprintf(buff, "%d.%d.%d.%d", (*p & 255), (*(p + 1) & 255), (*(p + 2) & 255), (*(p + 3) & 255));
  return buff;
}                                                        

// my_pkt analyzes packets in skbuff
static int my_pkt(struct sk_buff *skb, struct device *d, struct packet_type *pt)
{
  if (skb->nh.iph->protocol == IPPROTO_TCP) {
// outgoing packets
    if (skb->nh.iph->saddr == fromaddr) {
#ifdef DEBUG
      printk("[%s] PACKET SENT FROM LOCALHOST:%d TO %s:%d HOST\n", MODNAME, ntohs(skb->h.th->source), my_ntoa(skb->nh.iph->daddr), ntohs(skb->h.th->dest));
#endif
    } else {
// incoming packets
      if (skb->nh.iph->daddr == fromaddr) {
#ifdef DEBUG
      printk("[%s] PACKET RECV FROM %s:%d HOST TO LOCALHOST:%d HOST\n", MODNAME, my_ntoa(skb->nh.iph->saddr), ntohs(skb->h.th->source), ntohs(skb->h.th->dest));
#endif
      }
    }
  }
  kfree_skb(skb);
  return 0;
}

static int __init modinit(void)
{
  printk("[%s] MODULE LOADED (by Paolo Ardoino < paolo.ardoino@gmail.com >) \n", MODNAME);
  
  fromaddr = my_addr(MYADDR);
  
  myskb.type = htons(ETH_P_ALL);
  myskb.func = my_pkt;
  myskb.dev = NULL;
  dev_add_pack(&myskb);
  
  return 0;
}


static void __exit modcleanup(void)
{
  printk("[%s] CLEANUP COMPLETE\n", MODNAME);
  dev_remove_pack(&myskb);
  return;
}

module_init(modinit);
module_exit(modcleanup);

/*****************************************************************************/