mirror of
https://github.com/cmand/yarrp.git
synced 2024-05-11 05:55:06 +00:00
253 lines
8.8 KiB
C++
253 lines
8.8 KiB
C++
/****************************************************************************
|
|
Program: $Id: trace.cpp 39 2015-12-30 20:28:36Z rbeverly $
|
|
Date: $Date: 2015-12-30 12:28:36 -0800 (Wed, 30 Dec 2015) $
|
|
Description: traceroute class
|
|
****************************************************************************/
|
|
#include "yarrp.h"
|
|
|
|
Traceroute4::Traceroute4(YarrpConfig *_config, Stats *_stats) : Traceroute(_config, _stats)
|
|
{
|
|
if (config->testing) return;
|
|
memset(&source, 0, sizeof(struct sockaddr_in));
|
|
if (config->probesrc) {
|
|
source.sin_family = AF_INET;
|
|
if (inet_pton(AF_INET, config->probesrc, &source.sin_addr) != 1)
|
|
fatal("** Bad source address.");
|
|
cout << ">> Using IP source: " << config->probesrc << endl;
|
|
} else {
|
|
infer_my_ip(&source);
|
|
}
|
|
inet_ntop(AF_INET, &source.sin_addr, addrstr, INET_ADDRSTRLEN);
|
|
config->set("SourceIP", addrstr, true);
|
|
payloadlen = 0;
|
|
outip = (struct ip *)calloc(1, PKTSIZE);
|
|
outip->ip_v = IPVERSION;
|
|
outip->ip_hl = sizeof(struct ip) >> 2;
|
|
outip->ip_src.s_addr = source.sin_addr.s_addr;
|
|
sndsock = raw_sock(&source);
|
|
if (config->probe and config->receive) {
|
|
lock(); /* grab mutex; make listener thread block. */
|
|
pthread_create(&recv_thread, NULL, listener, this);
|
|
}
|
|
}
|
|
|
|
Traceroute4::~Traceroute4() {
|
|
if (outip)
|
|
free(outip);
|
|
}
|
|
|
|
void Traceroute4::probePrint(struct in_addr *targ, int ttl) {
|
|
uint32_t diff = elapsed();
|
|
if (config->probesrc)
|
|
cout << inet_ntoa(source.sin_addr) << " -> ";
|
|
cout << inet_ntoa(*targ) << " ttl: ";
|
|
cout << ttl;
|
|
if (config->instance)
|
|
cout << " i=" << (int) config->instance;
|
|
cout << " t=" << diff;
|
|
(config->coarse) ? cout << "ms" << endl : cout << "us" << endl;
|
|
}
|
|
|
|
void
|
|
Traceroute4::probe(const char *targ, int ttl) {
|
|
struct sockaddr_in target;
|
|
memset(&target, 0, sizeof(target));
|
|
target.sin_family = AF_INET;
|
|
#ifdef _BSD
|
|
target.sin_len = sizeof(target);
|
|
#endif
|
|
inet_aton(targ, &(target.sin_addr));
|
|
probe(&target, ttl);
|
|
}
|
|
|
|
void
|
|
Traceroute4::probe(uint32_t addr, int ttl) {
|
|
struct sockaddr_in target;
|
|
memset(&target, 0, sizeof(target));
|
|
target.sin_family = AF_INET;
|
|
#ifdef _BSD
|
|
target.sin_len = sizeof(target);
|
|
#endif
|
|
target.sin_addr.s_addr = addr;
|
|
probe(&target, ttl);
|
|
}
|
|
|
|
void
|
|
Traceroute4::probe(struct sockaddr_in *target, int ttl) {
|
|
outip->ip_ttl = ttl;
|
|
outip->ip_id = htons(ttl + (config->instance << 8));
|
|
outip->ip_off = 0; // htons(IP_DF);
|
|
outip->ip_dst.s_addr = (target->sin_addr).s_addr;
|
|
outip->ip_sum = 0;
|
|
if (TR_UDP == config->type) {
|
|
probeUDP(target, ttl);
|
|
} else if ( (TR_ICMP == config->type) || (TR_ICMP_REPLY == config->type) ) {
|
|
probeICMP(target, ttl);
|
|
} else if ( (TR_TCP_SYN == config->type) || (TR_TCP_ACK == config->type) ) {
|
|
probeTCP(target, ttl);
|
|
} else {
|
|
cerr << "** bad trace type:" << config->type << endl;
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
void
|
|
Traceroute4::probeUDP(struct sockaddr_in *target, int ttl) {
|
|
unsigned char *ptr = (unsigned char *)outip;
|
|
struct udphdr *udp = (struct udphdr *)(ptr + (outip->ip_hl << 2));
|
|
unsigned char *data = (unsigned char *)(ptr + (outip->ip_hl << 2) + sizeof(struct udphdr));
|
|
|
|
uint32_t diff = elapsed();
|
|
payloadlen = 2;
|
|
/* encode MSB of timestamp in UDP payload length */
|
|
if (diff >> 16)
|
|
payloadlen += (diff>>16);
|
|
if (verbosity > HIGH) {
|
|
cout << ">> UDP probe: ";
|
|
probePrint(&target->sin_addr, ttl);
|
|
}
|
|
|
|
packlen = sizeof(struct ip) + sizeof(struct udphdr) + payloadlen;
|
|
|
|
outip->ip_p = IPPROTO_UDP;
|
|
#if defined(_BSD) && !defined(_NEW_FBSD)
|
|
outip->ip_len = packlen;
|
|
outip->ip_off = IP_DF;
|
|
#else
|
|
outip->ip_len = htons(packlen);
|
|
outip->ip_off = ntohs(IP_DF);
|
|
#endif
|
|
/* encode destination IPv4 address as cksum(ipdst) */
|
|
uint16_t dport = in_cksum((unsigned short *)&(outip->ip_dst), 4);
|
|
udp->uh_sport = htons(dport);
|
|
udp->uh_dport = htons(dstport);
|
|
udp->uh_ulen = htons(sizeof(struct udphdr) + payloadlen);
|
|
udp->uh_sum = 0;
|
|
|
|
outip->ip_sum = htons(in_cksum((unsigned short *)outip, 20));
|
|
|
|
/* compute UDP checksum */
|
|
memset(data, 0, 2);
|
|
u_short len = sizeof(struct udphdr) + payloadlen;
|
|
udp->uh_sum = p_cksum(outip, (u_short *) udp, len);
|
|
|
|
/* encode LSB of timestamp in checksum */
|
|
uint16_t crafted_cksum = diff & 0xFFFF;
|
|
/* craft payload such that the new cksum is correct */
|
|
uint16_t crafted_data = compute_data(udp->uh_sum, crafted_cksum);
|
|
memcpy(data, &crafted_data, 2);
|
|
if (crafted_cksum == 0x0000)
|
|
crafted_cksum = 0xFFFF;
|
|
udp->uh_sum = crafted_cksum;
|
|
|
|
if (sendto(sndsock, (char *)outip, packlen, 0, (struct sockaddr *)target, sizeof(*target)) < 0) {
|
|
cout << __func__ << "(): error: " << strerror(errno) << endl;
|
|
cout << ">> UDP probe: " << inet_ntoa(target->sin_addr) << " ttl: ";
|
|
cout << ttl << " t=" << diff << endl;
|
|
}
|
|
}
|
|
|
|
void
|
|
Traceroute4::probeTCP(struct sockaddr_in *target, int ttl) {
|
|
unsigned char *ptr = (unsigned char *)outip;
|
|
struct tcphdr *tcp = (struct tcphdr *)(ptr + (outip->ip_hl << 2));
|
|
|
|
packlen = sizeof(struct ip) + sizeof(struct tcphdr) + payloadlen;
|
|
outip->ip_p = IPPROTO_TCP;
|
|
#if defined(_BSD) && !defined(_NEW_FBSD)
|
|
outip->ip_len = packlen;
|
|
outip->ip_off = 0; //IP_DF;
|
|
#else
|
|
outip->ip_len = htons(packlen);
|
|
#endif
|
|
/* encode destination IPv4 address as cksum(ipdst) */
|
|
uint16_t dport = in_cksum((unsigned short *)&(outip->ip_dst), 4);
|
|
tcp->th_sport = htons(dport);
|
|
tcp->th_dport = htons(dstport);
|
|
/* encode send time into seq no as elapsed milliseconds */
|
|
uint32_t diff = elapsed();
|
|
if (verbosity > HIGH) {
|
|
cout << ">> TCP probe: ";
|
|
probePrint(&target->sin_addr, ttl);
|
|
}
|
|
tcp->th_seq = htonl(diff);
|
|
tcp->th_off = 5;
|
|
tcp->th_win = htons(0xFFFE);
|
|
tcp->th_sum = 0;
|
|
/* don't want to set SYN, lest we be tagged as SYN flood. */
|
|
if (TR_TCP_SYN == config->type) {
|
|
tcp->th_flags |= TH_SYN;
|
|
} else {
|
|
tcp->th_flags |= TH_ACK;
|
|
tcp->th_ack = htonl(target->sin_addr.s_addr);
|
|
}
|
|
/*
|
|
* explicitly computing cksum probably not required on most machines
|
|
* these days as offloaded by OS or NIC. but we'll be safe.
|
|
*/
|
|
outip->ip_sum = htons(in_cksum((unsigned short *)outip, 20));
|
|
/*
|
|
* bsd rawsock requires host ordered len and offset; rewrite here as
|
|
* chksum must be over htons() versions
|
|
*/
|
|
u_short len = sizeof(struct tcphdr) + payloadlen;
|
|
tcp->th_sum = p_cksum(outip, (u_short *) tcp, len);
|
|
if (sendto(sndsock, (char *)outip, packlen, 0, (struct sockaddr *)target, sizeof(*target)) < 0) {
|
|
cout << __func__ << "(): error: " << strerror(errno) << endl;
|
|
cout << ">> TCP probe: " << inet_ntoa(target->sin_addr) << " ttl: ";
|
|
cout << ttl << " t=" << diff << endl;
|
|
}
|
|
}
|
|
|
|
void
|
|
Traceroute4::probeICMP(struct sockaddr_in *target, int ttl) {
|
|
unsigned char *ptr = (unsigned char *)outip;
|
|
struct icmp *icmp = (struct icmp *)(ptr + (outip->ip_hl << 2));
|
|
unsigned char *data = (unsigned char *)(ptr + (outip->ip_hl << 2) + ICMP_MINLEN);
|
|
|
|
payloadlen = 2;
|
|
packlen = sizeof(struct ip) + ICMP_MINLEN + payloadlen;
|
|
outip->ip_p = IPPROTO_ICMP;
|
|
outip->ip_len = htons(packlen);
|
|
#if defined(_BSD) && !defined(_NEW_FBSD)
|
|
outip->ip_len = packlen;
|
|
outip->ip_off = 0; //IP_DF;
|
|
#else
|
|
outip->ip_len = htons(packlen);
|
|
#endif
|
|
/* encode send time into icmp id and seq as elapsed milli/micro seconds */
|
|
uint32_t diff = elapsed();
|
|
if (verbosity > HIGH) {
|
|
cout << ">> ICMP probe: ";
|
|
probePrint(&target->sin_addr, ttl);
|
|
}
|
|
icmp->icmp_type = ICMP_ECHO;
|
|
if (TR_ICMP_REPLY == config->type)
|
|
icmp->icmp_type = ICMP_ECHOREPLY;
|
|
icmp->icmp_code = 0;
|
|
icmp->icmp_cksum = 0;
|
|
icmp->icmp_id = htons(diff & 0xFFFF);
|
|
icmp->icmp_seq = htons((diff >> 16) & 0xFFFF);
|
|
outip->ip_sum = htons(in_cksum((unsigned short *)outip, 20));
|
|
|
|
/* compute ICMP checksum */
|
|
memset(data, 0, 2);
|
|
u_short len = ICMP_MINLEN + payloadlen;
|
|
icmp->icmp_cksum = in_cksum((u_short *) icmp, len);
|
|
|
|
/* encode cksum(ipdst) into checksum */
|
|
uint16_t crafted_cksum = in_cksum((unsigned short *)&(outip->ip_dst), 4);
|
|
/* craft payload such that the new cksum is correct */
|
|
uint16_t crafted_data = compute_data(icmp->icmp_cksum, crafted_cksum);
|
|
memcpy(data, &crafted_data, 2);
|
|
if (crafted_cksum == 0x0000)
|
|
crafted_cksum = 0xFFFF;
|
|
icmp->icmp_cksum = crafted_cksum;
|
|
|
|
if (sendto(sndsock, (char *)outip, packlen, 0, (struct sockaddr *)target, sizeof(*target)) < 0) {
|
|
cout << __func__ << "(): error: " << strerror(errno) << endl;
|
|
cout << ">> ICMP probe: " << inet_ntoa(target->sin_addr) << " ttl: ";
|
|
cout << ttl << " t=" << diff << endl;
|
|
}
|
|
}
|