diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e3dcaa8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.18.4) +include(CheckSymbolExists) + +set(CMAKE_VERBOSE_MAKEFILE ON) + +project( + ssldump + VERSION 1.9 + LANGUAGES C +) + +configure_file(base/pcap-snoop.c.in base/pcap-snoop.c) + +set(SOURCES + ${CMAKE_BINARY_DIR}/base/pcap-snoop.c + base/network.c + base/proto_mod.c + base/tcppack.c + base/tcpconn.c + null/null_analyze.c + common/lib/r_data.c + common/lib/r_assoc.c + common/lib/r_errors.c + common/lib/debug.c + ssl/ssl_analyze.c + ssl/ssldecode.c + ssl/sslprint.c + ssl/ssl.enums.c + ssl/sslxprint.c + ssl/ciphersuites.c + ssl/ssl_rec.c + pcap/logpkt.c + pcap/pcap_logger.c + pcap/sys.c +) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/modules/") + +find_package(OpenSSL REQUIRED) +find_package(PCAP REQUIRED) +find_package(LIBNET REQUIRED) +find_package(json-c REQUIRED) + +add_executable(${PROJECT_NAME} ${SOURCES}) + +check_symbol_exists(strdup "string.h" HAVE_STRDUP) +if(HAVE_STRDUP) + add_definitions(-DHAVE_STRDUP) +endif() + +add_definitions(-DLINUX) +add_definitions(-DOPENSSL) +add_definitions(-D_DEFAULT_SOURCE=1) + +target_include_directories(ssldump + PRIVATE + ${PROJECT_SOURCE_DIR}/common/include + ${PROJECT_SOURCE_DIR}/common/lib + ${PROJECT_SOURCE_DIR}/null + ${PROJECT_SOURCE_DIR}/ssl + ${PROJECT_SOURCE_DIR}/base + ${PROJECT_SOURCE_DIR}/pcap + ${OPENSSL_INCLUDE_DIR} + ${PCAP_INCLUDE_DIR} + ${LIBNET_INCLUDE_DIR} + ${json-c_INCLUDE_DIR} +) + +target_link_libraries(ssldump + PRIVATE + ${OPENSSL_LIBRARIES} + pcap + net + json-c +) + diff --git a/base/pcap-snoop.c b/base/pcap-snoop.c deleted file mode 100644 index 3d3a85b..0000000 --- a/base/pcap-snoop.c +++ /dev/null @@ -1,574 +0,0 @@ -/** - pcap-snoop.c - - - Copyright (C) 1999-2001 RTFM, Inc. - All Rights Reserved - - This package is a SSLv3/TLS protocol analyzer written by Eric - Rescorla and licensed by RTFM, Inc. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - 3. All advertising materials mentioning features or use of this - software must display the following acknowledgement: - - This product includes software developed by Eric Rescorla for - RTFM, Inc. - - 4. Neither the name of RTFM, Inc. nor the name of Eric Rescorla may - be used to endorse or promote products derived from this - software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY ERIC RESCORLA AND RTFM, INC. ``AS IS'' - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - SUCH DAMAGE. - - $Id: pcap-snoop.c,v 1.14 2002/09/09 21:02:58 ekr Exp $ - - - ekr@rtfm.com Tue Dec 29 10:17:41 1998 - */ - - - - -#include -#include -#include -#ifndef _WIN32 -#include -#endif -#include -#ifndef _WIN32 -#include -#include -#else -#include -#include -#endif -#include - -#include -#include -#include "network.h" -#include -#include -#include "null_analyze.h" -#include "ssl_analyze.h" -#ifdef ENABLE_RECORD -#include "record_analyze.h" -#endif -#include "pcap_logger.h" - -#ifndef ETHERTYPE_8021Q -# define ETHERTYPE_8021Q 0x8100 -#endif - -char *collapse_args PROTO_LIST((int argc,char **argv)); -static int pcap_if_type=DLT_NULL; -int err_exit PROTO_LIST((char *str,int num)); -int usage PROTO_LIST((void)); -int print_version PROTO_LIST((void)); -void sig_handler PROTO_LIST((int sig)); -void pcap_cb PROTO_LIST((u_char *ptr,const struct pcap_pkthdr *hdr,const u_char *data)); -int main PROTO_LIST((int argc,char **argv)); - -int packet_cnt = 0; // Packet counter used for connection pool cleaning -int conn_freq = 100; // Number of packets after which a connection pool - // cleaning is performed -int conn_ttl = 100; // TTL of inactive connections in connection pool -struct timeval last_packet_seen_time = // Timestamp of the last packet of the - (struct timeval) {0}; // last block of conn_freq packets seen - -logger_mod *logger=NULL; - -int err_exit(str,num) - char *str; - int num; - { - fprintf(stderr,"ERROR: %s\n",str); - sig_handler(SIGQUIT); - exit(num); - } - -int usage() - { - fprintf(stderr,"Usage: ssldump [-r dumpfile] [-i interface] [-l sslkeylogfile] [-w outpcapfile]\n"); - fprintf(stderr," [-k keyfile] [-p password] [-vtaTznsAxVNde]\n"); - fprintf(stderr," [filter]\n"); - exit(0); - } - -int print_version() - { - printf(PACKAGE_STRING "\n"); - printf("Maintained by a bunch of volunteers, see https://github.com/adulau/ssldump/blob/master/CREDITS\n"); - printf("Copyright (C) 2015-2023 the aforementioned volunteers\n"); - printf("Copyright (C) 1998-2001 RTFM, Inc.\n"); - printf("All rights reserved.\n"); -#ifdef OPENSSL - printf("Compiled with OpenSSL: decryption enabled\n"); -#endif - exit(0); - } - -pcap_t *p; -proto_mod *mod=&ssl_mod; -n_handler *n; -char *interface_name=0; -char *file=0; -char *filter=0; -void sig_handler(int sig) - { - int freed_conn = 0; - fflush(stdout); - if (logger) - logger->vtbl->deinit(); - - freed_conn = destroy_all_conn(); - if(freed_conn && !(NET_print_flags & NET_PRINT_JSON)) - printf("Cleaned %d remaining connection(s) from connection pool\n", freed_conn); - - network_handler_destroy(mod, &n); - - if(p) - pcap_close(p); - if(interface_name) - free(interface_name); - if(filter) - free(filter); - if(file) - free(file); - - exit(sig); - } - -void pcap_cb(ptr,hdr,data) - u_char *ptr; - const struct pcap_pkthdr *hdr; - const u_char *data; - { - n_handler *n; - int len; - struct ether_header *e_hdr=(struct ether_header *)data; - int type, cleaned_conn; - - n=(n_handler *)ptr; - if(hdr->caplen!=hdr->len) err_exit("Length mismatch",-1); - - len=hdr->len; - - switch(pcap_if_type){ - case DLT_RAW: -#ifdef DLT_LOOP - case DLT_LOOP: -#endif - case DLT_NULL: - data+=4; - len-=4; - break; - case DLT_EN10MB: - if(len < sizeof(struct ether_header)) { - if(!(NET_print_flags & NET_PRINT_JSON)) - printf("Frame size too small to contain Ethernet header, skipping ...\n"); - return; - } - - type=ntohs(e_hdr->ether_type); - - data+=sizeof(struct ether_header); - len-=sizeof(struct ether_header); - - /* if vlans, push past VLAN header (4 bytes) */ - if(type==ETHERTYPE_8021Q) { - type=ntohs(*(u_int16_t *)(data + 2)); - - data+=4; - len+=4; - } - - if(type!=ETHERTYPE_IP && type!=ETHERTYPE_IPV6) - return; - - break; - case DLT_IEEE802: - data+=22; - len-=22; - break; - case DLT_FDDI: - data+=21; - len-=21; - break; -#ifdef __amigaos__ - case DLT_MIAMI: - data+=16; - len-=16; - break; -#endif - case DLT_SLIP: -#ifdef DLT_SLIP_BSDOS - case DLT_SLIP_BSDOS: -#endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__) - data+=16; - len-=16; -#else - data+=24; - len-=24; -#endif - break; - case DLT_PPP: -#ifdef DLT_PPP_BSDOS - case DLT_PPP_BSDOS: -#endif -#ifdef DLT_PPP_SERIAL - case DLT_PPP_SERIAL: -#endif -#ifdef DLT_PPP_ETHER - case DLT_PPP_ETHER: -#endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__) - data+=4; - len-=4; -#else -#if defined(sun) || defined(__sun) - data+=8; - len-=8; -#else - data+=24; - len-=24; -#endif -#endif - break; -#ifdef DLT_ENC - case DLT_ENC: - data+=12; - len-=12; - break; -#endif -#ifdef DLT_LINUX_SLL - case DLT_LINUX_SLL: - data+=16; - len-=16; - break; -#endif -#ifdef DLT_IPNET - case DLT_IPNET: - data+=24; - len-=24; - break; -#endif - } - - if(type == ETHERTYPE_IPV6) - network_process_packet(n,(struct timeval *) &hdr->ts,(u_char *)data,len, AF_INET6); - else - network_process_packet(n,(struct timeval *) &hdr->ts,(u_char *)data,len, AF_INET); - - if(packet_cnt == conn_freq) { - packet_cnt = 0; - memcpy(&last_packet_seen_time,&hdr->ts,sizeof(struct timeval)); - if((cleaned_conn = clean_old_conn()) && !(NET_print_flags & NET_PRINT_JSON)) - printf("%d inactive connection(s) cleaned from connection pool\n", cleaned_conn); - } else { - packet_cnt++; - } - } - -typedef struct module_def_ { - char *name; - proto_mod *mod; -} module_def; - -static module_def modules[]={ - {"SSL",&ssl_mod}, - {"NULL",&null_mod}, -#ifdef ENABLE_RECORD - {"RECORD",&record_mod}, -#endif - {0,0} -}; - - -int parse_ssl_flag PROTO_LIST((int c)); - -int main(argc,argv) - int argc; - char **argv; - { - int r; -#ifdef _WIN32 - __declspec(dllimport) char *optarg; - __declspec(dllimport) int optind; -#else - extern char *optarg; - extern int optind; -#endif - pcap_if_t *interfaces; - bpf_u_int32 localnet,netmask; - int c; - module_def *m=0; - int no_promiscuous=0; - int freed_conn=0; - - char errbuf[PCAP_ERRBUF_SIZE]; - - signal(SIGINT,sig_handler); - - while((c=getopt(argc,argv,"vr:F:f:S:jyTt:ai:k:l:w:p:znsAxXhHVNdqem:P"))!=EOF){ - switch(c){ - case 'v': - print_version(); - break; - case 'f': - fprintf(stderr,"-f option replaced by -r. Use that in the future\n"); - case 'r': - file=strdup(optarg); - break; - case 'S': - ssl_mod.vtbl->parse_flags(optarg); - break; - case 'y': - NET_print_flags|=NET_PRINT_TYPESET; - /*Kludge*/ - SSL_print_flags |= SSL_PRINT_NROFF; - break; - case 'j': - NET_print_flags |= NET_PRINT_JSON; - SSL_print_flags |= SSL_PRINT_JSON; - break; - case 'z': - NET_print_flags |= NET_PRINT_TS; - break; - case 'a': - NET_print_flags |= NET_PRINT_ACKS; - break; - case 'A': - SSL_print_flags |= SSL_PRINT_ALL_FIELDS; - break; - case 'T': - NET_print_flags |= NET_PRINT_TCP_HDR; - break; - case 'i': - interface_name=strdup(optarg); - break; - case 'k': - SSL_keyfile=strdup(optarg); - break; - case 'l': - SSL_keylogfile=strdup(optarg); - break; - case 'w': - logger=&pcap_mod; - if(logger->vtbl->init(optarg)!=0){ - fprintf(stderr,"Can not open/create out pcap %s\n", - optarg); - exit(1); - } - break; - case 'p': - SSL_password=strdup(optarg); - break; - case 'P': - ++no_promiscuous; - break; - case 'n': - NET_print_flags |= NET_PRINT_NO_RESOLVE; - break; - case 't': - conn_ttl=atoi(optarg); - break; - case 'F': - conn_freq=atoi(optarg); - break; - case 'm': - for(m=modules;m->name!=0;m++){ - if(!strcmp(m->name,optarg)){ - mod=m->mod; - break; - } - } - if(!m->name){ - fprintf(stderr,"Request analysis module %s not found\n", - optarg); - exit(1); - } - break; - case 'h': - usage(); - printf("Do 'man ssldump' for documentation\n"); - exit(1); - - case '?': - usage(); - exit(1); - - /* must be an SSL flag. This is kind of a gross - special case */ - default: - parse_ssl_flag(c); - break; - } - } - - argv+=optind; - argc-=optind; - - if(!file){ - if(!interface_name){ - if(pcap_findalldevs(&interfaces,errbuf)==-1) { - fprintf(stderr,"PCAP: %s\n",errbuf); - err_exit("Aborting",-1); - } - interface_name=interfaces->name; - if(!interface_name){ - fprintf(stderr,"PCAP: %s\n",errbuf); - err_exit("Aborting",-1); - } - } - if(!(p=pcap_open_live(interface_name,65535,!no_promiscuous,1000,errbuf))){ - fprintf(stderr,"PCAP: %s\n",errbuf); - err_exit("Aborting",-1); - } - - if (pcap_lookupnet(interface_name, &localnet, &netmask, errbuf) < 0) - fprintf(stderr,"PCAP: %s\n", errbuf); - } - else{ - if(!(p=pcap_open_offline(file,errbuf))){ - fprintf(stderr,"PCAP: %s\n",errbuf); - err_exit("Aborting",-1); - } - - netmask=0; - localnet=0; - } - - if(argc!=0) - filter=collapse_args(argc,argv); - - if(filter){ - struct bpf_program fp; - - /* (F5 patch) - * reformat filter to include traffic with or without the 802.1q - * vlan header. for example, "port 80" becomes: - * "( port 80 ) or ( vlan and port 80 )". - * note that if the filter includes the literals vlan, tagged, or - * untagged, then it is assumed that the user knows what she is - * doing, and the filter is not reformatted. - */ - if ((pcap_datalink(p) == DLT_EN10MB) && - (filter != NULL) && - (strstr(filter,"vlan") == NULL)) { - char *tmp_filter; - char *fmt = "( (not ether proto 0x8100) and (%s) ) or ( vlan and (%s) )"; - - tmp_filter = (char *)malloc((strlen(filter) * 2) + strlen(fmt) + 1); - if (tmp_filter == NULL) { - fprintf(stderr,"PCAP: malloc failed\n"); - err_exit("Aborting",-1); - } - - sprintf(tmp_filter,fmt,filter,filter); - free(filter); - filter = tmp_filter; - } - - if(pcap_compile(p,&fp,filter,0,netmask)<0) - verr_exit("PCAP: %s\n",pcap_geterr(p)); - - if(pcap_setfilter(p,&fp)<0) - verr_exit("PCAP: %s\n",pcap_geterr(p)); - } - - pcap_if_type=pcap_datalink(p); - - if(!(NET_print_flags & NET_PRINT_JSON)) - if(NET_print_flags & NET_PRINT_TYPESET) - printf("\n.nf\n.ps -2\n"); - - if((r=network_handler_create(mod,&n))) - err_exit("Couldn't create network handler",r); - - pcap_loop(p,-1,pcap_cb,(u_char *)n); - - if(!(NET_print_flags & NET_PRINT_JSON)) - if(NET_print_flags & NET_PRINT_TYPESET) - printf("\n.ps\n.fi\n"); - - freed_conn = destroy_all_conn(); - if(freed_conn && !(NET_print_flags & NET_PRINT_JSON)) - printf("Cleaned %d remaining connection(s) from connection pool\n", freed_conn); - - network_handler_destroy(mod, &n); - pcap_close(p); - - free(n); - - if(filter) - free(filter); - if(file) - free(file); - if(interface_name) - free(interface_name); - if(SSL_keyfile) - free(SSL_keyfile); - if(SSL_keylogfile) - free(SSL_keylogfile); - if(SSL_password) - free(SSL_password); - if (logger) - { - logger->vtbl->deinit(); - } - - exit(0); - } - - -char *collapse_args(argc,argv) - int argc; - char **argv; - { - int i,len=0; - char *ret; - - if(!argc) - return(0); - - for(i=0;i and licensed by RTFM, Inc. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + 3. All advertising materials mentioning features or use of this + software must display the following acknowledgement: + + This product includes software developed by Eric Rescorla for + RTFM, Inc. + + 4. Neither the name of RTFM, Inc. nor the name of Eric Rescorla may + be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY ERIC RESCORLA AND RTFM, INC. ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + SUCH DAMAGE. + + $Id: pcap-snoop.c,v 1.14 2002/09/09 21:02:58 ekr Exp $ + + + ekr@rtfm.com Tue Dec 29 10:17:41 1998 + */ + + + + +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#ifndef _WIN32 +#include +#include +#else +#include +#include +#endif +#include + +#include +#include +#include "network.h" +#include +#include +#include "null_analyze.h" +#include "ssl_analyze.h" +#ifdef ENABLE_RECORD +#include "record_analyze.h" +#endif +#include "pcap_logger.h" + +#ifndef ETHERTYPE_8021Q +# define ETHERTYPE_8021Q 0x8100 +#endif + +char *collapse_args PROTO_LIST((int argc,char **argv)); +static int pcap_if_type=DLT_NULL; +int err_exit PROTO_LIST((char *str,int num)); +int usage PROTO_LIST((void)); +int print_version PROTO_LIST((void)); +void sig_handler PROTO_LIST((int sig)); +void pcap_cb PROTO_LIST((u_char *ptr,const struct pcap_pkthdr *hdr,const u_char *data)); +int main PROTO_LIST((int argc,char **argv)); + +int packet_cnt = 0; // Packet counter used for connection pool cleaning +int conn_freq = 100; // Number of packets after which a connection pool + // cleaning is performed +int conn_ttl = 100; // TTL of inactive connections in connection pool +struct timeval last_packet_seen_time = // Timestamp of the last packet of the + (struct timeval) {0}; // last block of conn_freq packets seen + +logger_mod *logger=NULL; + +int err_exit(str,num) + char *str; + int num; + { + fprintf(stderr,"ERROR: %s\n",str); + sig_handler(SIGQUIT); + exit(num); + } + +int usage() + { + fprintf(stderr,"Usage: ssldump [-r dumpfile] [-i interface] [-l sslkeylogfile] [-w outpcapfile]\n"); + fprintf(stderr," [-k keyfile] [-p password] [-vtaTznsAxVNde]\n"); + fprintf(stderr," [filter]\n"); + exit(0); + } + +int print_version() + { + printf("@ssldump_VERSION@\n"); + printf("Maintained by a bunch of volunteers, see https://github.com/adulau/ssldump/blob/master/CREDITS\n"); + printf("Copyright (C) 2015-2023 the aforementioned volunteers\n"); + printf("Copyright (C) 1998-2001 RTFM, Inc.\n"); + printf("All rights reserved.\n"); +#ifdef OPENSSL + printf("Compiled with OpenSSL: decryption enabled\n"); +#endif + exit(0); + } + +pcap_t *p; +proto_mod *mod=&ssl_mod; +n_handler *n; +char *interface_name=0; +char *file=0; +char *filter=0; +void sig_handler(int sig) + { + int freed_conn = 0; + fflush(stdout); + if (logger) + logger->vtbl->deinit(); + + freed_conn = destroy_all_conn(); + if(freed_conn && !(NET_print_flags & NET_PRINT_JSON)) + printf("Cleaned %d remaining connection(s) from connection pool\n", freed_conn); + + network_handler_destroy(mod, &n); + + if(p) + pcap_close(p); + if(interface_name) + free(interface_name); + if(filter) + free(filter); + if(file) + free(file); + + exit(sig); + } + +void pcap_cb(ptr,hdr,data) + u_char *ptr; + const struct pcap_pkthdr *hdr; + const u_char *data; + { + n_handler *n; + int len; + struct ether_header *e_hdr=(struct ether_header *)data; + int type, cleaned_conn; + + n=(n_handler *)ptr; + if(hdr->caplen!=hdr->len) err_exit("Length mismatch",-1); + + len=hdr->len; + + switch(pcap_if_type){ + case DLT_RAW: +#ifdef DLT_LOOP + case DLT_LOOP: +#endif + case DLT_NULL: + data+=4; + len-=4; + break; + case DLT_EN10MB: + if(len < sizeof(struct ether_header)) { + if(!(NET_print_flags & NET_PRINT_JSON)) + printf("Frame size too small to contain Ethernet header, skipping ...\n"); + return; + } + + type=ntohs(e_hdr->ether_type); + + data+=sizeof(struct ether_header); + len-=sizeof(struct ether_header); + + /* if vlans, push past VLAN header (4 bytes) */ + if(type==ETHERTYPE_8021Q) { + type=ntohs(*(u_int16_t *)(data + 2)); + + data+=4; + len+=4; + } + + if(type!=ETHERTYPE_IP && type!=ETHERTYPE_IPV6) + return; + + break; + case DLT_IEEE802: + data+=22; + len-=22; + break; + case DLT_FDDI: + data+=21; + len-=21; + break; +#ifdef __amigaos__ + case DLT_MIAMI: + data+=16; + len-=16; + break; +#endif + case DLT_SLIP: +#ifdef DLT_SLIP_BSDOS + case DLT_SLIP_BSDOS: +#endif +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__) + data+=16; + len-=16; +#else + data+=24; + len-=24; +#endif + break; + case DLT_PPP: +#ifdef DLT_PPP_BSDOS + case DLT_PPP_BSDOS: +#endif +#ifdef DLT_PPP_SERIAL + case DLT_PPP_SERIAL: +#endif +#ifdef DLT_PPP_ETHER + case DLT_PPP_ETHER: +#endif +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__APPLE__) + data+=4; + len-=4; +#else +#if defined(sun) || defined(__sun) + data+=8; + len-=8; +#else + data+=24; + len-=24; +#endif +#endif + break; +#ifdef DLT_ENC + case DLT_ENC: + data+=12; + len-=12; + break; +#endif +#ifdef DLT_LINUX_SLL + case DLT_LINUX_SLL: + data+=16; + len-=16; + break; +#endif +#ifdef DLT_IPNET + case DLT_IPNET: + data+=24; + len-=24; + break; +#endif + } + + if(type == ETHERTYPE_IPV6) + network_process_packet(n,(struct timeval *) &hdr->ts,(u_char *)data,len, AF_INET6); + else + network_process_packet(n,(struct timeval *) &hdr->ts,(u_char *)data,len, AF_INET); + + if(packet_cnt == conn_freq) { + packet_cnt = 0; + memcpy(&last_packet_seen_time,&hdr->ts,sizeof(struct timeval)); + if((cleaned_conn = clean_old_conn()) && !(NET_print_flags & NET_PRINT_JSON)) + printf("%d inactive connection(s) cleaned from connection pool\n", cleaned_conn); + } else { + packet_cnt++; + } + } + +typedef struct module_def_ { + char *name; + proto_mod *mod; +} module_def; + +static module_def modules[]={ + {"SSL",&ssl_mod}, + {"NULL",&null_mod}, +#ifdef ENABLE_RECORD + {"RECORD",&record_mod}, +#endif + {0,0} +}; + + +int parse_ssl_flag PROTO_LIST((int c)); + +int main(argc,argv) + int argc; + char **argv; + { + int r; +#ifdef _WIN32 + __declspec(dllimport) char *optarg; + __declspec(dllimport) int optind; +#else + extern char *optarg; + extern int optind; +#endif + pcap_if_t *interfaces; + bpf_u_int32 localnet,netmask; + int c; + module_def *m=0; + int no_promiscuous=0; + int freed_conn=0; + + char errbuf[PCAP_ERRBUF_SIZE]; + + signal(SIGINT,sig_handler); + + while((c=getopt(argc,argv,"vr:F:f:S:jyTt:ai:k:l:w:p:znsAxXhHVNdqem:P"))!=EOF){ + switch(c){ + case 'v': + print_version(); + break; + case 'f': + fprintf(stderr,"-f option replaced by -r. Use that in the future\n"); + case 'r': + file=strdup(optarg); + break; + case 'S': + ssl_mod.vtbl->parse_flags(optarg); + break; + case 'y': + NET_print_flags|=NET_PRINT_TYPESET; + /*Kludge*/ + SSL_print_flags |= SSL_PRINT_NROFF; + break; + case 'j': + NET_print_flags |= NET_PRINT_JSON; + SSL_print_flags |= SSL_PRINT_JSON; + break; + case 'z': + NET_print_flags |= NET_PRINT_TS; + break; + case 'a': + NET_print_flags |= NET_PRINT_ACKS; + break; + case 'A': + SSL_print_flags |= SSL_PRINT_ALL_FIELDS; + break; + case 'T': + NET_print_flags |= NET_PRINT_TCP_HDR; + break; + case 'i': + interface_name=strdup(optarg); + break; + case 'k': + SSL_keyfile=strdup(optarg); + break; + case 'l': + SSL_keylogfile=strdup(optarg); + break; + case 'w': + logger=&pcap_mod; + if(logger->vtbl->init(optarg)!=0){ + fprintf(stderr,"Can not open/create out pcap %s\n", + optarg); + exit(1); + } + break; + case 'p': + SSL_password=strdup(optarg); + break; + case 'P': + ++no_promiscuous; + break; + case 'n': + NET_print_flags |= NET_PRINT_NO_RESOLVE; + break; + case 't': + conn_ttl=atoi(optarg); + break; + case 'F': + conn_freq=atoi(optarg); + break; + case 'm': + for(m=modules;m->name!=0;m++){ + if(!strcmp(m->name,optarg)){ + mod=m->mod; + break; + } + } + if(!m->name){ + fprintf(stderr,"Request analysis module %s not found\n", + optarg); + exit(1); + } + break; + case 'h': + usage(); + printf("Do 'man ssldump' for documentation\n"); + exit(1); + + case '?': + usage(); + exit(1); + + /* must be an SSL flag. This is kind of a gross + special case */ + default: + parse_ssl_flag(c); + break; + } + } + + argv+=optind; + argc-=optind; + + if(!file){ + if(!interface_name){ + if(pcap_findalldevs(&interfaces,errbuf)==-1) { + fprintf(stderr,"PCAP: %s\n",errbuf); + err_exit("Aborting",-1); + } + interface_name=interfaces->name; + if(!interface_name){ + fprintf(stderr,"PCAP: %s\n",errbuf); + err_exit("Aborting",-1); + } + } + if(!(p=pcap_open_live(interface_name,65535,!no_promiscuous,1000,errbuf))){ + fprintf(stderr,"PCAP: %s\n",errbuf); + err_exit("Aborting",-1); + } + + if (pcap_lookupnet(interface_name, &localnet, &netmask, errbuf) < 0) + fprintf(stderr,"PCAP: %s\n", errbuf); + } + else{ + if(!(p=pcap_open_offline(file,errbuf))){ + fprintf(stderr,"PCAP: %s\n",errbuf); + err_exit("Aborting",-1); + } + + netmask=0; + localnet=0; + } + + if(argc!=0) + filter=collapse_args(argc,argv); + + if(filter){ + struct bpf_program fp; + + /* (F5 patch) + * reformat filter to include traffic with or without the 802.1q + * vlan header. for example, "port 80" becomes: + * "( port 80 ) or ( vlan and port 80 )". + * note that if the filter includes the literals vlan, tagged, or + * untagged, then it is assumed that the user knows what she is + * doing, and the filter is not reformatted. + */ + if ((pcap_datalink(p) == DLT_EN10MB) && + (filter != NULL) && + (strstr(filter,"vlan") == NULL)) { + char *tmp_filter; + char *fmt = "( (not ether proto 0x8100) and (%s) ) or ( vlan and (%s) )"; + + tmp_filter = (char *)malloc((strlen(filter) * 2) + strlen(fmt) + 1); + if (tmp_filter == NULL) { + fprintf(stderr,"PCAP: malloc failed\n"); + err_exit("Aborting",-1); + } + + sprintf(tmp_filter,fmt,filter,filter); + free(filter); + filter = tmp_filter; + } + + if(pcap_compile(p,&fp,filter,0,netmask)<0) + verr_exit("PCAP: %s\n",pcap_geterr(p)); + + if(pcap_setfilter(p,&fp)<0) + verr_exit("PCAP: %s\n",pcap_geterr(p)); + } + + pcap_if_type=pcap_datalink(p); + + if(!(NET_print_flags & NET_PRINT_JSON)) + if(NET_print_flags & NET_PRINT_TYPESET) + printf("\n.nf\n.ps -2\n"); + + if((r=network_handler_create(mod,&n))) + err_exit("Couldn't create network handler",r); + + pcap_loop(p,-1,pcap_cb,(u_char *)n); + + if(!(NET_print_flags & NET_PRINT_JSON)) + if(NET_print_flags & NET_PRINT_TYPESET) + printf("\n.ps\n.fi\n"); + + freed_conn = destroy_all_conn(); + if(freed_conn && !(NET_print_flags & NET_PRINT_JSON)) + printf("Cleaned %d remaining connection(s) from connection pool\n", freed_conn); + + network_handler_destroy(mod, &n); + pcap_close(p); + + free(n); + + if(filter) + free(filter); + if(file) + free(file); + if(interface_name) + free(interface_name); + if(SSL_keyfile) + free(SSL_keyfile); + if(SSL_keylogfile) + free(SSL_keylogfile); + if(SSL_password) + free(SSL_password); + if (logger) + { + logger->vtbl->deinit(); + } + + exit(0); + } + + +char *collapse_args(argc,argv) + int argc; + char **argv; + { + int i,len=0; + char *ret; + + if(!argc) + return(0); + + for(i=0;i