|
|
@@ -0,0 +1,223 @@
|
|
|
+#include<stdio.h>
|
|
|
+#include<stdlib.h>
|
|
|
+#include<string.h>
|
|
|
+#include<pcap/pcap.h>
|
|
|
+#include<stdbool.h>
|
|
|
+#include<inttypes.h>
|
|
|
+#include<netinet/ether.h>
|
|
|
+#include<arpa/inet.h>
|
|
|
+#include"linkedList.h"
|
|
|
+#include"timecap.h"
|
|
|
+
|
|
|
+#ifndef PROG_NAME
|
|
|
+#define PROG_NAME "a.out"
|
|
|
+#endif
|
|
|
+
|
|
|
+// Seconds
|
|
|
+#define KEY_EPS 1
|
|
|
+
|
|
|
+#define SSH_SETUP_PACKET_COUNT 4
|
|
|
+
|
|
|
+#define FLAG_SHORT_HELP "-h"
|
|
|
+#define FLAG_LONG_HELP "--help"
|
|
|
+
|
|
|
+#define FLAG_SHORT_DIFF "-t"
|
|
|
+#define FLAG_LONG_DIFF "--time-diff"
|
|
|
+
|
|
|
+#define FLAG_SHORT_LENG "-l"
|
|
|
+#define FLAG_LONG_LENG "--len-diff"
|
|
|
+
|
|
|
+/* Format of keylog lines in log file.
|
|
|
+ * 4 = the fd SSH reads user input from (don't know why it isn't 0 but it isn't)
|
|
|
+ * 16384 = How many bytes SSH reads as a time
|
|
|
+ * The last %c is there to check that the entire string matched correctly.
|
|
|
+ * This does not read the entire line. Call read_line after using this.
|
|
|
+ */
|
|
|
+#define KEYLOG_FORMAT "%lf read(%*d, \"%m[^\"]\", 16384) %c"
|
|
|
+
|
|
|
+#define S_TO_NS 1000000000
|
|
|
+#define S_TO_US 1000000
|
|
|
+
|
|
|
+#define DEFAULT_SYN_E {3, 0}
|
|
|
+
|
|
|
+#define DEFAULT_TIM_E 20
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ FILE* keylog;
|
|
|
+ char* keylogName;
|
|
|
+ struct timeval keylogStart;
|
|
|
+ List* timecaps;
|
|
|
+ struct timeval synEpsiolon;
|
|
|
+ size_t keyEpsilon;
|
|
|
+} Args;
|
|
|
+
|
|
|
+void check_error(int cond, char* str) {
|
|
|
+ if (cond) {
|
|
|
+ perror(str);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void print_usage(int exitCode) {
|
|
|
+ printf("Usage: %s [options] keylog pcap [pcap ...]\n"
|
|
|
+ "Pair a keylog to a SSH TCP stream.\n\n"
|
|
|
+ "Options:\n"
|
|
|
+ "%-20s Show this help message and exit\n"
|
|
|
+ "%-20s The allowable difference in time (in seconds) between keylog \n"
|
|
|
+ "%-20s start and flow start\n"
|
|
|
+ "%-20s The allowable difference in estimated keys between keylog and\n"
|
|
|
+ "%-20s flow \n",
|
|
|
+ PROG_NAME,
|
|
|
+ " "FLAG_SHORT_HELP", "FLAG_LONG_HELP,
|
|
|
+ " "FLAG_SHORT_DIFF", "FLAG_LONG_DIFF, "",
|
|
|
+ " "FLAG_SHORT_LENG", "FLAG_LONG_LENG, "");
|
|
|
+ exit(exitCode);
|
|
|
+}
|
|
|
+
|
|
|
+struct timeval double_to_timeval(double in) {
|
|
|
+ struct timeval time;
|
|
|
+ time.tv_sec = in;
|
|
|
+ time.tv_usec = (in - time.tv_sec) * S_TO_US;
|
|
|
+ return time;
|
|
|
+}
|
|
|
+
|
|
|
+void parse_flag(char** argv, Args* res, size_t* i) {
|
|
|
+ double d;
|
|
|
+ char* arg = argv[*i];
|
|
|
+ if (strcmp(arg, FLAG_SHORT_HELP) == 0 || strcmp(arg, FLAG_LONG_HELP) == 0) {
|
|
|
+ print_usage(0);
|
|
|
+ }
|
|
|
+ else if (strcmp(arg, FLAG_SHORT_DIFF) == 0 ||
|
|
|
+ strcmp(arg, FLAG_LONG_DIFF) == 0) {
|
|
|
+ if (sscanf(argv[++*i], " %lf", &d) == 1 && d > 0) {
|
|
|
+ res->synEpsiolon = double_to_timeval(d);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ print_usage(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (0 == strcmp(arg, FLAG_SHORT_LENG) ||
|
|
|
+ 0 == strcmp(arg, FLAG_LONG_LENG)) {
|
|
|
+ if (1 != sscanf(argv[++*i], " %zu", &res->keyEpsilon)) {
|
|
|
+ print_usage(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* Assumes each pcap has at least one packet and each pcap doesn't overlap.
|
|
|
+ */
|
|
|
+static void add_timecap(List* pcaps, char* filename) {
|
|
|
+ char* errBuf = alloca(PCAP_ERRBUF_SIZE + strlen(filename) +
|
|
|
+ sizeof(NO_PACKET_ERR));
|
|
|
+ TimeCap* cap = new_timecap(filename, errBuf);
|
|
|
+ if (cap == NULL) {
|
|
|
+ fprintf(stderr, "%s: %s\n", filename, errBuf);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ list_add_head(pcaps, cap);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int read_line(FILE* keylog) {
|
|
|
+ int c;
|
|
|
+ while ('\n' != (c = fgetc(keylog)) && EOF != c) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ return EOF == c? EOF : 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct timeval get_keylog_start(FILE* keylog) {
|
|
|
+ double seconds;
|
|
|
+ if (fscanf(keylog, " %lf", &seconds) != 1) {
|
|
|
+ fprintf(stderr, "Failed to read timestame from keylog file.\n");
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ read_line(keylog);
|
|
|
+ return double_to_timeval(seconds);
|
|
|
+}
|
|
|
+
|
|
|
+static Args get_args(int argc, char** argv) {
|
|
|
+ Args res = {NULL, NULL, {0, 0}, new_list(NULL), DEFAULT_SYN_E, DEFAULT_TIM_E};
|
|
|
+ size_t i = 1;
|
|
|
+ while (argv[i]) {
|
|
|
+ if (argv[i][0] == '-') {
|
|
|
+ parse_flag(argv, &res, &i);
|
|
|
+ }
|
|
|
+ else if (res.keylog) {
|
|
|
+ add_timecap(res.timecaps, argv[i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ res.keylog = fopen(argv[i], "r");
|
|
|
+ res.keylogName = argv[i];
|
|
|
+ check_error(res.keylog == NULL, argv[i]);
|
|
|
+ res.keylogStart = get_keylog_start(res.keylog);
|
|
|
+ }
|
|
|
+ ++i;
|
|
|
+ }
|
|
|
+ if (res.keylog == NULL || res.timecaps == NULL) {
|
|
|
+ print_usage(1);
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+void timeval_subtract(struct timeval *result,
|
|
|
+ struct timeval *x,
|
|
|
+ struct timeval *y) {
|
|
|
+ *result = *x;
|
|
|
+ if (result->tv_usec < y->tv_usec) {
|
|
|
+ result->tv_sec -= 1;
|
|
|
+ result->tv_usec += 1*S_TO_US;
|
|
|
+ }
|
|
|
+ result->tv_sec -= y->tv_sec;
|
|
|
+ result->tv_usec -= y->tv_usec;
|
|
|
+ result->tv_sec = abs(result->tv_sec);
|
|
|
+ result->tv_usec = abs(result->tv_usec);
|
|
|
+}
|
|
|
+
|
|
|
+int timercmp_eps(struct timeval* a, struct timeval* b, struct timeval eps) {
|
|
|
+ struct timeval diff;
|
|
|
+ timeval_subtract(&diff, a, b);
|
|
|
+ return timercmp(&diff, &eps, <);
|
|
|
+}
|
|
|
+
|
|
|
+size_t count_lines(FILE* file) {
|
|
|
+ size_t res = 1;
|
|
|
+ while (EOF != read_line(file)) {
|
|
|
+ ++res;
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+int is_match(void* tc, void* a) {
|
|
|
+ TimeCap* cap = (TimeCap*) tc;
|
|
|
+ Args* args = (Args*) a;
|
|
|
+ size_t line_count;
|
|
|
+ if (timercmp_eps(&args->keylogStart, &cap->time, args->synEpsiolon)) {
|
|
|
+ line_count = count_lines(args->keylog);
|
|
|
+ return line_count <= cap->pack_count + args->keyEpsilon &&
|
|
|
+ line_count >= cap->pack_count - args->keyEpsilon;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void cleanup(Args args) {
|
|
|
+ delete_list(args.timecaps, delete_timecap);
|
|
|
+ fclose(args.keylog);
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char** argv) {
|
|
|
+ Args args = get_args(argc, argv);
|
|
|
+ TimeCap* cap = (TimeCap*) list_find(args.timecaps, &args, is_match);
|
|
|
+ int exitStatus = 0;
|
|
|
+ if (cap != NULL) {
|
|
|
+ printf("%s\n", cap->name);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ fprintf(stderr, "Failed to find matching flow file for %s.\n",
|
|
|
+ args.keylogName);
|
|
|
+ }
|
|
|
+ cleanup(args);
|
|
|
+ return exitStatus;
|
|
|
+}
|