簡體   English   中英

如何從linux tun / tap中讀取數據包

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

我已經連接到現有的Tap設備

fd = open(...)

現在我想逐包讀取它。 如果我使用

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

我不會讀完1包。

我怎樣才能准確讀取1個數據包? 是否有某種標題表示數據包長度,或者在最壞的情況下,我將不得不解析數據包並自己計算長度?

我對read()從tap設備讀取字節的方式錯了。 事實證明,當我使用read()它恰好讀取1幀,(如果n小於幀大小,則為n個字節)

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

您可以通過您指定的任何接口讀取進入的數據包,在此示例中為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;
  }

pcap_loop ,process_packet是進來的數據包的回調。

如果您有任何不確定之處,請告訴我。


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

這就是我從原始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