使用boost asio raw套接字创建第2层/以太网套接字(在C ++中) [英] Create a layer 2 / ethernet socket with boost asio raw socket (in C++)

查看:260
本文介绍了使用boost asio raw套接字创建第2层/以太网套接字(在C ++中)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用boost::asio库创建IP,TCP或UDP套接字非常容易.但是,例如,对于以太网套接字,您需要实现boost/asio/basic_raw_socket.hpp

It is fairly easy to create IP, TCP or UDP sockets using boost::asio library. But when it comes to Ethernet sockets for instance, you need to implement boost/asio/basic_raw_socket.hpp

由于没有这样的事在互联网上出现,而且我花了很长时间才找到答案,所以我将解决方法放在这里.

As there are no examples of such a thing over the internet and as I spent a long time before finding the answer, I'll put my work-around in here.

我发现最有用的资源是: AF_NETLINK(netlink)套接字使用boost :: asio

The most helpful resource I found was: AF_NETLINK (netlink) sockets using boost::asio

推荐答案

要做的第一件事是基于basic_raw_socket类创建一个以太网协议. 您可以根据要发送/接收的通信量来修改协议(htons(ETH_P_ALL))和族(PF_PACKET)字段.

First thing to do is to create an ethernet protocol based on the basic_raw_socket class. You can modify the protocol (htons(ETH_P_ALL)) and the family (PF_PACKET) fields, depending on the traffic you want to send/receive.

/// 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结构,可以在其中指定发送/接收流量的接口.

To bind the socket to the interface, an endpoint is required. The key point is to create a sockaddr_ll structure, in which the interface to send/receive traffic can be specified.

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

最后,您可以按以下步骤打开套接字并连接到端点:

Finally, you can open the socket and connect to the endpoint as follow:

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

这篇关于使用boost asio raw套接字创建第2层/以太网套接字(在C ++中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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