[tor-commits] [stegotorus/master] Add Vinod's program for generating HTTP trace files from pcap files.
zwol at torproject.org
zwol at torproject.org
Fri Jul 20 23:17:08 UTC 2012
commit 949aa9547d89d4b2d463a0460941a0cc35cec56d
Author: Zack Weinberg <zackw at cmu.edu>
Date: Thu Jul 12 16:24:20 2012 +0200
Add Vinod's program for generating HTTP trace files from pcap files.
* pgen.h, pgen_pcap.cc: New files.
* util.cc: Split libevent-using routines to util-net.cc.
* configure.ac: Detect availability of libpcap.
* Makefile.am: Build pgen_pcap if we have libpcap. Shuffle linkage
variables around a little so each program is only linked against the
libraries it needs.
---
Makefile.am | 27 ++-
configure.ac | 27 ++-
src/audit-globals.sh | 2 +-
src/pgen.h | 21 ++
src/pgen_pcap.cc | 617 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/util-net.cc | 134 +++++++++++
src/util.cc | 129 -----------
7 files changed, 822 insertions(+), 135 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 42eaede..d19aab6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,6 @@ ACLOCAL_AMFLAGS = -I config-aux --install
AM_CXXFLAGS = -Werror -Wall -Wextra -Wformat=2
AM_CPPFLAGS = -I. -I$(srcdir)/src -D_FORTIFY_SOURCE=2 $(lib_CPPFLAGS)
-LDADD = libstegotorus.a
noinst_LIBRARIES = libstegotorus.a
noinst_PROGRAMS = unittests tltester
@@ -41,6 +40,7 @@ libstegotorus_a_SOURCES = \
src/socks.cc \
src/steg.cc \
src/util.cc \
+ src/util-net.cc \
$(PROTOCOLS) $(STEGANOGRAPHERS)
if WINDOWS
@@ -54,8 +54,25 @@ nodist_libstegotorus_a_SOURCES = protolist.cc steglist.cc
stegotorus_SOURCES = \
src/main.cc
+stegotorus_LDADD = libstegotorus.a $(lib_LIBS)
+
# prevent stegotorus from being linked if s-a-g fails
-stegotorus_DEPENDENCIES = $(LDADD) stamp-audit-globals
+# it is known that $(lib_LIBS) contains nothing that needs to be depended upon
+stegotorus_DEPENDENCIES = libstegotorus.a stamp-audit-globals
+
+## payload trace generators
+
+# pgen_pcap is only built if we have libpcap
+if HAVE_PCAP
+bin_PROGRAMS += pgen_pcap
+
+pgen_pcap_SOURCES = \
+ src/pgen_pcap.cc \
+ src/compression.cc \
+ src/util.cc
+
+pgen_pcap_LDADD = $(pcap_LIBS) $(libz_LIBS)
+endif
UTGROUPS = \
src/test/unittest_base64.cc \
@@ -71,7 +88,10 @@ unittests_SOURCES = \
nodist_unittests_SOURCES = unitgrplist.cc
-tltester_SOURCES = src/test/tltester.cc
+unittests_LDADD = libstegotorus.a $(lib_LIBS)
+
+tltester_SOURCES = src/test/tltester.cc src/util.cc src/util-net.cc
+tltester_LDADD = $(libevent_LIBS)
noinst_HEADERS = \
src/base64.h \
@@ -80,6 +100,7 @@ noinst_HEADERS = \
src/crypt.h \
src/listener.h \
src/mkem.h \
+ src/pgen.h \
src/protocol.h \
src/rng.h \
src/socks.h \
diff --git a/configure.ac b/configure.ac
index 889cfae..dcad0db 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,8 +125,6 @@ PKG_CHECK_MODULES([libevent], [libevent >= 2.0])
PKG_CHECK_MODULES([libz], [zlib >= 1.2.3.4])
LIBS="$libevent_LIBS $libcrypto_LIBS $libz_LIBS"
-lib_CPPFLAGS="$libevent_CFLAGS $libcrypto_CFLAGS $libz_CFLAGS"
-AC_SUBST(lib_CPPFLAGS)
# ntohl and a bunch of related functions require a special library on Windows.
# It is possible that libevent or libcrypto has hooked us up already.
@@ -139,6 +137,31 @@ AC_SEARCH_LIBS([floor], [m], [], [
AC_MSG_ERROR([unable to find 'floor'])
])
+lib_LIBS="$LIBS"
+lib_CPPFLAGS="$libevent_CFLAGS $libcrypto_CFLAGS $libz_CFLAGS"
+LIBS=
+AC_SUBST(lib_LIBS)
+AC_SUBST(lib_CPPFLAGS)
+
+# pgen_pcap needs libpcap.
+pcap_LIBS=
+HAVE_PCAP=no
+AC_SEARCH_LIBS([pcap_open_offline], [pcap],
+ [AC_CACHE_CHECK([whether libpcap is usable], ac_cv_libpcap_usable,
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM(
+ [[#include <pcap/pcap.h>]],
+ [[char f;
+ pcap_t *p = pcap_open_offline("",&f);]])],
+ [ac_cv_libpcap_usable=yes], [ac_cv_libpcap_usable=no])])
+ if test $ac_cv_libpcap_usable = yes; then
+ HAVE_PCAP=yes
+ pcap_LIBS="$LIBS"
+ fi],
+ [])
+LIBS=
+AC_SUBST(pcap_LIBS)
+AM_CONDITIONAL(HAVE_PCAP, test $HAVE_PCAP = yes)
+
### System features ###
AC_CHECK_HEADERS([execinfo.h paths.h],,,[/**/])
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 2512bb6..21ff6d2 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -46,7 +46,7 @@ sed '
/^util log_min_sev$/d
/^util log_timestamps$/d
/^util log_ts_base$/d
- /^util the_evdns_base$/d
+ /^util-net the_evdns_base$/d
')
if [ -n "$symbols" ]; then
diff --git a/src/pgen.h b/src/pgen.h
new file mode 100644
index 0000000..c8e7a55
--- /dev/null
+++ b/src/pgen.h
@@ -0,0 +1,21 @@
+/* Copyright 2011, 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#ifndef PGEN_H
+#define PGEN_H
+
+// NOTE: this must be kept in sync with steg/payloads.h
+
+#define TYPE_SERVICE_DATA 0x1
+#define TYPE_HTTP_REQUEST 0x2
+#define TYPE_HTTP_RESPONSE 0x4
+
+/* struct for reading in the payload_gen dump file */
+struct pentry_header {
+ uint16_t ptype;
+ uint32_t length;
+ uint16_t port; /* network format */
+};
+
+#endif
diff --git a/src/pgen_pcap.cc b/src/pgen_pcap.cc
new file mode 100644
index 0000000..cb6e475
--- /dev/null
+++ b/src/pgen_pcap.cc
@@ -0,0 +1,617 @@
+/* Copyright 2011, 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#include "util.h"
+#include "pgen.h"
+#include "compression.h"
+
+#include <pcap/pcap.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <dirent.h>
+
+#define NUM_FLOWS 1000
+#define NUM_LISTS 1000
+
+#define CONN_DATA_REQUEST 1 /* payload packet sent by client */
+#define CONN_DATA_REPLY 2 /* payload packet sent by server */
+
+#define RECV_MTU 64000
+// #define PKT_MTU 1500
+#define MAX_CHAIN_LEN 4000
+
+#define MSG_INSERTED 1
+#define MSG_INVALID 0
+#define MSG_SEQ_WRAP -2
+#define MSG_DUPLICATE -3
+#define CHAIN_TOO_LONG -4
+#define MSG_OVERLAP -5
+#define CHAIN_HAS_GAPS_OVERLAPS -6
+#define CHAIN_EMPTY -7
+
+struct msg {
+ uint8_t *buf;
+ uint16_t len;
+ uint32_t seqno;
+ msg *next_msg;
+};
+
+struct flow {
+ uint32_t src_ip;
+ uint32_t dst_ip;
+ uint16_t sport;
+ uint16_t dport;
+ uint8_t flags;
+ uint8_t proto;
+ struct timeval change_time;
+ int sockfd;
+ flow *next_flow;
+ msg *msg_buf_chain;
+ int chain_len;
+ int msg_len_so_far;
+ int dir; /* data request or data reply */
+ uint32_t ack_so_far; /* what's acknowledged by other end so far */
+};
+
+static flow *flows[NUM_LISTS];
+static pcap_t *descr;
+static int dir_flag = 0;
+static char *bp_filter;
+static char errbuf[PCAP_ERRBUF_SIZE];
+static struct bpf_program fp;
+static uint32_t netp;
+static const char *argv0;
+
+#define RECV_MTU 64000
+#define PORT_HTTP 80
+
+static FILE *client_file;
+static FILE *server_file;
+
+static void ATTR_NORETURN
+usage()
+{
+ fprintf(stderr, "Usage: %s [-d dumpdir] [-r dumpfile] \"bpf filter\"\n",
+ argv0);
+ exit(1);
+}
+
+static void ATTR_NORETURN
+terminate(int)
+{
+ struct pcap_stat ps;
+ if (pcap_stats(descr, &ps) < 0) {
+ fputs("err: pcap stats not supported?\n", stderr);
+ exit(1);
+ }
+
+ printf("packets rcvd: %u, packets dropped: %u, interface drops: %u\n",
+ ps.ps_recv, ps.ps_drop, ps.ps_ifdrop);
+ exit(1);
+}
+
+static void
+free_msg_chain(flow *f)
+{
+ msg *m = f->msg_buf_chain;
+
+ while (m && f->chain_len > 0) {
+ msg *n = m->next_msg;
+ free(m);
+ m = n;
+ }
+
+ f->chain_len = 0;
+ f->msg_len_so_far = 0;
+ f->msg_buf_chain = 0;
+}
+
+static bool
+has_chain_gaps(flow *f)
+{
+ msg *m = f->msg_buf_chain;
+
+ while (m) {
+ if (!m->next_msg)
+ return false;
+
+ if (m->seqno + m->len < m->next_msg->seqno) {
+ fprintf(stderr, "gap seqnos: %u %u %u %d\n",
+ m->seqno, m->len, m->next_msg->seqno, f->dport);
+ return true;
+ }
+
+ if (m->seqno + m->len > m->next_msg-> seqno) {
+ fprintf(stderr, "overlap seqnos: %u %u %u\n",
+ m->seqno, m->len, m->next_msg->seqno);
+ return true;
+ }
+ m = m->next_msg;
+ }
+
+ return false;
+}
+
+static int
+write_inflate_msg(flow *f, FILE *file, pentry_header *ph)
+{
+ msg *m = f->msg_buf_chain;
+ uint8_t *buf;
+ int pos = 0;
+ uint8_t *outbuf;
+ int outlen;
+
+ uint8_t *hdr_end;
+ uint8_t *hdr;
+ int hdrlen;
+
+ if (!f->msg_buf_chain)
+ return CHAIN_EMPTY;
+
+ if (strstr((char*) m->buf, "Transfer-Encoding: chunked"))
+ // we don't handle this yet....need a loop to unzip chunks individually...
+ return MSG_INVALID;
+
+ hdr_end = (uint8_t*) strstr((char*) m->buf, "\r\n\r\n");
+ if (!hdr_end) {
+ fprintf(stderr, "hdr too long?? \n");
+ return MSG_INVALID;
+ }
+
+ hdr_end += 4;
+ hdrlen = hdr_end - m->buf;
+ hdr = (uint8_t *) xmemdup(m->buf, hdrlen);
+
+ buf = (uint8_t *) xmalloc(f->msg_len_so_far);
+ outbuf = (uint8_t *) xmalloc(f->msg_len_so_far * 20);
+
+ pos = 0;
+
+ if (!m)
+ return CHAIN_EMPTY;
+
+ memcpy(buf, hdr_end, m->len - hdrlen);
+ pos += m->len - hdrlen;
+ m = m->next_msg;
+
+ while (m) {
+ memcpy(buf+pos, m->buf, m->len);
+ pos += m->len;
+ m = m->next_msg;
+ }
+
+ outlen = decompress(buf, f->msg_len_so_far - hdrlen,
+ outbuf, f->msg_len_so_far*20);
+
+ if (outlen < 0) {
+ fprintf(stderr, "unzip failed outlen = %d %d %d\n",
+ outlen, pos, f->msg_len_so_far-hdrlen);
+ return MSG_INVALID;
+ }
+
+ ph->length = htonl(outlen+hdrlen);
+ fwrite(ph, sizeof(pentry_header), 1, file);
+ fwrite(hdr, hdrlen, 1, file);
+ fwrite(outbuf, outlen, 1, file);
+ free(buf);
+ free(outbuf);
+ free(hdr);
+ return 1;
+}
+
+static int
+write_msg_chains(flow *f, FILE *file, pentry_header *ph)
+{
+ msg *m = f->msg_buf_chain;
+ int cnt = 0;
+
+ if (has_chain_gaps(f))
+ return CHAIN_HAS_GAPS_OVERLAPS;
+
+ if (!m)
+ return CHAIN_EMPTY;
+
+ if (strstr((char*) m->buf, "200 OK") &&
+ strstr((char*) m->buf, "Content-Encoding: gzip"))
+ return write_inflate_msg(f, file, ph);
+
+ fwrite(ph, sizeof(pentry_header), 1, file);
+
+ while (m) {
+ fwrite(m->buf, m->len, 1, file);
+ cnt += m->len;
+ m = m->next_msg;
+ }
+
+ if (cnt != f->msg_len_so_far)
+ fprintf(stderr, "something funky in writing message\n");
+ return 1;
+}
+
+static bool
+is_valid_http_request(flow *f)
+{
+ if (!f->msg_buf_chain) {
+ fprintf(stderr, "is_valid_http_request: invalid chain %d\n", f->chain_len);
+ return false;
+ }
+
+ if (!strncmp((char*) f->msg_buf_chain->buf, "GET", 3) ||
+ !strncmp((char*) f->msg_buf_chain->buf, "POST", 4)) {
+ msg *m = f->msg_buf_chain;
+ while (m->next_msg)
+ m = m->next_msg;
+
+ if (m->buf[m->len-2] == '\r' && m->buf[m->len-1] == '\n') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int
+add_msg_to_flow(flow *f, uint8_t *buf, uint seq, int len)
+{
+ if (len > RECV_MTU)
+ return MSG_INVALID;
+
+ if (f->chain_len >= MAX_CHAIN_LEN)
+ return CHAIN_TOO_LONG;
+
+ if (seq > seq + len)
+ return MSG_SEQ_WRAP;
+
+ msg *p = 0;
+ msg *m = f->msg_buf_chain;
+
+ if (!m) {
+ m = (msg *)xzalloc(sizeof(msg));
+ m->buf = (uint8_t *)xmalloc(len);
+ memcpy(m->buf, buf, len);
+ m->seqno = seq;
+ f->chain_len = 1;
+ f->msg_len_so_far += len;
+ f->msg_buf_chain = m;
+ m->len = len;
+ return MSG_INSERTED;
+ }
+
+ while (m) {
+ if (m->seqno == seq)
+ return MSG_DUPLICATE;
+
+ if (m->seqno < seq) {
+ if (m->seqno > seq + len)
+ return MSG_OVERLAP;
+ p = m;
+ m = m->next_msg;
+ continue;
+ }
+
+ if (m->seqno < seq + len)
+ return MSG_OVERLAP;
+
+ msg *n;
+ if (!p) {
+ p = (msg *)xzalloc(sizeof(msg));
+ p->buf = (uint8_t *)xmalloc(len);
+ memcpy(p->buf, buf, len);
+ p->seqno = seq;
+ p->next_msg = m;
+ f->chain_len++;
+ f->msg_len_so_far += len;
+ f->msg_buf_chain = p;
+ p->len = len;
+ return MSG_INSERTED;
+ }
+
+ n = (msg *)xzalloc(sizeof(msg));
+ n->buf = (uint8_t *)xmemdup(buf, len);
+ memcpy(n->buf, buf, len);
+ n->seqno = seq;
+ n->next_msg = m;
+ p->next_msg = n;
+ f->chain_len++;
+ f->msg_len_so_far += len;
+ n->len = len;
+ return MSG_INSERTED;
+ }
+
+ m = (msg *)xzalloc(sizeof(msg));
+ m->buf = (uint8_t *)xmemdup(buf, len);
+ m->seqno = seq;
+ p->next_msg = m;
+ f->chain_len++;
+ f->msg_len_so_far += len;
+ m->len = len;
+ return MSG_INSERTED;
+}
+
+static int
+hash_flow(flow *f)
+{
+ return (f->src_ip + f->dst_ip + f->sport + f->dport) % NUM_LISTS;
+}
+
+static bool
+flow_compare(flow *f1, flow *f2)
+{
+ return (f1->src_ip == f2->src_ip && f1->dst_ip == f2->dst_ip
+ && f1->sport == f2->sport && f1->dport == f2->dport);
+}
+
+static flow *
+add_to_flows(flow *f)
+{
+ int hval = hash_flow(f);
+
+ flow *cflow = flows[hval];
+
+ if (!cflow) {
+ cflow = (flow *) xmalloc(sizeof(flow));
+ memcpy(cflow, f, sizeof(flow));
+ cflow->next_flow = 0;
+ flows[hval] = cflow;
+ return cflow;
+ }
+ else {
+ // add flow to the beginning of the chain
+ flow *old_flow = (flow *) xmalloc(sizeof(flow));
+ memcpy(old_flow, cflow, sizeof(flow));
+ memcpy(cflow, f, sizeof(flow));
+ cflow->next_flow = old_flow;
+ }
+ return cflow;
+}
+
+static flow *
+has_seen_flow(flow *f)
+{
+ int hval = hash_flow(f);
+ flow *cflow = flows[hval];
+
+ while (cflow) {
+ if (flow_compare(cflow, f))
+ return cflow;
+ cflow = cflow->next_flow;
+ }
+
+ return 0;
+}
+
+static flow *
+reverse_flow(flow *f)
+{
+ uint32_t tmp_ip;
+ uint16_t tmp_port;
+
+ tmp_ip = f->src_ip;
+ f->src_ip = f->dst_ip;
+ f->dst_ip = tmp_ip;
+
+ tmp_port = f->sport;
+ f->sport = f->dport;
+ f->dport = tmp_port;
+ return f;
+}
+
+static void
+write_http_packet(flow *f)
+{
+ pentry_header ph;
+ ph.length = htonl(f->msg_len_so_far);
+ ph.port = htons(80);
+
+ if (f->dir == CONN_DATA_REQUEST) {
+ ph.ptype = htons(TYPE_HTTP_REQUEST);
+ if (is_valid_http_request(f))
+ write_msg_chains(f, client_file, &ph);
+ }
+ else {
+ ph.ptype = htons(TYPE_HTTP_RESPONSE);
+ write_msg_chains(f, server_file, &ph);
+ }
+}
+
+static void
+write_packet(flow *f)
+{
+ uint16_t tport;
+ if (f->dir == CONN_DATA_REQUEST)
+ tport = f->dport;
+ else
+ tport = f->sport;
+
+ switch(tport) {
+ case PORT_HTTP:
+ write_http_packet(f);
+ }
+}
+
+static void
+my_callback(uint8_t * /*unused*/,
+ const struct pcap_pkthdr *pkthdr,
+ const uint8_t *packet)
+{
+
+ struct ether_header *eth = (struct ether_header*) (packet) ;
+ int rval;
+
+ if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
+
+ struct ip *iph = (struct ip*) (packet + sizeof(struct ether_header));
+ struct tcphdr *tcph = (struct tcphdr*)
+ ((uint8_t*)iph + sizeof(struct ip));
+
+ int len = htons(iph->ip_len) - 4*tcph->th_off - sizeof(struct ip);
+ uint8_t *payload = (uint8_t*) tcph + 4*tcph->th_off;
+ flow f;
+ flow *cflow;
+ flow *rflow;
+
+ memset(&f, 0, sizeof(flow));
+ f.src_ip = iph->ip_src.s_addr;
+ f.dst_ip = iph->ip_dst.s_addr;
+ f.sport = ntohs(tcph->th_sport);
+ f.dport = ntohs(tcph->th_dport);
+ f.flags = tcph->th_flags;
+ f.proto = iph->ip_p;
+ f.change_time = pkthdr->ts;
+
+ if (tcph->th_flags & TH_SYN && !(tcph->th_flags & TH_ACK)) {
+ f.dir = CONN_DATA_REQUEST;
+ add_to_flows(&f);
+ return;
+ }
+
+ else if ((tcph->th_flags & TH_SYN) && (tcph->th_flags & TH_ACK)) {
+ f.dir = CONN_DATA_REPLY;
+ add_to_flows(&f);
+ return;
+ }
+
+ cflow = has_seen_flow(&f);
+ if (!cflow)
+ return;
+
+ rflow = has_seen_flow(reverse_flow(&f));
+ if (!rflow)
+ return;
+
+ rflow->ack_so_far = ntohl(tcph->th_ack);
+ cflow->flags = cflow->flags | tcph->th_flags;
+
+ if (len > 0 && ntohl(tcph->th_seq) >= cflow->ack_so_far) {
+ if (rflow->msg_len_so_far > 0) {
+ write_packet(rflow);
+ free_msg_chain(rflow);
+ }
+
+ rval = add_msg_to_flow(cflow, payload, ntohl(tcph->th_seq), len);
+
+ if (rval <= 0 && rval !=MSG_DUPLICATE && rval != CHAIN_TOO_LONG) {
+ fprintf(stderr, "adding msg to flow failed %d %d\n", rval, len);
+ }
+ }
+
+
+ if (cflow->flags & TH_RST || cflow->flags & TH_FIN) {
+ if (rflow->msg_len_so_far > 0) {
+ write_packet(rflow);
+ free_msg_chain(rflow);
+ }
+ return;
+ }
+ }
+}
+
+static void
+handle_pcap_file(const char *filename)
+{
+ descr = pcap_open_offline(filename, errbuf);
+ if (!descr) {
+ fprintf(stderr, "%s: %s\n", filename, errbuf);
+ exit(1);
+ }
+
+ if (pcap_compile(descr, &fp, bp_filter, 1, netp) == -1) {
+ fprintf(stderr, "Error calling pcap_compile on \"%s\"\n", bp_filter);
+ exit(1);
+ }
+
+ /* set the compiled program as the filter */
+ if (pcap_setfilter(descr, &fp) == -1) {
+ fprintf(stderr,"Error setting filter\n");
+ exit(1);
+ }
+
+ /* main pcap loop */
+ pcap_loop(descr, -1, my_callback, 0);
+ pcap_close(descr);
+}
+
+static void
+list_files(const char *dirname)
+{
+ DIR *dip;
+ struct dirent *dit;
+ char *fname;
+ size_t plen = strlen(dirname);
+
+ if ((dip = opendir(dirname)) == 0) {
+ perror("opendir");
+ return;
+ }
+
+ while ((dit = readdir(dip)) != 0) {
+ if (!strcmp(dit->d_name, ".") || !strcmp(dit->d_name, ".."))
+ continue;
+
+ size_t dlen = strlen(dit->d_name);
+ fname = (char *)xmalloc(plen + dlen + 2);
+ memcpy(fname, dirname, plen);
+ fname[plen] = '/';
+ memcpy(fname + plen + 1, dit->d_name, dlen);
+ fname[plen + dlen + 1] = '\0';
+ fprintf(stderr, "%s\n", fname);
+ handle_pcap_file(fname);
+ free(fname);
+ }
+
+ closedir(dip);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ const char *dumpfile = 0;
+
+ argv0 = argv[0];
+
+ while ((c = getopt (argc, argv, "r:d:")) != -1) {
+ switch (c) {
+ case 'r':
+ dumpfile = optarg;
+ break;
+ case 'd':
+ dir_flag = 1;
+ dumpfile = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (!argv[optind] || !dumpfile)
+ usage();
+
+ bp_filter = xstrdup(argv[optind]);
+
+ client_file = fopen("traces/client.out", "w");
+ if (!client_file) {
+ perror("traces/client.out");
+ return 1;
+ }
+ server_file = fopen("traces/server.out", "w");
+ if (!server_file) {
+ perror("traces/server.out");
+ return 1;
+ }
+
+ /* catch ^C print stats and exit */
+ signal(SIGTERM, terminate);
+ signal(SIGINT, terminate);
+ signal(SIGHUP, terminate);
+
+ if (dir_flag)
+ list_files(dumpfile);
+ else
+ handle_pcap_file(dumpfile);
+
+ return 0;
+}
diff --git a/src/util-net.cc b/src/util-net.cc
new file mode 100644
index 0000000..0826eaa
--- /dev/null
+++ b/src/util-net.cc
@@ -0,0 +1,134 @@
+/* Copyright 2011 Nick Mathewson, George Kadianakis
+ * Copyright 2011, 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#include "util.h"
+
+#include <event2/dns.h>
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef AF_LOCAL
+#include <sys/un.h>
+#endif
+
+/**
+ Accepts a string 'address' of the form ADDRESS:PORT and attempts to
+ parse it into an 'evutil_addrinfo' structure.
+
+ If 'nodns' is set it means that 'address' was an IP address.
+ If 'passive' is set it means that the address is destined for
+ listening and not for connecting.
+
+ If no port was given in 'address', we set 'default_port' as the
+ port.
+*/
+struct evutil_addrinfo *
+resolve_address_port(const char *address, int nodns, int passive,
+ const char *default_port)
+{
+ struct evutil_addrinfo *ai = NULL;
+ struct evutil_addrinfo ai_hints;
+ int ai_res, ai_errno;
+ char *a = xstrdup(address), *cp;
+ const char *portstr;
+
+ if ((cp = strchr(a, ':'))) {
+ portstr = cp+1;
+ *cp = '\0';
+ } else if (default_port) {
+ portstr = default_port;
+ } else {
+ log_debug("error in address %s: port required", address);
+ free(a);
+ return NULL;
+ }
+
+ memset(&ai_hints, 0, sizeof(ai_hints));
+ ai_hints.ai_family = AF_UNSPEC;
+ ai_hints.ai_socktype = SOCK_STREAM;
+ ai_hints.ai_flags = EVUTIL_AI_ADDRCONFIG | EVUTIL_AI_NUMERICSERV;
+ if (passive)
+ ai_hints.ai_flags |= EVUTIL_AI_PASSIVE;
+ if (nodns)
+ ai_hints.ai_flags |= EVUTIL_AI_NUMERICHOST;
+
+ ai_res = evutil_getaddrinfo(a, portstr, &ai_hints, &ai);
+ ai_errno = errno;
+
+ free(a);
+
+ if (ai_res) {
+ if (ai_res == EVUTIL_EAI_SYSTEM)
+ log_warn("error resolving %s: %s [%s]",
+ address, evutil_gai_strerror(ai_res), strerror(ai_errno));
+ else
+ log_warn("error resolving %s: %s", address, evutil_gai_strerror(ai_res));
+
+ if (ai) {
+ evutil_freeaddrinfo(ai);
+ ai = NULL;
+ }
+ } else if (ai == NULL) {
+ log_warn("address resolution failed for %s", address);
+ }
+
+ return ai;
+}
+
+char *
+printable_address(struct sockaddr *addr, socklen_t addrlen)
+{
+ char apbuf[INET6_ADDRSTRLEN + 8]; /* []:65535 is 8 characters */
+
+ switch (addr->sa_family) {
+#ifndef _WIN32 /* Windows XP doesn't have inet_ntop. Fix later. */
+ case AF_INET: {
+ char abuf[INET6_ADDRSTRLEN];
+ struct sockaddr_in *sin = (struct sockaddr_in*)addr;
+ log_assert(addrlen >= sizeof(struct sockaddr_in));
+ if (!inet_ntop(AF_INET, &sin->sin_addr, abuf, INET6_ADDRSTRLEN))
+ break;
+ xsnprintf(apbuf, sizeof apbuf, "%s:%d", abuf, ntohs(sin->sin_port));
+ return xstrdup(apbuf);
+ }
+
+ case AF_INET6: {
+ char abuf[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
+ log_assert(addrlen >= sizeof(struct sockaddr_in6));
+ if (!inet_ntop(AF_INET, &sin6->sin6_addr, abuf, INET6_ADDRSTRLEN))
+ break;
+ xsnprintf(apbuf, sizeof apbuf, "[%s]:%d", abuf, ntohs(sin6->sin6_port));
+ return xstrdup(apbuf);
+ }
+#endif
+
+#ifdef AF_LOCAL
+ case AF_LOCAL:
+ return xstrdup(((struct sockaddr_un*)addr)->sun_path);
+#endif
+ default:
+ break;
+ }
+
+ xsnprintf(apbuf, sizeof apbuf, "<addr family %d>", addr->sa_family);
+ return xstrdup(apbuf);
+}
+
+static struct evdns_base *the_evdns_base = NULL;
+
+struct evdns_base *
+get_evdns_base(void)
+{
+ return the_evdns_base;
+}
+
+int
+init_evdns_base(struct event_base *base)
+{
+ the_evdns_base = evdns_base_new(base, 1);
+ return the_evdns_base == NULL ? -1 : 0;
+}
diff --git a/src/util.cc b/src/util.cc
index 3900f21..d06a1c8 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -9,14 +9,6 @@
#include <fcntl.h>
#include <unistd.h>
-#include <event2/dns.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef AF_LOCAL
-#include <sys/un.h>
-#endif
-
/**************************** Memory Allocation ******************************/
static void ATTR_NORETURN
@@ -132,127 +124,6 @@ ui64_log2(uint64_t u64)
return r;
}
-/************************ Network Routines *************************/
-
-/**
- Accepts a string 'address' of the form ADDRESS:PORT and attempts to
- parse it into an 'evutil_addrinfo' structure.
-
- If 'nodns' is set it means that 'address' was an IP address.
- If 'passive' is set it means that the address is destined for
- listening and not for connecting.
-
- If no port was given in 'address', we set 'default_port' as the
- port.
-*/
-struct evutil_addrinfo *
-resolve_address_port(const char *address, int nodns, int passive,
- const char *default_port)
-{
- struct evutil_addrinfo *ai = NULL;
- struct evutil_addrinfo ai_hints;
- int ai_res, ai_errno;
- char *a = xstrdup(address), *cp;
- const char *portstr;
-
- if ((cp = strchr(a, ':'))) {
- portstr = cp+1;
- *cp = '\0';
- } else if (default_port) {
- portstr = default_port;
- } else {
- log_debug("error in address %s: port required", address);
- free(a);
- return NULL;
- }
-
- memset(&ai_hints, 0, sizeof(ai_hints));
- ai_hints.ai_family = AF_UNSPEC;
- ai_hints.ai_socktype = SOCK_STREAM;
- ai_hints.ai_flags = EVUTIL_AI_ADDRCONFIG | EVUTIL_AI_NUMERICSERV;
- if (passive)
- ai_hints.ai_flags |= EVUTIL_AI_PASSIVE;
- if (nodns)
- ai_hints.ai_flags |= EVUTIL_AI_NUMERICHOST;
-
- ai_res = evutil_getaddrinfo(a, portstr, &ai_hints, &ai);
- ai_errno = errno;
-
- free(a);
-
- if (ai_res) {
- if (ai_res == EVUTIL_EAI_SYSTEM)
- log_warn("error resolving %s: %s [%s]",
- address, evutil_gai_strerror(ai_res), strerror(ai_errno));
- else
- log_warn("error resolving %s: %s", address, evutil_gai_strerror(ai_res));
-
- if (ai) {
- evutil_freeaddrinfo(ai);
- ai = NULL;
- }
- } else if (ai == NULL) {
- log_warn("address resolution failed for %s", address);
- }
-
- return ai;
-}
-
-char *
-printable_address(struct sockaddr *addr, socklen_t addrlen)
-{
- char apbuf[INET6_ADDRSTRLEN + 8]; /* []:65535 is 8 characters */
-
- switch (addr->sa_family) {
-#ifndef _WIN32 /* Windows XP doesn't have inet_ntop. Fix later. */
- case AF_INET: {
- char abuf[INET6_ADDRSTRLEN];
- struct sockaddr_in *sin = (struct sockaddr_in*)addr;
- log_assert(addrlen >= sizeof(struct sockaddr_in));
- if (!inet_ntop(AF_INET, &sin->sin_addr, abuf, INET6_ADDRSTRLEN))
- break;
- xsnprintf(apbuf, sizeof apbuf, "%s:%d", abuf, ntohs(sin->sin_port));
- return xstrdup(apbuf);
- }
-
- case AF_INET6: {
- char abuf[INET6_ADDRSTRLEN];
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
- log_assert(addrlen >= sizeof(struct sockaddr_in6));
- if (!inet_ntop(AF_INET, &sin6->sin6_addr, abuf, INET6_ADDRSTRLEN))
- break;
- xsnprintf(apbuf, sizeof apbuf, "[%s]:%d", abuf, ntohs(sin6->sin6_port));
- return xstrdup(apbuf);
- }
-#endif
-
-#ifdef AF_LOCAL
- case AF_LOCAL:
- return xstrdup(((struct sockaddr_un*)addr)->sun_path);
-#endif
- default:
- break;
- }
-
- xsnprintf(apbuf, sizeof apbuf, "<addr family %d>", addr->sa_family);
- return xstrdup(apbuf);
-}
-
-static struct evdns_base *the_evdns_base = NULL;
-
-struct evdns_base *
-get_evdns_base(void)
-{
- return the_evdns_base;
-}
-
-int
-init_evdns_base(struct event_base *base)
-{
- the_evdns_base = evdns_base_new(base, 1);
- return the_evdns_base == NULL ? -1 : 0;
-}
-
/************************ String Functions *************************/
/** Many of the functions in this section were carbon copied off tor.
Thank you tor! */
More information about the tor-commits
mailing list