Cybersecurity-Projects/PROJECTS/beginner/network-traffic-analyzer/cpp/src/packet/IP.cpp

181 lines
4.9 KiB
C++

#include "../../include/packet/IP.hpp"
#include <arpa/inet.h>
#include <array>
#include <cstdio>
#include <netinet/icmp6.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <stdexcept>
uint16_t IP_class::get_payload_len() const { return payload_len; }
TransportProtocol IP_class::get_protocol() const { return protocol; }
std::string IP_class::get_source() { return src; }
std::string IP_class::get_dest() { return dst; }
/*** Ipv4 ***/
IPv4::IPv4(const u_char *data)
: ip_hdr(reinterpret_cast<const ip *>(data)),
ip_hdr_len(static_cast<int>(ip_hdr->ip_hl) * 4) {
std::array<char, INET_ADDRSTRLEN> src_buf{};
inet_ntop(AF_INET, &ip_hdr->ip_src, src_buf.data(), sizeof(src_buf));
src = src_buf.data();
std::array<char, INET_ADDRSTRLEN> dst_buf{};
inet_ntop(AF_INET, &ip_hdr->ip_dst, dst_buf.data(), sizeof(dst_buf));
dst = dst_buf.data();
if (ip_hdr_len < 20) {
throw std::runtime_error("Failed to initial IPv4 ");
}
switch (ip_hdr->ip_p) {
case IPPROTO_TCP:
IPv4::handle_tcp();
break;
case IPPROTO_UDP:
IPv4::handle_udp();
break;
case IPPROTO_ICMP:
IPv4::handle_icmp();
break;
case IPPROTO_ICMPV6:
IPv4::handle_icmpv6();
break;
case IPPROTO_IGMP:
IPv4::handle_igmp();
break;
default:
protocol = TransportProtocol::UNKNOWN;
break;
}
}
void IPv4::handle_tcp() {
const auto *tcp = reinterpret_cast<const tcphdr *>(reinterpret_cast<const u_char *>(ip_hdr) + ip_hdr_len);
src_port = ntohs(tcp->source);
dest_port = ntohs(tcp->dest);
const auto tcp_hdr_len = static_cast<std::size_t>(tcp->doff) * 4U;
payload_ptr = reinterpret_cast<const u_char *>(tcp) + tcp_hdr_len;
payload_len = static_cast<uint16_t>(ntohs(ip_hdr->ip_len) - ip_hdr_len - static_cast<int>(tcp_hdr_len));
protocol = TransportProtocol::TCP;
}
void IPv4::handle_udp() {
const auto *udp = reinterpret_cast<const udphdr *>(reinterpret_cast<const u_char *>(ip_hdr) + ip_hdr_len);
dest_port = ntohs(udp->dest);
src_port = ntohs(udp->source);
payload_ptr = reinterpret_cast<const u_char *>(udp) + sizeof(udphdr);
payload_len = ntohs(udp->len) - sizeof(udphdr);
protocol = TransportProtocol::UDP;
}
void IPv4::handle_icmp() { protocol = TransportProtocol::ICMP; }
void IPv4::handle_icmpv6() { protocol = TransportProtocol::ICMP6; }
void IPv4::handle_igmp() { protocol = TransportProtocol::IGMP; }
uint16_t IPv4::get_src_port() { return src_port; }
uint16_t IPv4::get_dest_port() { return dest_port; }
/*** Ipv6 ***/
IPv6::IPv6(const u_char *data)
: ip_hdr(reinterpret_cast<const ip6_hdr *>(data)),
ptr(reinterpret_cast<const uint8_t *>(ip_hdr + 1)) {
uint8_t hdr = ip_hdr->ip6_nxt;
std::array<char, INET6_ADDRSTRLEN> src{};
inet_ntop(AF_INET6, &ip_hdr->ip6_src, src.data(), sizeof(src));
this->src = src.data();
std::array<char, INET6_ADDRSTRLEN> dst{};
inet_ntop(AF_INET6, &ip_hdr->ip6_dst, dst.data(), sizeof(dst));
this->dst = dst.data();
while (true) {
switch (hdr) {
case IPPROTO_TCP:
IPv6::handle_tcp();
return;
case IPPROTO_UDP:
IPv6::handle_udp();
return;
case IPPROTO_ICMP:
IPv6::handle_icmp();
return;
case IPPROTO_ICMPV6:
IPv6::handle_icmpv6();
return;
case IPPROTO_IGMP:
IPv6::handle_igmp();
return;
/* if we have an extension headers, dont leave from loop,
* keep find a protocol type
*/
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS: {
const auto *ext = reinterpret_cast<const ip6_ext *>(ptr);
hdr = ext->ip6e_nxt;
ptr += (static_cast<std::size_t>(ext->ip6e_len) + 1U) * 8U;
break;
}
case IPPROTO_FRAGMENT: {
const auto *frag = reinterpret_cast<const ip6_frag *>(ptr);
hdr = frag->ip6f_nxt;
ptr += sizeof(ip6_frag);
break;
}
default:
protocol = TransportProtocol::UNKNOWN;
return;
}
}
ptr = nullptr;
}
void IPv6::handle_tcp() {
const auto *const tcp = reinterpret_cast<const tcphdr *>(ptr);
dest_port = ntohs(tcp->dest);
src_port = ntohs(tcp->source);
const auto tcp_hdr_len = static_cast<std::size_t>(tcp->doff) * 4U;
payload_ptr = reinterpret_cast<const uint8_t *>(tcp) + tcp_hdr_len;
payload_len = static_cast<uint16_t>(ntohs(ip_hdr->ip6_plen) - static_cast<uint16_t>(tcp_hdr_len));
protocol = TransportProtocol::TCP;
ptr = nullptr;
}
void IPv6::handle_udp() {
const auto *const udp = reinterpret_cast<const udphdr *>(ptr);
dest_port = ntohs(udp->dest);
src_port = ntohs(udp->source);
payload_ptr = reinterpret_cast<const uint8_t *>(udp) + sizeof(udphdr);
payload_len = ntohs(udp->len) - sizeof(udphdr);
protocol = TransportProtocol::UDP;
ptr = nullptr;
}
void IPv6::handle_icmp() {
protocol = TransportProtocol::ICMP;
ptr = nullptr;
}
void IPv6::handle_icmpv6() {
protocol = TransportProtocol::ICMP6;
payload_len = ntohs(ip_hdr->ip6_plen) - sizeof(icmp6_hdr);
ptr = nullptr;
}
void IPv6::handle_igmp() {
protocol = TransportProtocol::IGMP;
ptr = nullptr;
}
uint16_t IPv6::get_src_port() { return src_port; }
uint16_t IPv6::get_dest_port() { return dest_port; }