diff --git a/.clang-format b/.clang-format index a953e4e..e8bb793 100644 --- a/.clang-format +++ b/.clang-format @@ -1,19 +1,21 @@ +# VERSION 8 + AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Left +AlignEscapedNewlines: DontAlign AlignOperands: true AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: true +AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: true BreakBeforeBinaryOperators: NonAssignment @@ -34,30 +36,30 @@ FixNamespaceComments: false ForEachMacros: [] IncludeBlocks: Merge IncludeCategories: - # C Standard library - - Regex: '^' - Priority: 1 - # C standard library - - Regex: '^' - Priority: 2 - # C++ standard library: input-output, exceptions, memory, threads - - Regex: '^<(ios(fwd)?|(i|o|io|f|s)stream|streambuf|iomanip|exception|stdexcept|system_error|new|memory|atomic|thread|(shared_)?mutex|future|condition_variable)>' - Priority: 3 - # C++ standard library: algorithms, containers, strings - - Regex: '^<(algorithm|array|bitset|deque|iterator|(forward_|initializer_)?list|(unordered_)?map|queue|(unordered_)?set|stack|string|tuple|vector)>' - Priority: 4 - # C++ standard library: utilities, numerics, types - - Regex: '^<(complex|chrono|functional|limits|locale|numeric|random|ratio|regex|type(info|index|_traits)|valarray)>' - Priority: 5 - # All other headers (C++ style) - - Regex: '^<.*>' - Priority: 6 - # All other headers (C style) - - Regex: '^<.*\.(h|hpp)>' - Priority: 7 - # All custom headers - - Regex: '^".*"' - Priority: 8 + # C Standard library + - Regex: '^' + Priority: 1 + # C standard library + - Regex: '^' + Priority: 2 + # C++ standard library: input-output, exceptions, memory, threads + - Regex: '^<(ios(fwd)?|(i|o|io|f|s)stream|streambuf|iomanip|exception|stdexcept|system_error|new|memory|atomic|thread|(shared_)?mutex|future|condition_variable)>' + Priority: 3 + # C++ standard library: algorithms, containers, strings + - Regex: '^<(algorithm|array|bitset|deque|iterator|(forward_|initializer_)?list|(unordered_)?map|queue|(unordered_)?set|stack|string|tuple|vector)>' + Priority: 4 + # C++ standard library: utilities, numerics, types + - Regex: '^<(complex|chrono|functional|limits|locale|numeric|random|ratio|regex|type(info|index|_traits)|valarray)>' + Priority: 5 + # All other headers (C++ style) + - Regex: '^<.*>' + Priority: 6 + # All other headers (C style) + - Regex: '^<.*\.(h|hpp)>' + Priority: 7 + # All custom headers + - Regex: '^".*"' + Priority: 8 IndentCaseLabels: true IndentPPDirectives: None IndentWidth: 4 @@ -68,7 +70,7 @@ MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: All PointerAlignment: Middle -ReflowComments: true +ReflowComments: false SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 47a9f3b..e4c0f9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,19 @@ cmake_minimum_required(VERSION 3.5) -project(Traceroute VERSION 0.5.190624) +project(Traceroute VERSION 0.6.191014) # COMPILER set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unknown-pragmas") # SOURCES -include_directories("${PROJECT_SOURCE_DIR}/include") +include_directories(include) set(SOURCES - "${PROJECT_SOURCE_DIR}/src/RawSocket.cpp" - "${PROJECT_SOURCE_DIR}/src/IPAddress.cpp" - "${PROJECT_SOURCE_DIR}/src/ICMPReceiver.cpp" - "${PROJECT_SOURCE_DIR}/src/ICMPSender.cpp" - "${PROJECT_SOURCE_DIR}/src/ICMPController.cpp" - "${PROJECT_SOURCE_DIR}/src/traceroute.cpp") + src/IPAddress.cpp + src/ICMPReceiver.cpp + src/ICMPSender.cpp + src/ICMPController.cpp + src/traceroute.cpp) # OUTPUT -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) add_executable(traceroute ${SOURCES}) diff --git a/README.md b/README.md index 05ec930..9a2014c 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Simple ICMP traceroute Traceroute shows a path through the Internet from your computer to a specified address. This implementation uses ICMP packages and raw sockets. ### Output format -When there are replies for *any* of the sent requests, then reply addresses are displayed with +When there are replies for *any* of the requests sent, then reply addresses are displayed with average reply time with count of responses. ``` -. [ (. -- () ``` -When there are no replies, then a single asterisk is displayed. +When there are no replies, then a single asterisk character is displayed. ``` . * ``` @@ -21,12 +21,12 @@ When there are no replies, then a single asterisk is displayed. ## Dependencies ### Standard build & run -> *versions used by the author are in double parentheses and italic* +> *versions last used by the author are in double parentheses and italic* Build process: + Linux-based operating system *((Debian testing))* -+ C++ 14 compiler *((g++ 8.3.0))* + [CMake](https://cmake.org/) *((3.13.4))* ++ C++ 14 compiler *((g++ 9.2.1))* + [GNU Make](https://www.gnu.org/software/make) *((4.2.1))* ----- diff --git a/include/ICMPController.hpp b/include/ICMPController.hpp index 84f3df8..ad5e229 100644 --- a/include/ICMPController.hpp +++ b/include/ICMPController.hpp @@ -2,19 +2,10 @@ #define ICMP_CONTROLLER_HPP_ #include -#include -#include #include -#include #include -#include -#include -#include -#include #include "ICMPReceiver.hpp" #include "ICMPSender.hpp" -#include "IPAddress.hpp" -#include "RawSocket.hpp" class ICMPController { @@ -33,7 +24,6 @@ class ICMPController private: IPAddress recv_echo(uint16_t id, uint16_t ttl); - std::tuple take_headers(uint8_t * ptr); }; #endif diff --git a/include/ICMPReceiver.hpp b/include/ICMPReceiver.hpp index 33b85f3..1357d75 100644 --- a/include/ICMPReceiver.hpp +++ b/include/ICMPReceiver.hpp @@ -2,14 +2,8 @@ #define ICMP_RECEIVER_HPP_ #include -#include -#include -#include -#include -#include #include #include -#include #include #include "IPAddress.hpp" #include "RawSocket.hpp" @@ -21,7 +15,7 @@ class ICMPReceiver sockaddr_in sender_address; public: - explicit ICMPReceiver(RawSocket & s) : socket{s} + explicit ICMPReceiver(RawSocket & s) : socket{s}, sender_address{} { } diff --git a/include/ICMPSender.hpp b/include/ICMPSender.hpp index 6a877b3..259673f 100644 --- a/include/ICMPSender.hpp +++ b/include/ICMPSender.hpp @@ -2,11 +2,8 @@ #define ICMP_SENDER_HPP_ #include -#include -#include -#include +#include #include -#include #include #include "IPAddress.hpp" #include "RawSocket.hpp" @@ -18,16 +15,12 @@ class ICMPSender sockaddr_in receiver_address; public: - explicit ICMPSender(RawSocket & s) : socket{s} + explicit ICMPSender(RawSocket & s) : socket{s}, receiver_address{} { } void send(const void * msg_buf, int msg_size, uint16_t ttl); void set_receiver(const IPAddress & addr); - icmphdr prepare_icmp(uint16_t id, uint16_t seq); - -private: - uint16_t count_checksum(const uint16_t * hdr, int length); }; #endif diff --git a/include/IPAddress.hpp b/include/IPAddress.hpp index 040fb96..ab5588d 100644 --- a/include/IPAddress.hpp +++ b/include/IPAddress.hpp @@ -2,19 +2,16 @@ #define IP_ADDRESS_HPP_ #include -#include +#include #include -#include -#include #include -#include #include -#include - -using addr_t = unsigned int; class IPAddress { +private: + using addr_t = uint32_t; + public: explicit IPAddress(addr_t a) : address{a} { @@ -39,6 +36,8 @@ class IPAddress explicit operator std::string() const; private: + std::vector quadruple() const; + addr_t address; }; diff --git a/include/RawSocket.hpp b/include/RawSocket.hpp index b169a68..9241484 100644 --- a/include/RawSocket.hpp +++ b/include/RawSocket.hpp @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include class SocketException : public std::logic_error diff --git a/src/ICMPController.cpp b/src/ICMPController.cpp index 9fba859..571fcea 100644 --- a/src/ICMPController.cpp +++ b/src/ICMPController.cpp @@ -1,10 +1,56 @@ #include "ICMPController.hpp" +#include +#include +#include +#include + +uint16_t count_checksum(const uint16_t * hdr, int length) +{ + if(length % 2 == 1) + throw SocketException("Incorrect length of ICMP header."); + + uint32_t sum = 0; + const uint16_t * ptr = hdr; + + for(int i = 0; i < length; i += 2) + { + sum += *ptr; + ++ptr; + } + + sum = (sum >> 16U) + (sum & 0xFFFFU); + + return (uint16_t)(~(sum + (sum >> 16U))); +} + +icmphdr prepare_icmp(uint16_t id, uint16_t seq) +{ + icmphdr header = {}; + + header.type = ICMP_ECHO; + header.code = 0; + header.un.echo.id = id; + header.un.echo.sequence = seq; + header.checksum = 0; + header.checksum = count_checksum((uint16_t *)&header, sizeof(header)); + + return header; +} + +std::tuple take_headers(uint8_t * ptr) +{ + auto * hIP = reinterpret_cast(ptr); + auto * hICMP = reinterpret_cast(ptr + 4U * hIP->ihl); + uint8_t * rest = ptr + 4U * hIP->ihl + sizeof(icmphdr); + + return std::make_tuple(hIP, hICMP, rest); +} void ICMPController::echo_request(const IPAddress & addr, uint16_t id, uint16_t ttl) { for(int i = 0; i < 3; ++i) { - icmphdr header = sender.prepare_icmp(id, 3 * ttl + i); + icmphdr header = prepare_icmp(id, 3 * ttl + i); sender.set_receiver(addr); sender.send(&header, sizeof(header), ttl); @@ -16,7 +62,7 @@ std::tuple, size_t, size_t> ICMPController::echo_reply(uint1 { std::set recv_addr; fd_set fd; - timeval timer; + timeval timer = {}; size_t avg_time = 0; size_t recv_num = 0; @@ -75,12 +121,3 @@ IPAddress ICMPController::recv_echo(uint16_t id, uint16_t ttl) return receiver.take_address(); } - -std::tuple ICMPController::take_headers(uint8_t * ptr) -{ - iphdr * hIP = (iphdr *)ptr; - icmphdr * hICMP = (icmphdr *)(ptr + 4 * hIP->ihl); - uint8_t * rest = ptr + 4 * hIP->ihl + sizeof(icmphdr); - - return std::make_tuple(hIP, hICMP, rest); -} diff --git a/src/ICMPReceiver.cpp b/src/ICMPReceiver.cpp index d7fd7c5..6fd2952 100644 --- a/src/ICMPReceiver.cpp +++ b/src/ICMPReceiver.cpp @@ -1,4 +1,8 @@ #include "ICMPReceiver.hpp" +#include +#include +#include +#include std::vector ICMPReceiver::receive() { diff --git a/src/ICMPSender.cpp b/src/ICMPSender.cpp index b7d556a..8086cdf 100644 --- a/src/ICMPSender.cpp +++ b/src/ICMPSender.cpp @@ -1,4 +1,7 @@ #include "ICMPSender.hpp" +#include +#include +#include void ICMPSender::send(const void * msg_buf, int msg_size, uint16_t ttl) { @@ -20,36 +23,3 @@ void ICMPSender::set_receiver(const IPAddress & addr) if(result < 1) throw SocketException("Invalid addressing."); } - -icmphdr ICMPSender::prepare_icmp(uint16_t id, uint16_t seq) -{ - icmphdr header; - - header.type = ICMP_ECHO; - header.code = 0; - header.un.echo.id = id; - header.un.echo.sequence = seq; - header.checksum = 0; - header.checksum = count_checksum((uint16_t *)&header, sizeof(header)); - - return header; -} - -uint16_t ICMPSender::count_checksum(const uint16_t * hdr, int length) -{ - if((length & 1) == 1) - throw SocketException("Incorrect length of ICMP header."); - - uint32_t sum = 0; - const uint16_t * ptr = hdr; - - for(int i = 0; i < length; i += 2) - { - sum += *ptr; - ++ptr; - } - - sum = (sum >> 16) + (sum & 0xFFFF); - - return (uint16_t)(~(sum + (sum >> 16))); -} diff --git a/src/IPAddress.cpp b/src/IPAddress.cpp index 3cb13c5..abb91c3 100644 --- a/src/IPAddress.cpp +++ b/src/IPAddress.cpp @@ -1,57 +1,77 @@ #include "IPAddress.hpp" +#include +#include +#include +#include -IPAddress::IPAddress(const std::string & st) +std::vector split(const std::string & st) { - std::vector splitted; - std::vector addr_bytes; + std::vector split_st; size_t begin_pos = 0; while(begin_pos != std::string::npos) { - size_t end_pos = st.find(".", begin_pos); + size_t end_pos = st.find('.', begin_pos); if(end_pos != std::string::npos) { - splitted.push_back(st.substr(begin_pos, end_pos - begin_pos)); + split_st.push_back(st.substr(begin_pos, end_pos - begin_pos)); begin_pos = end_pos + 1; } else { - splitted.push_back(st.substr(begin_pos)); + split_st.push_back(st.substr(begin_pos)); begin_pos = end_pos; } } - if(splitted.size() != 4) - throw std::invalid_argument("Parameter is not a valid IP adress"); + return split_st; +} + +IPAddress::IPAddress(const std::string & st) +{ + std::vector split_st = split(st); + std::vector addr_bytes; - if(std::any_of(splitted.begin(), splitted.end(), [](const std::string & s) { + if(split_st.size() != 4) + throw std::invalid_argument("Parameter is not a valid IP address"); + + if(std::any_of(split_st.begin(), split_st.end(), [](const std::string & s) { return std::any_of(s.begin(), s.end(), [](char c) { return c < '0' || c > '9'; }); })) - throw std::invalid_argument("Parameter is not a valid IP adress"); + throw std::invalid_argument("Parameter is not a valid IP address"); - addr_bytes.resize(splitted.size()); - std::transform(splitted.begin(), splitted.end(), addr_bytes.begin(), + addr_bytes.resize(split_st.size()); + std::transform(split_st.begin(), split_st.end(), addr_bytes.begin(), [](const std::string & s) { return stoul(s); }); if(std::any_of(addr_bytes.begin(), addr_bytes.end(), [](addr_t p) { return p > 255; })) - throw std::invalid_argument("Parameter is not a valid IP adress"); + throw std::invalid_argument("Parameter is not a valid IP address"); - this->address = std::accumulate(addr_bytes.begin(), addr_bytes.end(), 0, - [](addr_t acc, addr_t b) { return (acc << 8) | b; }); + address = std::accumulate(addr_bytes.begin(), addr_bytes.end(), 0, + [](addr_t acc, addr_t b) { return (acc << 8U) | b; }); } IPAddress::operator std::string() const { - return std::to_string((address & 0xFF000000) >> 24) + "." - + std::to_string((address & 0x00FF0000) >> 16) + "." - + std::to_string((address & 0x0000FF00) >> 8) + "." - + std::to_string(address & 0x000000FF); + std::vector q = quadruple(); + + return std::to_string(q[0]) + "." + std::to_string(q[1]) + "." + std::to_string(q[2]) + "." + + std::to_string(q[3]); +} + +std::vector IPAddress::quadruple() const +{ + return std::vector({(address & 0xFF000000U) >> 24U, + (address & 0x00FF0000U) >> 16U, (address & 0x0000FF00U) >> 8U, + address & 0x000000FFU}); } std::ostream & operator<<(std::ostream & os, const IPAddress & a) { - os << static_cast(a); + std::vector q = a.quadruple(); + + os << q[0] << "." << q[1] << "." << q[2] << "." << q[3]; return os; } diff --git a/src/RawSocket.cpp b/src/RawSocket.cpp deleted file mode 100644 index 4c252c5..0000000 --- a/src/RawSocket.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "RawSocket.hpp" diff --git a/src/traceroute.cpp b/src/traceroute.cpp index 22f0456..44c69e0 100644 --- a/src/traceroute.cpp +++ b/src/traceroute.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -6,13 +5,11 @@ #include #include #include "ICMPController.hpp" -#include "IPAddress.hpp" -#include "RawSocket.hpp" void print_results(uint16_t ttl, const std::set & recv_addr, size_t avg_time, size_t recv_num) { - std::cout << static_cast(ttl) << ". "; + std::cout << (ttl < 10 ? " " : "") << static_cast(ttl) << ". "; if(recv_addr.empty()) std::cout << "*\n"; @@ -21,7 +18,7 @@ void print_results(uint16_t ttl, const std::set & recv_addr, size_t a for(auto addr : recv_addr) std::cout << addr << " "; - std::cout << "[" << avg_time / 1000 << " ms (" << recv_num << ")]\n"; + std::cout << "-- " << avg_time / 1000 << " ms (" << recv_num << ")\n"; } } @@ -41,7 +38,7 @@ int main(int argc, char * argv[]) uint16_t pid = getpid(); int steps = 30; - std::cout << "traceroute :: destination " << addr << " :: max " << steps << " steps\n"; + std::cout << " traceroute :: destination " << addr << " :: max " << steps << " steps\n"; for(int i = 1; i <= steps; ++i) {