当使用TPACKET_V2时,Vlan id设置为0 [英] Vlan id is set to 0 when TPACKET_V2 is used

查看:617
本文介绍了当使用TPACKET_V2时,Vlan id设置为0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于这个TPACKET_V2的使用的问题。

I have a problem about the usage of this TPACKET_V2 .

我的问题是,在套接字上设置这种类型的数据包后,当我尝试接收一些数据包我不能从数据包读取vlan id(当然从数据包的头)vlan_tci是0。

My problem is that after setting of this type of packet on socket, when I try to receive some packets I can't read the vlan id from the packet (of course from the header of the packet) the vlan_tci is ever 0.

现在我使用开放suse sp1当我运行我的程序sless sp2我可以得到vlan id与不工作在 sless sp1 相同的程序,但奇怪的是,tcpdump是能够得到vlan id(在这个sless)和tcpdump设置TPACKET_V2(所以这意味着TPACKET_2是支持)

Now I'm using open suse sp1 and when I run my program on sless sp2 I 'm able to get the vlan id with the same program that doesn't work on sless sp1 but the weird thing is that tcpdump is able to get the vlan id (on this sless) and tcpdump set the TPACKET_V2 (so this means that TPACKET_2 is supported)

我的简单项目是基于这些功能, strong> createSocket ,那么有一个简单的方法是读取套接字上的数据包,我尝试获取有关vlan id的信息(在TPACKET_V1之前还有相对部分)

My simple project is based on these functions , all called by the function createSocket , then there is a simple method that is reading packets on the socket and there I try to get informations on vlan id (there there is also the relative part used before with the 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!有任何建议吗?

and in my function for receive packets and I try to read informations and in particular h_vlan_TCI from but I receive ever 0x00 !!! Any suggestions?

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)将很有可能是假的。

When the kernel removes the vlan it also changes eth_h.h_proto to the protocol after de vlan tag so ETH_P_8021Q == ntohs(frame->eth_h.h_proto) will most probably be false.

此外,如果你在标记的接口。eth0.100)而不是物理接口(eth0),您将看不到标签。

Also, if you are listening in the tagged interface (ie. eth0.100) instead of the physical interface (eth0) you will not see the tags.

这篇关于当使用TPACKET_V2时,Vlan id设置为0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