使用 boost::asio::generic::raw_protocol::socket 时 OS (Linux) 未添加第 2 层 header

Layer 2 header is not added by OS (Linux) when using boost::asio::generic::raw_protocol::socket

我正在使用 boost::asio::generic::raw_protocol::socket 打开家族 PF_PACKET 的套接字并键入 SOCK_DGRAM

在我的 header 文件中:

class MyClass
{
public:
MyClass(/*parameters*/);
typedef boost::asio::generic::raw_protocol raw_protocol_t;
typedef boost::asio::generic::basic_endpoint<raw_protocol_t> raw_endpoint_t;

void SetDestinationEndPoint(int ifIndex, int protocol, const uint8_t *destinationMacAddress);

private:
boost::shared_ptr<raw_protocol_t::socket> m_socketPtr;
raw_endpoint_t *m_pDestinationEndpoint;
};

在 .cpp 文件中:

MyClass::MyClass(/*parameters*/):
m_socketPtr(new raw_protocol_t::socket(IOWorker.get_service()) //in my class constructor
{
//constructor body
m_socketPtr->open(raw_protocol_t(PF_PACKET, SOCK_DGRAM));

sockaddr_ll sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sll_family = AF_PACKET;
sockaddr.sll_protocol = htons(protocol);
sockaddr.sll_ifindex = ifIndex;

m_socketPtr->bind(raw_endpoint_t(&sockaddr, sizeof(sockaddr)));
}
//then User sets destination endpoint
void MyClass::SetDestinationEndPoint(int ifIndex, int protocol, const uint8_t *destinationMacAddress)
{
struct sockaddr_ll ll;
memset(&ll, 0, sizeof(ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = ifIndex;
ll.sll_protocol = htons(protocol);
ll.sll_halen = ETH_ALEN;
memcpy(ll.sll_addr, destinationMacAddress, ETH_ALEN);
m_pDestinationEndpoint = new raw_endpoint_t(&ll, sizeof(ll), protocol);
}

最后,调用 async_send_to 以启动有效负载的发送:

m_socketPtr->async_send_to(boost::asio::buffer(bufferPtr->GetBuffer().get(), bufferPtr->GetBufferSize()),
*m_pDestinationEndpoint,
boost::bind(/*params*/));

缓冲区仅包含以太网负载,不包含以太网 header。根据我的理解,构建以太网 header 所需的一切都存在于 *m_pDestinationEndpoint 中(使用对 SetDestinationEndPoint() 的调用进行设置)。但是,我注意到只有有效载荷在没有以太网 header 的情况下被发送。我在这里错过了什么?其次,是否有必要使用单独的目标端点,或者我可以在对 async_send_to 的调用中使用 m_socketPtr->local_endpoint() (当然在调用之前在构造函数本身中设置目标 MAC 地址 bind)?

strace 附加到进程提供了一个提示:

strace  -e trace=network -p `pidof <process name>`

我希望找到

socket(PF_PACKET, SOCK_DGRAM, 1)

而是找到了

socket(PF_PACKET, SOCK_RAW, 1)

这让我相信 socket open 调用的第二个参数 class 没有指定套接字类型,而是协议族

所以我将协议 class 从 raw_protocol 更改为 datagram_protocol(以及对端点 classes 的类似更改)并且成功了!

class MyClass
{
public:
MyClass(/*parameters*/);
typedef boost::asio::generic::datagram_protocol datagram_protocol_t;
typedef boost::asio::generic::basic_endpoint<datagram_protocol_t> datagram_endpoint_t;

void SetDestinationEndPoint(int ifIndex, int protocol, const uint8_t *destinationMacAddress);

private:
boost::shared_ptr<datagram_protocol_t::socket> m_socketPtr;
datagram_endpoint_t *m_pDestinationEndpoint;
};