简体   繁体   English

如何从linux tun / tap中读取数据包

[英]How to read packet by packet from linux tun/tap

I have connected to an existing Tap device using 我已经连接到现有的Tap设备

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. 我不会读完1包。

How can i read exactly 1 packet? 我怎样才能准确读取1个数据包? 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? 是否有某种标题表示数据包长度,或者在最坏的情况下,我将不得不解析数据包并自己计算长度?

I was wrong about the way read() reads bytes from a tap device. 我对read()从tap设备读取字节的方式错了。 It turns out when I use read() it reads exactly 1 frame, (or n bytes if n is smaller then frame size) 事实证明,当我使用read()它恰好读取1帧,(如果n小于帧大小,则为n个字节)

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

You can read packets coming in through whatever interface you specify, in this example its wlan1. 您可以通过您指定的任何接口读取进入的数据包,在此示例中为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. pcap_loop ,process_packet是进来的数据包的回调。

Let me know if there is anything you are unsure of. 如果您有任何不确定之处,请告诉我。


PS Here is some links that should help you with parsing 802.11/ethernet headers. PS这里有一些链接可以帮助您解析802.11 /以太网标头。

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 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

This is how I parse packets from a raw layer3 network stream. 这就是我从原始layer3网络流解析数据包的方法。

#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM