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