使用 TPACKET_V2 时,Vlan id 设置为 0

2023-12-07

我对这个 TPACKET_V2 的使用有疑问。

我的问题是,在套接字上设置这种类型的数据包后,当我尝试接收一些数据包时,我无法从数据包中读取 vlan id(当然是从数据包的标头),vlan_tci 始终为 0。

现在我正在使用 open suse sp1,当我在 sless sp2 上运行我的程序时,我能够使用无法在 sless sp2 上运行的相同程序获取 vlan idsless sp1但奇怪的是tcpdump能够获取vlan id(在这个sless上)并且tcpdump设置TPACKET_V2(所以这意味着TPACKET_2受支持)

我的简单项目就是基于这些函数,全部由函数调用创建Socket,然后有一个简单的方法,读取套接字上的数据包,然后我尝试获取有关 vlan id 的信息(还有之前与 TPACKET_V1 使用的相关部分)

#include <linux/if_packet.h>
#include <linux/if_ether.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ether.h>

#include <linux/filter.h>
#include <net/if.h>
#include <arpa/inet.h>

    enum INTERFACE_T
    {
        RX_INTERFACE,
        TX_INTERFACE
    };

    static const char* PKT_TYPE[];

    // BLOCK_NUM*BLOCK_SIZE = FRAME_NUM*FRAME_SIZE
    enum { RX_BLOCK_SIZE = 8192,
        RX_BLOCK_NUM  = 256,
        RX_FRAME_SIZE = 2048,
        RX_FRAME_NUM  = 1024
    };

    enum { TX_BLOCK_SIZE = 8192,
        TX_BLOCK_NUM  = 256,
        TX_FRAME_SIZE = 2048,
        TX_FRAME_NUM  = 1024
    };

    struct RxFrame {
        struct tpacket2_hdr tp_h;  // Packet header
        uint8_t tp_pad[TPACKET_ALIGN(sizeof(tpacket2_hdr))-sizeof(tpacket2_hdr)];
        struct sockaddr_ll sa_ll; // Link level address information
        uint8_t sa_ll_pad[14];    //Alignment padding
        struct ethhdr eth_h;
    } __attribute__((packed));

    struct TxFrame
    {
        struct tpacket_hdr tp_h; // Packet header
        uint8_t tp_pad[TPACKET_ALIGN(sizeof(tpacket_hdr))-sizeof(tpacket_hdr)];
//      struct vlan_ethhdr vlan_eth_h;
//      struct arp arp;
    } __attribute__((packed));


    struct ring_buff {
        struct tpacket_req req;
        size_t  size;  // mmap size
        size_t  cur_frame;
        struct iovec *ring_buffer_;
        void *buffer;  // mmap
    };



int setIfFlags(short int flags)
{
    struct ifreq    ifr;

    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, if_name_.c_str(), sizeof(ifr.ifr_name));

    ifr.ifr_hwaddr.sa_family=getIfArptype();

    ifr.ifr_flags |= flags;
    if ( ioctl(socket_, SIOCSIFFLAGS, &ifr) == -1)
    {
        std::cout << "Error: ioctl(SIOSIFFLAGS) failed!" << std::endl;
        return 1;
    }
    return 0;
}


