diff --git a/base/pcap-snoop.c.in b/base/pcap-snoop.c.in index 06ea0d8..6f2d75e 100644 --- a/base/pcap-snoop.c.in +++ b/base/pcap-snoop.c.in @@ -75,6 +75,7 @@ #include "record_analyze.h" #endif #include "pcap_logger.h" +#include "tcpconn.h" #ifndef ETHERTYPE_8021Q #define ETHERTYPE_8021Q 0x8100 @@ -85,7 +86,8 @@ 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 sig_handler_quit PROTO_LIST((int sig)); +void sig_handler_usr PROTO_LIST((int sig)); void pcap_cb PROTO_LIST((u_char * ptr, const struct pcap_pkthdr *hdr, const u_char *data)); @@ -102,7 +104,7 @@ logger_mod *logger = NULL; int err_exit(char *str, int num) { fprintf(stderr, "ERROR: %s\n", str); - sig_handler(SIGQUIT); + sig_handler_quit(SIGQUIT); exit(num); } @@ -136,7 +138,7 @@ n_handler *n; char *interface_name = 0; char *file = 0; char *filter = 0; -void sig_handler(int sig) { +void sig_handler_quit(int sig) { int freed_conn = 0; fflush(stdout); if(logger) @@ -144,8 +146,8 @@ void sig_handler(int sig) { 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); + fprintf(stderr, "Cleaned %d remaining connection(s) from connection pool\n", + freed_conn); network_handler_destroy(mod, &n); @@ -161,6 +163,33 @@ void sig_handler(int sig) { exit(sig); } +void sig_handler_usr(int sig) { + int freed_conn = 0; + + if(sig == SIGUSR1) { + if(!first_conn) { + fprintf(stderr, + "Received SIGUSR1, connection pool empty, nothing to list.\n"); + } else { + fprintf( + stderr, + "Received SIGUSR1, listing currently tracked connection(s) ...\n"); + list_all_conn(); + } + } else if(sig == SIGUSR2) { + if(!first_conn) { + fprintf(stderr, + "Received SIGUSR2, connection pool empty, nothing to purge.\n"); + } else { + fprintf(stderr, "Received SIGUSR2, purging connection pool ...\n"); + freed_conn = destroy_all_conn(); + if(freed_conn && !(NET_print_flags & NET_PRINT_JSON)) + fprintf(stderr, "Purged %d connection(s) from connection pool\n", + freed_conn); + } + } +} + void pcap_cb(u_char *ptr, const struct pcap_pkthdr *hdr, const u_char *data) { n_handler *n; int len; @@ -186,9 +215,9 @@ void pcap_cb(u_char *ptr, const struct pcap_pkthdr *hdr, const u_char *data) { 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"); + fprintf(stderr, + "Frame size too small to contain Ethernet header, skipping " + "...\n"); return; } @@ -291,8 +320,9 @@ void pcap_cb(u_char *ptr, const struct pcap_pkthdr *hdr, const u_char *data) { 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); + fprintf(stderr, + "%d inactive connection(s) cleaned from connection pool\n", + cleaned_conn); } else { packet_cnt++; } @@ -330,7 +360,9 @@ int main(int argc, char **argv) { char errbuf[PCAP_ERRBUF_SIZE]; - signal(SIGINT, sig_handler); + signal(SIGINT, sig_handler_quit); + signal(SIGUSR1, sig_handler_usr); + signal(SIGUSR2, sig_handler_usr); while((c = getopt(argc, argv, "vr:F:f:S:jyTt:ai:k:l:w:p:znsAxXhHVNdqem:P")) != EOF) { @@ -442,6 +474,7 @@ int main(int argc, char **argv) { err_exit("Aborting", -1); } } + fprintf(stderr, "ssldump: listening on %s\n", interface_name); if(!(p = pcap_open_live(interface_name, 65535, !no_promiscuous, 1000, errbuf))) { fprintf(stderr, "PCAP: %s\n", errbuf); @@ -514,8 +547,8 @@ int main(int argc, char **argv) { 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); + fprintf(stderr, "Cleaned %d remaining connection(s) from connection pool\n", + freed_conn); network_handler_destroy(mod, &n); pcap_close(p); diff --git a/base/tcpconn.c b/base/tcpconn.c index 408d980..36b532c 100644 --- a/base/tcpconn.c +++ b/base/tcpconn.c @@ -47,15 +47,13 @@ #include "network.h" #include "tcpconn.h" -typedef struct conn_struct_ { - tcp_conn conn; - struct conn_struct_ *next; - struct conn_struct_ *prev; -} conn_struct; - int conn_number = 1; -static conn_struct *first_conn = 0; +conn_struct *first_conn = 0; +char *state_map[] = { + "UNKNOWN", "TCP_STATE_SYN1", "TCP_STATE_SYN2", + "TCP_STATE_ACK", "TCP_STATE_ESTABLISHED", "TCP_STATE_FIN1", + "TCP_STATE_CLOSED"}; extern struct timeval last_packet_seen_time; extern int conn_ttl; @@ -179,6 +177,30 @@ int clean_old_conn(void) { return i; } +void list_all_conn(void) { + conn_struct *conn; + tcp_conn *tcpconn; + struct timeval dt; + long freshness; + + fprintf(stderr, + " -> " + "\n"); + conn = first_conn; + while(conn) { + tcpconn = &conn->conn; + conn = conn->next; + freshness = + (timestamp_diff(&last_packet_seen_time, &tcpconn->last_seen_time, &dt)) + ? 0 + : dt.tv_sec; + fprintf(stderr, "Connection #%d %s:%d -> %s:%d %s %ld\n", + tcpconn->conn_number, tcpconn->i_name, tcpconn->i_port, + tcpconn->r_name, tcpconn->r_port, state_map[tcpconn->state], + freshness); + } +} + int destroy_all_conn(void) { int i = 0; while(first_conn) { diff --git a/base/tcpconn.h b/base/tcpconn.h index fc5ae22..c9eda10 100644 --- a/base/tcpconn.h +++ b/base/tcpconn.h @@ -62,6 +62,8 @@ typedef struct stream_data_ { segment *oo_queue; } stream_data; +extern char *state_map[]; + typedef struct tcp_conn_ { int conn_number; int state; @@ -92,6 +94,12 @@ typedef struct tcp_conn_ { struct conn_struct_ *backptr; } tcp_conn; +typedef struct conn_struct_ { + tcp_conn conn; + struct conn_struct_ *next; + struct conn_struct_ *prev; +} conn_struct; + int tcp_find_conn PROTO_LIST((tcp_conn * *connp, int *directionp, struct sockaddr_storage *src_addr, @@ -110,6 +118,9 @@ int free_tcp_segment_queue PROTO_LIST((segment * seg)); int copy_tcp_segment_queue PROTO_LIST((segment * *out, segment *in)); int clean_old_conn(void); +void list_all_conn(void); int destroy_all_conn(void); +extern conn_struct *first_conn; + #endif diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..dacb984 --- /dev/null +++ b/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +rm -Rf build && cmake -B build -G Ninja && ninja -C build diff --git a/ssl/ssl.enums.c b/ssl/ssl.enums.c index f34c9ae..feb8513 100644 --- a/ssl/ssl.enums.c +++ b/ssl/ssl.enums.c @@ -125,7 +125,7 @@ static int decode_ContentType_application_data(ssl_obj *ssl, if(NET_print_flags & NET_PRINT_JSON) { json_object_object_add(jobj, "msg_data", - json_object_new_string_len((char *) d.data, d.len)); + json_object_new_string_len((char *)d.data, d.len)); } else P_(P_AD) { print_data(ssl, &d); } else { diff --git a/ssldump.1 b/ssldump.1 index b6e0526..2edc7c5 100644 --- a/ssldump.1 +++ b/ssldump.1 @@ -534,6 +534,16 @@ and .B \-p flags. .LP +.SH SIGNALS +.LP +When it receives SIGUSR1, +.B ssldump +prints the list of currently tracked connection on stderr. +.LP +With SIGUSR2, +.B ssldump +purges its internal connection tracking data structures. +.LP .SH DECRYPTION .LP \fIssldump\fP can decrypt traffic between two hosts if the following two diff --git a/ssldump.md b/ssldump.md index 109430c..b34a1fd 100644 --- a/ssldump.md +++ b/ssldump.md @@ -371,6 +371,16 @@ and **-p** flags. + + +# Signals + +When it receives SIGUSR1, _ssldump_ prints the list of currently tracked +connection on stderr. + +With SIGUSR2, _ssldump_ purges its internal connection tracking data +structures. +