使用 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;
};
我正在使用 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;
};