PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/dsniff-2.4/urlsnarf.c

#
C | 320 lines | 261 code | 48 blank | 11 comment | 73 complexity | b926438ecd2269e18ef4e046829b995a MD5 | raw file
  1. /*
  2. * urlsnarf.c
  3. *
  4. * Sniff the network for HTTP request URLs, output in CLF format.
  5. *
  6. * Copyright (c) 1999 Dug Song <dugsong@monkey.org>
  7. *
  8. * $Id: urlsnarf.c,v 1.35 2001/03/15 09:26:13 dugsong Exp $
  9. */
  10. #include "config.h"
  11. #include <sys/types.h>
  12. #include <sys/socket.h>
  13. #include <netinet/in.h>
  14. #include <arpa/inet.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <unistd.h>
  18. #include <string.h>
  19. #include <regex.h>
  20. #include <time.h>
  21. #include <err.h>
  22. #include <libnet.h>
  23. #include <nids.h>
  24. #include <pcap.h>
  25. #include "pcaputil.h"
  26. #include "buf.h"
  27. #include "base64.h"
  28. #include "version.h"
  29. #define DEFAULT_PCAP_FILTER "tcp port 80 or port 8080 or port 3128"
  30. u_short Opt_dns = 1;
  31. int Opt_invert = 0;
  32. regex_t *pregex = NULL;
  33. static void
  34. usage(void)
  35. {
  36. fprintf(stderr, "Version: " VERSION "\n"
  37. "Usage: urlsnarf [-n] [-i interface | -p pcapfile] [[-v] pattern [expression]]\n");
  38. exit(1);
  39. }
  40. static int
  41. regex_match(char *string)
  42. {
  43. return (pregex == NULL ||
  44. ((regexec(pregex, string, 0, NULL, 0) == 0) ^ Opt_invert));
  45. }
  46. static char *
  47. timestamp(void)
  48. {
  49. static char tstr[32], sign;
  50. struct tm *t, gmt;
  51. time_t tt = time(NULL);
  52. int days, hours, tz, len;
  53. gmt = *gmtime(&tt);
  54. t = localtime(&tt);
  55. days = t->tm_yday - gmt.tm_yday;
  56. hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) +
  57. t->tm_hour - gmt.tm_hour);
  58. tz = hours * 60 + t->tm_min - gmt.tm_min;
  59. len = strftime(tstr, sizeof(tstr), "%d/%b/%Y:%X", t);
  60. if (len < 0 || len > sizeof(tstr) - 5)
  61. return (NULL);
  62. if (tz < 0) {
  63. sign = '-';
  64. tz = -tz;
  65. }
  66. else sign = '+';
  67. snprintf(tstr + len, sizeof(tstr) - len, " %c%.2d%.2d",
  68. sign, tz / 60, tz % 60);
  69. return (tstr);
  70. }
  71. static char *
  72. escape_log_entry(char *string)
  73. {
  74. char *out;
  75. unsigned char *c, *o;
  76. size_t len;
  77. if (!string)
  78. return NULL;
  79. /* Determine needed length */
  80. for (c = string, len = 0; *c; c++) {
  81. if ((*c < 32) || (*c >= 128))
  82. len += 4;
  83. else if ((*c == '"') || (*c =='\\'))
  84. len += 2;
  85. else
  86. len++;
  87. }
  88. out = malloc(len+1);
  89. if (!out)
  90. return NULL;
  91. for (c = string, o = out; *c; c++, o++) {
  92. if ((*c < 32) || (*c >= 128)) {
  93. snprintf(o, 5, "\\x%02x", *c);
  94. o += 3;
  95. } else if ((*c == '"') || ((*c =='\\'))) {
  96. *(o++) = '\\';
  97. *o = *c;
  98. } else {
  99. *o = *c;
  100. }
  101. }
  102. out[len]='\0';
  103. return out;
  104. }
  105. static int
  106. process_http_request(struct tuple4 *addr, u_char *data, int len)
  107. {
  108. struct buf *msg, buf;
  109. char *p, *req, *uri, *user, *vhost, *referer, *agent;
  110. int i;
  111. buf_init(&buf, data, len);
  112. while ((i = buf_index(&buf, "\r\n\r\n", 4)) >= 0) {
  113. msg = buf_tok(&buf, NULL, i);
  114. msg->base[msg->end] = '\0';
  115. buf_skip(&buf, 4);
  116. if (!regex_match(buf_ptr(msg)))
  117. continue;
  118. if ((req = strtok(buf_ptr(msg), "\r\n")) == NULL)
  119. continue;
  120. if (strncmp(req, "GET ", 4) != 0 &&
  121. strncmp(req, "POST ", 5) != 0 &&
  122. strncmp(req, "CONNECT ", 8) != 0)
  123. continue;
  124. if ((uri = strchr(req, ' ')) == NULL)
  125. continue;
  126. *uri++ = '\0';
  127. if (strncmp(uri, "http://", 7) == 0) {
  128. for (uri += 7; *uri != '/'; uri++)
  129. ;
  130. }
  131. user = vhost = referer = agent = NULL;
  132. while ((p = strtok(NULL, "\r\n")) != NULL) {
  133. if (strncasecmp(p, "Authorization: Basic ", 21) == 0) {
  134. p += 21;
  135. i = base64_pton(p, p, strlen(p));
  136. p[i] = '\0';
  137. user = p;
  138. if ((p = strchr(p, ':')) != NULL)
  139. *p = '\0';
  140. }
  141. else if (strncasecmp(p, "Host: ", 6) == 0) {
  142. vhost = p + 6;
  143. }
  144. else if (strncasecmp(p, "Referer: ", 9) == 0) {
  145. referer = p + 9;
  146. }
  147. else if (strncasecmp(p, "User-Agent: ", 12) == 0) {
  148. agent = p + 12;
  149. }
  150. else if (strncasecmp(p, "Content-length: ", 16) == 0) {
  151. i = atoi(p + 16);
  152. buf_tok(NULL, NULL, i);
  153. }
  154. }
  155. user = escape_log_entry(user);
  156. vhost = escape_log_entry(vhost);
  157. uri = escape_log_entry(uri);
  158. referer = escape_log_entry(referer);
  159. agent = escape_log_entry(agent);
  160. printf("%s - %s [%s] \"%s http://%s%s\" - - \"%s\" \"%s\"\n",
  161. libnet_addr2name4(addr->saddr, Opt_dns),
  162. (user?user:"-"),
  163. timestamp(), req,
  164. (vhost?vhost:libnet_addr2name4(addr->daddr, Opt_dns)),
  165. uri,
  166. (referer?referer:"-"),
  167. (agent?agent:"-"));
  168. free(user);
  169. free(vhost);
  170. free(uri);
  171. free(referer);
  172. free(agent);
  173. }
  174. fflush(stdout);
  175. return (len - buf_len(&buf));
  176. }
  177. static void
  178. sniff_http_client(struct tcp_stream *ts, void **yoda)
  179. {
  180. int i;
  181. switch (ts->nids_state) {
  182. case NIDS_JUST_EST:
  183. ts->server.collect = 1;
  184. case NIDS_DATA:
  185. if (ts->server.count_new != 0) {
  186. i = process_http_request(&ts->addr, ts->server.data,
  187. ts->server.count -
  188. ts->server.offset);
  189. nids_discard(ts, i);
  190. }
  191. break;
  192. default:
  193. if (ts->server.count != 0) {
  194. process_http_request(&ts->addr, ts->server.data,
  195. ts->server.count -
  196. ts->server.offset);
  197. }
  198. break;
  199. }
  200. }
  201. static void
  202. null_syslog(int type, int errnum, struct ip *iph, void *data)
  203. {
  204. }
  205. int
  206. main(int argc, char *argv[])
  207. {
  208. extern char *optarg;
  209. extern int optind;
  210. int c;
  211. struct nids_chksum_ctl chksum_ctl;
  212. while ((c = getopt(argc, argv, "i:p:nvh?V")) != -1) {
  213. switch (c) {
  214. case 'i':
  215. nids_params.device = optarg;
  216. break;
  217. case 'p':
  218. nids_params.filename = optarg;
  219. break;
  220. case 'n':
  221. Opt_dns = 0;
  222. break;
  223. case 'v':
  224. Opt_invert = 1;
  225. break;
  226. default:
  227. usage();
  228. }
  229. }
  230. argc -= optind;
  231. argv += optind;
  232. if (argc > 0 && strlen(argv[0])) {
  233. if ((pregex = (regex_t *) malloc(sizeof(*pregex))) == NULL)
  234. err(1, "malloc");
  235. if (regcomp(pregex, argv[0], REG_EXTENDED|REG_NOSUB) != 0)
  236. errx(1, "invalid regular expression");
  237. }
  238. if (argc > 1) {
  239. nids_params.pcap_filter = copy_argv(argv + 1);
  240. }
  241. else nids_params.pcap_filter = DEFAULT_PCAP_FILTER;
  242. nids_params.scan_num_hosts = 0;
  243. nids_params.syslog = null_syslog;
  244. if (!nids_init())
  245. errx(1, "%s", nids_errbuf);
  246. nids_register_tcp(sniff_http_client);
  247. if (nids_params.pcap_filter != NULL) {
  248. if (nids_params.filename == NULL) {
  249. warnx("listening on %s [%s]", nids_params.device,
  250. nids_params.pcap_filter);
  251. }
  252. else {
  253. warnx("using %s [%s]", nids_params.filename,
  254. nids_params.pcap_filter);
  255. }
  256. }
  257. else {
  258. if (nids_params.filename == NULL) {
  259. warnx("listening on %s", nids_params.device);
  260. }
  261. else {
  262. warnx("using %s", nids_params.filename);
  263. }
  264. }
  265. chksum_ctl.netaddr = 0;
  266. chksum_ctl.mask = 0;
  267. chksum_ctl.action = NIDS_DONT_CHKSUM;
  268. nids_register_chksum_ctl(&chksum_ctl, 1);
  269. nids_run();
  270. /* NOTREACHED */
  271. exit(0);
  272. }