yonigo
yonigo

Reputation: 1087

How to read packet by packet from linux tun/tap

I have connected to an existing Tap device using

fd = open(...)

Now i want to read from it packet by packet. if i use

read(fd,buffer,sizeof(buffer));

I wont read exactly 1 packet.

How can i read exactly 1 packet? Is there some kind of header that says the packet length or in the worst case i will have to parse the packet and figure the length myself?

Upvotes: 7

Views: 6515

Answers (3)

pylover
pylover

Reputation: 8055

This is how I parse packets from a raw layer3 network stream.

#include "bigendian.h"

#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>


int pb_packet_read(PacketBuffer *b, int fd, int count, PacketCallback cb) {
    int i = 0;
    int result;
    Packet *p;
    unsigned char *start;
    size_t remaining;

    while (i < count) {
        if (b->packet == NULL) {
            if (b->level < 20 ) {
                // Read up to MTU bytes to determine packet header.
                result = read(fd, b->blob + b->level, MTU - b->level);
                if (result <= 0) {
                    return i;
                }
                b->level += result;
            }

            if (b->level < 20 ) {
                return i;
            }

            // Now, can read the packet total length
            start = b->blob;
            p = (Packet*) malloc(sizeof(Packet));
            p->start = start;
            p->version = start[0] >> 4;
            p->total_length = bigendian_deserialize_uint16(start + 2);
            memcpy(&(p->src.s_addr), start + 12, 4);
            memcpy(&(p->dst.s_addr), start + 16, 4);

            b->packet = p;


        }
        else {
            L_DEBUG("Using prev stored complete packet.");
            p = b->packet;
        }

        // Read the rest of the packet
        if (p->total_length > b->level) {
            remaining = p->total_length - b->level;
            L_DEBUG("Packet not completed, trying read more.");
            result = read(fd, b->blob + b->level, remaining);

            if(result <= 0) {
                if (result == EAGAIN) {
                    L_DEBUG("EAGAIN");
                }
                perror("READ BODY");
                return i;
            }
            b->level += result;
            if (result < remaining) {
                L_DEBUG("Not enough data");
                return i;
            }
        }

        if (b->level > p->total_length) {
            remaining = b->level - p->total_length;
            memcpy(b->blob, b->blob + p->total_length, remaining);
            b->level = remaining;
            L_DEBUG("Remaining data: %lu", remaining);
        }

        // Packet is ready to pass to callback.
        if(cb) {
            cb(p);
        }

        // Cleanup for the next packet
        i++;
        b->level = 0;
        free(b->packet);
        b->packet = NULL;
    }
    return i;
}

Upvotes: 2

yonigo
yonigo

Reputation: 1087

I was wrong about the way read() reads bytes from a tap device. It turns out when I use read() it reads exactly 1 frame, (or n bytes if n is smaller then frame size)

Upvotes: 5

dostrander
dostrander

Reputation: 747

Libpcap: http://www.tcpdump.org/pcap3_man.html

You can read packets coming in through whatever interface you specify, in this example its wlan1.

int main(){
    char *device = NULL;
    pcap_t* descr;

     if(argc > 0)
       device = "wlan1";

    if(device == NULL)
    {
      printf("%s\n",errbuf);
      exit(1);
    }
    descr = pcap_open_live(device,BUFSIZ,0,-1,errbuf);

    if(descr == NULL){ printf("pcap_open_live(): %s\n",errbuf); exit(1); }

    errbuf[0] = 0;
    handle = pcap_open_live(device, BUFSIZ,1,0,errbuf);

    pcap_loop(handle,-1, process_packet, NULL);
    pcap_close(handle);
    return 0;
  }

Where in pcap_loop the process_packet is the callback of the packets coming in.

Let me know if there is anything you are unsure of.


P.S. Here is some links that should help you with parsing 802.11/ethernet headers.

http://madwifi-project.org/wiki/DevDocs/RadiotapHeader http://yuba.stanford.edu/~casado/pcap/section2.html http://www.cacetech.com/documents/PPI%20Header%20format%201.0.7.pdf

Upvotes: 0

Related Questions