Kernel: Clean up and sanitize incoming packet handling a bit more

Once we've converted from an Ethernet frame to an IPv4 packet, we can
pass the IPv4Packet around instead of the EthernetFrameHeader.

Also add some more code to ignore invalid-looking packets.
This commit is contained in:
Andreas Kling 2019-08-09 10:42:01 +02:00
parent f9de264f88
commit 7e309e27dd
Notes: sideshowbarker 2024-07-19 12:48:07 +09:00

View file

@ -20,11 +20,11 @@
//#define UDP_DEBUG
//#define TCP_DEBUG
static void handle_arp(const EthernetFrameHeader&, int frame_size);
static void handle_ipv4(const EthernetFrameHeader&, int frame_size);
static void handle_icmp(const EthernetFrameHeader&, int frame_size);
static void handle_udp(const EthernetFrameHeader&, int frame_size);
static void handle_tcp(const EthernetFrameHeader&, int frame_size);
static void handle_arp(const EthernetFrameHeader&, size_t frame_size);
static void handle_ipv4(const EthernetFrameHeader&, size_t frame_size);
static void handle_icmp(const EthernetFrameHeader&, const IPv4Packet&);
static void handle_udp(const IPv4Packet&);
static void handle_tcp(const IPv4Packet&);
Lockable<HashMap<IPv4Address, MACAddress>>& arp_table()
{
@ -118,9 +118,9 @@ void NetworkTask_main()
}
}
void handle_arp(const EthernetFrameHeader& eth, int frame_size)
void handle_arp(const EthernetFrameHeader& eth, size_t frame_size)
{
constexpr int minimum_arp_frame_size = sizeof(EthernetFrameHeader) + sizeof(ARPPacket);
constexpr size_t minimum_arp_frame_size = sizeof(EthernetFrameHeader) + sizeof(ARPPacket);
if (frame_size < minimum_arp_frame_size) {
kprintf("handle_arp: Frame too small (%d, need %d)\n", frame_size, minimum_arp_frame_size);
return;
@ -180,9 +180,9 @@ void handle_arp(const EthernetFrameHeader& eth, int frame_size)
}
}
void handle_ipv4(const EthernetFrameHeader& eth, int frame_size)
void handle_ipv4(const EthernetFrameHeader& eth, size_t frame_size)
{
constexpr int minimum_ipv4_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet);
constexpr size_t minimum_ipv4_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv4Packet);
if (frame_size < minimum_ipv4_frame_size) {
kprintf("handle_ipv4: Frame too small (%d, need %d)\n", frame_size, minimum_ipv4_frame_size);
return;
@ -208,21 +208,19 @@ void handle_ipv4(const EthernetFrameHeader& eth, int frame_size)
switch ((IPv4Protocol)packet.protocol()) {
case IPv4Protocol::ICMP:
return handle_icmp(eth, frame_size);
return handle_icmp(eth, packet);
case IPv4Protocol::UDP:
return handle_udp(eth, frame_size);
return handle_udp(packet);
case IPv4Protocol::TCP:
return handle_tcp(eth, frame_size);
return handle_tcp(packet);
default:
kprintf("handle_ipv4: Unhandled protocol %u\n", packet.protocol());
break;
}
}
void handle_icmp(const EthernetFrameHeader& eth, int frame_size)
void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet)
{
(void)frame_size;
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
auto& icmp_header = *static_cast<const ICMPHeader*>(ipv4_packet.payload());
#ifdef ICMP_DEBUG
kprintf("handle_icmp: source=%s, destination=%s, type=%b, code=%b\n",
@ -266,10 +264,12 @@ void handle_icmp(const EthernetFrameHeader& eth, int frame_size)
}
}
void handle_udp(const EthernetFrameHeader& eth, int frame_size)
void handle_udp(const IPv4Packet& ipv4_packet)
{
(void)frame_size;
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
if (ipv4_packet.payload_size() < sizeof(UDPPacket)) {
kprintf("handle_udp: Packet too small (%u, need %zu)\n", ipv4_packet.payload_size());
return;
}
auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
if (!adapter) {
@ -298,18 +298,26 @@ void handle_udp(const EthernetFrameHeader& eth, int frame_size)
socket->did_receive(ipv4_packet.source(), udp_packet.source_port(), KBuffer::copy(&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
}
void handle_tcp(const EthernetFrameHeader& eth, int frame_size)
void handle_tcp(const IPv4Packet& ipv4_packet)
{
(void)frame_size;
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
if (!adapter) {
kprintf("handle_tcp: this packet is not for me, it's for %s\n", ipv4_packet.destination().to_string().characters());
if (ipv4_packet.payload_size() < sizeof(TCPPacket)) {
kprintf("handle_tcp: IPv4 payload is too small to be a TCP packet (%u, need %zu)\n", ipv4_packet.payload_size(), sizeof(TCPPacket));
return;
}
auto& tcp_packet = *static_cast<const TCPPacket*>(ipv4_packet.payload());
size_t minimum_tcp_header_size = 5 * sizeof(u32);
size_t maximum_tcp_header_size = 15 * sizeof(u32);
if (tcp_packet.header_size() < minimum_tcp_header_size || tcp_packet.header_size() > maximum_tcp_header_size) {
kprintf("handle_tcp: TCP packet header has invalid size %zu\n", tcp_packet.header_size());
}
if (ipv4_packet.payload_size() < tcp_packet.header_size()) {
kprintf("handle_tcp: IPv4 payload is smaller than TCP header claims (%u, supposedly %u)\n", ipv4_packet.payload_size(), tcp_packet.header_size());
return;
}
size_t payload_size = ipv4_packet.payload_size() - tcp_packet.header_size();
#ifdef TCP_DEBUG
@ -329,6 +337,12 @@ void handle_tcp(const EthernetFrameHeader& eth, int frame_size)
payload_size);
#endif
auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
if (!adapter) {
kprintf("handle_tcp: this packet is not for me, it's for %s\n", ipv4_packet.destination().to_string().characters());
return;
}
IPv4SocketTuple tuple(ipv4_packet.destination(), tcp_packet.destination_port(), ipv4_packet.source(), tcp_packet.source_port());
#ifdef TCP_DEBUG