5

我已使用连接到现有的 Tap 设备

fd = open(...)

现在我想逐包读取它。如果我使用

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

我不会准确读取 1 个数据包。

我怎样才能准确地读取 1 个数据包?是否有某种标头说明数据包长度,或者在最坏的情况下,我将不得不自己解析数据包并计算长度?

4

3 回答 3

4

read()从水龙头设备读取字节的方式是错误的。事实证明,当我使用read()它时,它恰好读取 1 帧,(如果 n 小于帧大小,则为 n 字节)

于 2013-09-06T08:34:53.510 回答
1

这就是我从原始 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;
}

于 2019-02-06T15:32:32.227 回答
0

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_loopprocess_packet 是传入数据包的回调。

如果您有任何不确定的地方,请告诉我。


PS 这里有一些链接可以帮助您解析 802.11/ethernet 标头。

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

于 2013-08-27T13:22:55.213 回答