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