2013-01-11 179 views
2

我對使用此TPACKET_V2有疑問。當使用TPACKET_V2時,Vlan id設置爲0

我的問題是,在套接字上設置了這種類型的包之後,當我試圖接收一些包時,我無法從包中讀取vlan id(當然是從包頭中)vlan_tci永遠0

現在我使用的是開放的SUSE SP1,當我在sless SP2上運行我的程序我是能夠獲得與同一個程序的VLAN ID不上sless SP1但奇怪的工作是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!有什麼建議麼?

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() 

} 

回答

1

當內核中刪除它也改變eth_h.h_proto以德VLAN標籤後的協議的VLAN,使ETH_P_8021Q == ntohs(frame->eth_h.h_proto)將最有可能是假的。另外,如果您在標記接口(即eth0.100)而不是物理接口(eth0)中偵聽,您將看不到標記。

相關問題