使用TPACKET_V2时,Vlan ID设置为0

我有一个TPACKET_V2的使用问题。

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

现在我正在使用开放的suse sp1,当我在sless sp2上运行我的程序时,我能够使用与sless sp1不兼容的程序来获得vlan id,但奇怪的是tcpdump能够获得vlan id(在这个sless上)和tcpdump设置TPACKET_V2(所以这意味着TPACKET_2被支持)

我的简单的项目是基于这些函数,所有由函数createSocket调用,然后有一个简单的方法,读取套接字上的数据包,我试图获得有关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! 有什么build议么?

 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)中收听,您将看不到标签。