使用boost::asio库创建IP、TCP或UDP套接字相当容易。但是,例如,当谈到以太网套接字时,您需要实现boost/asio/basic_raw_socket.hpp。
由于互联网上没有这样的例子,而且我花了很长时间才找到答案,所以我会把我的工作放在这里。
我发现的最有用的资源是:NETLINK (netlink) sockets using boost::asio
发布于 2014-10-06 16:06:41
首先要做的是创建一个基于basic_raw_socket类的以太网协议。您可以修改协议(hton(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()));发布于 2015-01-01 14:39:56
可以使用generic::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)));发布于 2022-11-06 12:37:59
下面是一个使用boost asio原始套接字从回送设备中捕获一个数据包的演示:
#include <iostream>
#include <string>
#include <array>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <boost/asio.hpp>
#include <boost/format.hpp>
int main()
{
const std::string port = "lo";
std::array<uint8_t, 20> buffer;
uint bytes_received;
sockaddr_ll sockaddr{0};
sockaddr.sll_family = PF_PACKET;
sockaddr.sll_protocol = htons(ETH_P_ALL);
sockaddr.sll_ifindex = if_nametoindex(port.c_str());
sockaddr.sll_hatype = 1;
boost::asio::io_service ios;
boost::asio::generic::raw_protocol::endpoint endpoint(&sockaddr, sizeof(sockaddr), SOCK_RAW);
boost::asio::generic::raw_protocol::socket socket(ios, endpoint);
socket.non_blocking();
bytes_received = socket.receive(boost::asio::buffer(buffer, buffer.size()));
std::cout << "Received " << bytes_received << " bytes" << std::endl;
std::cout << "Source MAC address: ";
std::cout << boost::format("%02X-%02X-%02X-%02X-%02X-%02X") %
buffer[0] % buffer[1] % buffer[2] %
buffer[3] % buffer[4] % buffer[5];
std::cout << std::endl;
std::cout << "Dest MAC address: ";
std::cout << boost::format("%02X-%02X-%02X-%02X-%02X-%02X") %
buffer[6] % buffer[7] % buffer[8] %
buffer[9] % buffer[10] % buffer[11];
std::cout << std::endl;
return 0;
}https://stackoverflow.com/questions/26212014
复制相似问题