// #include <boost/asio/detail/config.hpp>
// #include <boost/asio/detail/socket_types.hpp>
// #include <boost/asio/basic_raw_socket.hpp>
// #include <boost/asio/ip/basic_endpoint.hpp>
// #include <boost/asio/ip/basic_resolver.hpp>
// #include <boost/asio/ip/basic_resolver_iterator.hpp>
// #include <boost/asio/ip/basic_resolver_query.hpp>
// #include <boost/asio/detail/push_options.hpp>
// #include <boost/asio.hpp>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <cstddef>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
class ipv4_header
{
public:
ipv4_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }
unsigned char version() const { return (rep_[0] >> 4) & 0xF; }
unsigned short header_length() const { return (rep_[0] & 0xF) * 4; }
unsigned char type_of_service() const { return rep_[1]; }
unsigned short total_length() const { return decode(2, 3); }
unsigned short identification() const { return decode(4, 5); }
bool dont_fragment() const { return (rep_[6] & 0x40) != 0; }
bool more_fragments() const { return (rep_[6] & 0x20) != 0; }
unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; }
unsigned int time_to_live() const { return rep_[8]; }
unsigned char protocol() const { return rep_[9]; }
unsigned short header_checksum() const { return decode(10, 11); }
boost::asio::ip::address_v4 source_address() const
{
boost::asio::ip::address_v4::bytes_type bytes = {{rep_[12], rep_[13], rep_[14], rep_[15]}};
return boost::asio::ip::address_v4(bytes);
}
boost::asio::ip::address_v4 destination_address() const
{
boost::asio::ip::address_v4::bytes_type bytes = {{rep_[16], rep_[17], rep_[18], rep_[19]}};
return boost::asio::ip::address_v4(bytes);
}
friend std::istream& operator>>(std::istream& is, ipv4_header& header)
{
is.read(reinterpret_cast<char*>(header.rep_), 20);
if (header.version() != 4) is.setstate(std::ios::failbit);
std::streamsize options_length = header.header_length() - 20;
if (options_length < 0 || options_length > 40)
is.setstate(std::ios::failbit);
else
is.read(reinterpret_cast<char*>(header.rep_) + 20, options_length);
return is;
}
private:
unsigned short decode(int a, int b) const { return (rep_[a] << 8) + rep_[b]; }
unsigned char rep_[60];
};
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;
}
ll_endpoint() {}
/// 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 (struct sockaddr*)&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.sll_family == e2.sockaddr.sll_family) &&
(e1.sockaddr.sll_protocol == e2.sockaddr.sll_protocol) &&
(e1.sockaddr.sll_ifindex == e2.sockaddr.sll_ifindex) &&
(e1.sockaddr.sll_hatype == e2.sockaddr.sll_hatype);
}
/// Compare two endpoints for inequality.
friend bool operator!=(const ll_endpoint<Protocol>& e1, const ll_endpoint<Protocol>& e2) { return !(e1 == e2); }
/// Compare endpoints for ordering.
friend bool operator<(const ll_endpoint<Protocol>& e1, const ll_endpoint<Protocol>& e2)
{
return e1.sockaddr.sll_ifindex < e2.sockaddr.sll_ifindex;
}
/// Compare endpoints for ordering.
friend bool operator>(const ll_endpoint<Protocol>& e1, const ll_endpoint<Protocol>& e2)
{
return e2.sockaddr.sll_ifindex < e1.sockaddr.sll_ifindex;
}
/// 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); }
};
/// 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_;
};
boost::asio::io_service io_service;
ll_protocol::socket socket_(io_service);
boost::asio::streambuf reply_buffer_;
void start_receive();
void handle_receive(const boost::system::error_code& error, std::size_t length);
char buff[2048];
void start_receive()
{
// Wait for a reply. We prepare the buffer to receive up to 64KB.
socket_.async_receive(boost::asio::buffer(buff,
2048), boost::bind(handle_receive, _1, _2));
}
void handle_receive(const boost::system::error_code& error, std::size_t length)
{
if (error)
{
std::cout << "async_receive error:" << error.message() << std::endl;
return;
}
// // Decode the reply packet.
// std::istream is(&reply_buffer_);
// ipv4_header ipv4_hdr;
// is >> ipv4_hdr;
// // Print out some information about the reply packet.
// std::cout << "protocol:" << (iipv4_hdr.protocol()
// << " " << length - ipv4_hdr.header_length()
// << " bytes from " << ipv4_hdr.source_address()
// << " to " << ipv4_hdr.destination_address() << std::endl;
struct iphdr* ip = (struct iphdr*)(buff + ETH_HLEN);
int ip_header_length = ip->ihl * 4;
int eth_ip_hdr_len = ETH_HLEN + ip_header_length;
// printf("IP packet size: %d\n", htons(ip->tot_len));
struct sockaddr_in source;
struct sockaddr_in dest;
memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = ip->saddr;
memset(&dest, 0, sizeof(dest));
dest.sin_addr.s_addr = ip->daddr;
printf("%s -> ", inet_ntoa(source.sin_addr));
printf("%s ", inet_ntoa(dest.sin_addr));
std::string srcIp(inet_ntoa(source.sin_addr));
std::string dstIp(inet_ntoa(dest.sin_addr));
u_char protocol = ip->protocol;
if (protocol == IPPROTO_TCP)
{
struct tcphdr* tcp = (struct tcphdr*)(buff + eth_ip_hdr_len);
int dstPort = ntohs(tcp->dest);
int tcp_header_length = tcp->doff * 4;
printf("%d -> %d\n", ntohs(tcp->source), ntohs(tcp->dest));
printf("TCP seq: %u\n", ntohl(tcp->seq));
printf("payload size: %d\n", htons(ip->tot_len) - ip_header_length - tcp_header_length);
}
else if (protocol == IPPROTO_UDP)
{
struct udphdr* udp = (struct udphdr*)(buff + eth_ip_hdr_len);
int dstPort = ntohs(udp->dest);
int udp_header_length = 8;
printf("%d -> %d\n", ntohs(udp->source), ntohs(udp->dest));
printf("UDP\n");
printf("payload size: %d\n", ntohs(udp->len) - udp_header_length);
}
else
{
printf("Unknown protocol:%d\n", protocol + 0);
}
start_receive();
}
int main()
{
socket_.open(ll_protocol());
std::string ifname("em1");
ll_endpoint<ll_protocol> ep((const char*)ifname.c_str());
std::cout << ">>>" << ((sockaddr_ll*)ep.data())->sll_ifindex << std::endl;
socket_.bind(ep);
start_receive();
io_service.run();
while (1)
{
sleep(5);
std::cout << "runing..." << std::endl;
}
}
使用boost asio raw socket创建第2层/ ethernet套接字(在C ++中)
于 2022-05-11 22:06:46 首次发布
本文档介绍了如何在C++中利用Boost.Asio库创建第二层(Layer 2)或以太网套接字,以便进行原始的网络通信。通过这种方法,开发者可以直接操作数据链路层的包,实现更底层的网络编程。

721

被折叠的 条评论
为什么被折叠?



