main.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<stdbool.h>
  4. #include<string.h>
  5. #include<pcap/pcap.h>
  6. #include<stdbool.h>
  7. #include<inttypes.h>
  8. #include<netinet/ether.h>
  9. #include<arpa/inet.h>
  10. #include"linkedList.h"
  11. #include"timecap.h"
  12. #ifndef PROG_NAME
  13. #define PROG_NAME "a.out"
  14. #endif
  15. // Seconds
  16. #define KEY_EPS 1
  17. #define SSH_SETUP_PACKET_COUNT 4
  18. #define FLAG_SHORT_HELP "-h"
  19. #define FLAG_LONG_HELP "--help"
  20. #define FLAG_SHORT_DIFF "-t"
  21. #define FLAG_LONG_DIFF "--time-diff"
  22. #define FLAG_SHORT_LENG "-l"
  23. #define FLAG_LONG_LENG "--len-diff"
  24. #define FLAG_SHORT_VERB "-v"
  25. #define FLAG_LONG_VERB "--verbose"
  26. /* Format of keylog lines in log file.
  27. * 4 = the fd SSH reads user input from (don't know why it isn't 0 but it isn't)
  28. * 16384 = How many bytes SSH reads as a time
  29. * The last %c is there to check that the entire string matched correctly.
  30. * This does not read the entire line. Call read_line after using this.
  31. */
  32. #define KEYLOG_FORMAT "%lf read(%*d, \"%m[^\"]\", 16384) %c"
  33. #define S_TO_NS 1000000000
  34. #define S_TO_US 1000000
  35. #define DEFAULT_SYN_E {3, 0}
  36. #define DEFAULT_TIM_E 20
  37. typedef struct {
  38. FILE* keylog;
  39. char* keylogName;
  40. struct timeval keylogStart;
  41. List* timecaps;
  42. struct timeval synEpsiolon;
  43. size_t keyEpsilon;
  44. bool verbose;
  45. size_t line_count;
  46. } Args;
  47. void check_error(int cond, char* str) {
  48. if (cond) {
  49. perror(str);
  50. exit(1);
  51. }
  52. }
  53. void print_usage(int exitCode) {
  54. printf("Usage: %s [options] keylog pcap [pcap ...]\n"
  55. "Pair a keylog to a SSH TCP stream.\n\n"
  56. "Options:\n"
  57. "%-20s Show this help message and exit\n"
  58. "%-20s Print reasons for rejecting pcap files\n"
  59. "%-20s The allowable difference in time (in seconds) between keylog \n"
  60. "%-20s start and flow start\n"
  61. "%-20s The allowable difference in estimated keys between keylog and\n"
  62. "%-20s flow \n",
  63. PROG_NAME,
  64. " "FLAG_SHORT_HELP", "FLAG_LONG_HELP,
  65. " "FLAG_SHORT_VERB", "FLAG_LONG_VERB,
  66. " "FLAG_SHORT_DIFF", "FLAG_LONG_DIFF, "",
  67. " "FLAG_SHORT_LENG", "FLAG_LONG_LENG, "");
  68. exit(exitCode);
  69. }
  70. struct timeval double_to_timeval(double in) {
  71. struct timeval time;
  72. time.tv_sec = in;
  73. time.tv_usec = (in - time.tv_sec) * S_TO_US;
  74. return time;
  75. }
  76. void parse_flag(char** argv, Args* res, size_t* i) {
  77. double d;
  78. char* arg = argv[*i];
  79. if (strcmp(arg, FLAG_SHORT_HELP) == 0 || strcmp(arg, FLAG_LONG_HELP) == 0) {
  80. print_usage(0);
  81. }
  82. else if (strcmp(arg, FLAG_SHORT_VERB) == 0 ||
  83. strcmp(arg, FLAG_LONG_VERB) == 0) {
  84. res->verbose = true;
  85. }
  86. else if (strcmp(arg, FLAG_SHORT_DIFF) == 0 ||
  87. strcmp(arg, FLAG_LONG_DIFF) == 0) {
  88. if (sscanf(argv[++*i], " %lf", &d) == 1 && d > 0) {
  89. res->synEpsiolon = double_to_timeval(d);
  90. }
  91. else {
  92. print_usage(1);
  93. }
  94. }
  95. else if (0 == strcmp(arg, FLAG_SHORT_LENG) ||
  96. 0 == strcmp(arg, FLAG_LONG_LENG)) {
  97. if (1 != sscanf(argv[++*i], " %zu", &res->keyEpsilon)) {
  98. print_usage(1);
  99. }
  100. }
  101. }
  102. /* Assumes each pcap has at least one packet and each pcap doesn't overlap.
  103. */
  104. static void add_timecap(List* pcaps, char* filename) {
  105. char* errBuf = alloca(PCAP_ERRBUF_SIZE + strlen(filename) +
  106. sizeof(NO_PACKET_ERR));
  107. TimeCap* cap = new_timecap(filename, errBuf);
  108. if (cap == NULL) {
  109. fprintf(stderr, "%s: %s\n", filename, errBuf);
  110. }
  111. else {
  112. list_add_head(pcaps, cap);
  113. }
  114. }
  115. static int read_line(FILE* keylog) {
  116. int c;
  117. while ('\n' != (c = fgetc(keylog)) && EOF != c) {
  118. continue;
  119. }
  120. return EOF == c? EOF : 0;
  121. }
  122. static struct timeval get_keylog_start(FILE* keylog) {
  123. double seconds;
  124. if (fscanf(keylog, " %lf", &seconds) != 1) {
  125. fprintf(stderr, "Failed to read timestame from keylog file.\n");
  126. exit(1);
  127. }
  128. read_line(keylog);
  129. return double_to_timeval(seconds);
  130. }
  131. size_t count_lines(FILE* file) {
  132. size_t res = 1;
  133. while (EOF != read_line(file)) {
  134. ++res;
  135. }
  136. return res;
  137. }
  138. static Args get_args(int argc, char** argv) {
  139. Args res = {NULL, NULL, {0, 0}, new_list(NULL), DEFAULT_SYN_E, DEFAULT_TIM_E};
  140. size_t i = 1;
  141. while (argv[i]) {
  142. if (argv[i][0] == '-') {
  143. parse_flag(argv, &res, &i);
  144. }
  145. else if (res.keylog) {
  146. add_timecap(res.timecaps, argv[i]);
  147. }
  148. else {
  149. res.keylog = fopen(argv[i], "r");
  150. res.keylogName = argv[i];
  151. check_error(res.keylog == NULL, argv[i]);
  152. res.keylogStart = get_keylog_start(res.keylog);
  153. res.line_count = count_lines(res.keylog);
  154. }
  155. ++i;
  156. }
  157. if (res.keylog == NULL || res.timecaps == NULL) {
  158. print_usage(1);
  159. }
  160. return res;
  161. }
  162. void timeval_subtract(struct timeval *result,
  163. struct timeval *x,
  164. struct timeval *y) {
  165. *result = *x;
  166. if (result->tv_usec < y->tv_usec) {
  167. result->tv_sec -= 1;
  168. result->tv_usec += 1*S_TO_US;
  169. }
  170. result->tv_sec -= y->tv_sec;
  171. result->tv_usec -= y->tv_usec;
  172. result->tv_sec = abs(result->tv_sec);
  173. result->tv_usec = abs(result->tv_usec);
  174. }
  175. int timercmp_eps(struct timeval* a, struct timeval* b, struct timeval eps) {
  176. struct timeval diff;
  177. timeval_subtract(&diff, a, b);
  178. return timercmp(&diff, &eps, <);
  179. }
  180. #define LOG(ARGS, FMT, ...) do { \
  181. if ((ARGS)->verbose) { \
  182. fprintf(stderr, (FMT), ##__VA_ARGS__); \
  183. } \
  184. } while (0)
  185. int is_match(void* tc, void* a) {
  186. TimeCap* cap = (TimeCap*) tc;
  187. Args* args = (Args*) a;
  188. int res;
  189. if (timercmp_eps(&args->keylogStart, &cap->time, args->synEpsiolon)) {
  190. res = args->line_count <= cap->pack_count + args->keyEpsilon &&
  191. args->line_count >= cap->pack_count - args->keyEpsilon;
  192. if (!res) {
  193. LOG(args, "PCAP %s had incompatible line numbers.\n", cap->name);
  194. LOG(args, "%zu keys, %zu packets.\n", args->line_count, cap->pack_count);
  195. }
  196. return res;
  197. }
  198. else {
  199. LOG(args, "PCAP %s had incompatible timestamp.\n", cap->name);
  200. return 0;
  201. }
  202. }
  203. void cleanup(Args args) {
  204. delete_list(args.timecaps, delete_timecap);
  205. fclose(args.keylog);
  206. }
  207. int main(int argc, char** argv) {
  208. Args args = get_args(argc, argv);
  209. TimeCap* cap = (TimeCap*) list_find(args.timecaps, &args, is_match);
  210. int exitStatus = 0;
  211. if (cap != NULL) {
  212. printf("%s\n", cap->name);
  213. }
  214. else {
  215. fprintf(stderr, "Failed to find matching flow file for %s.\n",
  216. args.keylogName);
  217. exitStatus = 1;
  218. }
  219. cleanup(args);
  220. return exitStatus;
  221. }