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

230 lines
7.5 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"
Traceroute6::Traceroute6(YarrpConfig *_config, Stats *_stats) : Traceroute(_config, _stats) {
memset(&source6, 0, sizeof(struct sockaddr_in6));
if (config->probesrc) {
source6.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, config->probesrc, &source6.sin6_addr) != 1)
fatal("** Bad source address.");
} else {
infer_my_ip6(&source6);
}
inet_ntop(AF_INET6, &source6.sin6_addr, addrstr, INET6_ADDRSTRLEN);
config->set("SourceIP", addrstr, true);
#ifdef _LINUX
sndsock = raw_sock6(&source6);
#else
/* Init BPF socket */
sndsock = bpfget();
if (sndsock < 0) fatal("bpf open error\n");
struct ifreq bound_if;
strcpy(bound_if.ifr_name, config->int_name);
if (ioctl(sndsock, BIOCSETIF, &bound_if) > 0) fatal("ioctl err\n");
#endif
pcount = 0;
assert(config);
assert(config->srcmac);
/* Set Ethernet header */
frame = (uint8_t *)calloc(1, PKTSIZE);
memcpy (frame, config->dstmac, 6 * sizeof (uint8_t));
memcpy (frame + 6, config->srcmac, 6 * sizeof (uint8_t));
frame[12] = 0x86; /* IPv6 Ethertype */
frame[13] = 0xdd;
/* Set static IP6 header fields */
outip = (struct ip6_hdr *) (frame + ETH_HDRLEN);
outip->ip6_flow = htonl(0x6<<28|tc<<20|flow);
outip->ip6_src = source6.sin6_addr;
/* Init yarrp payload struct */
payload = (struct ypayload *)malloc(sizeof(struct ypayload));
payload->id = htonl(0x79727036);
payload->instance = config->instance;
if (config->probe and config->receive) {
pthread_create(&recv_thread, NULL, listener6, this);
/* give listener thread time to startup */
sleep(1);
}
}
Traceroute6::~Traceroute6() {
free(frame);
}
void Traceroute6::probePrint(struct in6_addr addr, int ttl) {
uint32_t diff = elapsed();
inet_ntop(AF_INET6, &source6.sin6_addr, addrstr, INET6_ADDRSTRLEN);
if (config->probesrc)
cout << addrstr << " -> ";
//inet_ntop(AF_INET6, &(outip->ip6_dst), addrstr, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
cout << addrstr << " ttl: " << ttl << " t=" << diff;
(config->coarse) ? cout << "ms" << endl : cout << "us" << endl;
}
void
Traceroute6::probe(struct in6_addr addr, int ttl) {
#ifdef _LINUX
struct sockaddr_ll target;
memset(&target, 0, sizeof(target));
target.sll_ifindex = if_nametoindex(config->int_name);
target.sll_family = AF_PACKET;
memcpy(target.sll_addr, config->srcmac, 6 * sizeof(uint8_t));
target.sll_halen = 6;
probe(&target, addr, ttl);
#else
probe(NULL, addr, ttl);
#endif
}
void
Traceroute6::probe(void *target, struct in6_addr addr, int ttl) {
outip->ip6_hlim = ttl;
outip->ip6_dst = addr;
uint16_t ext_hdr_len = 0;
uint16_t transport_hdr_len = 0;
switch(config->type) {
case TR_ICMP6:
outip->ip6_nxt = IPPROTO_ICMPV6;
transport_hdr_len = sizeof(struct icmp6_hdr);
break;
case TR_UDP6:
outip->ip6_nxt = IPPROTO_UDP;
transport_hdr_len = sizeof(struct udphdr);
break;
case TR_TCP6_SYN:
case TR_TCP6_ACK:
outip->ip6_nxt = IPPROTO_TCP;
transport_hdr_len = sizeof(struct tcphdr);
break;
default:
cerr << "** bad trace type" << endl;
assert(false);
}
/* Shim in an extension header? */
if (config->v6_eh != 255) {
if (config->v6_eh == 44) {
make_frag_eh(outip->ip6_nxt);
} else {
make_hbh_eh(outip->ip6_nxt);
}
outip->ip6_nxt = config->v6_eh;
ext_hdr_len = 8;
}
/* Populate a yarrp payload */
payload->ttl = ttl;
payload->fudge = 0;
payload->target = addr;
uint32_t diff = elapsed();
payload->diff = diff;
u_char *data = (u_char *)(frame + ETH_HDRLEN + sizeof(ip6_hdr)
+ ext_hdr_len + transport_hdr_len);
memcpy(data, payload, sizeof(struct ypayload));
/* Populate transport header */
packlen = transport_hdr_len + sizeof(struct ypayload);
make_transport(ext_hdr_len);
/* Copy yarrp payload again, after changing fudge for cksum */
memcpy(data, payload, sizeof(struct ypayload));
outip->ip6_plen = htons(packlen + ext_hdr_len);
/* xmit frame */
if (verbosity > HIGH) {
cout << ">> " << Tr_Type_String[config->type] << " probe: ";
probePrint(addr, ttl);
}
uint16_t framelen = ETH_HDRLEN + sizeof(ip6_hdr) + ext_hdr_len + packlen;
#ifdef _LINUX
if (sendto(sndsock, frame, framelen, 0, (struct sockaddr *)target,
sizeof(struct sockaddr_ll)) < 0)
{
fatal("%s: error: %s", __func__, strerror(errno));
}
#else
/* use the BPF to send */
write(sndsock, frame, framelen);
#endif
pcount++;
}
void
Traceroute6::make_frag_eh(uint8_t nxt) {
void *transport = frame + ETH_HDRLEN + sizeof(ip6_hdr);
struct ip6_frag *eh = (struct ip6_frag *) transport;
eh->ip6f_nxt = nxt;
eh->ip6f_reserved = 0;
eh->ip6f_offlg = 0;
eh->ip6f_ident = 0x8008;
}
void
Traceroute6::make_hbh_eh(uint8_t nxt) {
uint8_t *transport = frame + ETH_HDRLEN + sizeof(ip6_hdr);
struct ip6_ext *eh = (struct ip6_ext *) transport;
eh->ip6e_nxt = nxt;
eh->ip6e_len = 0;
transport+=2;
struct ip6_opt *opt = (struct ip6_opt *) transport;
opt->ip6o_type = IP6OPT_PADN;
opt->ip6o_len = 4;
transport+=2;
memset(transport, 0, 4);
}
void
Traceroute6::make_transport(int ext_hdr_len) {
void *transport = frame + ETH_HDRLEN + sizeof(ip6_hdr) + ext_hdr_len;
uint16_t sum = in_cksum((unsigned short *)&(outip->ip6_dst), 16);
if (config->type == TR_ICMP6) {
struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)transport;
icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
icmp6->icmp6_code = 0;
icmp6->icmp6_cksum = 0;
icmp6->icmp6_id = htons(sum);
icmp6->icmp6_seq = htons(pcount);
icmp6->icmp6_cksum = p_cksum(outip, (u_short *) icmp6, packlen);
} else if (config->type == TR_UDP6) {
struct udphdr *udp = (struct udphdr *)transport;
udp->uh_sport = htons(sum);
udp->uh_dport = htons(dstport);
udp->uh_ulen = htons(packlen);
udp->uh_sum = 0;
udp->uh_sum = p_cksum(outip, (u_short *) udp, packlen);
/* set checksum for paris goodness */
uint16_t crafted_cksum = htons(0xbeef);
payload->fudge = compute_data(udp->uh_sum, crafted_cksum);
udp->uh_sum = crafted_cksum;
} else if (config->type == TR_TCP6_SYN || config->type == TR_TCP6_ACK) {
struct tcphdr *tcp = (struct tcphdr *)transport;
tcp->th_sport = htons(sum);
tcp->th_dport = htons(dstport);
tcp->th_seq = htonl(1);
tcp->th_off = 5;
tcp->th_win = htons(65535);
tcp->th_sum = 0;
tcp->th_x2 = 0;
tcp->th_flags = 0;
tcp->th_urp = htons(0);
if (config->type == TR_TCP6_SYN)
tcp->th_flags |= TH_SYN;
else
tcp->th_flags |= TH_ACK;
tcp->th_sum = p_cksum(outip, (u_short *) tcp, packlen);
/* set checksum for paris goodness */
uint16_t crafted_cksum = htons(0xbeef);
payload->fudge = compute_data(tcp->th_sum, crafted_cksum);
tcp->th_sum = crafted_cksum;
}
}