Commit aae034d1 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Write a bunch of module documentation.

This commit adds or improves the module-level documenation for:

  buffers.c circuitstats.c command.c connection_edge.c control.c
  cpuworker.c crypto_curve25519.c crypto_curve25519.h
  crypto_ed25519.c crypto_format.c dircollate.c dirserv.c dns.c
  dns_structs.h fp_pair.c geoip.c hibernate.c keypin.c ntmain.c
  onion.c onion_fast.c onion_ntor.c onion_tap.c periodic.c
  protover.c protover.h reasons.c rephist.c replaycache.c
  routerlist.c routerparse.c routerset.c statefile.c status.c
  tor_main.c workqueue.c

In particular, I've tried to explain (for each documented module)
what each module does, what's in it, what the big idea is, why it
belongs in Tor, and who calls it.  In a few cases, I've added TODO
notes about refactoring opportunities.

I've also renamed an argument, and fixed a few DOCDOC comments.
parent 55c468c5
......@@ -5,6 +5,14 @@
* \file crypto_curve25519.c
* \brief Wrapper code for a curve25519 implementation.
* Curve25519 is an Elliptic-Curve Diffie Hellman handshake, designed by
* Dan Bernstein. For more information, see
* Tor uses Curve25519 as the basis of its "ntor" circuit extension
* handshake, and in related code. The functions in this module are
* used to find the most suitable available Curve25519 implementation,
* to provide wrappers around it, and so on.
......@@ -39,15 +47,23 @@ int curve25519_donna(uint8_t *mypublic,
static void pick_curve25519_basepoint_impl(void);
/** This is set to 1 if we have an optimized Ed25519-based
* implementation for multiplying a value by the basepoint; to 0 if we
* don't, and to -1 if we haven't checked. */
static int curve25519_use_ed = -1;
* Helper function: call the most appropriate backend to compute the
* scalar "secret" times the point "point". Store the result in
* "output". Return 0 on success, negative on failure.
curve25519_impl(uint8_t *output, const uint8_t *secret,
const uint8_t *basepoint)
const uint8_t *point)
uint8_t bp[CURVE25519_PUBKEY_LEN];
int r;
memcpy(bp, basepoint, CURVE25519_PUBKEY_LEN);
memcpy(bp, point, CURVE25519_PUBKEY_LEN);
/* Clear the high bit, in case our backend foolishly looks at it. */
bp[31] &= 0x7f;
#ifdef USE_CURVE25519_DONNA
......@@ -61,6 +77,11 @@ curve25519_impl(uint8_t *output, const uint8_t *secret,
return r;
* Helper function: Multiply the scalar "secret" by the Curve25519
* basepoint (X=9), and store the result in "output". Return 0 on
* success, -1 on false.
curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret)
......@@ -85,6 +106,10 @@ curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret)
return r;
* Override the decision of whether to use the Ed25519-based basepoint
* multiply function. Used for testing.
curve25519_set_impl_params(int use_ed)
......@@ -142,6 +167,10 @@ curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
return 0;
* Given a secret key in <b>seckey</b>, create the corresponding public
* key in <b>key_out</b>.
curve25519_public_key_generate(curve25519_public_key_t *key_out,
const curve25519_secret_key_t *seckey)
......@@ -149,6 +178,11 @@ curve25519_public_key_generate(curve25519_public_key_t *key_out,
curve25519_basepoint_impl(key_out->public_key, seckey->secret_key);
* Construct a new keypair in *<b>keypair_out</b>. If <b>extra_strong</b>
* is true, this key is possibly going to get used more than once, so
* use a better-than-usual RNG. Return 0 on success, -1 on failure. */
curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
int extra_strong)
......@@ -159,7 +193,13 @@ curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
return 0;
/* DOCDOC */
/** Store the keypair <b>keypair</b>, including its secret and public
* parts, to the file <b>fname</b>. Use the string tag <b>tag</b> to
* distinguish this from other Curve25519 keypairs. Return 0 on success,
* -1 on failure.
* See crypto_write_tagged_contents_to_file() for more information on
* the metaformat used for these keys.*/
curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
const char *fname,
......@@ -182,7 +222,10 @@ curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
return r;
/* DOCDOC */
/** Read a curve25519 keypair from a file named <b>fname</b> created by
* curve25519_keypair_write_to_file(). Store the keypair in
* <b>keypair_out</b>, and the associated tag string in <b>tag_out</b>.
* Return 0 on success, and -1 on failure. */
curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
char **tag_out,
......@@ -197,6 +240,7 @@ curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
if (len != sizeof(content))
goto end;
/* Make sure that the public key matches the secret key */
memcpy(keypair_out->seckey.secret_key, content, CURVE25519_SECKEY_LEN);
curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey);
if (tor_memneq(keypair_out->pubkey.public_key,
......@@ -14,12 +14,20 @@
/** Length of the result of a curve25519 handshake. */
#define CURVE25519_OUTPUT_LEN 32
/** Wrapper type for a curve25519 public key */
/** Wrapper type for a curve25519 public key.
* (We define a separate type for these to make it less likely that we'll
* mistake them for secret keys.)
* */
typedef struct curve25519_public_key_t {
uint8_t public_key[CURVE25519_PUBKEY_LEN];
} curve25519_public_key_t;
/** Wrapper type for a curve25519 secret key */
/** Wrapper type for a curve25519 secret key
* (We define a separate type for these to make it less likely that we'll
* mistake them for public keys.)
typedef struct curve25519_secret_key_t {
uint8_t secret_key[CURVE25519_SECKEY_LEN];
} curve25519_secret_key_t;
......@@ -5,6 +5,14 @@
* \file crypto_ed25519.c
* \brief Wrapper code for an ed25519 implementation.
* Ed25519 is a Schnorr signature on a Twisted Edwards curve, defined
* by Dan Bernstein. For more information, see
* This module wraps our choice of Ed25519 backend, and provides a few
* convenience functions for checking and generating signatures. It also
* provides Tor-specific tools for key blinding and for converting Ed25519
* keys to and from the corresponding Curve25519 keys.
#include "orconfig.h"
......@@ -28,7 +36,7 @@
static void pick_ed25519_impl(void);
static int ed25519_impl_spot_check(void);
/** An Ed25519 implementation */
/** An Ed25519 implementation, as a set of function pointers. */
typedef struct {
int (*selftest)(void);
......@@ -53,6 +61,8 @@ typedef struct {
} ed25519_impl_t;
/** The Ref10 Ed25519 implementation. This one is pure C and lightly
* optimized. */
static const ed25519_impl_t impl_ref10 = {
......@@ -71,6 +81,8 @@ static const ed25519_impl_t impl_ref10 = {
/** The Ref10 Ed25519 implementation. This one is heavily optimized, but still
* mostly C. The C still tends to be heavily platform-specific. */
static const ed25519_impl_t impl_donna = {
......@@ -89,8 +101,15 @@ static const ed25519_impl_t impl_donna = {
/** Which Ed25519 implementation are we using? NULL if we haven't decided
* yet. */
static const ed25519_impl_t *ed25519_impl = NULL;
/** Helper: Return our chosen Ed25519 implementation.
* This should only be called after we've picked an implementation, but
* it _does_ recover if you forget this.
static inline const ed25519_impl_t *
......@@ -101,7 +120,12 @@ get_ed_impl(void)
/** For testing: used to remember our actual choice of Ed25519
* implementation */
static const ed25519_impl_t *saved_ed25519_impl = NULL;
/** For testing: Use the Ed25519 implementation called <b>name</b> until
* crypto_ed25519_testing_restore_impl is called. Recognized names are
* "donna" and "ref10". */
crypto_ed25519_testing_force_impl(const char *name)
......@@ -114,6 +138,9 @@ crypto_ed25519_testing_force_impl(const char *name)
ed25519_impl = &impl_ref10;
/** For testing: go back to whatever Ed25519 implementation we had picked
* before crypto_ed25519_testing_force_impl was called.
......@@ -123,6 +123,10 @@ crypto_read_tagged_contents_from_file(const char *fname,
return r;
/** Encode <b>pkey</b> as a base64-encoded string, without trailing "="
* characters, in the buffer <b>output</b>, which must have at least
* CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on
* failure. */
curve25519_public_to_base64(char *output,
const curve25519_public_key_t *pkey)
......@@ -135,6 +139,9 @@ curve25519_public_to_base64(char *output,
return 0;
/** Try to decode a base64-encoded curve25519 public key from <b>input</b>
* into the object at <b>pkey</b>. Return 0 on success, -1 on failure.
* Accepts keys with or without a trailing "=". */
curve25519_public_from_base64(curve25519_public_key_t *pkey,
const char *input)
......@@ -6,6 +6,20 @@
* \brief Implements worker threads, queues of work for them, and mechanisms
* for them to send answers back to the main thread.
* The main structure here is a threadpool_t : it manages a set of worker
* threads, a queue of pending work, and a reply queue. Every piece of work
* is a workqueue_entry_t, containing data to process and a function to
* process it with.
* The main thread informs the worker threads of pending work by using a
* condition variable. The workers inform the main process of completed work
* by using an alert_sockets_t object, as implemented in compat_threads.c.
* The main thread can also queue an "update" that will be handled by all the
* workers. This is useful for updating state that all the workers share.
* In Tor today, there is currently only one thread pool, used in cpuworker.c.
#include "orconfig.h"
......@@ -6,10 +6,22 @@
* \file buffers.c
* \brief Implements a generic interface buffer. Buffers are
* fairly opaque string holders that can read to or flush from:
* memory, file descriptors, or TLS connections. Buffers are implemented
* as linked lists of memory chunks.
* \brief Implements a generic buffer interface.
* A buf_t is a (fairly) opaque byte-oriented FIFO that can read to or flush
* from memory, sockets, file descriptors, TLS connections, or another buf_t.
* Buffers are implemented as linked lists of memory chunks.
* All socket-backed and TLS-based connection_t objects have a pair of
* buffers: one for incoming data, and one for outcoming data. These are fed
* and drained from functions in connection.c, trigged by events that are
* monitored in main.c.
* This module has basic support for reading and writing on buf_t objects. It
* also contains specialized functions for handling particular protocols
* on a buf_t backend, including SOCKS (used in connection_edge.c), Tor cells
* (used in connection_or.c and channeltls.c), HTTP (used in directory.c), and
* line-oriented communication (used in control.c).
#include "or.h"
......@@ -9,6 +9,18 @@
* \brief Maintains and analyzes statistics about circuit built times, so we
* can tell how long we may need to wait for a fast circuit to be constructed.
* By keeping these statistics, a client learns when it should time out a slow
* circuit for being too slow, and when it should keep a circuit open in order
* to wait for it to complete.
* The information here is kept in a circuit_built_times_t structure, which is
* currently a singleton, but doesn't need to be. It's updated by calls to
* circuit_build_times_count_timeout() from circuituse.c,
* circuit_build_times_count_close() from circuituse.c, and
* circuit_build_times_add_time() from circuitbuild.c, and inspected by other
* calls into this module, mostly from circuitlist.c. Observations are
* persisted to disk via the or_state_t-related calls.
......@@ -329,7 +341,6 @@ circuit_build_times_min_timeout(void)
"circuit_build_times_min_timeout() called, cbtmintimeout is %d",
return num;
......@@ -7,6 +7,26 @@
* \file command.c
* \brief Functions for processing incoming cells.
* When we receive a cell from a client or a relay, it arrives on some
* channel, and tells us what to do with it. In this module, we dispatch based
* on the cell type using the functions command_process_cell() and
* command_process_var_cell(), and deal with the cell accordingly. (These
* handlers are installed on a channel with the command_setup_channel()
* function.)
* Channels have a chance to handle some cell types on their own before they
* are ever passed here --- typically, they do this for cells that are
* specific to a given channel type. For example, in channeltls.c, the cells
* for the initial connection handshake are handled before we get here. (Of
* course, the fact that there _is_ only one channel type for now means that
* we may have gotten the factoring wrong here.)
* Handling other cell types is mainly farmed off to other modules, after
* initial sanity-checking. CREATE* cells are handled ultimately in onion.c,
* CREATED* cells trigger circuit creation in circuitbuild.c, DESTROY cells
* are handled here (since they're simple), and RELAY cells, in all their
* complexity, are passed off to relay.c.
/* In-points to command.c:
......@@ -7,6 +7,51 @@
* \file connection_edge.c
* \brief Handle edge streams.
* An edge_connection_t is a subtype of a connection_t, and represents two
* critical concepts in Tor: a stream, and an edge connection. From the Tor
* protocol's point of view, a stream is a bi-directional channel that is
* multiplexed on a single circuit. Each stream on a circuit is identified
* with a separate 16-bit stream ID, local to the (circuit,exit) pair.
* Streams are created in response to client requests.
* An edge connection is one thing that can implement a stream: it is either a
* TCP application socket that has arrived via (e.g.) a SOCKS request, or an
* exit connection.
* Not every instance of edge_connection_t truly represents an edge connction,
* however. (Sorry!) We also create edge_connection_t objects for streams that
* we will not be handling with TCP. The types of these streams are:
* <ul>
* <li>DNS lookup streams, created on the client side in response to
* a UDP DNS request received on a DNSPort, or a RESOLVE command
* on a controller.
* <li>DNS lookup streams, created on the exit side in response to
* a RELAY_RESOLVE cell from a client.
* <li>Tunneled directory streams, created on the directory cache side
* in response to a RELAY_BEGINDIR cell. These streams attach directly
* to a dir_connection_t object without ever using TCP.
* </ul>
* This module handles general-purpose functionality having to do with
* edge_connection_t. On the client side, it accepts various types of
* application requests on SocksPorts, TransPorts, and NATDPorts, and
* creates streams appropriately.
* This module is also responsible for implementing stream isolation:
* ensuring that streams that should not be linkable to one another are
* kept to different circuits.
* On the exit side, this module handles the various stream-creating
* type of RELAY cells by launching appropriate outgoing connections,
* DNS requests, or directory connection objects.
* And for all edge connections, this module is responsible for handling
* incoming and outdoing data as it arrives or leaves in the relay.c
* module. (Outgoing data will be packaged in
* connection_edge_process_inbuf() as it calls
* connection_edge_package_raw_inbuf(); incoming data from RELAY_DATA
* cells is applied in connection_edge_process_relay_cell().)
......@@ -5,7 +5,31 @@
* \file control.c
* \brief Implementation for Tor's control-socket interface.
* See doc/spec/control-spec.txt for full details on protocol.
* A "controller" is an external program that monitors and controls a Tor
* instance via a text-based protocol. It connects to Tor via a connection
* to a local socket.
* The protocol is line-driven. The controller sends commands terminated by a
* CRLF. Tor sends lines that are either <em>replies</em> to what the
* controller has said, or <em>events</em> that Tor sends to the controller
* asynchronously based on occurrences in the Tor network model.
* See the control-spec.txt file in the torspec.git repository for full
* details on protocol.
* This module generally has two kinds of entry points: those based on having
* received a command on a controller socket, which are handled in
* connection_control_process_inbuf(), and dispatched to individual functions
* with names like control_handle_COMMANDNAME(); and those based on events
* that occur elsewhere in Tor, which are handled by functions with names like
* control_event_EVENTTYPE().
* Controller events are not sent immediately; rather, they are inserted into
* the queued_control_events array, and flushed later from
* flush_queued_events_cb(). Doing this simplifies our callgraph greatly,
* by limiting the number of places in Tor that can call back into the network
* stack.
......@@ -8,7 +8,11 @@
* \brief Uses the workqueue/threadpool code to farm CPU-intensive activities
* out to subprocesses.
* Right now, we only use this for processing onionskins.
* The multithreading backend for this module is in workqueue.c; this module
* specializes workqueue.c.
* Right now, we only use this for processing onionskins, and invoke it mostly
* from onion.c.
#include "or.h"
#include "channel.h"
......@@ -8,6 +8,17 @@
* \brief Collation code for figuring out which identities to vote for in
* the directory voting process.
* During the consensus calculation, when an authority is looking at the vote
* documents from all the authorities, it needs to compute the consensus for
* each relay listed by at least one authority. But the notion of "each
* relay" can be tricky: some relays have Ed25519 keys, and others don't.
* Moreover, older consensus methods did RSA-based ID collation alone, and
* ignored Ed25519 keys. We need to support those too until we're completely
* sure that authorities will never downgrade.
* This module is invoked exclusively from dirvote.c.
......@@ -21,6 +32,9 @@ static void dircollator_collate_by_ed25519(dircollator_t *dc);
* RSA SHA1 digest) to an array of vote_routerstatus_t. */
typedef struct ddmap_entry_s {
HT_ENTRY(ddmap_entry_s) node;
/** A SHA1-RSA1024 identity digest and Ed25519 identity key,
* concatenated. (If there is no ed25519 identity key, there is no
* entry in this table.) */
uint8_t d[DIGEST_LEN + DIGEST256_LEN];
/* The nth member of this array corresponds to the vote_routerstatus_t (if
* any) received for this digest pair from the nth voter. */
......@@ -43,12 +57,16 @@ ddmap_entry_new(int n_votes)
sizeof(vote_routerstatus_t *) * n_votes);
/** Helper: compute a hash of a single ddmap_entry_t's identity (or
* identities) */
static unsigned
ddmap_entry_hash(const ddmap_entry_t *ent)
return (unsigned) siphash24g(ent->d, sizeof(ent->d));
/** Helper: return true if <b>a</b> and <b>b</b> have the same
* identity/identities. */
static unsigned
ddmap_entry_eq(const ddmap_entry_t *a, const ddmap_entry_t *b)
......@@ -56,7 +74,7 @@ ddmap_entry_eq(const ddmap_entry_t *a, const ddmap_entry_t *b)
/** Record the RSA identity of <b>ent</b> as <b>rsa_sha1</b>, and the
* ed25519 identity as <b>ed25519</b>. */
* ed25519 identity as <b>ed25519</b>. Both must be provided. */
static void
ddmap_entry_set_digests(ddmap_entry_t *ent,
const uint8_t *rsa_sha1,
......@@ -72,8 +90,12 @@ HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash,
ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_)
/** Helper: add a single vote_routerstatus_t <b>vrs</b> to the collator
* <b>dc</b>, indexing it by its RSA key digest, and by the 2-tuple of
* its RSA key digest and Ed25519 key. */
* <b>dc</b>, indexing it by its RSA key digest, and by the 2-tuple of its RSA
* key digest and Ed25519 key. It must come from the <b>vote_num</b>th
* vote.
* Requires that the vote is well-formed -- that is, that it has no duplicate
* routerstatus entries. We already checked for that when parsing the vote. */
static void
dircollator_add_routerstatus(dircollator_t *dc,
int vote_num,
......@@ -82,9 +104,12 @@ dircollator_add_routerstatus(dircollator_t *dc,
const char *id = vrs->status.identity_digest;
/* Clear this flag; we might set it later during the voting process */
vrs->ed25519_reflects_consensus = 0;
(void) vote;
(void) vote; // We don't currently need this.
/* First, add this item to the appropriate RSA-SHA-Id array. */
vote_routerstatus_t **vrs_lst = digestmap_get(dc->by_rsa_sha1, id);
if (NULL == vrs_lst) {
vrs_lst = tor_calloc(dc->n_votes, sizeof(vote_routerstatus_t *));
......@@ -98,6 +123,7 @@ dircollator_add_routerstatus(dircollator_t *dc,
if (! vrs->has_ed25519_listing)
/* Now add it to the appropriate <Ed,RSA-SHA-Id> array. */
ddmap_entry_t search, *found;
memset(&search, 0, sizeof(search));
ddmap_entry_set_digests(&search, (const uint8_t *)id, ed);
......@@ -36,6 +36,24 @@
* \file dirserv.c
* \brief Directory server core implementation. Manages directory
* contents and generates directories.
* This module implements most of directory cache functionality, and some of
* the directory authority functionality. The directory.c module delegates
* here in order to handle incoming requests from clients, via
* connection_dirserv_flushed_some() and its kin. In order to save RAM, this
* module is reponsible for spooling directory objects (in whole or in part)
* onto buf_t instances, and then closing the dir_connection_t once the
* objects are totally flushed.
* The directory.c module also delegates here for handling descriptor uploads
* via dirserv_add_multiple_descriptors().
* Additionally, this module handles some aspects of voting, including:
* deciding how to vote on individual flags (based on decisions reached in
* rephist.c), of formatting routerstatus lines, and deciding what relays to
* include in an authority's vote. (TODO: Those functions could profitably be
* split off. They only live in this file because historically they were
* shared among the v1, v2, and v3 directory code.)
/** How far in the future do we allow a router to get? (seconds) */
......@@ -9,6 +9,42 @@
* This is implemented as a wrapper around Adam Langley's eventdns.c code.
* (We can't just use gethostbyname() and friends because we really need to
* be nonblocking.)
* There are three main cases when a Tor relay uses dns.c to launch a DNS
* request:
* <ol>
* <li>To check whether the DNS server is working more or less correctly.
* This happens via dns_launch_correctness_checks(). The answer is
* reported in the return value from later calls to
* dns_seems_to_be_broken().
* <li>When a client has asked the relay, in a RELAY_BEGIN cell, to connect
* to a given server by hostname. This happens via dns_resolve().
* <li>When a client has asked the rela, in a RELAY_RESOLVE cell, to look
* up a given server's IP address(es) by hostname. This also happens via
* dns_resolve().
* </ol>
* Each of these gets handled a little differently.
* To check for correctness, we look up some hostname we expect to exist and
* have real entries, some hostnames which we expect to definitely not exist,
* and some hostnames that we expect to probably not exist. If too many of
* the hostnames that shouldn't exist do exist, that's a DNS hijacking
* attempt. If too many of the hostnames that should exist have the same
* addresses as the ones that shouldn't exist, that's a very bad DNS hijacking
* attempt, or a very naughty captive portal. And if the hostnames that
* should exist simply don't exist, we probably have a broken nameserver.
* To handle client requests, we first check our cache for answers. If there
* isn't something up-to-date, we've got to launch A or AAAA requests as
* appropriate. How we handle responses to those in particular is a bit
* complex; see dns_lookup() and set_exitconn_info_from_resolve().
* When a lookup is finally complete, the inform_pending_connections()
* function will tell all of the streams that have been waiting for the
* resolve, by calling connection_exit_connect() if the client sent a
* RELAY_BEGIN cell, and by calling send_resolved_cell() or
* send_hostname_cell() if the client sent a RELAY_RESOLVE cell.
......@@ -793,8 +829,14 @@ dns_resolve_impl,(edge_connection_t *exitconn, int is_resolve,
/** Given an exit connection <b>exitconn</b>, and a cached_resolve_t
* <b>resolve</b> whose DNS lookups have all succeeded or failed, update the
* appropriate fields (address_ttl and addr) of <b>exitconn</b>.
* <b>resolve</b> whose DNS lookups have all either succeeded or failed,
* update the appropriate fields (address_ttl and addr) of <b>exitconn</b>.
* The logic can be complicated here, since we might have launched both
* an A lookup and an AAAA lookup, and since either of those might have
* succeeded or failed, and since we want to answer a RESOLVE cell with
* a full answer but answer a BEGIN cell with whatever answer the client
* would accept <i>and</i> we could still connect to.
* If this is a reverse lookup, set *<b>hostname_out</b> to a newly allocated
* copy of the name resulting hostname.
......@@ -1137,7 +1179,12 @@ dns_found_answer(const char *address, uint8_t query_type,
/** Given a pending cached_resolve_t that we just finished resolving,
* inform every connection that was waiting for the outcome of that
* resolution. */
* resolution.
* Do this by sending a RELAY_RESOLVED cell (if the pending stream had sent us
* RELAY_RESOLVE cell), or by launching an exit connection (if the pending
* stream had send us a RELAY_BEGIN cell).
static void
inform_pending_connections(cached_resolve_t *resolve)
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
* \file dns_structs.h