|
|
|
@@ -1,3 +1,187 @@
|
|
|
|
|
//
|
|
|
|
|
// Created by Arron Nelson on 3/26/2025.
|
|
|
|
|
//
|
|
|
|
|
#include "ehs/io/socket/ICMP_W32.h"
|
|
|
|
|
|
|
|
|
|
#include <winsock2.h>
|
|
|
|
|
#include <WS2tcpip.h>
|
|
|
|
|
#include <iphlpapi.h>
|
|
|
|
|
|
|
|
|
|
struct iphdr
|
|
|
|
|
{
|
|
|
|
|
u_char ip_hl:4, ip_v:4;
|
|
|
|
|
u_char ip_tos;
|
|
|
|
|
u_short ip_len;
|
|
|
|
|
u_short ip_id;
|
|
|
|
|
u_short ip_off;
|
|
|
|
|
u_char ip_ttl;
|
|
|
|
|
u_char ip_p;
|
|
|
|
|
u_short ip_sum;
|
|
|
|
|
in_addr ip_src, ip_dst;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace ehs
|
|
|
|
|
{
|
|
|
|
|
ICMP::ICMP()
|
|
|
|
|
: hdl(EHS_INVALID_SOCKET)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICMP::ICMP(const IP version)
|
|
|
|
|
: BaseICMP(version)
|
|
|
|
|
{
|
|
|
|
|
hdl = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
|
|
|
|
if (hdl < 0)
|
|
|
|
|
{
|
|
|
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to create ICMP socket with error #" + Str_8::FromNum(errno) + ".");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EHS_LOG_SUCCESS();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICMP::ICMP(ICMP &&icmp) noexcept
|
|
|
|
|
: BaseICMP((BaseICMP &&)icmp), hdl(icmp.hdl)
|
|
|
|
|
{
|
|
|
|
|
icmp.hdl = EHS_INVALID_SOCKET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICMP::ICMP(const ICMP &icmp)
|
|
|
|
|
: BaseICMP(icmp), hdl(icmp.hdl)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICMP & ICMP::operator=(ICMP &&icmp) noexcept
|
|
|
|
|
{
|
|
|
|
|
if (this == &icmp)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
BaseICMP::operator=((BaseICMP &&)icmp);
|
|
|
|
|
|
|
|
|
|
hdl = icmp.hdl;
|
|
|
|
|
|
|
|
|
|
icmp.hdl = EHS_INVALID_SOCKET;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICMP & ICMP::operator=(const ICMP &icmp)
|
|
|
|
|
{
|
|
|
|
|
if (this == &icmp)
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
|
|
BaseICMP::operator=(icmp);
|
|
|
|
|
|
|
|
|
|
hdl = icmp.hdl;
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UInt_64 ICMP::Send(const Str_8 &address, ICMP_Header header, const Byte *data, const UInt_64 size)
|
|
|
|
|
{
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
{
|
|
|
|
|
EHS_LOG_INT(LogType::WARN, 0, "Socket is not initialized.");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
header.checksum = 0;
|
|
|
|
|
|
|
|
|
|
Serializer<UInt_64> payload(Endianness::LE);
|
|
|
|
|
payload.Write(header);
|
|
|
|
|
payload.Resize(payload.Size() + size);
|
|
|
|
|
|
|
|
|
|
Util::Copy(&payload[payload.GetOffset()], data, size);
|
|
|
|
|
|
|
|
|
|
payload.SetOffset(payload.GetOffset() + size);
|
|
|
|
|
|
|
|
|
|
header.checksum = ComputeChecksum((UInt_16 *)&payload[0], payload.Size());
|
|
|
|
|
|
|
|
|
|
payload.SetOffset(0);
|
|
|
|
|
payload.Write(header);
|
|
|
|
|
payload.SetOffset(payload.Size());
|
|
|
|
|
|
|
|
|
|
sockaddr_in dst_addr = {};
|
|
|
|
|
dst_addr.sin_family = AF_INET;
|
|
|
|
|
inet_pton(AF_INET, address, &(dst_addr.sin_addr));
|
|
|
|
|
|
|
|
|
|
SInt_64 sent = sendto(hdl, (const char *)&payload[0], payload.Size(), 0, (sockaddr *)&dst_addr, sizeof(dst_addr));
|
|
|
|
|
if (sent < 0)
|
|
|
|
|
{
|
|
|
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to send packet with error #" + Str_8::FromNum(errno) + ".");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EHS_LOG_SUCCESS();
|
|
|
|
|
|
|
|
|
|
return sent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UInt_64 ICMP::Receive(Str_8 &address, ICMP_Header header, Serializer<UInt_64> &data)
|
|
|
|
|
{
|
|
|
|
|
if (!IsValid())
|
|
|
|
|
{
|
|
|
|
|
EHS_LOG_INT(LogType::WARN, 0, "Socket is not initialized.");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serializer<UInt_64> payload(Endianness::LE);
|
|
|
|
|
payload.Resize(1500);
|
|
|
|
|
|
|
|
|
|
sockaddr_in remote = {};
|
|
|
|
|
socklen_t from_len = sizeof(remote);
|
|
|
|
|
|
|
|
|
|
SInt_64 recv = recvfrom(hdl, (char *)&payload[0], 1500, 0, (sockaddr *)&remote, &from_len);
|
|
|
|
|
if (recv < 0)
|
|
|
|
|
{
|
|
|
|
|
int code = errno;
|
|
|
|
|
if (code == EAGAIN)
|
|
|
|
|
EHS_LOG_SUCCESS();
|
|
|
|
|
else
|
|
|
|
|
EHS_LOG_INT(LogType::ERR, 0, "Failed to receive packet with error #" + Str_8::FromNum(code) + ".");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
payload.Resize(recv);
|
|
|
|
|
|
|
|
|
|
char tmpAddr[INET_ADDRSTRLEN];
|
|
|
|
|
|
|
|
|
|
if (!inet_ntop(remote.sin_family, &remote.sin_addr, tmpAddr, INET_ADDRSTRLEN))
|
|
|
|
|
{
|
|
|
|
|
EHS_LOG_INT(LogType::ERR, 1, "Failed to convert IPv4 address with error #" + Str_8::FromNum(errno) + ".");
|
|
|
|
|
|
|
|
|
|
return recv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
address = tmpAddr;
|
|
|
|
|
iphdr ipHeader = payload.Read<iphdr>();
|
|
|
|
|
header = payload.Read<ICMP_Header>();
|
|
|
|
|
data = Serializer<UInt_64>(payload.GetEndianness(), &payload[payload.GetOffset()], payload.Size() - payload.GetOffset());
|
|
|
|
|
|
|
|
|
|
EHS_LOG_SUCCESS();
|
|
|
|
|
|
|
|
|
|
return recv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ICMP::SetReceiveTimeout(UInt_64 timeout)
|
|
|
|
|
{
|
|
|
|
|
timeval result = {};
|
|
|
|
|
result.tv_sec = (long)timeout;
|
|
|
|
|
result.tv_usec = 0;
|
|
|
|
|
|
|
|
|
|
if (setsockopt(hdl, SOL_SOCKET, SO_RCVTIMEO, (const char *)&result, sizeof(result)) < 0)
|
|
|
|
|
{
|
|
|
|
|
EHS_LOG_INT(LogType::WARN, 0, "Failed to set receive timeout with error #" + Str_8::FromNum(errno) + ".");
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EHS_LOG_SUCCESS();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ICMP::IsValid() const
|
|
|
|
|
{
|
|
|
|
|
return hdl != EHS_INVALID_SOCKET;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|