2013-01-11 4 views
2

이 TPACKET_V2의 사용법에 문제가 있습니다.TPACKET_V2를 사용하면 Vlan ID가 0으로 설정됩니다.

내 문제는 소켓에서이 유형의 패킷을 설정 한 후 일부 패킷을 수신하려고 할 때 패킷의 헤더 (물론 헤더의 비트)를 읽을 수 없다는 것입니다. vlan_tci는 항상 있습니다.

0은 이제 오픈 수세의 SP1을 사용하고 내가 sless의 SP2를 내 프로그램을 실행할 때 나는 'sless SP1의하지만 이상한 것은 작동하지 않습니다 같은 프로그램에 VLAN ID를 얻을 수 있어요 해요 tcpdump가 vlan id (이 sless)를 가져올 수 있고 tcpdump가 TPACKET_V2를 설정했다는 것입니다. (따라서 TPACKET_2가 지원됩니다.)

간단한 프로젝트는이 함수를 기반으로합니다. 함수 의 createSocket은 다음 소켓 패킷을 판독하는 간단한 방법이 거기에 I가 VLAN ID의 정보를 얻으려고

#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); 
} 

(이 또한 TPACKET_V1 함께 이전에 사용 상대적인 부분이) 내 패킷 수신 패킷에 대한 정보 및 특히 h_vlan_TCI 읽으려고하지만 0x00 수신합니다 !!! 어떤 제안? 커널은 또한 드 VLAN 태그 후 프로토콜 eth_h.h_proto을 변경하는 VLAN을 제거 할 때

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_P_8021Q == ntohs(frame->eth_h.h_proto) 아마 대부분 거짓 일 것이다.

또한 물리적 인터페이스 (eth0) 대신 태그가 지정된 인터페이스 (예 : eth0.100)에서 수신 중이면 태그가 표시되지 않습니다.

관련 문제