Respond to ICMP Echo Requests (aka pings)

This commit is contained in:
Sijmen 2020-12-11 03:39:21 +01:00
parent 18c5bbd29d
commit 9cfcb0ddf7
Signed by: vijfhoek
GPG key ID: DAF7821E067D9C48
7 changed files with 265 additions and 31 deletions

View file

@ -1941,7 +1941,6 @@ extern "C"
MsDelay(1000); MsDelay(1000);
} }
const auto ipAddress = 0x0A00000B;
uint8_t ipBuffer[USPI_FRAME_BUFFER_SIZE]; uint8_t ipBuffer[USPI_FRAME_BUFFER_SIZE];
if (USPiEthernetAvailable()) { if (USPiEthernetAvailable()) {
@ -1952,14 +1951,15 @@ extern "C"
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK); screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
// Send an ARP announcement // Send an ARP announcement
SendArpAnnouncement(macAddress, ipAddress); SendArpAnnouncement(macAddress, Ipv4Address);
while (true) while (true)
{ {
size_t size; size_t size;
if (!USPiReceiveFrame(ipBuffer, &size)) if (!USPiReceiveFrame(ipBuffer, &size))
{ {
const auto targetIp = 0x0A00000A; /*
const auto targetIp = 0xC0A80128;
const auto targetMacIter = ArpTable.find(targetIp); const auto targetMacIter = ArpTable.find(targetIp);
if (targetMacIter != ArpTable.end()) if (targetMacIter != ArpTable.end())
@ -1970,10 +1970,11 @@ extern "C"
else else
{ {
// Send an ARP request to find the MAC address belonging to this IP. // Send an ARP request to find the MAC address belonging to this IP.
SendArpRequest(MacBroadcast, macAddress, targetIp, ipAddress); SendArpRequest(MacBroadcast, macAddress, targetIp, Ipv4Address);
} }
*/
MsDelay(1000); MsDelay(100);
continue; continue;
} }
@ -1991,6 +1992,12 @@ extern "C"
{ {
HandleArpFrame(ipBuffer); HandleArpFrame(ipBuffer);
} }
else if (header.type == ETHERTYPE_IPV4)
{
uint64_t debug = HandleIpv4Frame(ipBuffer);
snprintf(tempBuffer, tempBufferSize, "Debug: %016llx", debug);
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
}
} }
} }

View file

