Skip to content
This repository has been archived by the owner on Mar 4, 2021. It is now read-only.

Commit

Permalink
Merge pull request #153 from bassosimone/feature/testing-portolan-ope…
Browse files Browse the repository at this point in the history
…ndns

Teach portolan traceroute about reply packets.
  • Loading branch information
bassosimone committed Oct 14, 2015
2 parents ae837a3 + f95ba79 commit 637dabd
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 20 deletions.
16 changes: 16 additions & 0 deletions include/measurement_kit/traceroute/android.hpp
Expand Up @@ -99,6 +99,22 @@ class AndroidProber : public measurement_kit::common::NonCopyable,
/// calculate *precisely* the RTT.
ProbeResult on_socket_readable();

/// Returns the source address of the error message.
/// \param s IPv4 socket address
/// \return source address of the error message
static std::string get_source_addr(const sockaddr_in *s);

/// Returns the source address of the error message.
/// \param s IPv6 socket address
/// \return source address of the error message
static std::string get_source_addr(const sockaddr_in6 *s);

/// Returns the source address of the error message.
/// \param use_ipv4 whether we are using IPv4
/// \param ss Pointer to sockaddr_storage struct
/// \return source address of the error message
static std::string get_source_addr(bool use_ipv4, const sockaddr_storage *ss);

/// Returns the source address of the error message.
/// \param use_ipv4 whether we are using IPv4
/// \param err socket error structure
Expand Down
5 changes: 4 additions & 1 deletion include/measurement_kit/traceroute/interface.hpp
Expand Up @@ -55,9 +55,10 @@ enum class ProbeResultMeaning {
NO_ROUTE_TO_HOST = 1, ///< No route to host
ADDRESS_UNREACH = 2, ///< E.g., link down
PROTO_NOT_IMPL = 3, ///< UDP not implemented
DEST_REACHED = 4, ///< Port is closed = dest. reached
PORT_IS_CLOSED = 4, ///< Port is closed
TTL_EXCEEDED = 5, ///< TTL is too small
ADMIN_FILTER = 6, ///< E.g., firewall rule
GOT_REPLY_PACKET = 7, ///< We got a real reply packet
};

