Repo-Init
 
Loading...
Searching...
No Matches
RawSocket.cpp
Go to the documentation of this file.
2
4
5#include <algorithm>
6#include <chrono>
7#include <cstring>
8#include <format>
9#include <ios>
10#include <iterator>
11#include <stdexcept>
12#include <utility>
13
14#include <net/ethernet.h>
15#include <net/if.h>
16#include <netinet/in.h>
17#include <sys/socket.h>
18#include <unistd.h>
19
20void RawSocket::init(int domain, int type, int protocol)
21{
22 _sockFd = socket(domain, type, protocol); // Init socket
23 if (_sockFd < 0)
24 {
25 throw std::ios_base::failure(getErrnoString(errno));
26 }
27 if (bind(_sockFd, std::bit_cast<sockaddr *>(&_addr), sizeof(_addr)) < 0)
28 {
29 throw std::ios_base::failure(std::string("Bind failed: ") + getErrnoString(errno));
30 }
31}
32
33RawSocket::RawSocket(std::string iface, bool isWrite) : _writeMode(isWrite), _iFace(std::move(iface))
34{
35 // Prepare socket address
36 memset(static_cast<void *>(&_addr), 0, sizeof(sockaddr_ll));
37 _addr.sll_family = AF_PACKET;
38 _addr.sll_protocol = htons(ETH_P_ALL);
39 _addr.sll_ifindex = static_cast<int>(if_nametoindex(_iFace.c_str()));
40 if (_addr.sll_ifindex == 0)
41 {
42 throw std::ios_base::failure(std::string("Can't find interface: ") + getErrnoString(errno));
43 }
44
45 // Interface request
46 ifreq ifr{};
47 memset(static_cast<void *>(&ifr), 0, sizeof(ifreq));
48 const auto maxIfaceNameLen = static_cast<size_t>(IFNAMSIZ - 1);
49 const size_t ifaceNameLen = _iFace.size() < maxIfaceNameLen ? _iFace.size() : maxIfaceNameLen;
50 auto *const ifaceNameBegin = std::begin(ifr.ifr_name);
51 std::copy_n(_iFace.begin(), ifaceNameLen, ifaceNameBegin);
52 *std::next(ifaceNameBegin, static_cast<std::ptrdiff_t>(ifaceNameLen)) = '\0';
53
54 if (isWrite)
55 {
56 init(PF_PACKET, SOCK_RAW, IPPROTO_RAW);
57 if (setsockopt(_sockFd, SOL_SOCKET, SO_BINDTODEVICE, static_cast<void *>(&ifr), sizeof(ifr)) < 0)
58 {
59 throw std::ios_base::failure(std::string("Can't set socket options: ") + getErrnoString(errno));
60 }
61 }
62 else
63 {
64 init(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
65 }
66 _isReady = true;
67}
68
69int RawSocket::writeData(const unsigned char *data, size_t dataLen)
70{
71 if (!_isReady || !_writeMode)
72 {
73 return -EPERM;
74 }
75
76 auto startTime = std::chrono::high_resolution_clock::now();
77 const auto retval = static_cast<int>(write(_sockFd, data, dataLen));
78
79 // Update stats
80 _stats.processingTime += static_cast<double>((std::chrono::high_resolution_clock::now() - startTime).count());
81 if (retval > 0)
82 {
83 _stats.sentBytes += static_cast<size_t>(retval);
84 }
85
86 return retval;
87}
88
89int RawSocket::readData(unsigned char *data, size_t dataLen)
90{
91 if (!_isReady || _writeMode)
92 {
93 return -EPERM;
94 }
95 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
96 socklen_t socketLen = sizeof(_addr);
97
98 auto startTime = std::chrono::high_resolution_clock::now();
99 const auto retval =
100 static_cast<int>(recvfrom(_sockFd, data, dataLen, 0, std::bit_cast<sockaddr *>(&_addr), &socketLen));
101
102 // Update stats
103 _stats.processingTime += static_cast<double>((std::chrono::high_resolution_clock::now() - startTime).count());
104 if (retval > 0)
105 {
106 _stats.receivedBytes += static_cast<size_t>(retval);
107 }
108
109 return retval;
110}
111
112RawSocketStats RawSocket::getStats(bool resetInternalStats)
113{
114 if (resetInternalStats)
115 {
116 RawSocketStats buffer = _stats;
117 _stats = {.sentBytes = 0, .receivedBytes = 0, .processingTime = 0.0};
118 return buffer;
119 }
120 return _stats;
121}
122
std::string getErrnoString(int errVal)
int _sockFd
Socket descriptor.
Definition RawSocket.hpp:30
RawSocket(std::string iface, bool isWrite=false)
Definition RawSocket.cpp:33
bool _writeMode
Mode indicator. True = Write, False = Read.
Definition RawSocket.hpp:28
RawSocketStats _stats
Internal structure for statistics.
Definition RawSocket.hpp:36
RawSocketStats getStats(bool resetInternalStats=false)
bool _isReady
Ready flag.
Definition RawSocket.hpp:26
void init(int domain, int type, int protocol)
Definition RawSocket.cpp:20
std::string _iFace
Currently used ethernet interface.
Definition RawSocket.hpp:32
int readData(unsigned char *data, size_t dataLen)
Definition RawSocket.cpp:89
int writeData(const unsigned char *data, size_t dataLen)
Definition RawSocket.cpp:69
sockaddr_ll _addr
Socket structure.
Definition RawSocket.hpp:34