@ -51,7 +51,7 @@ struct Ipv4ArpPacket
return 28; return 28;
} }
static Ipv4ArpPacket Deserialize(uint8_t* buffer) static Ipv4ArpPacket Deserialize(const uint8_t* buffer)
{ {
Ipv4ArpPacket self; Ipv4ArpPacket self;

View file

@ -7,14 +7,18 @@ struct EthernetFrameHeader
MacAddress macSource; MacAddress macSource;
std::uint16_t type; std::uint16_t type;
EthernetFrameHeader() {}
EthernetFrameHeader(std::uint16_t type) : EthernetFrameHeader(std::uint16_t type) :
macDestination{255, 255, 255, 255, 255, 255}, macDestination{255, 255, 255, 255, 255, 255},
macSource{0, 0, 0, 0, 0, 0}, macSource{0, 0, 0, 0, 0, 0},
type(type) type(type)
{ {}
}
EthernetFrameHeader(MacAddress macDestination, MacAddress macSource, uint16_t type) :
macDestination(macDestination), macSource(macSource), type(type)
{}
EthernetFrameHeader() : EthernetFrameHeader(0) {}
std::size_t Serialize(uint8_t* buffer) std::size_t Serialize(uint8_t* buffer)
{ {
@ -32,7 +36,7 @@ struct EthernetFrameHeader
return i; return i;
} }
static EthernetFrameHeader Deserialize(uint8_t* buffer) static EthernetFrameHeader Deserialize(const uint8_t* buffer)
{ {
EthernetFrameHeader self; EthernetFrameHeader self;
memcpy(self.macDestination.data(), buffer + 0, self.macDestination.size()); memcpy(self.macDestination.data(), buffer + 0, self.macDestination.size());
@ -52,9 +56,16 @@ struct EthernetFrame
EthernetFrame() {} EthernetFrame() {}
EthernetFrame(std::uint16_t type, T payload) : header(type), payload(payload), crc(0) EthernetFrame(std::uint16_t type, T payload) : header(type), payload(payload)
{ {}
}
EthernetFrame(
MacAddress macDestination,
MacAddress macSource,
std::uint16_t type,
T payload
) : header(macDestination, macSource, type), payload(payload)
{}
std::size_t Serialize(uint8_t* buffer) std::size_t Serialize(uint8_t* buffer)
{ {
@ -79,7 +90,7 @@ struct EthernetFrame
return i; return i;
} }
static EthernetFrame<T> Deserialize(uint8_t* buffer) static EthernetFrame<T> Deserialize(const uint8_t* buffer)
{ {
EthernetFrame<T> self; EthernetFrame<T> self;

View file

@ -1,18 +1,26 @@
#pragma once #pragma once
#include "net.h" #include "net.h"
enum IcmpType
{
ICMP_ECHO_REPLY = 0,
ICMP_ECHO_REQUEST = 8,
};
struct IcmpPacketHeader struct IcmpPacketHeader
{ {
std::uint8_t type; std::uint8_t type;
std::uint8_t code; std::uint8_t code;
std::uint16_t checksum; std::uint16_t checksum;
IcmpPacketHeader() {}
IcmpPacketHeader(std::uint8_t type, std::uint8_t code) : IcmpPacketHeader(std::uint8_t type, std::uint8_t code) :
type(type), code(code), checksum(0) type(type), code(code), checksum(0)
{ {}
}
std::size_t Serialize(uint8_t* buffer) { std::size_t Serialize(uint8_t* buffer) const
{
size_t i = 0; size_t i = 0;
buffer[i++] = type; buffer[i++] = type;
buffer[i++] = code; buffer[i++] = code;
@ -20,6 +28,15 @@ struct IcmpPacketHeader
buffer[i++] = checksum >> 8; buffer[i++] = checksum >> 8;
return i; return i;
} }
static IcmpPacketHeader Deserialize(const uint8_t* buffer)
{
IcmpPacketHeader self;
self.type = buffer[0];
self.code = buffer[1];
self.checksum = buffer[2] << 8 | buffer[3];
return self;
}
} __attribute__((packed)); } __attribute__((packed));
@ -29,10 +46,15 @@ struct IcmpPacket
IcmpPacketHeader header; IcmpPacketHeader header;
T payload; T payload;
IcmpPacket() {}
IcmpPacket(std::uint8_t type, std::uint8_t code) :
header(type, code)
{}
IcmpPacket(std::uint8_t type, std::uint8_t code, T payload) : IcmpPacket(std::uint8_t type, std::uint8_t code, T payload) :
header(type, code), payload(payload) header(type, code), payload(payload)
{ {}
}
std::size_t Serialize(uint8_t* buffer) std::size_t Serialize(uint8_t* buffer)
{ {
@ -48,15 +70,25 @@ struct IcmpPacket
return i; return i;
} }
static IcmpPacket<T> Deserialize(const uint8_t* buffer)
{
IcmpPacket<T> self;
self.header = IcmpPacketHeader::Deserialize(buffer);
self.payload = T::Deserialize(buffer + sizeof(IcmpPacketHeader));
return self;
}
} __attribute__((packed)); } __attribute__((packed));
template <class T> template <class T>
struct IcmpEchoRequest struct IcmpEchoRequest
{ {
uint16_t identifier; uint16_t identifier;
uint16_t sequenceNumber; uint16_t sequenceNumber;
T data; T data;
IcmpEchoRequest() {}
IcmpEchoRequest(T data) : identifier(0), sequenceNumber(0), data(data) IcmpEchoRequest(T data) : identifier(0), sequenceNumber(0), data(data)
{} {}
@ -73,4 +105,77 @@ struct IcmpEchoRequest
return i; return i;
} }
static IcmpEchoRequest<T> Deserialize(const uint8_t* buffer)
{
IcmpEchoRequest self;
self.identifier = buffer[0] << 8 | buffer[1];
self.sequenceNumber = buffer[2] << 8 | buffer[3];
memcpy(self.data, buffer + 4, sizeof(T));
return self;
}
} __attribute__((packed));
template <>
struct IcmpEchoRequest<void>
{
uint16_t identifier;
uint16_t sequenceNumber;
IcmpEchoRequest() : identifier(0), sequenceNumber(0)
{}
size_t Serialize(uint8_t* buffer)
{
size_t i = 0;
buffer[i++] = identifier >> 8;
buffer[i++] = identifier;
buffer[i++] = sequenceNumber >> 8;
buffer[i++] = sequenceNumber;
return i;
}
static IcmpEchoRequest Deserialize(const uint8_t* buffer)
{
IcmpEchoRequest self;
self.identifier = buffer[0] << 8 | buffer[1];
self.sequenceNumber = buffer[2] << 8 | buffer[3];
return self;
}
} __attribute__((packed));
template <class T>
struct IcmpEchoResponse
{
uint16_t identifier;
uint16_t sequenceNumber;
T data;
IcmpEchoResponse() {}
IcmpEchoResponse(T data) : identifier(0), sequenceNumber(0), data(data)
{}
size_t Serialize(uint8_t* buffer)
{
size_t i = 0;
buffer[i++] = identifier >> 8;
buffer[i++] = identifier;
buffer[i++] = sequenceNumber >> 8;
buffer[i++] = sequenceNumber;
memcpy(buffer + i, &data, sizeof(T));
i += sizeof(T);
return i;
}
static IcmpEchoResponse<T> Deserialize(const uint8_t* buffer)
{
IcmpEchoResponse self;
self.identifier = buffer[0] << 8 | buffer[1];
self.sequenceNumber = buffer[2] << 8 | buffer[3];
memcpy(self.data, buffer + 4, sizeof(T));
return self;
}
} __attribute__((packed)); } __attribute__((packed));

View file

@ -1,6 +1,11 @@
#pragma once #pragma once
#include "net.h" #include "net.h"
enum IpProtocols
{
IP_PROTO_ICMP = 1,
};
struct Ipv4Header struct Ipv4Header
{ {
unsigned int version : 4; unsigned int version : 4;
@ -17,6 +22,8 @@ struct Ipv4Header
uint32_t sourceIp; uint32_t sourceIp;
uint32_t destinationIp; uint32_t destinationIp;
Ipv4Header() {}
Ipv4Header( Ipv4Header(
uint8_t protocol, uint32_t sourceIp, uint32_t destinationIp, uint16_t totalLength uint8_t protocol, uint32_t sourceIp, uint32_t destinationIp, uint16_t totalLength
) : ) :
@ -70,6 +77,31 @@ struct Ipv4Header
return i; return i;
} }
static Ipv4Header Deserialize(const uint8_t* buffer)
{
Ipv4Header self;
self.version = buffer[0] >> 4;
self.ihl = buffer[0] & 0x0F;
self.dscp = buffer[1] >> 2;
self.ecn = buffer[1] & 0x03;
self.totalLength = buffer[2] << 8 | buffer[3];
self.identification = buffer[4] << 8 | buffer[5];
self.flags = buffer[6] >> 5;
self.fragmentOffset = (buffer[6] & 0x1F) << 8 | buffer[7];
self.ttl = buffer[8];
self.protocol = buffer[9];
self.headerChecksum = buffer[10] << 8 | buffer[11];
self.sourceIp = buffer[12] << 24 | buffer[13] << 16 | buffer[14] << 8 | buffer[15];
self.destinationIp = buffer[16] << 24 | buffer[17] << 16 | buffer[18] << 8 | buffer[19];
return self;
}
} __attribute__((packed)); } __attribute__((packed));
template<class T> template<class T>
@ -78,6 +110,8 @@ struct Ipv4Packet
Ipv4Header header; Ipv4Header header;
T payload; T payload;
Ipv4Packet() {}
Ipv4Packet(uint8_t protocol, uint32_t sourceIp, uint32_t destinationIp, T payload) : Ipv4Packet(uint8_t protocol, uint32_t sourceIp, uint32_t destinationIp, T payload) :
header(protocol, sourceIp, destinationIp, sizeof(Ipv4Packet<T>)), header(protocol, sourceIp, destinationIp, sizeof(Ipv4Packet<T>)),
payload(payload) payload(payload)
@ -91,4 +125,13 @@ struct Ipv4Packet
i += payload.Serialize(buffer + i); i += payload.Serialize(buffer + i);
return i; return i;
} }
static Ipv4Packet<T> Deserialize(const uint8_t* buffer)
{
Ipv4Packet<T> self;
self.header = Ipv4Header::Deserialize(buffer);
self.payload = T::Deserialize(buffer + sizeof(Ipv4Header));
return self;
}
} __attribute__((packed)); } __attribute__((packed));

