-
Notifications
You must be signed in to change notification settings - Fork 13
/
listener6.cpp
154 lines (146 loc) · 5.51 KB
/
listener6.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/****************************************************************************
Program: $Id: listener.cpp 40 2016-01-02 18:54:39Z rbeverly $
Date: $Date: 2016-01-02 10:54:39 -0800 (Sat, 02 Jan 2016) $
Description: yarrp listener thread
****************************************************************************/
#include "yarrp.h"
#include <signal.h>
static volatile bool run = true;
void intHandler(int dummy);
#ifndef _LINUX
int bpfinit(char *dev, size_t *bpflen) {
int rcvsock = -1;
debug(DEVELOP, ">> Listener6 BPF");
rcvsock = bpfget();
if (rcvsock < 0) fatal("bpf open error\n");
struct ifreq bound_if;
strcpy(bound_if.ifr_name, dev);
if (ioctl(rcvsock, BIOCSETIF, &bound_if) > 0) fatal("ioctl err\n");
uint32_t enable = 1;
if (ioctl(rcvsock, BIOCSHDRCMPLT, &enable) <0) fatal("ioctl err\n");
if (ioctl(rcvsock, BIOCIMMEDIATE, &enable) <0) fatal("ioctl err\n");
struct bpf_program fcode = {0};
struct bpf_insn insns[] = {
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IPV6, 0, 3),
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 20),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_ICMPV6, 0, 1),
BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
BPF_STMT(BPF_RET+BPF_K, 0),
};
fcode.bf_len = sizeof(insns) / sizeof(struct bpf_insn);
fcode.bf_insns = &insns[0];
if(ioctl(rcvsock, BIOCSETF, &fcode) < 0) fatal("set filter\n");
ioctl(rcvsock, BIOCGBLEN, bpflen);
return rcvsock;
}
#endif
void *listener6(void *args) {
fd_set rfds;
Traceroute6 *trace = reinterpret_cast < Traceroute6 * >(args);
struct timeval timeout;
unsigned char *buf = (unsigned char *) calloc(1,PKTSIZE);
uint32_t nullreads = 0;
int n, len;
TTLHisto *ttlhisto = NULL;
uint32_t elapsed = 0;
struct ip6_hdr *ip = NULL; /* IPv6 hdr */
struct icmp6_hdr *ippayload = NULL; /* ICMP6 hdr */
int rcvsock; /* receive (icmp) socket file descriptor */
/* block until main thread says we're ready. */
trace->lock();
trace->unlock();
#ifdef _LINUX
if ((rcvsock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
cerr << "yarrp listener socket error:" << strerror(errno) << endl;
}
/* bind PF_PACKET to single interface */
struct ifreq ifr;
strncpy(ifr.ifr_name, trace->config->int_name, IFNAMSIZ);
if (ioctl(rcvsock, SIOCGIFINDEX, &ifr) < 0) fatal ("ioctl err");;
struct sockaddr_ll sll;
memset(&sll, 0, sizeof(sll));
sll.sll_family = PF_PACKET;
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_ifindex = ifr.ifr_ifindex;
if (bind(rcvsock, (struct sockaddr*) &sll, sizeof(sll)) < 0) {
fatal("Bind to PF_PACKET socket");
}
#else
/* Init BPF */
size_t blen = 0;
rcvsock = bpfinit(trace->config->int_name, &blen);
unsigned char *bpfbuf = (unsigned char *) calloc(1,blen);
struct bpf_hdr *bh = NULL;
#endif
signal(SIGINT, intHandler);
while (true and run) {
if (nullreads >= MAXNULLREADS)
break;
#ifdef _LINUX
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(rcvsock, &rfds);
n = select(rcvsock + 1, &rfds, NULL, NULL, &timeout);
if (n == 0) {
nullreads++;
cerr << ">> Listener: timeout " << nullreads;
cerr << "/" << MAXNULLREADS << endl;
continue;
}
if (n == -1) {
fatal("select error");
}
nullreads = 0;
memset(buf, 0, PKTSIZE);
len = recv(rcvsock, buf, PKTSIZE, 0);
#else
memset(bpfbuf, 0, blen);
len = read(rcvsock, bpfbuf, blen);
unsigned char *p = bpfbuf;
reloop:
bh = (struct bpf_hdr *)p;
buf = p + bh->bh_hdrlen; /* realign buf */
#endif
if (len == -1) {
fatal("%s %s", __func__, strerror(errno));
}
ip = (struct ip6_hdr *)(buf + ETH_HDRLEN);
if (ip->ip6_nxt == IPPROTO_ICMPV6) {
ippayload = (struct icmp6_hdr *)&buf[ETH_HDRLEN + sizeof(struct ip6_hdr)];
elapsed = trace->elapsed();
if ( (ippayload->icmp6_type == ICMP6_TIME_EXCEEDED) or
(ippayload->icmp6_type == ICMP6_DST_UNREACH) or
(ippayload->icmp6_type == ICMP6_ECHO_REPLY) ) {
ICMP *icmp = new ICMP6(ip, ippayload, elapsed, trace->config->coarse);
if (icmp->is_yarrp) {
if (verbosity > LOW)
icmp->print();
/* Fill mode logic. */
if (trace->config->fillmode) {
if ( (icmp->getTTL() >= trace->config->maxttl) and
(icmp->getTTL() < trace->config->fillmode) ) {
trace->stats->fills+=1;
trace->probe(icmp->quoteDst6(), icmp->getTTL() + 1);
}
}
icmp->write(&(trace->config->out), trace->stats->count);
/* TTL tree histogram */
if (trace->ttlhisto.size() > icmp->quoteTTL()) {
ttlhisto = trace->ttlhisto[icmp->quoteTTL()];
ttlhisto->add(icmp->getSrc6(), elapsed);
}
if (verbosity > DEBUG)
trace->dumpHisto();
}
delete icmp;
}
}
#ifndef _LINUX
p += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
if (p < bpfbuf + len) goto reloop;
#endif
}
return NULL;
}