//////////////////////////////////////////////////////////////////////////// // LogToPcap.c // Pcap converter for Snort Unified Log Files // Copyright (c) 2002 Dragos Ruiu / dursec.com // All rights reserved. // // License: Free for non-commercial individual use. // // Build instructions: cc -o logtopcap logtopcap.c //////////////////////////////////////////////////////////////////////////// #include #include #include #include //////////////////////////////////////////////////////////////////////////// ////////////////////// Defines and Data Structures ///////////////////////// //////////////////////////////////////////////////////////////////////////// /* Memory managment primitives - assumed free returns null on error */ #ifndef ALLOC #define ALLOC(x) malloc(x) #endif #ifndef FREE #define FREE(x) free((void *)x) #endif #ifndef NULL #define NULL 0 #endif #ifndef ERROR #define ERROR(x) fprintf(stderr,"%s\n",x); #endif ////////////////////// // file magic ////////////////////// #define UNIFIEDMAGIC 0x2DAC5CEB #define PCAPMAGIC 0xA1B2C3D4 #define ALERTMAGIC 0xDEAD4137 #define LOGMAGIC 0xDEAD1080 //////////////////// // pcap and snort 1.x logfile header //////////////////// typedef struct _LogFileHead { u_int16_t version_major; u_int16_t version_minor; u_int32_t timezone; u_int32_t sigfigs; u_int32_t snaplen; u_int32_t linktype; } LogFileHead; //////////////////// // snort 1.x alert header //////////////////// typedef struct _AlertHead { u_int32_t version_major; u_int32_t version_minor; u_int32_t timezone; } AlertFileHead; //////////////////// // snort 2.x unified header //////////////////// typedef struct _UnifiedFileHead { u_int32_t flags; } UnifiedFileHead; //////////////////// // file header union //////////////////// typedef struct _FHeader { u_int32_t magic; union _head { UnifiedFileHead uni; LogFileHead log; AlertFileHead alert; } head; } FHeader; //////////////////// // snort2.x data header //////////////////// #define DHALERT 0x1 #define DHPACKET 0x2 typedef struct _DataHeader { u_int32_t type; u_int32_t length; } DataHeader; //////////////////// // snort alert events //////////////////// typedef struct EventType { u_int32_t sig_generator; /* which part of snort generated the alert? */ u_int32_t sig_id; /* sig id for this generator */ u_int32_t sig_rev; /* sig revision for this id */ u_int32_t classification; /* event classification */ u_int32_t priority; /* event priority */ u_int32_t event_id; /* event ID */ u_int32_t event_reference; /* reference to other events */ struct timeval ref_time; /* reference time for the event reference */ } Event; //////////////////// // snort uses the equivalent to the pcap pkthdr struct //////////////////// typedef struct _PcapHdr { struct timeval ts; /* packet timestamp */ u_int32_t caplen; /* packet capture length */ u_int32_t pktlen; /* packet "real" length */ } PcapHdr; //////////////////// // unified log packet header format // // One of these per packet in the log file, the packets are appended in the // file after each UnifiedLog header //////////////////// typedef struct _UnifiedLog { Event event; u_int32_t flags; /* bitmap for interesting flags */ PcapHdr pkth; } UnifiedLog; //////////////////////////// // Unified alert message format //////////////////////////// typedef struct _UnifiedAlert { Event event; struct timeval ts; /* event timestamp */ u_int32_t sip; /* src ip */ u_int32_t dip; /* dest ip */ u_int16_t sp; /* src port */ u_int16_t dp; /* dest port */ u_int32_t protocol; /* protocol id */ u_int32_t flags; /* any other flags (fragmented, etc) */ } UnifiedAlert; //////////////// // misc stupf //////////////// char *undefined = "Undefined"; //////////////////////////////////////////////////////////////////////////// ///////////////////////// string routines //////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////// // string length //////////////////// int stlen(str) const char *str; { const char *s; for (s = str; *s; ++s) ; return (s - str); } //////////////////// // Copy src to string dst of size siz. At most siz-1 characters // will be copied. Always NUL terminates (unless siz == 0). // Returns strlen(src); if retval >= siz, truncation occurred. //////////////////// int stlcpy(char *dst, char *src, int siz) { char *d, *s; int n; n = siz; d = dst; s = src; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == '\0') break; } while (--n); } /* Not enough room in dst, add NUL and traverse rest of src */ if (!n) { if (siz) *d = '\0'; /* NUL-terminate dst */ while (*s++ != '\0') ; } return(s - src - 1); /* count does not include NUL */ } //////////////////// // copy string into allocated buffer //////////////////// char *AllocStr(char *buf) { char *tbuf; int len; len = stlen(buf)+1; if((tbuf = (char *)ALLOC(len)) == NULL) { ERROR("AllocStr Out of Memory."); return undefined; } stlcpy(tbuf, buf, len); return tbuf; } //////////////////// // char *IpStr( ipaddr ) // Returns string representation of IPv4 ip address // or "Undefined" on memory allocation errors // // caveat: user must remember to free the result //////////////////// const char *IpStr(u_int32_t ip) { char buf[128]; sprintf(buf,"%d.%d.%d.%d", (ip&0xff000000)>>24, (ip&0x00ff0000)>>16, (ip&0x0000ff00)>>8, (ip&0x000000ff) ); return AllocStr(buf); } //////////////////// // TsStr( ts ) // Returns string representation of timestamps // or "Undefined" on memory allocation errors // // caveat: user must remember to free the result //////////////////// const char *TsStr(struct timeval ts) { char buf[128], buf2[128], *tbuf; strftime(buf, 128, "%m/%d %R:%S", localtime((time_t *)&(ts.tv_sec))); snprintf(buf2, 128, "%s.%d", buf, ts.tv_usec); return AllocStr(buf2); } //////////////////////////////////////////////////////////////////////////// ///////////////////////// snort io routines //////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////// // print unified alert //////////////////// void PrintAlert(UnifiedAlert *a, FILE *f) { const char *buf; fprintf(f, "Alert:\n"); fprintf(f, " Event Generator: %d\n", a->event.sig_generator); fprintf(f, " Event Signature ID: %d\n", a->event.sig_id); fprintf(f, " Event Signature Revision: %d\n", a->event.sig_rev); fprintf(f, " Event Classification: %d\n", a->event.classification); fprintf(f, " Event Priority: %d\n", a->event.priority); fprintf(f, " Event ID: %d\n", a->event.event_id); fprintf(f, " Event Reference: %d\n", a->event.event_reference); buf = TsStr(a->event.ref_time); fprintf(f, " Event Reference Time: %s\n", buf); FREE(buf); buf = TsStr(a->ts); fprintf(f, " Alert Timestamp: %s\n", buf); FREE(buf); buf = IpStr(a->sip); fprintf(f, " Source IP: %08X - %s\n", a->sip, buf); FREE(buf); buf = IpStr(a->dip); fprintf(f, " Destination IP: %08X - %s\n", a->dip, buf); FREE(buf); fprintf(f, " Source Port: %d\n", a->sp); fprintf(f, " Destination Port: %d\n", a->dp); fprintf(f, " Protocol: %d\n", a->protocol); fprintf(f, " Flags: %08X\n", a->flags); fprintf(f, "\n"); } //////////////////// // print pcap packet header //////////////////// void PrintPcapHdr(PcapHdr *p, FILE *f) { const char *buf; fprintf(f, "Pcap Header:\n"); buf = TsStr(p->ts); fprintf(f, " Packet Timestamp: %s\n", buf); FREE(buf); fprintf(f, " Capture Length: %d\n", p->caplen); fprintf(f, " Packet Length: %d\n", p->pktlen); fprintf(f, "\n"); } //////////////////// // print unfied log packet header //////////////////// void PrintLog(UnifiedLog *l, FILE *f) { const char *buf; fprintf(f, "Logged Packet Header:\n"); fprintf(f, " Event Generator: %d\n", l->event.sig_generator); fprintf(f, " Event Signature ID: %d\n", l->event.sig_id); fprintf(f, " Event Signature Revision: %d\n", l->event.sig_rev); fprintf(f, " Event Classification: %d\n", l->event.classification); fprintf(f, " Event Priority: %d\n", l->event.priority); fprintf(f, " Event ID: %d\n", l->event.event_id); fprintf(f, " Event Reference: %d\n", l->event.event_reference); buf = TsStr(l->event.ref_time); fprintf(f, " Event Reference Time: %s\n", buf); FREE(buf); fprintf(f, " Flags: %08X\n", l->flags); PrintPcapHdr(&(l->pkth),f); } //////////////////// // packet hexdump //////////////////// void PrintPacket(char *p, int len, FILE *f) { int i; fprintf(f, "Packet:\n"); for(i = 0; i < len ;) { fprintf(f,"%02X ",(unsigned char)p[i]); if(!((++i)%32)) fprintf(f, "\n"); } fprintf(f, "\n"); } //////////////////// // print snort2.x unified dataheader //////////////////// void PrintDataHeader(DataHeader *d, FILE *f) { fprintf(f, "Data Header:\n"); fprintf(f, " Type: %d(0x%08X)\n", d->type, d->type); fprintf(f, " Length: %d(0x08X)\n", d->length, d->length); fprintf(f, "\n"); } //////////////////// // print pcap header //////////////////// PrintLogHead(LogFileHead *l, FILE *f) { fprintf(f, "Log File Header:\n"); fprintf(f, " Major Version: %d(%04X)\n", l->version_major, l->version_major); fprintf(f, " Minor Version: %d(%04X)\n", l->version_minor, l->version_minor); fprintf(f, " Timezone: %d(0x%08X)\n", l->timezone, l->timezone); fprintf(f, " Sigfigs: %d(0x%08X)\n", l->sigfigs, l->sigfigs); fprintf(f, " Snaplen: %d(0x%08X)\n", l->snaplen, l->snaplen); fprintf(f, " Linktype: %d(0x%08X)\n", l->linktype, l->linktype); fprintf(f, "\n"); } //////////////////// // print snort1.x alert file header //////////////////// PrintAlertHead(AlertFileHead *a, FILE *f) { fprintf(f, "Log File Header:\n"); fprintf(f, " Major Version: %d(%08X)\n", a->version_major, a->version_major); fprintf(f, " Minor Version: %d(%08X)\n", a->version_minor, a->version_minor); fprintf(f, " Timezone: %d(0x%08X)\n", a->timezone, a->timezone); fprintf(f, "\n"); } //////////////////// // print snort2.x unified file header //////////////////// PrintUnifiedHead(UnifiedFileHead *u, FILE *f) { fprintf(f, "Unified File Header:\n"); fprintf(f, " Flags: %d(%08X)\n", u->flags, u->flags); fprintf(f, "\n"); } //////////////////// // ConvertLog(in, out, dump) // // reads logfile (all variants) // outputs pcap and optionally text //////////////////// int ConvertLog(char *in, char *out, char *dump) { FILE *fd, *ofd, *dfd; size_t count; u_int32_t magic; u_int32_t nmagic; UnifiedAlert abuf; DataHeader dhbuf; UnifiedLog lbuf; PcapHdr pbuf; FHeader header; char buf[65536]; // open file if(in == NULL) { ERROR("Bad Filename."); return(0); } fd = fopen(in, "r"); if(fd == NULL) { ERROR("Unable to open input file."); return(0); } ofd = fopen(out, "w"); if(dfd == NULL) { ERROR("Unable to open output file."); return(0); } if(dump) { dfd = fopen(dump, "w"); if(dfd == NULL) { ERROR("Unable to open dump file."); return(0); } } // read header // first check magic if(dump) fprintf(dfd, "Input File: %s\n",in); count = fread(&magic, sizeof(magic), 1, fd); fprintf(stderr, "\nInput Magic: %08X\n", magic); if(dump) fprintf(dfd, "Input Magic: %08X\n", magic); if(count != 1) { ERROR("Unable to read file magic."); return(0); } if(magic == UNIFIEDMAGIC) { count = fread(&(header.head.uni), sizeof(UnifiedFileHead), 1, fd); if(dump) PrintUnifiedHead(&(header.head.uni), dfd); } else if(magic == LOGMAGIC || magic == PCAPMAGIC) { count = fread(&(header.head.log), sizeof(LogFileHead), 1, fd); if(dump) PrintLogHead(&(header.head.log), dfd); } else if(magic == ALERTMAGIC) { count = fread(&(header.head.alert), sizeof(AlertFileHead), 1, fd); if(dump) PrintAlertHead(&(header.head.alert), dfd); } else { ERROR("Bad Magic. Bailing!"); exit(1); } nmagic = PCAPMAGIC; fwrite(&nmagic, sizeof(magic), 1, ofd); header.head.log.version_major = (u_int16_t)2; header.head.log.version_minor = (u_int16_t)4; if(magic == UNIFIEDMAGIC) { header.head.log.sigfigs = 0; header.head.log.timezone = 0; header.head.log.snaplen = 600; header.head.log.linktype = 0; } fwrite(&(header.head.log), sizeof(LogFileHead), 1, ofd); while(count) { if(magic == UNIFIEDMAGIC) { count = fread(&dhbuf, sizeof(dhbuf), 1, fd); if(dump) PrintDataHeader(&dhbuf, dfd); if(dhbuf.type == DHALERT) { count = fread(&abuf, sizeof(UnifiedAlert), 1, fd); if(dump) PrintAlert(&abuf, dfd); } if(dhbuf.type != DHPACKET) { if(dhbuf.length >65535) { ERROR("Corrupt Data Header. Bogus long lenght. Bailing!"); exit(1); } count = fread(buf, dhbuf.length, 1, fd); if(dump) PrintPacket(buf, dhbuf.length, dfd); } } if(magic == LOGMAGIC || (magic == UNIFIEDMAGIC && dhbuf.type == DHPACKET)) { count = fread(&lbuf, sizeof(UnifiedLog), 1, fd); if(dump) PrintLog(&lbuf, dfd); } else if(magic == PCAPMAGIC) { count = fread(&(lbuf.pkth), sizeof(PcapHdr), 1, fd); if(dump) PrintPcapHdr(&(lbuf.pkth), dfd); } if(magic == ALERTMAGIC) { count = fread(&abuf, sizeof(UnifiedAlert), 1, fd); if(dump) PrintAlert(&abuf, dfd); } else { if(lbuf.pkth.caplen > 65535) { ERROR("Corrupt Packet Length. Bailing!"); exit(1); } if(count) count = fread(buf, lbuf.pkth.caplen, 1, fd); if(dump) PrintPacket(buf, lbuf.pkth.caplen, dfd); if(count) { fwrite(&(lbuf.pkth), sizeof(PcapHdr), 1, ofd); fwrite(buf, lbuf.pkth.caplen, 1, ofd); } } if(dump) fprintf(dfd, "\n--logtopcap--\n"); } if(fclose(fd) != 0) ERROR("Error on input file close."); if(fclose(ofd) != 0) ERROR("Error on output file close."); if(dump) if(fclose(dfd) != 0) ERROR("Error on dump file close."); } //////////////////////////////////////////////////////////////////////////// ////////////////////////// Main Logic ////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { fprintf(stderr,"Snort Log->Pcap converter and file dumper V1.0 (c) 2002 Dragos Ruiu(dr@dursec.com)"); if(argc < 3) { fprintf(stderr,"\n\nUsage: %s infile outfile [dumpfile]\n\n",(char *)argv[0]); exit(1); } if(argc >= 4) ConvertLog(argv[1], argv[2], argv[3]); else ConvertLog(argv[1], argv[2], NULL); } ////END////