View file

@ -7,8 +7,6 @@
#include "types.h" #include "types.h"
#include <uspi.h> #include <uspi.h>
const uint32_t Ipv4Address = 0x0A00000B;
// //
// ARP // ARP
// //
@ -57,7 +55,6 @@ void SendArpAnnouncement(MacAddress mac, uint32_t ip)
void HandleArpFrame(uint8_t* buffer) void HandleArpFrame(uint8_t* buffer)
{ {
const auto macAddress = GetMacAddress(); const auto macAddress = GetMacAddress();
const auto ipAddress = 0x0A00000B;
const auto frame = EthernetFrame<Ipv4ArpPacket>::Deserialize(buffer); const auto frame = EthernetFrame<Ipv4ArpPacket>::Deserialize(buffer);
const auto arp = frame.payload; const auto arp = frame.payload;
@ -65,20 +62,40 @@ void HandleArpFrame(uint8_t* buffer)
if (arp.hardwareType == 1 && if (arp.hardwareType == 1 &&
arp.protocolType == ETHERTYPE_IPV4 && arp.protocolType == ETHERTYPE_IPV4 &&
arp.operation == ARP_OPERATION_REQUEST && arp.operation == ARP_OPERATION_REQUEST &&
arp.targetIp == ipAddress) arp.targetIp == Ipv4Address)
{ {
SendArpReply(arp.senderMac, macAddress, arp.senderIp, ipAddress); SendArpReply(arp.senderMac, macAddress, arp.senderIp, Ipv4Address);
} }
else if (arp.hardwareType == 1 && else if (arp.hardwareType == 1 &&
arp.protocolType == ETHERTYPE_IPV4 && arp.protocolType == ETHERTYPE_IPV4 &&
arp.operation == ARP_OPERATION_REPLY && arp.operation == ARP_OPERATION_REPLY &&
arp.targetIp == ipAddress && arp.targetIp == Ipv4Address &&
arp.targetMac == macAddress) arp.targetMac == macAddress)
{ {
ArpTable.insert(std::make_pair(arp.senderIp, arp.senderMac)); ArpTable.insert(std::make_pair(arp.senderIp, arp.senderMac));
} }
} }
//
// IPv4
//
uint64_t HandleIpv4Frame(const uint8_t* buffer)
{
const auto frame = EthernetFrame<Ipv4Header>::Deserialize(buffer);
const auto header = frame.payload;
if (header.version != 4) return 0x4;
if (header.ihl != 5) return 0x8; // Not supported
if (header.destinationIp != Ipv4Address) return 0x10 | std::uint64_t{header.destinationIp} << 32;
if (header.fragmentOffset != 0) return 0x20; // TODO Support this
if (header.protocol == IP_PROTO_ICMP)
{
return HandleIcmpFrame(buffer) | 0x2;
}
return 0x0;
}
// //
// ICMP // ICMP
@ -98,6 +115,51 @@ void SendIcmpEchoRequest(MacAddress mac, uint32_t ip)
USPiSendFrame(buffer, size); USPiSendFrame(buffer, size);
} }
uint64_t HandleIcmpFrame(const uint8_t* buffer)
{
const auto frame = EthernetFrame<Ipv4Packet<IcmpPacketHeader>>::Deserialize(buffer);
const auto packetHeader = frame.payload.payload;
if (packetHeader.type == ICMP_ECHO_REQUEST)
{
// TODO This should not be hardcoded lol
typedef EthernetFrame<Ipv4Packet<IcmpPacket<IcmpEchoRequest<uint8_t[56]>>>> Frame;
auto frameReq = Frame::Deserialize(buffer);
auto echoReq = frameReq.payload.payload.payload;
IcmpEchoResponse<uint8_t[56]> echoResp;
echoResp.identifier = echoReq.identifier;
echoResp.sequenceNumber = echoReq.sequenceNumber;
memcpy(echoResp.data, echoReq.data, 56);
const auto sourceIp = frame.payload.header.sourceIp;
IcmpPacket<decltype(echoResp)> icmpResp(ICMP_ECHO_REPLY, 0, echoResp);
Ipv4Packet<decltype(icmpResp)> ipv4Resp(
IP_PROTO_ICMP,
Ipv4Address,
sourceIp,
icmpResp
);
EthernetFrame<decltype(ipv4Resp)> frameResp(
frame.header.macSource,
GetMacAddress(),
ETHERTYPE_IPV4,
ipv4Resp
);
uint8_t bufferResp[USPI_FRAME_BUFFER_SIZE];
const auto size = frameResp.Serialize(bufferResp);
USPiSendFrame(bufferResp, size);
return 0x1;
}
return 0x0 | std::uint64_t{packetHeader.type} << 32;
}
// //
// Helpers // Helpers
// //
@ -213,5 +275,7 @@ MacAddress GetMacAddress()
return macAddress; return macAddress;
} }
MacAddress MacBroadcast{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; const uint32_t Ipv4Address = 0xC0A80164;
const MacAddress MacBroadcast{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
std::unordered_map<std::uint32_t, MacAddress> ArpTable; std::unordered_map<std::uint32_t, MacAddress> ArpTable;

View file

@ -15,10 +15,9 @@ enum ArpOperation {
ARP_OPERATION_REPLY = 2, ARP_OPERATION_REPLY = 2,
}; };
typedef std::array<std::uint8_t, 6> MacAddress; typedef std::array<uint8_t, 6> MacAddress;
void HandleArpFrame(uint8_t* buffer);
void HandleArpFrame(std::uint8_t* buffer);
void SendArpPacket(ArpOperation operation, void SendArpPacket(ArpOperation operation,
MacAddress targetMac, MacAddress targetMac,
MacAddress senderMac, MacAddress senderMac,
@ -34,13 +33,18 @@ void SendArpReply(MacAddress targetMac,
uint32_t targetIp); uint32_t targetIp);
void SendArpAnnouncement(MacAddress mac, uint32_t ip); void SendArpAnnouncement(MacAddress mac, uint32_t ip);
uint64_t HandleIpv4Frame(const uint8_t* buffer);
void SendIcmpEchoRequest(MacAddress mac, uint32_t ip); void SendIcmpEchoRequest(MacAddress mac, uint32_t ip);
uint64_t HandleIcmpFrame(const uint8_t* buffer);
std::uint32_t Crc32(const std::uint8_t* buffer, std::size_t size); std::uint32_t Crc32(const std::uint8_t* buffer, std::size_t size);
std::uint16_t InternetChecksum(const void* data, std::size_t size); std::uint16_t InternetChecksum(const void* data, std::size_t size);
MacAddress GetMacAddress(); MacAddress GetMacAddress();
extern MacAddress MacBroadcast; extern const MacAddress MacBroadcast;
extern const uint32_t Ipv4Address;
extern std::unordered_map<std::uint32_t, MacAddress> ArpTable; extern std::unordered_map<std::uint32_t, MacAddress> ArpTable;
struct UdpDatagramHeader struct UdpDatagramHeader