/// Result of a traceroute probe
Expand All @@ -70,6 +71,8 @@ class ProbeResult {
unsigned char icmp_type = 255; ///< Raw ICMP/ICMPv6 type
unsigned char icmp_code = 255; ///< Raw ICMP/ICMPv6 code
ssize_t recv_bytes = 0; ///< Bytes recv'd
bool valid_reply = false; ///< Whether reply is valid
std::string reply; ///< Reply packet data

/// Maps ICMP/ICMPv6 type and code to a meaning
ProbeResultMeaning get_meaning();
Expand Down
57 changes: 47 additions & 10 deletions src/traceroute/android.cpp
Expand Up @@ -42,6 +42,7 @@
#include <arpa/inet.h>
#include <linux/errqueue.h>

#include <errno.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
Expand Down Expand Up @@ -147,6 +148,7 @@ void AndroidProber::send_probe(std::string addr, int port, int ttl,
throw std::runtime_error("payload too large");
if (sendto(sockfd_, payload.data(), payload.length(), 0, (sockaddr *)&ss,
sslen) != (ssize_t)payload.length()) {
measurement_kit::warn("sendto() failed: errno %d", errno);
throw std::runtime_error("sendto() failed");
}

Expand All @@ -167,6 +169,8 @@ ProbeResult AndroidProber::on_socket_readable() {
cmsghdr *cmsg;
iovec iov;
timespec arr_time;
sockaddr_storage storage;
socklen_t solen;

measurement_kit::debug("on_socket_readable()");

Expand All @@ -192,8 +196,26 @@ ProbeResult AndroidProber::on_socket_readable() {
msg.msg_control = controlbuff;
msg.msg_controllen = sizeof(controlbuff);
msg.msg_flags = 0;
if ((r.recv_bytes = recvmsg(sockfd_, &msg, MSG_ERRQUEUE)) < 0)
if ((r.recv_bytes = recvmsg(sockfd_, &msg, MSG_ERRQUEUE)) < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) { // Defensive
measurement_kit::debug("it seems we received a valid reply packet back");
memset(&storage, 0, sizeof (storage));
solen = sizeof (storage);
if ((r.recv_bytes = recvfrom(sockfd_, buff, sizeof (buff), 0,
(sockaddr *) &storage, &solen)) < 0) {
throw std::runtime_error("recv() failed");
}
measurement_kit::debug("recv_bytes = %lu", r.recv_bytes);
r.valid_reply = true;
measurement_kit::debug("valid_reply = %d", r.valid_reply);
r.reply = std::string((const char *) buff, r.recv_bytes);
measurement_kit::debug("reply = <%lu bytes>", r.reply.length());
r.interface_ip = get_source_addr(use_ipv4_, &storage);
measurement_kit::debug("interface_ip = %s", r.interface_ip.c_str());
return r;
}
throw std::runtime_error("recvmsg() failed");
}
measurement_kit::debug("recv_bytes = %lu", r.recv_bytes);

if (use_ipv4_) {
Expand Down Expand Up @@ -243,21 +265,36 @@ ProbeResult AndroidProber::on_socket_readable() {
return r;
}

std::string AndroidProber::get_source_addr(const sockaddr_in *sin) {
char ip[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &sin->sin_addr, ip, INET_ADDRSTRLEN) == NULL)
throw std::runtime_error("inet_ntop failed");
return std::string(ip);
}

std::string AndroidProber::get_source_addr(const sockaddr_in6 *sin6) {
char ip[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, &sin6->sin6_addr, ip, INET6_ADDRSTRLEN) == NULL)
throw std::runtime_error("inet_ntop failed");
return std::string(ip);
}

std::string AndroidProber::get_source_addr(bool use_ipv4,
const sockaddr_storage *ss) {
if (use_ipv4) {
return get_source_addr((sockaddr_in *) ss);
}
return get_source_addr((sockaddr_in6 *) ss);
}

std::string AndroidProber::get_source_addr(bool use_ipv4,
sock_extended_err *se) {
// Note: I'm not annoyed by this function, if you are feel free to refactor
if (use_ipv4) {
char ip[INET_ADDRSTRLEN];
const sockaddr_in *sin = (const sockaddr_in *)SO_EE_OFFENDER(se);
if (inet_ntop(AF_INET, &sin->sin_addr, ip, INET_ADDRSTRLEN) == NULL)
throw std::runtime_error("inet_ntop failed");
return std::string(ip);
return get_source_addr(sin);
} else {
char ip[INET6_ADDRSTRLEN];
const sockaddr_in6 *sin6 = (const sockaddr_in6 *)SO_EE_OFFENDER(se);
if (inet_ntop(AF_INET6, &sin6->sin6_addr, ip, INET6_ADDRSTRLEN) == NULL)
throw std::runtime_error("inet_ntop failed");
return std::string(ip);
return get_source_addr(sin6);
}
}

Expand Down
23 changes: 14 additions & 9 deletions src/traceroute/interface.cpp
Expand Up @@ -55,7 +55,7 @@ struct ProbeResultMapping {

static ProbeResultMapping MAPPINGv4[] = {
{ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, PRM_::TTL_EXCEEDED},
{ICMP_UNREACH, ICMP_UNREACH_PORT, PRM_::DEST_REACHED},
{ICMP_UNREACH, ICMP_UNREACH_PORT, PRM_::PORT_IS_CLOSED},
{ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, PRM_::PROTO_NOT_IMPL},
{ICMP_UNREACH, ICMP_UNREACH_NET, PRM_::NO_ROUTE_TO_HOST},
{ICMP_UNREACH, ICMP_UNREACH_HOST, PRM_::ADDRESS_UNREACH},
Expand All @@ -64,31 +64,36 @@ static ProbeResultMapping MAPPINGv4[] = {

static ProbeResultMapping MAPPINGv6[] = {
{ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, PRM_::TTL_EXCEEDED},
{ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, PRM_::DEST_REACHED},
{ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, PRM_::PORT_IS_CLOSED},
{ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, PRM_::NO_ROUTE_TO_HOST},
{ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR, PRM_::ADDRESS_UNREACH},
{ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN, PRM_::ADMIN_FILTER},
{255, 255, PRM_::OTHER},
};

#undef PRM_

ProbeResultMeaning ProbeResult::get_meaning() {
if (valid_reply) {
measurement_kit::debug("type %d code %d meaning %d (got reply packet)",
icmp_type, icmp_code, PRM_::GOT_REPLY_PACKET);
return PRM_::GOT_REPLY_PACKET;
}
for (auto m = is_ipv4 ? &MAPPINGv4[0] : &MAPPINGv6[0];
m->meaning != ProbeResultMeaning::OTHER; ++m) {
m->meaning != PRM_::OTHER; ++m) {
if (m->type == icmp_type && m->code == icmp_code) {
measurement_kit::debug("type %d code %d meaning %d", icmp_type, icmp_code,
m->meaning);
m->meaning);
return m->meaning;
}
}
measurement_kit::debug("type %d code %d meaning %d", icmp_type, icmp_code,
ProbeResultMeaning::OTHER);
return ProbeResultMeaning::OTHER;
measurement_kit::debug("type %d code %d meaning %d (other)", icmp_type,
icmp_code, PRM_::OTHER);
return PRM_::OTHER;
}

ProberInterface::~ProberInterface() {}

#undef PRM_

} // namespace traceroute
} // namespace measurement_kit

Expand Down
38 changes: 38 additions & 0 deletions test/traceroute/android.cpp
Expand Up @@ -52,6 +52,44 @@ TEST_CASE("Typical IPv4 traceroute usage") {
prober.send_probe("8.8.8.8", 33434, ttl, payload, 1.0);
measurement_kit::loop();
}

TEST_CASE("Check whether it works when destination sends reply") {

std::string payload(256, '\0');
auto prober = Prober<AndroidProber>(true, 11829);
auto ttl = 1;

prober.on_result([&prober, &ttl, &payload](ProbeResult r) {
std::cout << ttl << " " << r.interface_ip << " " << r.rtt << " ms\n";
if (r.get_meaning() != ProbeResultMeaning::TTL_EXCEEDED || ttl >= 64) {
measurement_kit::break_loop();
return;
}
prober.send_probe("208.67.222.222", 53, ++ttl, payload, 1.0);
});

prober.on_timeout([&prober, &ttl, &payload]() {
std::cout << ttl << " *\n";
if (ttl >= 64) {
measurement_kit::break_loop();
return;
}
prober.send_probe("208.67.222.222", 53, ++ttl, payload, 1.0);
});

prober.on_error([&prober, &ttl, &payload](std::runtime_error err) {
std::cout << ttl << " error: " << err.what() << "\n";
if (ttl >= 64) {
measurement_kit::break_loop();
return;
}
prober.send_probe("208.67.222.222", 53, ++ttl, payload, 1.0);
});

prober.send_probe("208.67.222.222", 53, ttl, payload, 1.0);
measurement_kit::loop();
}

#else
int main() { return 0; }
#endif

0 comments on commit 637dabd

Please sign in to comment.