From c736a9838b5523608cb0c0120fb3d3f9c463e4a7 Mon Sep 17 00:00:00 2001 From: Baptiste Wicht Date: Sun, 10 Jul 2016 17:27:12 +0200 Subject: [PATCH] Basic IP decoding --- kernel/include/ip_layer.hpp | 22 ++++++++++++++ kernel/src/ethernet_layer.cpp | 3 +- kernel/src/ip_layer.cpp | 54 +++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 kernel/src/ip_layer.cpp diff --git a/kernel/include/ip_layer.hpp b/kernel/include/ip_layer.hpp index 171a637a..70d635c6 100644 --- a/kernel/include/ip_layer.hpp +++ b/kernel/include/ip_layer.hpp @@ -10,6 +10,8 @@ #include +#include "network.hpp" + namespace network { namespace ip { @@ -19,6 +21,9 @@ namespace ip { struct address { uint32_t raw_address = 0; + address(){} + address(uint32_t raw) : raw_address(raw) {} + uint8_t operator()(size_t index) const { return (raw_address >> ((3 - index) * 8)) & 0xFF; } @@ -41,6 +46,23 @@ inline address make_address(uint8_t a, uint8_t b, uint8_t c, uint8_t d){ return addr; } +struct header { + uint8_t version_ihl; + uint8_t dscp_ecn; + uint16_t total_len; + uint16_t identification; + uint16_t flags_offset; + uint8_t ttl; + uint8_t protocol; + uint16_t header_checksum; + uint32_t source_ip; + uint32_t target_ip; +} __attribute__((packed)); + +static_assert(sizeof(header) == 20, "The size of an IPv4 header must be 20 bytes"); + +void decode(network::interface_descriptor& interface, network::ethernet::packet& packet); + } // end of ip namespace } // end of network namespace diff --git a/kernel/src/ethernet_layer.cpp b/kernel/src/ethernet_layer.cpp index a90b92b3..b38076c0 100644 --- a/kernel/src/ethernet_layer.cpp +++ b/kernel/src/ethernet_layer.cpp @@ -12,6 +12,7 @@ #include "logging.hpp" #include "kernel_utils.hpp" #include "arp_layer.hpp" +#include "ip_layer.hpp" namespace { @@ -70,7 +71,7 @@ void network::ethernet::decode(network::interface_descriptor& interface, packet& switch(packet.type){ case ether_type::IPV4: - logging::logf(logging::log_level::TRACE, "ethernet: IPV4 Packet (unsupported)\n"); + network::ip::decode(interface, packet); break; case ether_type::IPV6: logging::logf(logging::log_level::TRACE, "ethernet: IPV6 Packet (unsupported)\n"); diff --git a/kernel/src/ip_layer.cpp b/kernel/src/ip_layer.cpp new file mode 100644 index 00000000..b458a5cb --- /dev/null +++ b/kernel/src/ip_layer.cpp @@ -0,0 +1,54 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013-2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#include +#include + +#include "ip_layer.hpp" +#include "logging.hpp" +#include "kernel_utils.hpp" + +void network::ip::decode(network::interface_descriptor& interface, network::ethernet::packet& packet){ + header* arp_header = reinterpret_cast(packet.payload + packet.index); + + logging::logf(logging::log_level::TRACE, "ip: Start IPv4 packet handling\n"); + + auto version = arp_header->version_ihl >> 4; + + if(version != 4){ + logging::logf(logging::log_level::ERROR, "ip: IPv6 Packet received instead of IPv4\n"); + + return; + } + + auto ihl = arp_header->version_ihl & 0xF; + auto length = switch_endian_16(arp_header->total_len); + auto data_length = length - ihl * 4; + + logging::logf(logging::log_level::TRACE, "ip: Data Length: %u\n", size_t(data_length)); + logging::logf(logging::log_level::TRACE, "ip: Time To Live: %u\n", size_t(arp_header->ttl)); + + network::ip::address source(switch_endian_32(arp_header->source_ip)); + network::ip::address target(switch_endian_32(arp_header->target_ip)); + + logging::logf(logging::log_level::TRACE, "ip: Source Protocol Address %u.%u.%u.%u \n", + uint64_t(source(0)), uint64_t(source(1)), uint64_t(source(2)), uint64_t(source(3))); + logging::logf(logging::log_level::TRACE, "ip: Target Protocol Address %u.%u.%u.%u \n", + uint64_t(target(0)), uint64_t(target(1)), uint64_t(target(2)), uint64_t(target(3))); + + auto protocol = arp_header->protocol; + + if(protocol == 0x01){ + logging::logf(logging::log_level::DEBUG, "ip: ICMP packet detected\n"); + } else if(protocol == 0x06){ + logging::logf(logging::log_level::ERROR, "ip: TCP packet detected (unsupported)\n"); + } else if(protocol == 0x11){ + logging::logf(logging::log_level::ERROR, "ip: UDP packet detected (unsupported)\n"); + } else { + logging::logf(logging::log_level::ERROR, "ip: Packet of unknown protocol detected (%h)\n", size_t(protocol)); + } +}