Skip to content

Commit

Permalink
Command line parameters (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
ref-humbold authored Jul 11, 2023
1 parent 1c56e33 commit 7cbdfca
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 150 deletions.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Simple ICMP traceroute

## About
Traceroute shows a path through the Internet from your computer to a specified address. This implementation uses ICMP packages and raw sockets. Paths up to 32 steps are recognized.
Traceroute shows a path through the Internet from your computer to a specified address. This implementation uses ICMP packages and raw sockets. Only paths up to specified limit of steps (32 by default) are recognized.

### Output format
When there are replies for *any* of the requests sent, then reply addresses are displayed with their reply times and average reply time at the end:
Expand All @@ -29,9 +29,9 @@ General:
+ Linux-based operating system \
*((Debian testing))*
+ C++ compiler \
*((APT package `g++`, 12.2.+))*
*((APT package `g++`, 12.3.+))*
+ [CMake](https://cmake.org/) \
*((APT package `cmake`, 3.25.+))*
*((APT package `cmake`, 3.26.+))*
+ [GNU Make](https://www.gnu.org/software/make) \
*((APT package `make`, 4.3.+))*

Expand All @@ -58,7 +58,15 @@ $ make
Traceroute can be run directly using the executable file in the `buildOut/bin` root directory:
```sh
$ sudo /path-to-project-directory/buildOut/bin/traceroute ADDRESS
$ sudo /path-to-project-directory/buildOut/bin/traceroute OPTIONS ARGUMENTS
```

ADDRESS - IPv4 address of the destination
### Synopsis
**traceroute** \[**-L** *limit*\] *ADDRESS*

### Description
Track the route of Internet packages on their path to IPv4 address *ADDRESS*. Only paths of length up to *limit* are being tracked.

### Options
**-L** *limit*
> Declare maximal path length to track, default is 32.
35 changes: 35 additions & 0 deletions include/AppParameters.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef PARAMETERS_HPP_
#define PARAMETERS_HPP_

#include <exception>
#include <stdexcept>
#include <string>

struct ParametersException : public std::runtime_error
{
explicit ParametersException(const char * s) : std::runtime_error(s)
{
}

explicit ParametersException(const std::string & s) : std::runtime_error(s)
{
}
};

class AppParameters
{
public:
AppParameters() : address{""}, steps{default_steps}
{
}

std::string address;
size_t steps;

private:
static constexpr size_t default_steps = 32;
};

AppParameters parse_args(int argc, char * argv[]);

#endif
82 changes: 0 additions & 82 deletions include/IPv4Address.hpp

This file was deleted.

15 changes: 8 additions & 7 deletions include/ICMPController.hpp → include/IcmpController.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cstdlib>
#include <iostream>
#include <map>
#include <optional>
#include <vector>
#include "SocketReceiver.hpp"
#include "SocketSender.hpp"
Expand All @@ -16,33 +17,33 @@ struct EchoReply
{
}

void add(IPv4Address addr, size_t time_ms);
void add(Ip4Address addr, size_t time_ms);

std::map<IPv4Address, std::vector<size_t>> address_times;
std::map<Ip4Address, std::vector<size_t>> address_times;
double average_time;
size_t received_count;
};

std::ostream & operator<<(std::ostream & os, const EchoReply & reply);

#pragma endregion
#pragma region ICMPController
#pragma region IcmpController

class ICMPController
class IcmpController
{
public:
explicit ICMPController(const RawSocket & s)
explicit IcmpController(const RawSocket & s)
: socket{s}, sender{SocketSender(s)}, receiver{SocketReceiver(s)}
{
}

void echo_request(const IPv4Address & address, uint16_t id, uint16_t ttl);
void echo_request(const Ip4Address & address, uint16_t id, uint16_t ttl);
EchoReply echo_reply(uint16_t id, uint16_t ttl);

const uint16_t attempts = 3;

private:
IPv4Address receive_echo(uint16_t id, uint16_t ttl);
std::optional<Ip4Address> receive_echo(uint16_t id, uint16_t ttl);
uint16_t count_checksum(const uint16_t * header, size_t length);
icmphdr prepare_icmp(uint16_t id, uint16_t seq);
std::tuple<const iphdr *, const icmphdr *, const uint8_t *>
Expand Down
82 changes: 82 additions & 0 deletions include/Ip4Address.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#ifndef IP4_ADDRESS_HPP_
#define IP4_ADDRESS_HPP_

#include <cinttypes>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

class Ip4Address
{
public:
using addr_t = uint32_t;

explicit Ip4Address(addr_t address) : address{address}
{
}

explicit Ip4Address(const std::string & str);

Ip4Address(const Ip4Address &) = default;
Ip4Address(Ip4Address &&) = default;
Ip4Address & operator=(const Ip4Address &) = default;
Ip4Address & operator=(Ip4Address &&) = default;

friend bool operator==(const Ip4Address & a1, const Ip4Address & a2);
friend bool operator<(const Ip4Address & a1, const Ip4Address & a2);
friend std::ostream & operator<<(std::ostream & os, const Ip4Address & a);

explicit operator addr_t() const
{
return address;
}

explicit operator std::string() const;

private:
std::vector<addr_t> quadruple() const;
std::vector<std::string> split(const std::string & str) const;

addr_t address;
};

inline bool operator==(const Ip4Address & a1, const Ip4Address & a2)
{
return a1.address == a2.address;
}

inline bool operator!=(const Ip4Address & a1, const Ip4Address & a2)
{
return !(a1 == a2);
}

inline bool operator<(const Ip4Address & a1, const Ip4Address & a2)
{
return a1.address < a2.address;
}

inline bool operator<=(const Ip4Address & a1, const Ip4Address & a2)
{
return (a1 < a2) || (a1 == a2);
}

inline bool operator>(const Ip4Address & a1, const Ip4Address & a2)
{
return !(a1 <= a2);
}

inline bool operator>=(const Ip4Address & a1, const Ip4Address & a2)
{
return !(a1 < a2);
}

inline std::ostream & operator<<(std::ostream & os, const Ip4Address & addr)
{
std::vector<Ip4Address::addr_t> q = addr.quadruple();

os << q[0] << "." << q[1] << "." << q[2] << "." << q[3];
return os;
}

#endif
4 changes: 2 additions & 2 deletions include/SocketReceiver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <vector>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>
#include "IPv4Address.hpp"
#include "Ip4Address.hpp"
#include "RawSocket.hpp"

class SocketReceiver
Expand All @@ -31,7 +31,7 @@ class SocketReceiver::Message
{
}

IPv4Address address() const;
Ip4Address address() const;

const std::vector<uint8_t> & message() const
{
Expand Down
4 changes: 2 additions & 2 deletions include/SocketSender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <cstdlib>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>
#include "IPv4Address.hpp"
#include "Ip4Address.hpp"
#include "RawSocket.hpp"

class SocketSender
Expand All @@ -16,7 +16,7 @@ class SocketSender
}

void send(const void * message_buffer, int message_size) const;
SocketSender & address(const IPv4Address & addr);
SocketSender & address(const Ip4Address & addr);

SocketSender & ttl(uint16_t value)
{
Expand Down
62 changes: 62 additions & 0 deletions src/AppParameters.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "AppParameters.hpp"
#include <unistd.h>

using namespace std::string_literals;

size_t parse_number(const std::string & s, const std::string & arg_name)
{
size_t pos, value;

try
{
value = std::stoul(s, &pos);
}
catch(const std::invalid_argument & e)
{
throw ParametersException("Given "s + arg_name + " is not a number"s);
}

if(pos < s.length())
throw ParametersException("Given "s + arg_name + " is not a number"s);

return value;
}

AppParameters parse_args(int argc, char * argv[])
{
AppParameters params;
const std::string optstring = ":L:"s;
int option = getopt(argc, argv, optstring.c_str());

opterr = 0;

while(option != -1)
{
switch(option)
{
case 'L':
params.steps = parse_number(optarg, "limit"s);
break;

case '?':
throw ParametersException("Unknown option -"s + static_cast<char>(optopt));

case ':':
throw ParametersException("Option -"s + static_cast<char>(optopt)
+ " requires an argument"s);

default:
break;
}

option = getopt(argc, argv, optstring.c_str());
}

int index = optind;

if(index >= argc)
throw ParametersException("No destination IP specified");

params.address = argv[index];
return params;
}
Loading

0 comments on commit 7cbdfca

Please sign in to comment.