1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 // Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License Version 2 as published
8 // by the Free Software Foundation. You may not use, modify or distribute
9 // this program under any other version of the GNU General Public License.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 //--------------------------------------------------------------------------
20 // u2spewfoo.cc author Adam Keeton
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <arpa/inet.h>
27 #include <sys/socket.h>
28
29 #include <cctype>
30 #include <cerrno>
31 #include <cstdlib>
32 #include <cstring>
33
34 #include "u2_common.h"
35
36 static long s_pos = 0, s_off = 0;
37
38 #define TO_IP(x) x >> 24, ((x) >> 16)& 0xff, ((x) >> 8)& 0xff, (x)& 0xff
39
new_iterator(char * filename)40 static u2iterator* new_iterator(char* filename)
41 {
42 FILE* f = fopen(filename, "rb");
43 u2iterator* ret;
44
45 if (!f)
46 {
47 printf("ERROR: Failed to open file: %s\n\tErrno: %s\n",
48 filename, strerror(errno));
49 return nullptr;
50 }
51
52 ret = (u2iterator*)malloc(sizeof(u2iterator));
53
54 if (!ret)
55 {
56 printf("ERROR: Failed to initialize iterator\n");
57 fclose(f);
58 return nullptr;
59 }
60
61 ret->file = f;
62 ret->filename = strdup(filename);
63 if (!ret->filename )
64 {
65 printf("ERROR: Failed to initialize iterator for %s\n", filename);
66 free(ret);
67 fclose(f);
68 return nullptr;
69 }
70 return ret;
71 }
72
free_iterator(u2iterator * it)73 static inline void free_iterator(u2iterator* it)
74 {
75 if (!it)
76 return;
77
78 if (it->file)
79 fclose(it->file);
80 if (it->filename)
81 free(it->filename);
82 free(it);
83 }
84
get_record(u2iterator * it,u2record * record)85 static bool get_record(u2iterator* it, u2record* record)
86 {
87 uint32_t bytes_read;
88 uint8_t* tmp;
89
90 if (!it || !it->file)
91 return false;
92
93 /* check if the log was rotated */
94 if (feof(it->file))
95 {
96 /* Get next timestamped file? */
97 puts("Hit the EOF .. and this is not being handled yet.");
98 return false;
99 }
100
101 if ( s_off )
102 {
103 if ( fseek(it->file, s_pos+s_off, SEEK_SET) )
104 {
105 puts("Unable to SEEK on current file .. and this is not being handled yet.");
106 return false;
107 }
108 s_off = 0;
109 }
110
111 /* read type and length */
112 bytes_read = fread(record, 1, sizeof(uint32_t) * 2, it->file);
113 /* But they're in network order! */
114 record->type= ntohl(record->type);
115 record->length= ntohl(record->length);
116
117 //if(record->type == UNIFIED2_PACKET) record->length+=4;
118
119 if (bytes_read == 0)
120 /* EOF */
121 return false;
122
123 if (bytes_read != sizeof(uint32_t)*2)
124 {
125 puts("ERROR: Failed to read record metadata.");
126 printf("\tRead %u of %zu bytes\n", bytes_read, sizeof(uint32_t)*2);
127 return false;
128 }
129
130 s_pos = ftell(it->file);
131
132 tmp = (uint8_t*)realloc(record->data, record->length);
133
134 if (!tmp)
135 {
136 puts("ERROR: Failed to allocate record memory.");
137 free(record->data);
138 record->data = nullptr;
139 return false;
140 }
141
142 record->data = tmp;
143
144 bytes_read = fread(record->data, 1, record->length, it->file);
145
146 if (bytes_read != record->length)
147 {
148 puts("ERROR: Failed to read all record data.");
149 printf("\tRead %u of %u bytes\n", bytes_read, record->length);
150
151 if ( record->type != UNIFIED2_PACKET ||
152 bytes_read < ntohl(((Serial_Unified2Packet*)record->data)->packet_length)
153 )
154 return false;
155
156 clearerr(it->file);
157 }
158
159 return true;
160 }
161
extradata_dump(u2record * record)162 static void extradata_dump(u2record* record)
163 {
164 uint8_t* field, * data;
165 int i;
166 int len = 0;
167 SerialUnified2ExtraData event;
168 Unified2ExtraDataHdr eventHdr;
169 uint32_t ip;
170 char ip6buf[INET6_ADDRSTRLEN+1];
171 struct in6_addr ipAddr;
172
173 memcpy(&eventHdr, record->data, sizeof(Unified2ExtraDataHdr));
174
175 memcpy(&event, record->data + sizeof(Unified2ExtraDataHdr), sizeof(SerialUnified2ExtraData));
176
177 /* network to host ordering */
178 field = (uint8_t*)&eventHdr;
179 for (i=0; i<2; i++, field+=4)
180 {
181 *(uint32_t*)field = ntohl(*(uint32_t*)field);
182 }
183
184 field = (uint8_t*)&event;
185 for (i=0; i<6; i++, field+=4)
186 {
187 *(uint32_t*)field = ntohl(*(uint32_t*)field);
188 }
189
190 printf("\n(ExtraDataHdr)\n"
191 "\tevent type: %u\tevent length: %u\n",
192 eventHdr.event_type, eventHdr.event_length);
193
194 printf("\n(ExtraData)\n"
195 "\tsensor id: %u\tevent id: %u\tevent second: %u\n"
196 "\ttype: %u\tdatatype: %u\tbloblength: %u\t",
197 event.sensor_id, event.event_id,
198 event.event_second, event.type,
199 event.data_type, event.blob_length);
200
201 len = event.blob_length - sizeof(event.blob_length) - sizeof(event.data_type);
202
203 switch (event.type)
204 {
205 case EVENT_INFO_XFF_IPV4:
206 memcpy(&ip, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData),
207 sizeof(uint32_t));
208 ip = ntohl(ip);
209 printf("Original Client IP: %u.%u.%u.%u\n", TO_IP(ip));
210 break;
211
212 case EVENT_INFO_XFF_IPV6:
213 memcpy(&ipAddr, record->data + sizeof(Unified2ExtraDataHdr) +
214 sizeof(SerialUnified2ExtraData), sizeof(struct in6_addr));
215 inet_ntop(AF_INET6, &ipAddr, ip6buf, INET6_ADDRSTRLEN);
216 printf("Original Client IP: %s\n", ip6buf);
217 break;
218
219 case EVENT_INFO_GZIP_DATA:
220 printf("GZIP Decompressed Data: %.*s\n",
221 len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
222 break;
223
224 case EVENT_INFO_JSNORM_DATA:
225 printf("Normalized JavaScript Data: %.*s\n",
226 len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
227 break;
228
229 case EVENT_INFO_SMTP_FILENAME:
230 printf("SMTP Attachment Filename: %.*s\n",
231 len,record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
232 break;
233
234 case EVENT_INFO_SMTP_MAILFROM:
235 printf("SMTP MAIL FROM Addresses: %.*s\n",
236 len,record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
237 break;
238
239 case EVENT_INFO_SMTP_RCPTTO:
240 printf("SMTP RCPT TO Addresses: %.*s\n",
241 len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
242 break;
243
244 case EVENT_INFO_SMTP_EMAIL_HDRS:
245 printf("SMTP EMAIL HEADERS: \n%.*s\n",
246 len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
247 break;
248
249 case EVENT_INFO_HTTP_URI:
250 printf("HTTP URI: %.*s\n",
251 len, record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData));
252 break;
253
254 case EVENT_INFO_HTTP_HOSTNAME:
255 printf("HTTP Hostname: ");
256 data = record->data + sizeof(Unified2ExtraDataHdr) + sizeof(SerialUnified2ExtraData);
257 for (i=0; i < len; i++)
258 {
259 if (iscntrl(data[i]))
260 printf("%c",'.');
261 else
262 printf("%c",data[i]);
263 }
264 printf("\n");
265 break;
266
267 case EVENT_INFO_IPV6_SRC:
268 memcpy(&ipAddr, record->data + sizeof(Unified2ExtraDataHdr) +
269 sizeof(SerialUnified2ExtraData), sizeof(struct in6_addr));
270 inet_ntop(AF_INET6, &ipAddr, ip6buf, INET6_ADDRSTRLEN);
271 printf("IPv6 Source Address: %s\n", ip6buf);
272 break;
273
274 case EVENT_INFO_IPV6_DST:
275 memcpy(&ipAddr, record->data + sizeof(Unified2ExtraDataHdr) +
276 sizeof(SerialUnified2ExtraData), sizeof(struct in6_addr));
277 inet_ntop(AF_INET6, &ipAddr, ip6buf, INET6_ADDRSTRLEN);
278 printf("IPv6 Destination Address: %s\n", ip6buf);
279 break;
280
281 default:
282 break;
283 }
284 }
285
lookup(const char * list[],unsigned size,unsigned idx)286 static const char* lookup(const char* list[], unsigned size, unsigned idx)
287 {
288 if ( idx < size )
289 return list[idx];
290
291 static char buf[8];
292 snprintf(buf, sizeof(buf), "%u", idx);
293 return buf;
294 }
295
get_status(uint8_t stat)296 static const char* get_status(uint8_t stat)
297 {
298 const char* stats[] = { "allow", "can't", "would", "force" };
299 return lookup(stats, sizeof(stats)/sizeof(stats[0]), stat);
300 }
301
get_action(uint8_t act)302 static const char* get_action(uint8_t act)
303 {
304 const char* acts[] = { "trust", "pass", "hold", "retry", "drop", "block", "reset" };
305 return lookup(acts, sizeof(acts)/sizeof(acts[0]), act);
306 }
307
print_addr_port(const char * which,unsigned af,const uint32_t * addr,uint16_t port)308 static void print_addr_port(
309 const char* which, unsigned af, const uint32_t* addr, uint16_t port)
310 {
311 uint16_t fam = (af == 0x4) ? AF_INET : AF_INET6;
312 unsigned idx = (fam == AF_INET) ? 3 : 0;
313
314 char ip_buf[INET6_ADDRSTRLEN+1];
315 inet_ntop(fam, addr+idx, ip_buf, sizeof(ip_buf));
316
317 printf("\t%s IP: %s\tPort: %hu\n", which, ip_buf, htons(port));
318 }
319
event3_dump(u2record * record)320 static void event3_dump(u2record* record)
321 {
322 Unified2Event event;
323 memcpy(&event, record->data, sizeof(event));
324
325 printf("%s", "\n(Event)\n");
326
327 printf("\tSnort ID: %u\tEvent ID: %u\tSeconds: %u.%06u\n",
328 htonl(event.snort_id), htonl(event.event_id),
329 htonl(event.event_second), htonl(event.event_microsecond));
330
331 printf(
332 "\tPolicy ID:\tContext: %u\tInspect: %u\tDetect: %u\n",
333 htonl(event.policy_id_context), htonl(event.policy_id_inspect),
334 htonl(event.policy_id_detect));
335
336 printf(
337 "\tRule %u:%u:%u\tClass: %u\tPriority: %u\n",
338 htonl(event.rule_gid), htonl(event.rule_sid), htonl(event.rule_rev),
339 htonl(event.rule_class), htonl(event.rule_priority));
340
341 printf(
342 "\tMPLS Label: %u\tVLAN ID: %hu\tIP Version: 0x%hhX\tIP Proto: %hhu\n",
343 htonl(event.pkt_mpls_label), htons(event.pkt_vlan_id),
344 event.pkt_ip_ver, event.pkt_ip_proto);
345
346 print_addr_port("Src", event.pkt_ip_ver >> 4, event.pkt_src_ip, event.pkt_src_port_itype);
347 print_addr_port("Dst", event.pkt_ip_ver & 0xF, event.pkt_dst_ip, event.pkt_dst_port_icode);
348
349 printf("\tApp Name: %s\n", event.app_name[0] ? event.app_name : "none");
350
351 printf(
352 "\tStatus: %s\tAction: %s\n",
353 get_status(event.snort_status), get_action(event.snort_action));
354 }
355
event2_dump(u2record * record)356 static void event2_dump(u2record* record)
357 {
358 uint8_t* field;
359 int i;
360
361 Unified2IDSEvent event;
362
363 memcpy(&event, record->data, sizeof(event));
364
365 /* network to host ordering
366 In the event structure, only the last 40 bits are not 32 bit fields
367 The first 11 fields need to be converted */
368 field = (uint8_t*)&event;
369 for (i=0; i<11; i++, field+=4)
370 {
371 *(uint32_t*)field = ntohl(*(uint32_t*)field);
372 }
373
374 /* last 3 fields, with the exception of the last most since it's just one byte */
375 *(uint16_t*)field = ntohs(*(uint16_t*)field); /* sport_itype */
376 field += 2;
377 *(uint16_t*)field = ntohs(*(uint16_t*)field); /* dport_icode */
378 field +=6;
379 *(uint32_t*)field = ntohl(*(uint32_t*)field); /* mpls_label */
380 field += 4;
381 /* policy_id and vlanid */
382 for (i=0; i<2; i++, field+=2)
383 {
384 *(uint16_t*)field = ntohs(*(uint16_t*)field);
385 }
386 /* done changing the network ordering */
387
388 printf("\n(Event)\n"
389 "\tsensor id: %u\tevent id: %u\tevent second: %u\tevent microsecond: %u\n"
390 "\tsig id: %u\tgen id: %u\trevision: %u\t classification: %u\n"
391 "\tpriority: %u\tip source: %u.%u.%u.%u\tip destination: %u.%u.%u.%u\n"
392 "\tsrc port: %hu\tdest port: %hu\tip_proto: %hhu\timpact_flag: %hhu\tblocked: %hhu\n"
393 "\tmpls label: %u\tvlan id: %hu\tpolicy id: %hu\tappid: %s\n",
394 event.sensor_id, event.event_id,
395 event.event_second, event.event_microsecond,
396 event.signature_id, event.generator_id,
397 event.signature_revision, event.classification_id,
398 event.priority_id, TO_IP(event.ip_source),
399 TO_IP(event.ip_destination), event.sport_itype,
400 event.dport_icode, to_utype(event.ip_proto),
401 event.impact_flag, event.blocked,
402 event.mpls_label, event.vlanId, event.pad2, event.app_name);
403 }
404
event2_6_dump(u2record * record)405 static void event2_6_dump(u2record* record)
406 {
407 uint8_t* field;
408 int i;
409 char ip6buf[INET6_ADDRSTRLEN+1];
410 Unified2IDSEventIPv6 event;
411
412 memcpy(&event, record->data, sizeof(event));
413
414 /* network to host ordering
415 In the event structure, only the last 40 bits are not 32 bit fields
416 The first fields need to be converted */
417 field = (uint8_t*)&event;
418 for (i=0; i<9; i++, field+=4)
419 {
420 *(uint32_t*)field = ntohl(*(uint32_t*)field);
421 }
422
423 field = field + 2*sizeof(struct in6_addr);
424
425 /* last 3 fields, with the exception of the last most since it's just one byte */
426 *(uint16_t*)field = ntohs(*(uint16_t*)field); /* sport_itype */
427 field += 2;
428 *(uint16_t*)field = ntohs(*(uint16_t*)field); /* dport_icode */
429 field +=6;
430 *(uint32_t*)field = ntohl(*(uint32_t*)field); /* mpls_label */
431 field += 4;
432 /* policy_id and vlanid */
433 for (i=0; i<2; i++, field+=2)
434 {
435 *(uint16_t*)field = ntohs(*(uint16_t*)field);
436 }
437 /* done changing the network ordering */
438
439 inet_ntop(AF_INET6, &event.ip_source, ip6buf, INET6_ADDRSTRLEN);
440
441 printf("\n(IPv6 Event)\n"
442 "\tsensor id: %u\tevent id: %u\tevent second: %u\tevent microsecond: %u\n"
443 "\tsig id: %u\tgen id: %u\trevision: %u\t classification: %u\n"
444 "\tpriority: %u\tip source: %s\t",
445 event.sensor_id, event.event_id,
446 event.event_second, event.event_microsecond,
447 event.signature_id, event.generator_id,
448 event.signature_revision, event.classification_id,
449 event.priority_id, ip6buf);
450
451 inet_ntop(AF_INET6, &event.ip_destination, ip6buf, INET6_ADDRSTRLEN);
452 printf("ip destination: %s\n"
453 "\tsrc port: %hu\tdest port: %hu\tip_proto: %hhu\timpact_flag: %hhu\tblocked: %hhu\n"
454 "\tmpls label: %u\tvlan id: %hu\tpolicy id: %hu\tappid: %s\n",
455 ip6buf, event.sport_itype,
456 event.dport_icode, to_utype(event.ip_proto),
457 event.impact_flag, event.blocked,
458 event.mpls_label, event.vlanId, event.pad2, event.app_name);
459 }
460
461 #define LOG_CHARS 16
462
LogBuffer(const uint8_t * p,unsigned n)463 static void LogBuffer(const uint8_t* p, unsigned n)
464 {
465 char hex[(3*LOG_CHARS)+1];
466 char txt[LOG_CHARS+1];
467 unsigned odx = 0, idx = 0, at = 0;
468
469 for ( idx = 0; idx < n; idx++)
470 {
471 uint8_t byte = p[idx];
472 sprintf(hex + 3*odx, "%2.02X ", byte);
473 txt[odx++] = isprint(byte) ? byte : '.';
474
475 if ( odx == LOG_CHARS )
476 {
477 txt[odx] = hex[3*odx] = '\0';
478 printf("[%5u] %s %s\n", at, hex, txt);
479 at = idx + 1;
480 odx = 0;
481 }
482 }
483 if ( odx )
484 {
485 txt[odx] = hex[3*odx] = '\0';
486 printf("[%5u] %-48.48s %s\n", at, hex, txt);
487 }
488 }
489
packet_dump(u2record * record)490 static void packet_dump(u2record* record)
491 {
492 uint32_t counter;
493 uint8_t* field;
494
495 unsigned offset = sizeof(Serial_Unified2Packet)-4;
496 unsigned reclen = record->length - offset;
497
498 Serial_Unified2Packet packet;
499 memcpy(&packet, record->data, offset);
500
501 /* network to host ordering
502 The first 7 fields need to be converted */
503 field = (uint8_t*)&packet;
504 for (counter=0; counter<7; counter++, field+=4)
505 {
506 *(uint32_t*)field = ntohl(*(uint32_t*)field);
507 }
508 /* done changing from network ordering */
509
510 if (record->type == UNIFIED2_PACKET)
511 printf("\nPacket\n"
512 "\tsensor id: %u\tevent id: %u\tevent second: %u\n"
513 "\tpacket second: %u\tpacket microsecond: %u\n"
514 "\tlinktype: %u\tpacket_length: %u\n",
515 packet.sensor_id, packet.event_id, packet.event_second,
516 packet.packet_second, packet.packet_microsecond, packet.linktype,
517 packet.packet_length);
518 else
519 printf("\nBuffer\n"
520 "\tsensor_id: %u\tevent_id: %u\tevent_second: %u\n"
521 "\tpacket_second: %u\tpacket_microsecond: %u\n"
522 "\tpacket_length: %u\n",
523 packet.sensor_id, packet.event_id, packet.event_second,
524 packet.packet_second, packet.packet_microsecond, packet.packet_length);
525
526 if ( record->length <= offset )
527 return;
528
529 if ( packet.packet_length != reclen )
530 {
531 printf("ERROR: logged %u but packet_length = %u\n",
532 record->length-offset, packet.packet_length);
533
534 if ( packet.packet_length < reclen )
535 {
536 reclen = packet.packet_length;
537 s_off = reclen + offset;
538 }
539 }
540 LogBuffer(record->data+offset, reclen);
541 }
542
u2dump(char * file)543 static int u2dump(char* file)
544 {
545 u2record record;
546 u2iterator* it = new_iterator(file);
547
548 memset(&record, 0, sizeof(record));
549
550 if (!it)
551 {
552 printf("ERROR: failed to create new iterator with file: %s\n", file);
553 return -1;
554 }
555
556 while ( get_record(it, &record) )
557 {
558 if ( record.type == UNIFIED2_EVENT3 and record.length == sizeof(Unified2Event) )
559 event3_dump(&record);
560
561 else if ( (record.type == UNIFIED2_PACKET) or (record.type == UNIFIED2_BUFFER) )
562 packet_dump(&record);
563
564 else if (record.type == UNIFIED2_EXTRA_DATA)
565 extradata_dump(&record);
566
567 // deprecated
568 else if ( record.type == UNIFIED2_IDS_EVENT_VLAN and
569 record.length == sizeof(Unified2IDSEvent) )
570 {
571 event2_dump(&record);
572 }
573 else if ( record.type == UNIFIED2_IDS_EVENT_IPV6_VLAN and
574 record.length == sizeof(Unified2IDSEventIPv6) )
575 {
576 event2_6_dump(&record);
577 }
578 else
579 {
580 printf("WARNING: skipping unknown record (%u) or bad length (%u)\n",
581 record.type, record.length);
582 }
583 }
584
585 free_iterator(it);
586
587 if (record.data)
588 free(record.data);
589
590 return 0;
591 }
592
main(int argc,char ** argv)593 int main(int argc, char** argv)
594 {
595 if (argc != 2)
596 {
597 puts("usage: u2spewfoo <file>");
598 return 1;
599 }
600
601 return u2dump(argv[1]);
602 }
603
604