commit 949aa9547d89d4b2d463a0460941a0cc35cec56d Author: Zack Weinberg zackw@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! */
tor-commits@lists.torproject.org