int bindSocket()
{
    struct sockaddr_ll sll;

    memset(&sll, 0, sizeof(sll));

    sll.sll_family   = AF_PACKET;
    sll.sll_protocol = htons(ETH_P_ALL);
    sll.sll_ifindex  = ifIndex_;
    sll.sll_hatype   = 0;
    sll.sll_pkttype  = 0;
    sll.sll_halen    = 0;

    if (bind(socket_, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
        std::cout << "Error: bind() failed!" << std::endl;
        return 1;
    }
    return 0;
}


int packetMmap(ring_buff * rb)
{
    assert(rb);

    rb->buffer = mmap(0, rb->size, PROT_READ | PROT_WRITE, MAP_SHARED, socket_, 0);
    if (rb->buffer == MAP_FAILED) {
        std::cout << "Error: mmap() failed!" << std::endl;
        return 1; 
    }
    return 0;
}



void packetMunmap(ring_buff * rb)
{
    assert(rb);

    if (rb->buffer)
    {
        munmap(rb->buffer, rb->size);
        rb->buffer = NULL;
        rb->size = 0;
    }
}



int frameBufferCreate(ring_buff * rb)
{
    assert(rb);

    rb->ring_buffer_ =  (struct iovec*) malloc(rb->req.tp_frame_nr * sizeof(*rb->ring_buffer_));
    if (!rb->ring_buffer_) {
        std::cout << "No memory available !!!" << std::endl;
        return 1;
    }

    memset(rb->ring_buffer_, 0, rb->req.tp_frame_nr * sizeof(*rb->ring_buffer_));

    for (unsigned int i = 0; i < rb->req.tp_frame_nr; i++) {
        rb->ring_buffer_[i].iov_base = static_cast<void *>(static_cast<char *>(rb->buffer)+(i*rb->req.tp_frame_size));
        rb->ring_buffer_[i].iov_len = rb->req.tp_frame_size;
    }

    return 0;
}


void setRingBuffer(struct ring_buff *ringbuf) { rb_ = ringbuf; }


int setVlanTaggingStripping()
{
    socklen_t len;
    int val;
    unsigned int sk_type, tp_reserve, maclen, tp_hdrlen, netoff, macoff;
        unsigned int tp_hdr_len;
    unsigned int frame_size = RX_FRAME_SIZE;


    val = TPACKET_V2;
    len = sizeof(val);
    if (getsockopt(socket_, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) {
        std::cout << "Error: getsockopt(SOL_PACKET, PACKET_HDRLEN) failed (can't get TPACKET_V2 header len on packet)" << std::endl;
                return 1;

    }
        tp_hdr_len = val;
    std::cout << "TPACKET_V2 header is supported (hdr len is " << val << ")"<< std::endl;
    std::cout << "tpacket2_hdrs header is supported (hdr len is " << sizeof(tpacket2_hdr) << ")"<< std::endl;

    val = TPACKET_V2;
    if (setsockopt(socket_, SOL_PACKET, PACKET_VERSION, &val, sizeof(val)) < 0) {
        std::cout << "Error: setsockopt(SOL_PACKET, PACKET_VERSION) failed (can't activate TPACKET_V2 on packet)" << std::endl;
        return 1;
    }
    std::cout << "TPACKET_V2 version is configured !!! " << std::endl;

    /* Reserve space for VLAN tag reconstruction */
    val = VLAN_TAG_LEN;
    if (setsockopt(socket_, SOL_PACKET, PACKET_RESERVE, &val, sizeof(val)) < 0) {
        std::cout << "Error: setsockopt(SOL_PACKET, PACKET_RESERVE) failed (can't set up reserve on packet)" << std::endl;
        return 1;
    }
    std::cout<< "Reserve space for VLAN tag reconstruction is configured !!! " << std::endl;

    return 0;
}


int setSoBufforce(int optname, int buffSize)
{
    if (setsockopt(socket_, SOL_SOCKET, SO_SNDBUFFORCE, &buffSize, sizeof(buffSize)) == -1)
    {
        std::cout << "Error: setsocketopt("<< (optname == SO_SNDBUFFORCE ? "SO_SNDBUFFORCE" : "SO_RCVBUFFORCE") << ") failed!" << std::endl;
        return 1;
    }
    return 0;
}

 createSocket(std::string ifName, INTERFACE_T ifType)
{
    if (ifName.empty())
    {
        std::cout << "Error: interface is empty!" << std::endl;;
        return NULL;
    }

    //Create the socket
    if ( (socket_ = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1 )
    {
        std::cout << "Error: calling socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) failed!" << std::endl;
    }

    std::cout << "Creating Socket on interface= " << ifName << " to listen to ETH_P_ALL"<<std::endl;;


    s->setIfFlags(IFF_PROMISC|IFF_BROADCAST);

    //allocate space for ring buffer
    ring_buff *rb = (ring_buff *) malloc(sizeof(ring_buff));

    //  use the same size for RX/TX ring

    //set the version , here I insert the use of TPACKET_V2!
    setVlanTaggingStripping();

    rb->req.tp_block_size = RX_BLOCK_SIZE;
    rb->req.tp_block_nr   = RX_BLOCK_NUM;
    rb->req.tp_frame_size = RX_FRAME_SIZE;
    rb->req.tp_frame_nr   = RX_FRAME_NUM;

    setPacketRing(PACKET_RX_RING,&rb->req);

    rb->size = (rb->req.tp_block_size)*(rb->req.tp_block_nr);
    rb->cur_frame = 0;

    // Tweak send/rcv buffer size
    int sndBufSz = 4194304; // Send buffer in bytes
    int rcvBufSz = 4194304; // Receive buffer in bytes

    if (setSoBufforce(SO_SNDBUFFORCE, sndBufSz))
    {
      //close socket
    }

    if (setSoBufforce(SO_RCVBUFFORCE, rcvBufSz))
    {
        //close socket
    }

    // Add ARP filter so we will only receive ARP packet on this socket
    struct sock_filter BPF_code[6];
    struct sock_fprog filter;

    bindSocket();

    if (packetMmap(rb))
    {
        std::cout << "Error: mmap() failed!" << std::endl;
        //close socket
    }

    frameBufferCreate(rb);
    setRingBuffer(rb);
}

在我的接收数据包函数中,我尝试读取信息,特别是 h_vlan_TCI,但我收到过 0x00 !有什么建议么?

struct vlan_ethhdr* vlan_eth_h = (struct vlan_ethhdr*)&frame->eth_h


void readRawSocket(socket_)
{

    while (*(unsigned long*)rb->ring_buffer_[rb->cur_frame].iov_base)
    {
              RxFrame* frame = (RxFrame *)rb->ring_buffer_[rb->cur_frame].iov_base;
#if 0
                tpacket_hdr* h = &frame->tp_h;
                char buffer[256];
                sprintf (buffer, " -tpacket(v1): status=%ld,len=%d,snaplen=%d,mac=%d,net=%d,sec=%d,usec=%d",
                         h->tp_status, h->tp_len, h->tp_snaplen, h->tp_mac,h->tp_net, h->tp_sec, h->tp_usec);
                std::cout << std::string(buffer) << std::endl;
#else
                tpacket2_hdr* h = &frame->tp_h;
                char buffer[512];
                sprintf (buffer, " -tpacket(v2): status=%d,len=%d,snaplen=%d,mac=%d,net=%d,sec=%d,nsec=%d,vlan_tci=%d (vlan_tci=0x%04x)",
                         h->tp_status, h->tp_len, h->tp_snaplen, h->tp_mac, h->tp_net,  h->tp_sec, h->tp_nsec, h->tp_vlan_tci,  ntohs(h->tp_vlan_tci));
                std::cout << std::string(buffer) << std::endl;
#endif

        if ( ETH_P_8021Q == ntohs(frame->eth_h.h_proto) )
        {
                    struct vlan_ethhdr* vlan_eth_h = (struct vlan_ethhdr*)&frame->eth_h;
                    int vlan_tag = VLAN_TAG(ntohs(vlan_eth_h->h_vlan_TCI));
                   std::cout << " -Vlan " << vlan_tag << " packet to this host received";

                }

        rb->cur_frame = ( rb->cur_frame+1) % rx_socket_->getFrameNum();
    } // while()

}

当内核删除 vlan 时,它也会改变eth_h.h_proto到 de vlan 标签之后的协议ETH_P_8021Q == ntohs(frame->eth_h.h_proto)很可能是假的。

另外,如果您在标记的接口(即 eth0.100)而不是物理接口(eth0)中监听,您将看不到标签。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 TPACKET_V2 时,Vlan id 设置为 0 的相关文章

  • 为什么这个 Web api 控制器不并发?

    我有一个 Web API 控制器 里面有以下方法 public string Tester Thread Sleep 2000 return OK 当我调用它 10 次 使用 Fiddler 时 我预计所有 10 次调用都会在大约 2 秒后
  • 如何在 VC++ CString 中验证有效的整数和浮点数

    有人可以告诉我一种有效的方法来验证 CString 对象中存在的数字是有效整数还是浮点数吗 Use tcstol http msdn microsoft com en us library w4z2wdyc aspx and tcstod
  • Grpc - 将消息从一个客户端发送到连接到同一服务器的另一个客户端

    是否可以将消息从一个客户端发送到连接到同一服务器的另一个客户端 我想将数据从一个客户端发送到服务器然后发送到特定客户端 我想我需要获取客户端 ID 但我不知道如何获取此 ID 以及如何从服务器将此消息发送到该客户端 我这里有一个样本 这是一
  • 现代 C++ 编译器是否能够在某些情况下避免调用 const 函数两次?

    例如 如果我有以下代码 class SomeDataProcessor public bool calc const SomeData d1 const SomeData d2 const private Some non mutable
  • 循环遍历 C 结构中的元素以提取单个元素的值和数据类型

    我有一个要求 我有一个 C 语言的大结构 由大约 30 多个不同数据类型的不同元素组成 typedef struct type1 element1 type2 element2 type3 element3 type2 element4 1
  • 传递 constexpr 对象

    我决定给予新的C 14的定义constexpr旋转并充分利用它 我决定编写一个小的编译时字符串解析器 然而 我正在努力保持我的对象constexpr将其传递给函数时 考虑以下代码 include
  • extern 声明和函数定义都在同一文件中

    我只是浏览了一下gcc源文件 在gcc c 我发现了类似的东西 extern int main int char int main int argc char argv 现在我的疑问是extern是告诉编译器特定的函数不在这个文件中 但可以
  • 如何将 .txt 文件中的数据转换为 xml? C#

    我在一个文本文件中有数千行数据 我想通过将其转换为更容易搜索的内容来轻松搜索 我希望 XML 或其他类型的大型数据结构 尽管我不确定它是否是最好的对于我的想法 每行的数据如下所示 第 31 册 托马斯 乔治 32 34 154 每本书都不是
  • 处理右值时的 insert 与 emplace

    std string myString std unordered set
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • Unix 中的访问时间是多少

    我想知道访问时间是多少 我在网上搜索但得到了相同的定义 读 被改变 我知道与touch我们可以改变它 谁能用一个例子来解释一下它是如何改变的 有没有办法在unix中获取创建日期 时间 stat结构 The stat 2 结构跟踪所有文件日期
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • 将 Word 转换为 PDF - 禁用“保存”对话框

    我有一个用 C 编写的 Word 到 PDF 转换器 除了一件事之外 它工作得很好 有时 在某些 Word 文件上 后台会出现一条消息保存源文件中的更改 gt 是 否 取消 但我没有对源文件进行任何更改 我只想从 Word 文件创建 PDF
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • 没有“对 *this”功能的右值引用的解决方法

    我有一个围绕可移动对象的代理容器类 并希望代理能够隐式生成对底层对象的右值引用 但仅当代理本身被移动时 我相信我将能够按照提案 n2439 实施此行为 将移动语义扩展到 this http www open std org jtc1 sc2
  • 在 System.Type 上使用条件断点时出错

    这是函数 public void Init System Type Type this Type Type BuildFieldAttributes BuildDataColumns FieldAttributes 我在第一行设置了一个断点
  • 是否允许全局静态标识符以单个 _ 开头?

    换句话说 可能static 文件范围 全局变量恰好以一个下划线开头 而不会产生与 C 实现发生名称冲突的可能性 https www gnu org software libc manual html node Reserved Names

随机推荐