1 /*
2 * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3 *
4 * This file is part of MooseFS.
5 *
6 * MooseFS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 2 (only).
9 *
10 * MooseFS is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MooseFS; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18 * or visit http://www.gnu.org/licenses/gpl-2.0.html
19 */
20
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <pcap.h>
27
28 #include "MFSCommunication.h"
29
30 typedef struct _userdata {
31 uint8_t bytesskip;
32 } userdata;
33
34 struct _mfscmd {
35 uint32_t command;
36 const char *commandstr;
37 } cmdtab[]={
38 #include "commands.h"
39 {0,NULL}};
40
41 typedef struct _mfscommand {
42 uint32_t command;
43 char *commandstr;
44 uint8_t colorcode;
45 uint8_t display;
46 } mfscommand;
47
48 static mfscommand *mfscmdtab = NULL;
49 static uint32_t mfscmdtableng = 0;
50
commands_cmp(const void * a,const void * b)51 int commands_cmp(const void *a,const void *b) {
52 const mfscommand *aa = (const mfscommand*)a;
53 const mfscommand *bb = (const mfscommand*)b;
54 return (aa->command>bb->command)?1:(aa->command<bb->command)?-1:0;
55 }
56
commands_convert(void)57 void commands_convert(void) {
58 uint32_t i;
59 uint8_t ccode;
60 char *p;
61 mfscmdtableng = 0;
62 for (i=0 ; cmdtab[i].commandstr!=NULL ; i++) {
63 mfscmdtableng++;
64 }
65 if (mfscmdtableng==0) {
66 mfscmdtab = NULL;
67 return;
68 }
69 mfscmdtab = malloc(sizeof(mfscommand)*mfscmdtableng);
70 for (i=0 ; cmdtab[i].commandstr!=NULL ; i++) {
71 mfscmdtab[i].command = cmdtab[i].command;
72 mfscmdtab[i].commandstr = strdup(cmdtab[i].commandstr);
73 p = mfscmdtab[i].commandstr;
74 ccode = 0;
75 if (p[0]!=0 && p[1]!=0 && p[2]=='T' && p[3]=='O') {
76 if (p[0]=='A' && p[1]=='N') {
77 if (p[4]=='A' && p[5]=='N') {
78 ccode = 8; /* ANTOAN */
79 } else if (p[4]=='C' && p[5]=='L') {
80 ccode = 13; /* ANTOCL */
81 } else if (p[4]=='C' && p[5]=='S') {
82 ccode = 14; /* ANTOCS */
83 } else if (p[4]=='M' && p[5]=='A') {
84 ccode = 1; /* ANTOMA */
85 }
86 } else if (p[0]=='C' && p[1]=='L') {
87 if (p[4]=='A' && p[5]=='N') {
88 ccode = 5; /* CLTOAN */
89 } else if (p[4]=='C' && p[5]=='S') {
90 ccode = 11; /* CLTOCS */
91 } else if (p[4]=='M' && p[5]=='A') {
92 ccode = 10; /* CLTOMA */
93 }
94 } else if (p[0]=='C' && p[1]=='S') {
95 if (p[4]=='A' && p[5]=='N') {
96 ccode = 6; /* CSTOAN */
97 } else if (p[4]=='C' && p[5]=='L') {
98 ccode = 3; /* CSTOCL */
99 } else if (p[4]=='M' && p[5]=='A') {
100 ccode = 4; /* CSTOMA */
101 }
102 } else if (p[0]=='M' && p[1]=='A') {
103 if (p[4]=='A' && p[5]=='N') {
104 ccode = 9; /* MATOAN */
105 } else if (p[4]=='C' && p[5]=='L') {
106 ccode = 2; /* MATOCL */
107 } else if (p[4]=='C' && p[5]=='S') {
108 ccode = 12; /* MATOCS */
109 }
110 }
111 }
112 mfscmdtab[i].colorcode = ccode;
113 mfscmdtab[i].display = 1;
114 }
115 qsort(mfscmdtab,mfscmdtableng,sizeof(mfscommand),commands_cmp);
116 }
117
commands_find(uint32_t cmd,uint8_t * color,uint8_t * display)118 const char* commands_find(uint32_t cmd,uint8_t *color,uint8_t *display) {
119 int32_t first,last,middle;
120 first = 0;
121 last = mfscmdtableng-1;
122 middle = (first+last)/2;
123
124 while (first<=last) {
125 if (mfscmdtab[middle].command<cmd) {
126 first = middle + 1;
127 } else if (mfscmdtab[middle].command>cmd) {
128 last = middle - 1;
129 } else {
130 *color = mfscmdtab[middle].colorcode;
131 *display = mfscmdtab[middle].display;
132 return mfscmdtab[middle].commandstr;
133 }
134 middle = (first+last)/2;
135 }
136 *color = 0;
137 *display = 0;
138 return NULL;
139 }
140
commands_exclude(const char * opt)141 void commands_exclude(const char *opt) {
142 char *str;
143 char *p;
144 uint32_t i;
145
146 str = strdup(opt);
147 for (p=strtok(str," ,;") ; p!=NULL ; p=strtok(NULL," ,;")) {
148 for (i=0 ; i<mfscmdtableng ; i++) {
149 if (strcmp(p,mfscmdtab[i].commandstr)==0) {
150 mfscmdtab[i].display = 0;
151 }
152 }
153 }
154 free(str);
155 }
156
commands_onlyuse(const char * opt)157 void commands_onlyuse(const char *opt) {
158 char *str;
159 char *p;
160 uint32_t i;
161 static uint8_t ft = 1;
162
163 if (ft) { // do it once
164 for (i=0 ; i<mfscmdtableng ; i++) {
165 mfscmdtab[i].display = 0;
166 }
167 ft = 0;
168 }
169
170 str = strdup(opt);
171 for (p=strtok(str," ,;") ; p!=NULL ; p=strtok(NULL," ,;")) {
172 for (i=0 ; i<mfscmdtableng ; i++) {
173 if (strcmp(p,mfscmdtab[i].commandstr)==0) {
174 mfscmdtab[i].display = 1;
175 }
176 }
177 }
178 free(str);
179 }
180
181
182
183
184
185 #define COLOR_PAYLOAD_ADDR "\033[38;5;159m"
186 #define COLOR_PAYLOAD_HEX "\033[38;5;228m"
187 #define COLOR_TIMESTAMP "\033[38;5;231m"
188 #define COLOR_ADDR_SRCHI "\033[38;5;156m"
189 #define COLOR_ADDR_DSTHI "\033[38;5;217m"
190 #define COLOR_ADDR_SRCLO "\033[38;5;194m"
191 #define COLOR_ADDR_DSTLO "\033[38;5;224m"
192 #define COLOR_WRONGPACKET "\033[38;5;199m"
193 #define COLOR_NEWCONN "\033[38;5;116m"
194 #define COLOR_CLOSECONN "\033[38;5;100m"
195 #define COLOR_DATA "\033[38;5;180m"
196 #define COLOR_CLEAR "\033(B\033[m"
197
198 static const char* color_tab[] = {
199 "\033[30m",
200 "\033[31m",
201 "\033[32m",
202 "\033[33m",
203 "\033[34m",
204 "\033[35m",
205 "\033[36m",
206 "\033[37m",
207 "\033[90m",
208 "\033[91m",
209 "\033[92m",
210 "\033[93m",
211 "\033[94m",
212 "\033[95m",
213 "\033[96m",
214 "\033[97m",
215 NULL
216 };
217
hexdump(const uint8_t * ptr,uint32_t len)218 void hexdump(const uint8_t *ptr,uint32_t len) {
219 uint8_t eol;
220 uint32_t i;
221 eol = 0;
222 for (i=0 ; i<len ; i++) {
223 eol = 1;
224 if ((i&0x1F)==0) {
225 printf(COLOR_PAYLOAD_ADDR "\t0x%05X:" COLOR_PAYLOAD_HEX,i);
226 }
227 printf(" %02X",ptr[i]);
228 if ((i&0x1F)==0x1F) {
229 printf(COLOR_CLEAR "\n");
230 eol = 0;
231 }
232 }
233 if (eol) {
234 printf(COLOR_CLEAR "\n");
235 }
236 }
237
238 // stupid implementation
239 typedef struct _connection {
240 uint32_t srcip,dstip;
241 uint16_t srcport,dstport;
242 uint32_t seq;
243 struct _connection *next;
244 } connection;
245
246 static connection *connhead = NULL;
247
packet_find(uint32_t srcip,uint16_t srcport,uint32_t dstip,uint16_t dstport)248 static inline connection** packet_find(uint32_t srcip,uint16_t srcport,uint32_t dstip,uint16_t dstport) {
249 connection *c,**cp;
250 cp = &connhead;
251 while ((c = *cp)) {
252 if (c->srcip==srcip && c->dstip==dstip && c->srcport==srcport && c->dstport==dstport) {
253 return cp;
254 }
255 cp = &(c->next);
256 }
257 return NULL;
258 }
259
print_info(const struct timeval * ts,const uint8_t * ip,uint16_t srcport,uint16_t dstport)260 static inline void print_info(const struct timeval *ts,const uint8_t *ip,uint16_t srcport,uint16_t dstport) {
261 printf(COLOR_TIMESTAMP "%ld.%06u : ",(long)(ts->tv_sec),(unsigned)(ts->tv_usec));
262 printf("%s%3u.%3u.%3u.%3u : %5" PRIu16 COLOR_CLEAR " -> %s%3u.%3u.%3u.%3u : %5"PRIu16 COLOR_CLEAR " ",(srcport<49152)?COLOR_ADDR_SRCLO:COLOR_ADDR_SRCHI,ip[12],ip[13],ip[14],ip[15],srcport,(dstport<49152)?COLOR_ADDR_DSTLO:COLOR_ADDR_DSTHI,ip[16],ip[17],ip[18],ip[19],dstport);
263 }
264
parse_packet(u_char * args,const struct pcap_pkthdr * header,const u_char * packet)265 void parse_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
266 userdata *ud = (userdata*)args;
267 const uint8_t *ip;
268 const uint8_t *tcp;
269 const uint8_t *payload;
270 uint32_t iplen;
271 uint32_t iphdrlen;
272 uint32_t tcplen;
273 uint32_t tcphdrlen;
274 uint32_t payloadlen;
275 uint32_t seqno,skip;
276 uint32_t srcip,dstip;
277 uint16_t srcport,dstport;
278 uint32_t mfscmd,mfslen;
279 uint8_t ccode,display;
280 const char *commandstr;
281 connection *c,**cp;
282
283 // printf("%ld.%06u: capleng = %u ; leng = %u (%u + %u)\n",(long)(header->ts.tv_sec),(unsigned)(header->ts.tv_usec),header->caplen,header->len,ud->bytesskip,header->len-ud->bytesskip);
284 if (ud->bytesskip>=header->caplen) { // no data
285 return;
286 }
287 ip = packet+ud->bytesskip;
288 iplen = header->caplen-ud->bytesskip;
289 // hexdump(ip,iplen);
290 // printf("\n");
291 if ((ip[0]&0xF0)!=0x40) {
292 return; // this is not IPv4 packet - ignore
293 }
294 if (iplen<20) {
295 return; // packet truncated on IP header - ignore
296 }
297 if (ip[9]!=6) {
298 return; // this is not TCP packet - ignore
299 }
300 iphdrlen = 4 * (ip[0] & 0xF);
301 if (iplen < iphdrlen) {
302 return; // packet truncated on IP header (options) - ignore
303 }
304 tcp = ip + iphdrlen;
305 tcplen = iplen - iphdrlen;
306 // hexdump(tcp,tcplen);
307 // printf("\n");
308 if (tcplen<20) {
309 return; // packet truncated on TCP header - ignore
310 }
311 tcphdrlen = 4 * (tcp[12] >> 4);
312 if (tcplen < tcphdrlen) {
313 return; // packet truncated on TCP header (options) - ignore
314 }
315 srcip = ((ip[12]*256U+ip[13])*256U+ip[14])*256U+ip[15];
316 dstip = ((ip[16]*256U+ip[17])*256U+ip[18])*256U+ip[19];
317 srcport = tcp[0]*256U+tcp[1];
318 dstport = tcp[2]*256U+tcp[3];
319 seqno = ((tcp[4]*256U+tcp[5])*256U+tcp[6])*256U+tcp[7];
320 cp = packet_find(srcip,srcport,dstip,dstport);
321 if (tcp[13]&0x2) { // SYN
322 print_info(&(header->ts),ip,srcport,dstport);
323 printf(COLOR_NEWCONN "... new connection ..." COLOR_CLEAR "\n");
324 }
325 if (tcp[13]&0x5) { // RST | FIN
326 print_info(&(header->ts),ip,srcport,dstport);
327 printf(COLOR_CLOSECONN "... close connection ..." COLOR_CLEAR "\n");
328 if (cp!=NULL) {
329 c = *cp;
330 *cp = c->next;
331 free(c);
332 }
333 return;
334 }
335 payload = tcp + tcphdrlen;
336 payloadlen = tcplen - tcphdrlen;
337 if (cp!=NULL) {
338 c = *cp;
339 if (c->seq > seqno) {
340 skip = c->seq - seqno;
341 print_info(&(header->ts),ip,srcport,dstport);
342 printf(COLOR_DATA "... data in packet ..." COLOR_CLEAR "\n");
343 } else {
344 skip = 0;
345 }
346 if (skip < payloadlen) {
347 payload += skip;
348 payloadlen -= skip;
349 } else {
350 return;
351 }
352 }
353 // hexdump(payload,payloadlen);
354 while (payloadlen>=8) {
355 mfscmd = ((payload[0]*256U+payload[1])*256U+payload[2])*256U+payload[3];
356 mfslen = ((payload[4]*256U+payload[5])*256U+payload[6])*256U+payload[7];
357 commandstr = commands_find(mfscmd,&ccode,&display);
358 if (commandstr && mfslen<=100000000) {
359 if (display) {
360 print_info(&(header->ts),ip,srcport,dstport);
361 if (ccode>=1 && ccode<=15) {
362 printf("%s",color_tab[ccode]);
363 }
364 printf("%s",commandstr);
365 if (ccode) {
366 printf(COLOR_CLEAR);
367 }
368 printf("\n");
369 if (payloadlen-8<=128) {
370 if (mfslen < payloadlen-8) {
371 hexdump(payload+8,mfslen);
372 } else {
373 hexdump(payload+8,payloadlen-8);
374 }
375 } else {
376 if (mfslen < 128) {
377 hexdump(payload+8,mfslen);
378 } else {
379 hexdump(payload+8,128);
380 printf("\t(...)\n");
381 }
382 }
383 }
384 if (mfslen + 8 == payloadlen) {
385 if (cp!=NULL) {
386 c = *cp;
387 *cp = c->next;
388 free(c);
389 }
390 payloadlen = 0;
391 payload = NULL;
392 } else if (mfslen + 8 < payloadlen) {
393 payloadlen -= (mfslen + 8);
394 payload += (mfslen + 8);
395 seqno += (mfslen + 8);
396 } else {
397 if (cp!=NULL) {
398 c = *cp;
399 c->seq = seqno + mfslen + 8;
400 } else {
401 c = malloc(sizeof(connection));
402 c->srcip = srcip;
403 c->dstip = dstip;
404 c->srcport = srcport;
405 c->dstport = dstport;
406 c->seq = seqno + mfslen + 8;
407 c->next = connhead;
408 connhead = c;
409 }
410 payloadlen = 0;
411 payload = NULL;
412 }
413 } else {
414 print_info(&(header->ts),ip,srcport,dstport);
415 printf(COLOR_WRONGPACKET "... not mfs packet (%u:%u) ..." COLOR_CLEAR "\n",mfscmd,mfslen);
416 if (cp!=NULL) {
417 c = *cp;
418 *cp = c->next;
419 free(c);
420 }
421 return;
422 }
423 }
424 return;
425 }
426
usage(const char * appname)427 void usage(const char *appname) {
428 fprintf(stderr,"usage: %s [-i interface] [-f pcap_filter] [-c packet count] [-e commands] [-o commands]\n\t-e: do not display this commands\n\t-o: when present only this commands will be displayed\n",appname);
429 }
430
main(int argc,char ** argv)431 int main(int argc, char **argv) {
432 char ch;
433 char errbuf[PCAP_ERRBUF_SIZE];
434 char *dev;
435 char *filter;
436 int32_t packetcnt;
437 bpf_u_int32 devnet;
438 bpf_u_int32 devmask;
439 pcap_t *handle;
440 int datalink;
441 struct bpf_program fp;
442 userdata udm;
443
444 commands_convert();
445
446 dev = NULL;
447 filter = NULL;
448 packetcnt = -1;
449
450 while ((ch = getopt(argc, argv, "si:f:c:e:o:?")) != -1) {
451 switch (ch) {
452 case 's':
453 if (filter) {
454 free(filter);
455 }
456 filter = strdup("port 9419 or port 9420 or port 9421 or port 9422");
457 break;
458 case 'i':
459 if (dev) {
460 free(dev);
461 }
462 dev = strdup(optarg);
463 break;
464 case 'f':
465 if (filter) {
466 free(filter);
467 }
468 filter = strdup(optarg);
469 break;
470 case 'c':
471 packetcnt = strtol(optarg,NULL,0);
472 break;
473 case 'e':
474 commands_exclude(optarg);
475 break;
476 case 'o':
477 commands_onlyuse(optarg);
478 break;
479 default:
480 usage(argv[0]);
481 return 1;
482 }
483 }
484
485 if (dev==NULL) {
486 dev = pcap_lookupdev(errbuf);
487 if (dev == NULL) {
488 fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
489 return 1;
490 }
491 }
492
493
494 if (pcap_lookupnet(dev, &devnet, &devmask, errbuf)<0) {
495 printf("Device: %s\n",dev);
496 fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
497 devnet = 0;
498 devmask = 0;
499 } else {
500 // printf("Device: %s (%u.%u.%u.%u/%u.%u.%u.%u)\n", dev, (devnet>>24)&0xFF,(devnet>>16)&0xFF,(devnet>>8)&0xFF,devnet&0xFF,(devmask>>24)&0xFF,(devmask>>16)&0xFF,(devmask>>8)&0xFF,devmask&0xFF); // BIG/LITTLE ENDIAN ???
501 printf("Device: %s (%u.%u.%u.%u/%u.%u.%u.%u)\n", dev, devnet&0xFF,(devnet>>8)&0xFF,(devnet>>16)&0xFF,(devnet>>24)&0xFF,devmask&0xFF,(devmask>>8)&0xFF,(devmask>>16)&0xFF,(devmask>>24)&0xFF);
502 }
503
504 handle = pcap_open_live(dev, 100000, 1, 1000, errbuf);
505 if (handle == NULL) {
506 fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
507 return 1;
508 }
509
510 datalink = pcap_datalink(handle);
511 if (datalink == DLT_EN10MB) {
512 udm.bytesskip = 14;
513 } else if (datalink == DLT_NULL) {
514 udm.bytesskip = 4;
515 } else if (datalink == DLT_RAW) {
516 udm.bytesskip = 0;
517 } else {
518 fprintf(stderr, "%s is not an Ethernet (type: %s)\n", dev, pcap_datalink_val_to_name(datalink));
519 return 1;
520 }
521
522 if (filter!=NULL) {
523 if (pcap_compile(handle, &fp, filter, 0, devnet)<0) {
524 fprintf(stderr, "Couldn't parse filter %s: %s\n", filter, pcap_geterr(handle));
525 return 1;
526 }
527
528 if (pcap_setfilter(handle, &fp)<0) {
529 fprintf(stderr, "Couldn't install filter %s: %s\n", filter, pcap_geterr(handle));
530 return 1;
531 }
532 }
533
534 pcap_loop(handle,packetcnt,parse_packet,(void*)(&udm));
535
536 pcap_freecode(&fp);
537 pcap_close(handle);
538
539 printf("\nCapture complete.\n");
540 return 0;
541 }
542
543