2014-10-06 100 views

回答

6

首先要做的是创建基于basic_raw_socket类以太网协议。 您可以修改协议(htons(ETH_P_ALL))和系列(PF_PACKET)字段,具体取决于您想要发送/接收的流量。

/// Create a link-layer protocol associated with a link-layer endpoint 
class ll_protocol 
{ 
public: 
    /// Obtain an identifier for the type of the protocol. 
    int type() const 
    { 
     return SOCK_RAW; 
    } 

    /// Obtain an identifier for the protocol. 
    int protocol() const 
    { 
     return protocol_; 
    } 

    /// Obtain an identifier for the protocol family. 
    int family() const 
    { 
     return family_; 
    } 

    // Construct with a specific family. 
    explicit ll_protocol(int protocol, int family) : 
      protocol_(protocol), family_(family) 
    { 
    } 
    explicit ll_protocol() : 
      protocol_(htons(ETH_P_ALL)), family_(PF_PACKET) 
    { 
    } 

    typedef boost::asio::basic_raw_socket<ll_protocol> socket; 
    typedef ll_endpoint<ll_protocol> endpoint; 

private: 
    int protocol_; 
    int family_; 
}; 

要将套接字绑定到接口,需要端点。关键是要创建一个sockaddr_ll结构,其中可以指定发送/接收流量的接口。

#include <net/ethernet.h> 
#include <sys/socket.h> 
#include <linux/if_packet.h> 
#include <cstddef> 

template <typename Protocol> 
class ll_endpoint 
{ 
private: 
    sockaddr_ll sockaddr; 
public: 
    /// The protocol type associated with the endpoint. 
    typedef Protocol protocol_type; 
    typedef boost::asio::detail::socket_addr_type data_type; 

    /// Constructor 
    ll_endpoint(const char* ifname) 
    { 
     sockaddr.sll_family = PF_PACKET; 
     sockaddr.sll_protocol = htons(ETH_P_ALL); 
     sockaddr.sll_ifindex = if_nametoindex(ifname); 
     sockaddr.sll_hatype = 1; 
    } 

    /// Assign from another endpoint. 
    ll_endpoint& operator=(const ll_endpoint& other) 
    { 
     sockaddr = other.sockaddr; 
     return *this; 
    } 

    /// The protocol associated with the endpoint. 
    protocol_type protocol() const 
    { 
     return protocol_type(); 
    } 

    /// Get the underlying endpoint in the native type. 
    data_type* data() 
    { 
     return &sockaddr; 
    } 

    /// Get the underlying endpoint in the native type. 
    const data_type* data() const 
    { 
     return (struct sockaddr*)&sockaddr; 
    } 

    /// Get the underlying size of the endpoint in the native type. 
    std::size_t size() const 
    { 
     return sizeof(sockaddr); 
    } 

    /// Set the underlying size of the endpoint in the native type. 
    void resize(std::size_t size) 
    { 
    /* nothing we can do here */ 
    } 

    /// Get the capacity of the endpoint in the native type. 
    std::size_t capacity() const 
    { 
     return sizeof(sockaddr); 
    } 

    /// Compare two endpoints for equality. 
    friend bool operator==(const ll_endpoint<Protocol>& e1, 
       const ll_endpoint<Protocol>& e2) 
    { 
     return e1.sockaddr == e2.sockaddr; 
    } 

    /// Compare two endpoints for inequality. 
    friend bool operator!=(const ll_endpoint<Protocol>& e1, 
       const ll_endpoint<Protocol>& e2) 
    { 
     return !(e1.sockaddr == e2.sockaddr); 
    } 

    /// Compare endpoints for ordering. 
    friend bool operator<(const ll_endpoint<Protocol>& e1, 
       const ll_endpoint<Protocol>& e2) 
    { 
     return e1.sockaddr < e2.sockaddr; 
    } 

    /// Compare endpoints for ordering. 
    friend bool operator>(const ll_endpoint<Protocol>& e1, 
       const ll_endpoint<Protocol>& e2) 
    { 
     return e2.sockaddr < e1.sockaddr; 
    } 

    /// Compare endpoints for ordering. 
    friend bool operator<=(const ll_endpoint<Protocol>& e1, 
       const ll_endpoint<Protocol>& e2) 
    { 
     return !(e2 < e1); 
    } 

    /// Compare endpoints for ordering. 
    friend bool operator>=(const ll_endpoint<Protocol>& e1, 
       const ll_endpoint<Protocol>& e2) 
    { 
     return !(e1 < e2); 
    } 
}; 

最后,你可以打开插座和连接到端点如下:

string ifname("eth1"); 
ll_protocol::socket socket; 
socket.open(ll_protocol()); 
socket.bind(ll_endpoint<ll_protocol>((const char*)ifname.c_str())); 
7

原始套接字可使用通用:: raw_protocol东西打开:

std::string ifname("eth1"); 

typedef boost::asio::generic::raw_protocol raw_protocol_t; 
typedef boost::asio::generic::basic_endpoint<raw_protocol_t> raw_endpoint_t; 

sockaddr_ll sockaddr; 
memset(&sockaddr, 0, sizeof(sockaddr)); 
sockaddr.sll_family = PF_PACKET; 
sockaddr.sll_protocol = htons(ETH_P_ALL); 
sockaddr.sll_ifindex = if_nametoindex(ifname.c_str()); 
sockaddr.sll_hatype = 1; 

raw_protocol_t::socket socket(io_service, raw_protocol_t(PF_PACKET, SOCK_RAW)) 
socket.bind(raw_endpoint_t(&sockaddr, sizeof(sockaddr))); 
+0

相反你的意思是创建ll_endpoint模板?很高兴知道。 :) – 2015-02-16 16:48:29