-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathxesflow.c
246 lines (198 loc) · 6.6 KB
/
xesflow.c
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "xenoeye.h"
#include "sflow.h"
static void sflow_parse_payload(uint8_t *end, uint8_t *p);
#undef LOG
#define LOG(...) \
do { \
char _buf[4096]; \
int _ret = snprintf(_buf, sizeof(_buf), __VA_ARGS__); \
if (_ret >= (int)(sizeof(_buf))) { \
fprintf(stderr, \
"Next line truncated to %d symbols", \
_ret); \
} \
printf("%s [%s, line %d, function %s()]\n", \
_buf, __FILE__, __LINE__, __func__); \
} while (0)
#include "xe-dns.h"
#include "xe-sni.h"
#define USER_TYPE uint8_t *
#define ON_ETH(D, V) \
do { \
(void)data; \
char buf[32]; \
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", \
V->h_source[0], V->h_source[1], V->h_source[2], \
V->h_source[3], V->h_source[4], V->h_source[5]); \
LOG("\t\t\tEthernet src: %s", buf); \
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", \
V->h_dest[0], V->h_dest[1], V->h_dest[2], \
V->h_dest[3], V->h_dest[4], V->h_dest[5]); \
LOG("\t\t\tEthernet dst: %s", buf); \
LOG("\t\t\tEthernet proto: 0x%x", be16toh(V->h_proto)); \
} while (0)
#define ON_VLAN1(D, V) \
LOG("\t\t\tVLAN %d", be16toh(V->h_vlan_TCI));
#define ON_VLAN2(D, V) \
LOG("\t\t\tVLAN2 %d", be16toh(V->h_vlan_TCI));
#define ON_IP(D, V) \
do { \
char s[INET_ADDRSTRLEN + 1]; \
inet_ntop(AF_INET, &V->saddr, s, INET_ADDRSTRLEN); \
LOG("\t\t\tIPv4 src: %s", s); \
inet_ntop(AF_INET, &V->daddr, s, INET_ADDRSTRLEN); \
LOG("\t\t\tIPv4 dst: %s", s); \
LOG("\t\t\tTOS: 0x%0x", V->tos); \
LOG("\t\t\tID: %d", be16toh(V->id)); \
LOG("\t\t\tTTL: %d", V->ttl); \
LOG("\t\t\tIP protocol: %d", V->protocol); \
} while (0)
#define ON_IP6(D, V) \
do { \
char s[INET6_ADDRSTRLEN + 1]; \
inet_ntop(AF_INET6, &V->ip6_src, s, INET6_ADDRSTRLEN); \
LOG("\t\t\tIPv6 src: %s", s); \
inet_ntop(AF_INET6, &V->ip6_dst, s, INET6_ADDRSTRLEN); \
LOG("\t\t\tIPv6 dst: %s", s); \
LOG("\t\t\tTTL: %d", V->ip6_ctlun.ip6_un1.ip6_un1_hlim); \
LOG("\t\t\tIP protocol: %d", (int)nexthdr); \
} while (0)
#define ON_UDP(D, V) \
do { \
LOG("\t\t\tUDP src port: %d", be16toh(V->source)); \
LOG("\t\t\tUDP dst port: %d", be16toh(V->dest)); \
} while (0)
#define ON_TCP(D, V) \
do { \
LOG("\t\t\tTCP src port: %d", be16toh(V->source)); \
LOG("\t\t\tTCP dst port: %d", be16toh(V->dest)); \
LOG("\t\t\tTCP flags: 0x%0x", V->th_flags); \
} while (0)
#define ON_ICMP(D, V) \
do { \
LOG("\t\t\tICMP type: %d", V->type); \
LOG("\t\t\tICMP code: %d", V->code); \
} while (0)
#define ON_PAYLOAD(D, P) sflow_parse_payload(D, P);
#include "rawparse.h"
#undef ON_ICMP
#undef ON_TCP
#undef ON_UDP
#undef ON_IP
#undef ON_ETH
static void
sflow_parse_payload(uint8_t *end, uint8_t *p)
{
if (xe_sni(p, end, NULL)) {
return;
}
if (xe_dns(p, end, NULL, NULL)) {
return;
}
}
static inline int
sf5_eth(struct sfdata *s, uint8_t *p, enum RP_TYPE t, uint32_t header_len)
{
(void)s;
uint8_t *end = p + header_len;
if (rawpacket_parse(p, end, t, end)
< RP_PARSER_STATE_NO_IP) {
/* Skip non-IP samples */
return 0;
}
return 1;
}
#include "sflow-impl.h"
#undef USER_TYPE
#define USER_TYPE uint8_t **
#undef ON_PAYLOAD
#define ON_PAYLOAD(D, P) *D = P;
#define rawpacket_parse rawpacket_parse_sflow
#include "rawparse.h"
static void
print_usage(const char *prog_name)
{
LOG("Usage: %s -i eth0 [-f \"udp and port 6543\"]", prog_name);
}
int
main(int argc, char *argv[])
{
int opt;
char *ifname = NULL;
char *filter = "";
pcap_t *p_handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
int ret = EXIT_FAILURE;
while ((opt = getopt(argc, argv, "f:hi:")) != -1) {
switch (opt) {
case 'i':
ifname = optarg;
break;
case 'f':
filter = optarg;
break;
case 'h':
default:
print_usage(argv[0]);
return EXIT_FAILURE;
}
}
if (!ifname) {
LOG("Interface name is required");
print_usage(argv[0]);
return EXIT_FAILURE;
}
p_handle = pcap_open_live(ifname, BUFSIZ, 1, 1000, errbuf);
if (p_handle == NULL) {
LOG("Can't open device '%s': %s", ifname, errbuf);
return EXIT_FAILURE;
}
if (pcap_compile(p_handle, &fp, filter,
1, PCAP_NETMASK_UNKNOWN) == -1) {
LOG("Can't parse filter '%s': %s", filter,
pcap_geterr(p_handle));
goto fail_filter;
}
if (pcap_setfilter(p_handle, &fp) == -1) {
LOG("Can't set filter '%s': %s", filter,
pcap_geterr(p_handle));
goto fail_setfilter;
}
for (;;) {
int rc;
struct pcap_pkthdr *header;
const unsigned char *packet;
struct flow_packet_info fpi;
uint8_t *sflow_data = NULL;
rc = pcap_next_ex(p_handle, &header, &packet);
if (rc == 1) {
enum RP_PARSER_STATE ps;
uint8_t *ptr = (uint8_t *)packet;
int len;
ps = rawpacket_parse_sflow(ptr, ptr + header->caplen,
RP_TYPE_ETHER, &sflow_data);
if (ps != RP_PARSER_STATE_OK) {
continue;
}
if (!sflow_data) {
continue;
}
len = header->caplen - (sflow_data - packet);
memcpy(fpi.rawpacket, sflow_data, len);
sflow_process(NULL, 0, &fpi, len);
} else {
LOG("Error reading the packets: %s",
pcap_geterr(p_handle));
}
}
ret = EXIT_SUCCESS;
fail_setfilter:
pcap_freecode(&fp);
fail_filter:
pcap_close(p_handle);
return ret;
}