1
0
mirror of https://github.com/cmand/yarrp.git synced 2024-05-11 05:55:06 +00:00
Files
cmand-yarrp/trace4.cpp

253 lines
8.8 KiB
C++
Raw Normal View History

2018-12-05 10:50:35 -08:00
/****************************************************************************
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;
2018-12-05 10:50:35 -08:00
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);
2018-12-05 10:50:35 -08:00
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. */
2018-12-05 10:50:35 -08:00
pthread_create(&recv_thread, NULL, listener, this);
}
}
Traceroute4::~Traceroute4() {
if (outip)
free(outip);
2018-12-05 10:50:35 -08:00
}
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) {
2018-12-05 10:50:35 -08:00
probeUDP(target, ttl);
} else if ( (TR_ICMP == config->type) || (TR_ICMP_REPLY == config->type) ) {
2018-12-05 10:50:35 -08:00
probeICMP(target, ttl);
} else if ( (TR_TCP_SYN == config->type) || (TR_TCP_ACK == config->type) ) {
2018-12-05 10:50:35 -08:00
probeTCP(target, ttl);
} else {
cerr << "** bad trace type:" << config->type << endl;
2018-12-05 10:50:35 -08:00
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)
2018-12-05 10:50:35 -08:00
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)
2018-12-05 10:50:35 -08:00
outip->ip_len = packlen;
outip->ip_off = 0; //IP_DF;
#else
outip->ip_len = htons(packlen);
2018-12-05 10:50:35 -08:00
#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) {
2018-12-05 10:50:35 -08:00
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)
2018-12-05 10:50:35 -08:00
outip->ip_len = packlen;
outip->ip_off = 0; //IP_DF;
#else
outip->ip_len = htons(packlen);
2018-12-05 10:50:35 -08:00
#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)
2018-12-05 10:50:35 -08:00
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;
}
}