diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a58d8b..1950770 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,5 +25,4 @@ file(GLOB_RECURSE 1261nat_src_files "src/*.h" "src/*.cpp") add_executable(1261nat ${1261nat_src_files} ) target_link_libraries (1261nat tins) - ADD_SUBDIRECTORY(test) diff --git a/src/Icmp4ToIcmp6PacketHandler.cpp b/src/Icmp4ToIcmp6PacketHandler.cpp index d73fdb1..cb52654 100644 --- a/src/Icmp4ToIcmp6PacketHandler.cpp +++ b/src/Icmp4ToIcmp6PacketHandler.cpp @@ -29,15 +29,18 @@ bool Icmp4ToIcmp6PacketHandler::handle(IN const Tins::PDU & pdu, IN IPacketHandl // create icmp6 pdu const Tins::ICMP::Flags type = icmpv4Pdu->type(); std::unique_ptr icmpv6Pdu; - switch (type) { - case Tins::ICMP::Flags::ECHO_REPLY: - icmpv6Pdu = std::make_unique(Tins::ICMPv6::ECHO_REQUEST); - break; - case Tins::ICMP::Flags::ECHO_REQUEST: - icmpv6Pdu = std::make_unique(Tins::ICMPv6::ECHO_REPLY); - break; - default: - return false; + switch (type) + { + case Tins::ICMP::Flags::ECHO_REPLY: + icmpv6Pdu = std::make_unique(Tins::ICMPv6::ECHO_REPLY); + break; + + case Tins::ICMP::Flags::ECHO_REQUEST: + icmpv6Pdu = std::make_unique(Tins::ICMPv6::ECHO_REQUEST); + break; + + default: + return false; } icmpv6Pdu->identifier(icmpv4Pdu->id()); @@ -45,13 +48,13 @@ bool Icmp4ToIcmp6PacketHandler::handle(IN const Tins::PDU & pdu, IN IPacketHandl icmpv6Pdu->code(0); // replace icmp4 with icmp6 content, adress translation will bo den by Ip4ToIp6PacketHandler - const Tins::IP * ipPdu = pdu.find_pdu(); + Tins::PDU * clonePdu = pdu.clone(); + Tins::IP * ipPdu = clonePdu->find_pdu(); if(ipPdu == nullptr) { return false; } - Tins::IP * cloneIpPdu = ipPdu->clone(); - cloneIpPdu->inner_pdu(*icmpv6Pdu); - return Ip4ToIp6PacketHandler::handle(*cloneIpPdu, callBackHandler); + ipPdu->inner_pdu(*icmpv6Pdu); + return Ip4ToIp6PacketHandler::handle(*clonePdu, callBackHandler); } diff --git a/src/Icmp6ToIcmp4PacketHandler.cpp b/src/Icmp6ToIcmp4PacketHandler.cpp index af2500c..8162a94 100644 --- a/src/Icmp6ToIcmp4PacketHandler.cpp +++ b/src/Icmp6ToIcmp4PacketHandler.cpp @@ -31,18 +31,22 @@ bool Icmp6ToIcmp4PacketHandler::handle(IN const Tins::PDU & pdu, IN IPacketHandl // create icmp6 pdu const Tins::ICMPv6::Types type = icmpv6Pdu->type(); std::unique_ptr icmpv4Pdu; - switch (type) { - case Tins::ICMPv6::ECHO_REPLY: - icmpv4Pdu = std::make_unique(Tins::ICMP::Flags::ECHO_REQUEST); - break; - case Tins::ICMPv6::ECHO_REQUEST: - icmpv4Pdu = std::make_unique(Tins::ICMP::Flags::ECHO_REPLY); - break; - case Tins::ICMPv6::NEIGHBOUR_SOLICIT: - case Tins::ICMPv6::NEIGHBOUR_ADVERT: - return ndpToArpHandler->handle(pdu, callBackHandler); - default: - return false; + switch (type) + { + case Tins::ICMPv6::ECHO_REPLY: + icmpv4Pdu = std::make_unique(Tins::ICMP::Flags::ECHO_REPLY); + break; + + case Tins::ICMPv6::ECHO_REQUEST: + icmpv4Pdu = std::make_unique(Tins::ICMP::Flags::ECHO_REQUEST); + break; + + case Tins::ICMPv6::NEIGHBOUR_SOLICIT: + case Tins::ICMPv6::NEIGHBOUR_ADVERT: + return ndpToArpHandler->handle(pdu, callBackHandler); + + default: + return false; } icmpv4Pdu->id(icmpv6Pdu->identifier()); @@ -50,13 +54,13 @@ bool Icmp6ToIcmp4PacketHandler::handle(IN const Tins::PDU & pdu, IN IPacketHandl icmpv4Pdu->code(0); // replace icmp4 with icmp6 content, adress translation will bo den by Ip4ToIp6PacketHandler - const Tins::IPv6 * ipv6Pdu = pdu.find_pdu(); + Tins::PDU * clonePdu = pdu.clone(); + Tins::IPv6 * ipv6Pdu = clonePdu->find_pdu(); if(ipv6Pdu == nullptr) { return false; } - Tins::IPv6 * cloneIpv6Pdu = ipv6Pdu->clone(); - cloneIpv6Pdu->inner_pdu(*icmpv4Pdu); - return Ip6ToIp4PacketHandler::handle(*cloneIpv6Pdu, callBackHandler); + ipv6Pdu->inner_pdu(*icmpv4Pdu); + return Ip6ToIp4PacketHandler::handle(*clonePdu, callBackHandler); } diff --git a/test/src/TestIcmp4ToIcmp6PacketHandler.cpp b/test/src/TestIcmp4ToIcmp6PacketHandler.cpp new file mode 100644 index 0000000..342ae2c --- /dev/null +++ b/test/src/TestIcmp4ToIcmp6PacketHandler.cpp @@ -0,0 +1,93 @@ +#include "fakeit.hpp" +#include "tins/ethernetII.h" +#include +#include +#include +#include +#include +#include +#include +#include "Icmp4ToIcmp6PacketHandler.h" +#include "IpAddressTranslator.h" +using namespace fakeit; + + +namespace TestIcmp4ToIcmp6PacketHandler +{ + Tins::PDU * currentInputPdu = nullptr; + + void compareToInputPdu(const Tins::PDU & answerPdu) + { + REQUIRE(currentInputPdu != nullptr); + REQUIRE(answerPdu.find_pdu() == nullptr); + + const Tins::IPv6 * ip6 = answerPdu.find_pdu(); + const Tins::IP * ip = currentInputPdu->find_pdu(); + REQUIRE(ip != nullptr); + REQUIRE(ip6 != nullptr); + REQUIRE(ip->src_addr() == Tins::IPv4Address(IpAddressTranslator::toIpv4AddressBytes(ip6->src_addr()))); + REQUIRE(ip->dst_addr() == Tins::IPv4Address(IpAddressTranslator::toIpv4AddressBytes(ip6->dst_addr()))); + REQUIRE(answerPdu.inner_pdu() != nullptr); + + const Tins::ICMPv6 * icmp6 = answerPdu.find_pdu(); + const Tins::ICMP * icmp = currentInputPdu->find_pdu(); + REQUIRE(icmp != nullptr); + REQUIRE(icmp6 != nullptr); + + REQUIRE(icmp->id() == icmp6->identifier()); + REQUIRE(icmp6->sequence() == icmp->sequence()); + const Tins::ICMP::Flags type = icmp->type(); + switch (type) { + case Tins::ICMP::Flags::ECHO_REPLY: + REQUIRE(icmp6->type() == Tins::ICMPv6::ECHO_REPLY); + break; + case Tins::ICMP::Flags::ECHO_REQUEST: + REQUIRE(icmp6->type() == Tins::ICMPv6::ECHO_REQUEST); + break; + } + + const Tins::EthernetII * currEth = currentInputPdu->find_pdu(); + if (currEth == nullptr) + { + return; + } + + const Tins::EthernetII * answerEth = answerPdu.find_pdu(); + REQUIRE(answerEth->src_addr() == currEth->src_addr()); + REQUIRE(answerEth->dst_addr() == currEth->dst_addr()); + } +} + +TEST_CASE( "test Icmp4ToIcmp6PacketHandler", "[Icmp4ToIcmp6PacketHandler]" ) { + Icmp4ToIcmp6PacketHandler handler("1::"); // tod fix prefix + Mock mockHandler; + When(Method(mockHandler, handle)).AlwaysDo([] (IN const Tins::PDU & pdu,...) + { + TestIcmp4ToIcmp6PacketHandler::compareToInputPdu(pdu); + return true; + }); + + Tins::EthernetII pkt = Tins::EthernetII() / Tins::IP() / Tins::TCP(); + TestIcmp4ToIcmp6PacketHandler::currentInputPdu = &pkt; + REQUIRE(handler.handle(pkt, nullptr) == false); + Verify(Method(mockHandler, handle)).Never(); + + REQUIRE(handler.handle(pkt, &mockHandler.get()) == false); + Verify(Method(mockHandler, handle)).Never(); + + Tins::ICMP echoRequest(Tins::ICMP::ECHO_REQUEST); + echoRequest.id(23); + echoRequest.sequence(42); + pkt = Tins::EthernetII("11:22:33:44:55:66", "66:55:44:33:22:11") / Tins::IP("1.2.3.4", "4.3.2.1") / echoRequest; + TestIcmp4ToIcmp6PacketHandler::currentInputPdu = &pkt; + REQUIRE(handler.handle(pkt, &mockHandler.get()) == true); + Verify(Method(mockHandler, handle)).Once(); + + Tins::ICMP echoReply(Tins::ICMP::ECHO_REPLY); + echoReply.id(24); + echoReply.sequence(45); + pkt = Tins::EthernetII("66:55:44:33:22:11", "11:22:33:44:55:66") / Tins::IP("4.3.2.1", "1.2.3.4") / echoReply; + TestIcmp4ToIcmp6PacketHandler::currentInputPdu = &pkt; + REQUIRE(handler.handle(pkt, &mockHandler.get()) == true); + Verify(Method(mockHandler, handle)).Twice(); +} diff --git a/test/src/TestIcmp6ToIcmp4PacketHandler.cpp b/test/src/TestIcmp6ToIcmp4PacketHandler.cpp new file mode 100644 index 0000000..72bbe28 --- /dev/null +++ b/test/src/TestIcmp6ToIcmp4PacketHandler.cpp @@ -0,0 +1,139 @@ +#include "fakeit.hpp" +#include "tins/arp.h" +#include "tins/ethernetII.h" +#include +#include +#include +#include +#include +#include +#include +#include "Icmp6ToIcmp4PacketHandler.h" +#include "IpAddressTranslator.h" +using namespace fakeit; + +namespace TestIcmp6ToIcmp4PacketHandler +{ + Tins::PDU * currentInputPdu = nullptr; + + void compareToInputPdu(const Tins::PDU & answerPdu) + { + REQUIRE(currentInputPdu != nullptr); + REQUIRE(answerPdu.find_pdu() == nullptr); + + const Tins::IP * ip = answerPdu.find_pdu(); + if (ip != nullptr) + { + const Tins::IPv6 * ip6 = currentInputPdu->find_pdu(); + REQUIRE(ip6 != nullptr); + REQUIRE(ip->src_addr() == Tins::IPv4Address(IpAddressTranslator::toIpv4AddressBytes(ip6->src_addr()))); + REQUIRE(ip->dst_addr() == Tins::IPv4Address(IpAddressTranslator::toIpv4AddressBytes(ip6->dst_addr()))); + REQUIRE(answerPdu.inner_pdu() != nullptr); + } + + const Tins::ICMPv6 * icmp6 = currentInputPdu->find_pdu(); + REQUIRE(icmp6 != nullptr); + + const Tins::ICMP * icmp = answerPdu.find_pdu(); + const Tins::ARP * arp = answerPdu.find_pdu(); + const Tins::ICMPv6::Types type = icmp6->type(); + switch (type) { + case Tins::ICMPv6::ECHO_REPLY: + REQUIRE(icmp != nullptr); + REQUIRE(icmp->id() == icmp6->identifier()); + REQUIRE(icmp6->sequence() == icmp->sequence()); + REQUIRE(icmp6->type() == Tins::ICMPv6::ECHO_REPLY); + break; + case Tins::ICMPv6::ECHO_REQUEST: + REQUIRE(icmp != nullptr); + REQUIRE(icmp->id() == icmp6->identifier()); + REQUIRE(icmp6->sequence() == icmp->sequence()); + REQUIRE(icmp6->type() == Tins::ICMPv6::ECHO_REQUEST); + break; + case Tins::ICMPv6::NEIGHBOUR_ADVERT: + REQUIRE(arp != nullptr); + REQUIRE(arp->opcode() == Tins::ARP::REPLY); + return; + case Tins::ICMPv6::NEIGHBOUR_SOLICIT: + REQUIRE(arp != nullptr); + REQUIRE(arp->opcode() == Tins::ARP::REQUEST); + return; + } + + const Tins::EthernetII * currEth = currentInputPdu->find_pdu(); + if (currEth == nullptr) + { + return; + } + + const Tins::EthernetII * answerEth = answerPdu.find_pdu(); + REQUIRE(answerEth->src_addr() == currEth->src_addr()); + REQUIRE(answerEth->dst_addr() == currEth->dst_addr()); + } +} + +TEST_CASE( "test Icmp6ToIcmp4PacketHandler", "[Icmp6ToIcmp4PacketHandler]" ) { + Icmp6ToIcmp4PacketHandler handler; + Mock mockHandler; + When(Method(mockHandler, handle)).AlwaysDo([] (IN const Tins::PDU & pdu,...) + { + TestIcmp6ToIcmp4PacketHandler::compareToInputPdu(pdu); + return true; + }); + + Tins::EthernetII pkt = Tins::EthernetII() / Tins::IPv6() / Tins::TCP(); + TestIcmp6ToIcmp4PacketHandler::currentInputPdu = &pkt; + REQUIRE(handler.handle(pkt, nullptr) == false); + Verify(Method(mockHandler, handle)).Never(); + + REQUIRE(handler.handle(pkt, &mockHandler.get()) == false); + Verify(Method(mockHandler, handle)).Never(); + + Tins::ICMPv6 echoRequest(Tins::ICMPv6::ECHO_REQUEST); + echoRequest.identifier(23); + echoRequest.sequence(42); + pkt = Tins::EthernetII("11:22:33:44:55:66", "66:55:44:33:22:11") / Tins::IPv6("::1", "::2") / echoRequest; + TestIcmp6ToIcmp4PacketHandler::currentInputPdu = &pkt; + REQUIRE(handler.handle(pkt, &mockHandler.get()) == true); + Verify(Method(mockHandler, handle)).Once(); + + Tins::ICMPv6 echoReply(Tins::ICMPv6::ECHO_REQUEST); + echoReply.identifier(22); + echoReply.sequence(21); + pkt = Tins::EthernetII("66:55:44:33:22:11", "11:22:33:44:55:66") / Tins::IPv6("::2", "::1") / echoReply; + TestIcmp6ToIcmp4PacketHandler::currentInputPdu = &pkt; + REQUIRE(handler.handle(pkt, &mockHandler.get()) == true); + Verify(Method(mockHandler, handle)).Twice(); + + Tins::IPv6Address targetIp6Address("aa::55:192.168.0.1"); + Tins::IPv6Address senderIp6Address("bb::22:192.168.0.2"); + Tins::IPv6Address solicitedIp6Address; + Tins::IPv6 ipv6NsPdu; + Tins::IPv6 ipv6NaPdu; + ipv6NsPdu.src_addr(senderIp6Address); + IpAddressTranslator::toSolicitedNodeAddress(targetIp6Address, solicitedIp6Address); + ipv6NsPdu.dst_addr(solicitedIp6Address); + ipv6NaPdu.src_addr(targetIp6Address); + ipv6NaPdu.dst_addr(senderIp6Address); + + Tins::EthernetII::address_type own_mac_address("01:02:03:12:34:56"); + Tins::EthernetII::address_type to_resolve_mac_address("50:60:70:65:43:21"); + Tins::ICMPv6 ndpNsPdu(Tins::ICMPv6::NEIGHBOUR_SOLICIT); + Tins::ICMPv6 ndpNaPdu(Tins::ICMPv6::NEIGHBOUR_ADVERT); + + ndpNsPdu.target_addr(targetIp6Address); + ndpNaPdu.target_addr(targetIp6Address); + + Tins::EthernetII ethNs(Tins::EthernetII::address_type(), own_mac_address); + Tins::EthernetII ethNa(own_mac_address, to_resolve_mac_address); + ethNs /= ipv6NsPdu / ndpNsPdu; + ethNa /= ipv6NaPdu / ndpNaPdu; + + TestIcmp6ToIcmp4PacketHandler::currentInputPdu = ðNs; + REQUIRE(handler.handle(ethNs, &mockHandler.get()) == true); + Verify(Method(mockHandler, handle)).AtLeastOnce(); + + TestIcmp6ToIcmp4PacketHandler::currentInputPdu = ðNa; + REQUIRE(handler.handle(ethNa, &mockHandler.get()) == true); + Verify(Method(mockHandler, handle)).AtLeastOnce(); +}