mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 05:03:43 +01:00
Merge remote-tracking branch 'asn-github/adaptive_padding-final'
This commit is contained in:
commit
b169c8c14f
@ -1021,6 +1021,26 @@ The following options are useful only for clients (that is, if
|
||||
The .exit address notation, if enabled via MapAddress, overrides
|
||||
this option.
|
||||
|
||||
[[MiddleNodes]] **MiddleNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints and country codes of nodes
|
||||
to use for "middle" hops in your normal circuits.
|
||||
Normal circuits include all circuits except for direct connections
|
||||
to directory servers. Middle hops are all hops other than exit and entry. +
|
||||
+
|
||||
This is an **experimental** feature that is meant to be used by researchers
|
||||
and developers to test new features in the Tor network safely. Using it
|
||||
without care will strongly influence your anonymity. This feature might get
|
||||
removed in the future.
|
||||
+
|
||||
The HSLayer2Node and HSLayer3Node options override this option for onion
|
||||
service circuits, if they are set. The vanguards addon will read this
|
||||
option, and if set, it will set HSLayer2Nodes and HSLayer3Nodes to nodes
|
||||
from this set.
|
||||
+
|
||||
The ExcludeNodes option overrides this option: any node listed in both
|
||||
MiddleNodes and ExcludeNodes is treated as excluded. See
|
||||
the **ExcludeNodes** option for more information on how to specify nodes.
|
||||
|
||||
[[EntryNodes]] **EntryNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints and country codes of nodes
|
||||
to use for the first hop in your normal circuits.
|
||||
@ -1037,13 +1057,14 @@ The following options are useful only for clients (that is, if
|
||||
If StrictNodes is set to 1, Tor will treat solely the ExcludeNodes option
|
||||
as a requirement to follow for all the circuits you generate, even if
|
||||
doing so will break functionality for you (StrictNodes applies to neither
|
||||
ExcludeExitNodes nor to ExitNodes). If StrictNodes is set to 0, Tor will
|
||||
still try to avoid nodes in the ExcludeNodes list, but it will err on the
|
||||
side of avoiding unexpected errors. Specifically, StrictNodes 0 tells Tor
|
||||
that it is okay to use an excluded node when it is *necessary* to perform
|
||||
relay reachability self-tests, connect to a hidden service, provide a
|
||||
hidden service to a client, fulfill a .exit request, upload directory
|
||||
information, or download directory information. (Default: 0)
|
||||
ExcludeExitNodes nor to ExitNodes, nor to MiddleNodes). If StrictNodes
|
||||
is set to 0, Tor will still try to avoid nodes in the ExcludeNodes list,
|
||||
but it will err on the side of avoiding unexpected errors.
|
||||
Specifically, StrictNodes 0 tells Tor that it is okay to use an excluded
|
||||
node when it is *necessary* to perform relay reachability self-tests,
|
||||
connect to a hidden service, provide a hidden service to a client,
|
||||
fulfill a .exit request, upload directory information, or download
|
||||
directory information. (Default: 0)
|
||||
|
||||
[[FascistFirewall]] **FascistFirewall** **0**|**1**::
|
||||
If 1, Tor will only create outgoing connections to ORs running on ports
|
||||
|
@ -421,6 +421,10 @@ static config_var_t option_vars_[] = {
|
||||
V(ExcludeExitNodes, ROUTERSET, NULL),
|
||||
OBSOLETE("ExcludeSingleHopRelays"),
|
||||
V(ExitNodes, ROUTERSET, NULL),
|
||||
/* Researchers need a way to tell their clients to use specific
|
||||
* middles that they also control, to allow safe live-network
|
||||
* experimentation with new padding machines. */
|
||||
V(MiddleNodes, ROUTERSET, NULL),
|
||||
V(ExitPolicy, LINELIST, NULL),
|
||||
V(ExitPolicyRejectPrivate, BOOL, "1"),
|
||||
V(ExitPolicyRejectLocalInterfaces, BOOL, "0"),
|
||||
@ -1693,6 +1697,7 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out)
|
||||
int routerset_usage =
|
||||
routerset_needs_geoip(options->EntryNodes) ||
|
||||
routerset_needs_geoip(options->ExitNodes) ||
|
||||
routerset_needs_geoip(options->MiddleNodes) ||
|
||||
routerset_needs_geoip(options->ExcludeExitNodes) ||
|
||||
routerset_needs_geoip(options->ExcludeNodes) ||
|
||||
routerset_needs_geoip(options->HSLayer2Nodes) ||
|
||||
@ -2132,6 +2137,7 @@ options_act(const or_options_t *old_options)
|
||||
options->HSLayer2Nodes) ||
|
||||
!routerset_equal(old_options->HSLayer3Nodes,
|
||||
options->HSLayer3Nodes) ||
|
||||
!routerset_equal(old_options->MiddleNodes, options->MiddleNodes) ||
|
||||
options->StrictNodes != old_options->StrictNodes) {
|
||||
log_info(LD_CIRC,
|
||||
"Changed to using entry guards or bridges, or changed "
|
||||
|
@ -72,6 +72,9 @@ struct or_options_t {
|
||||
routerset_t *ExitNodes; /**< Structure containing nicknames, digests,
|
||||
* country codes and IP address patterns of ORs to
|
||||
* consider as exits. */
|
||||
routerset_t *MiddleNodes; /**< Structure containing nicknames, digests,
|
||||
* country codes and IP address patterns of ORs to
|
||||
* consider as middles. */
|
||||
routerset_t *EntryNodes;/**< Structure containing nicknames, digests,
|
||||
* country codes and IP address patterns of ORs to
|
||||
* consider as entry points. */
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "core/mainloop/netstatus.h"
|
||||
#include "core/or/channel.h"
|
||||
#include "core/or/channelpadding.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "core/or/channeltls.h"
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuitmux_ewma.h"
|
||||
@ -645,9 +646,13 @@ tor_init(int argc, char *argv[])
|
||||
/* The options are now initialised */
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
/* Initialize channelpadding parameters to defaults until we get
|
||||
* a consensus */
|
||||
/* Initialize channelpadding and circpad parameters to defaults
|
||||
* until we get a consensus */
|
||||
channelpadding_new_consensus_params(NULL);
|
||||
circpad_new_consensus_params(NULL);
|
||||
|
||||
/* Initialize circuit padding to defaults+torrc until we get a consensus */
|
||||
circpad_machines_init();
|
||||
|
||||
/* Initialize predicted ports list after loading options */
|
||||
predicted_ports_init();
|
||||
@ -766,6 +771,7 @@ tor_free_all(int postfork)
|
||||
dns_free_all();
|
||||
clear_pending_onions();
|
||||
circuit_free_all();
|
||||
circpad_machines_free();
|
||||
entry_guards_free_all();
|
||||
pt_free_all();
|
||||
channel_tls_free_all();
|
||||
|
@ -32,6 +32,7 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/core/or/circuitlist.c \
|
||||
src/core/or/circuitmux.c \
|
||||
src/core/or/circuitmux_ewma.c \
|
||||
src/core/or/circuitpadding.c \
|
||||
src/core/or/circuitstats.c \
|
||||
src/core/or/circuituse.c \
|
||||
src/core/or/command.c \
|
||||
@ -227,6 +228,7 @@ noinst_HEADERS += \
|
||||
src/core/or/circuitmux.h \
|
||||
src/core/or/circuitmux_ewma.h \
|
||||
src/core/or/circuitstats.h \
|
||||
src/core/or/circuitpadding.h \
|
||||
src/core/or/circuituse.h \
|
||||
src/core/or/command.h \
|
||||
src/core/or/connection_edge.h \
|
||||
|
@ -12,6 +12,11 @@
|
||||
#include "core/or/cell_queue_st.h"
|
||||
|
||||
struct hs_token_t;
|
||||
struct circpad_machine_spec_t;
|
||||
struct circpad_machine_state_t;
|
||||
|
||||
/** Number of padding state machines on a circuit. */
|
||||
#define CIRCPAD_MAX_MACHINES (2)
|
||||
|
||||
/** "magic" value for an origin_circuit_t */
|
||||
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
|
||||
@ -177,6 +182,27 @@ struct circuit_t {
|
||||
/** Hashtable node: used to look up the circuit by its HS token using the HS
|
||||
circuitmap. */
|
||||
HT_ENTRY(circuit_t) hs_circuitmap_node;
|
||||
|
||||
/** Adaptive Padding state machines: these are immutable. The state machines
|
||||
* that come from the consensus are saved to a global structure, to avoid
|
||||
* per-circuit allocations. This merely points to the global copy in
|
||||
* origin_padding_machines or relay_padding_machines that should never
|
||||
* change or get deallocated.
|
||||
*
|
||||
* Each element of this array corresponds to a different padding machine,
|
||||
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
|
||||
const struct circpad_machine_spec_t *padding_machine[CIRCPAD_MAX_MACHINES];
|
||||
|
||||
/** Adaptive Padding machine info for above machines. This is the
|
||||
* per-circuit mutable information, such as the current state and
|
||||
* histogram token counts. Some of it is optional (aka NULL).
|
||||
* If a machine is being shut down, these indexes can be NULL
|
||||
* without the corresponding padding_machine being NULL, while we
|
||||
* wait for the other end to respond to our shutdown request.
|
||||
*
|
||||
* Each element of this array corresponds to a different padding machine,
|
||||
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
|
||||
struct circpad_machine_state_t *padding_info[CIRCPAD_MAX_MACHINES];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuitstats.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "core/or/command.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "core/or/connection_or.h"
|
||||
@ -950,12 +951,15 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
|
||||
crypt_path_t *hop = onion_next_hop_in_cpath(circ->cpath);
|
||||
circuit_build_times_handle_completed_hop(circ);
|
||||
|
||||
circpad_machine_event_circ_added_hop(circ);
|
||||
|
||||
if (hop) {
|
||||
/* Case two: we're on a hop after the first. */
|
||||
return circuit_send_intermediate_onion_skin(circ, hop);
|
||||
}
|
||||
|
||||
/* Case three: the circuit is finished. Do housekeeping tasks on it. */
|
||||
circpad_machine_event_circ_built(circ);
|
||||
return circuit_build_no_more_hops(circ);
|
||||
}
|
||||
|
||||
@ -2606,7 +2610,24 @@ choose_good_middle_server(uint8_t purpose,
|
||||
return choice;
|
||||
}
|
||||
|
||||
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
|
||||
if (options->MiddleNodes) {
|
||||
smartlist_t *sl = smartlist_new();
|
||||
routerset_get_all_nodes(sl, options->MiddleNodes,
|
||||
options->ExcludeNodes, 1);
|
||||
|
||||
smartlist_subtract(sl, excluded);
|
||||
|
||||
choice = node_sl_choose_by_bandwidth(sl, WEIGHT_FOR_MID);
|
||||
smartlist_free(sl);
|
||||
if (choice) {
|
||||
log_fn(LOG_INFO, LD_CIRC, "Chose fixed middle node: %s",
|
||||
hex_str(choice->identity, DIGEST_LEN));
|
||||
} else {
|
||||
log_fn(LOG_NOTICE, LD_CIRC, "Restricted middle not available");
|
||||
}
|
||||
} else {
|
||||
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
|
||||
}
|
||||
smartlist_free(excluded);
|
||||
return choice;
|
||||
}
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/or/circuitstats.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "app/config/config.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
@ -1231,6 +1232,9 @@ circuit_free_(circuit_t *circ)
|
||||
CIRCUIT_IS_ORIGIN(circ) ?
|
||||
TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0);
|
||||
|
||||
/* Free any circuit padding structures */
|
||||
circpad_circuit_free_all_machineinfos(circ);
|
||||
|
||||
if (should_free) {
|
||||
memwipe(mem, 0xAA, memlen); /* poison memory */
|
||||
tor_free(mem);
|
||||
|
2562
src/core/or/circuitpadding.c
Normal file
2562
src/core/or/circuitpadding.c
Normal file
File diff suppressed because it is too large
Load Diff
696
src/core/or/circuitpadding.h
Normal file
696
src/core/or/circuitpadding.h
Normal file
@ -0,0 +1,696 @@
|
||||
/*
|
||||
* Copyright (c) 2017, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitpadding.h
|
||||
* \brief Header file for circuitpadding.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITPADDING_H
|
||||
#define TOR_CIRCUITPADDING_H
|
||||
|
||||
#include "src/trunnel/circpad_negotiation.h"
|
||||
#include "lib/evloop/timers.h"
|
||||
|
||||
struct circuit_t;
|
||||
struct origin_circuit_t;
|
||||
struct cell_t;
|
||||
|
||||
/**
|
||||
* Signed error return with the specific property that negative
|
||||
* values mean error codes of various semantics, 0 means success,
|
||||
* and positive values are unused.
|
||||
*
|
||||
* XXX: Tor uses this concept a lot but just calls it int. Should we move
|
||||
* this somewhere centralized? Where?
|
||||
*/
|
||||
typedef int signed_error_t;
|
||||
|
||||
/**
|
||||
* These constants specify the types of events that can cause
|
||||
* transitions between state machine states.
|
||||
*
|
||||
* Note that SENT and RECV are relative to this endpoint. For
|
||||
* relays, SENT means packets destined towards the client and
|
||||
* RECV means packets destined towards the relay. On the client,
|
||||
* SENT means packets destined towards the relay, where as RECV
|
||||
* means packets destined towards the client.
|
||||
*/
|
||||
typedef enum {
|
||||
/* A non-padding cell was received. */
|
||||
CIRCPAD_EVENT_NONPADDING_RECV = 0,
|
||||
/* A non-padding cell was sent. */
|
||||
CIRCPAD_EVENT_NONPADDING_SENT = 1,
|
||||
/* A padding cell (RELAY_COMMAND_DROP) was sent. */
|
||||
CIRCPAD_EVENT_PADDING_SENT = 2,
|
||||
/* A padding cell was received. */
|
||||
CIRCPAD_EVENT_PADDING_RECV = 3,
|
||||
/* We tried to schedule padding but we ended up picking the infinity bin
|
||||
* which means that padding was delayed infinitely */
|
||||
CIRCPAD_EVENT_INFINITY = 4,
|
||||
/* All histogram bins are empty (we are out of tokens) */
|
||||
CIRCPAD_EVENT_BINS_EMPTY = 5,
|
||||
/* just a counter of the events above */
|
||||
CIRCPAD_EVENT_LENGTH_COUNT = 6
|
||||
} circpad_event_t;
|
||||
#define CIRCPAD_NUM_EVENTS ((int)CIRCPAD_EVENT_LENGTH_COUNT+1)
|
||||
|
||||
/** Boolean type that says if we decided to transition states or not */
|
||||
typedef enum {
|
||||
CIRCPAD_STATE_UNCHANGED = 0,
|
||||
CIRCPAD_STATE_CHANGED = 1
|
||||
} circpad_decision_t;
|
||||
|
||||
/** The type for the things in histogram bins (aka tokens) */
|
||||
typedef uint32_t circpad_hist_token_t;
|
||||
|
||||
/** The type for histogram indexes (needs to be negative for errors) */
|
||||
typedef int8_t circpad_hist_index_t;
|
||||
|
||||
/** The type for absolute time, from monotime_absolute_usec() */
|
||||
typedef uint64_t circpad_time_t;
|
||||
|
||||
/** The type for timer delays, in microseconds */
|
||||
typedef uint32_t circpad_delay_t;
|
||||
|
||||
/**
|
||||
* An infinite padding cell delay means don't schedule any padding --
|
||||
* simply wait until a different event triggers a transition.
|
||||
*
|
||||
* This means that the maximum delay we can scedule is UINT32_MAX-1
|
||||
* microseconds, or about 4300 seconds (1.25 hours).
|
||||
* XXX: Is this enough if we want to simulate light, intermittent
|
||||
* activity on an onion service?
|
||||
*/
|
||||
#define CIRCPAD_DELAY_INFINITE (UINT32_MAX)
|
||||
|
||||
/**
|
||||
* Macro to clarify when we're checking the infinity bin.
|
||||
*
|
||||
* Works with either circpad_state_t or circpad_machine_state_t
|
||||
*/
|
||||
#define CIRCPAD_INFINITY_BIN(mi) ((mi)->histogram_len-1)
|
||||
|
||||
/**
|
||||
* These constants form a bitfield that specifies when a state machine
|
||||
* should be applied to a circuit.
|
||||
*
|
||||
* If any of these elements is set, then the circuit will be tested against
|
||||
* that specific condition. If an element is unset, then we don't test it.
|
||||
* (E.g. If neither NO_STREAMS or STREAMS are set, then we will not care
|
||||
* whether a circuit has streams attached when we apply a state machine)
|
||||
*
|
||||
* The helper function circpad_circuit_state() converts circuit state
|
||||
* flags into this more compact representation.
|
||||
*/
|
||||
typedef enum {
|
||||
/* Only apply machine if the circuit is still building */
|
||||
CIRCPAD_CIRC_BUILDING = 1<<0,
|
||||
/* Only apply machine if the circuit is open */
|
||||
CIRCPAD_CIRC_OPENED = 1<<1,
|
||||
/* Only apply machine if the circuit has no attached streams */
|
||||
CIRCPAD_CIRC_NO_STREAMS = 1<<2,
|
||||
/* Only apply machine if the circuit has attached streams */
|
||||
CIRCPAD_CIRC_STREAMS = 1<<3,
|
||||
/* Only apply machine if the circuit still allows RELAY_EARLY cells */
|
||||
CIRCPAD_CIRC_HAS_RELAY_EARLY = 1<<4,
|
||||
/* Only apply machine if the circuit has depleted its RELAY_EARLY cells
|
||||
* allowance. */
|
||||
CIRCPAD_CIRC_HAS_NO_RELAY_EARLY = 1<<5
|
||||
} circpad_circuit_state_t;
|
||||
|
||||
/** Bitmask that says "apply this machine to all states" */
|
||||
#define CIRCPAD_STATE_ALL \
|
||||
(CIRCPAD_CIRC_BUILDING|CIRCPAD_CIRC_OPENED| \
|
||||
CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_NO_STREAMS| \
|
||||
CIRCPAD_CIRC_HAS_RELAY_EARLY|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY)
|
||||
|
||||
/**
|
||||
* A compact circuit purpose bitfield mask that allows us to compactly
|
||||
* specify which circuit purposes a machine should apply to.
|
||||
*
|
||||
* The helper function circpad_circ_purpose_to_mask() converts circuit
|
||||
* purposes into bit positions in this bitmask.
|
||||
*/
|
||||
typedef uint32_t circpad_purpose_mask_t;
|
||||
|
||||
/** Bitmask that says "apply this machine to all purposes". */
|
||||
#define CIRCPAD_PURPOSE_ALL (0xFFFFFFFF)
|
||||
|
||||
/**
|
||||
* This type specifies all of the conditions that must be met before
|
||||
* a client decides to initiate padding on a circuit.
|
||||
*
|
||||
* A circuit must satisfy every sub-field in this type in order
|
||||
* to be considered to match the conditions.
|
||||
*/
|
||||
typedef struct circpad_machine_conditions_t {
|
||||
/** Only apply the machine *if* the circuit has at least this many hops */
|
||||
unsigned min_hops : 3;
|
||||
|
||||
/** Only apply the machine *if* vanguards are enabled */
|
||||
unsigned requires_vanguards : 1;
|
||||
|
||||
/** Only apply the machine *if* the circuit's state matches any of
|
||||
* the bits set in this bitmask. */
|
||||
circpad_circuit_state_t state_mask;
|
||||
|
||||
/** Only apply a machine *if* the circuit's purpose matches one
|
||||
* of the bits set in this bitmask */
|
||||
circpad_purpose_mask_t purpose_mask;
|
||||
|
||||
} circpad_machine_conditions_t;
|
||||
|
||||
/**
|
||||
* Token removal strategy options.
|
||||
*
|
||||
* The WTF-PAD histograms are meant to specify a target distribution to shape
|
||||
* traffic towards. This is accomplished by removing tokens from the histogram
|
||||
* when either padding or non-padding cells are sent.
|
||||
*
|
||||
* When we see a non-padding cell at a particular time since the last cell, you
|
||||
* remove a token from the corresponding delay bin. These flags specify
|
||||
* which bin to choose if that bin is already empty.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Don't remove any tokens */
|
||||
CIRCPAD_TOKEN_REMOVAL_NONE = 0,
|
||||
/**
|
||||
* Remove from the first non-zero higher bin index when current is zero.
|
||||
* This is the recommended strategy from the Adaptive Padding paper. */
|
||||
CIRCPAD_TOKEN_REMOVAL_HIGHER = 1,
|
||||
/** Remove from the first non-zero lower bin index when current is empty. */
|
||||
CIRCPAD_TOKEN_REMOVAL_LOWER = 2,
|
||||
/** Remove from the closest non-zero bin index when current is empty. */
|
||||
CIRCPAD_TOKEN_REMOVAL_CLOSEST = 3,
|
||||
/** Remove from the closest bin by time value (since bins are
|
||||
* exponentially spaced). */
|
||||
CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC = 4,
|
||||
/** Only remove from the exact bin corresponding to this delay. If
|
||||
* the bin is 0, simply do nothing. Don't pick another bin. */
|
||||
CIRCPAD_TOKEN_REMOVAL_EXACT = 5
|
||||
} circpad_removal_t;
|
||||
|
||||
/**
|
||||
* Distribution types supported by circpad_distribution_sample().
|
||||
*
|
||||
* These can be used instead of histograms for the inter-packet
|
||||
* timing distribution, or to specify a distribution on the number
|
||||
* of cells that can be sent while in a specific state of the state
|
||||
* machine. */
|
||||
typedef enum {
|
||||
CIRCPAD_DIST_NONE = 0,
|
||||
CIRCPAD_DIST_UNIFORM = 1,
|
||||
CIRCPAD_DIST_LOGISTIC = 2,
|
||||
CIRCPAD_DIST_LOG_LOGISTIC = 3,
|
||||
CIRCPAD_DIST_GEOMETRIC = 4,
|
||||
CIRCPAD_DIST_WEIBULL = 5,
|
||||
CIRCPAD_DIST_PARETO = 6
|
||||
} circpad_distribution_type_t;
|
||||
|
||||
/**
|
||||
* Distribution information.
|
||||
*
|
||||
* This type specifies a specific distribution above, as well as
|
||||
* up to two parameters for that distribution. The specific
|
||||
* per-distribution meaning of these parameters is specified
|
||||
* in circpad_distribution_sample().
|
||||
*/
|
||||
typedef struct circpad_distribution_t {
|
||||
circpad_distribution_type_t type;
|
||||
double param1;
|
||||
double param2;
|
||||
} circpad_distribution_t;
|
||||
|
||||
/** State number type. Represents current state of state machine. */
|
||||
typedef uint16_t circpad_statenum_t;
|
||||
#define CIRCPAD_STATENUM_MAX (UINT16_MAX)
|
||||
|
||||
/** A histogram is used to sample padding delays given a machine state. This
|
||||
* constant defines the maximum histogram width (i.e. the max number of bins)
|
||||
*
|
||||
* Each histogram bin is twice as large as the previous. Two exceptions: The
|
||||
* first bin has zero width (which means that minimum delay is applied to the
|
||||
* next padding cell), and the last bin (infinity bin) has infinite width
|
||||
* (which means that the next padding cell will be delayed infinitely). */
|
||||
#define CIRCPAD_MAX_HISTOGRAM_LEN (sizeof(circpad_delay_t)*8 + 1)
|
||||
|
||||
/**
|
||||
* A state of a padding state machine. The information here are immutable and
|
||||
* represent the initial form of the state; it does not get updated as things
|
||||
* happen. The mutable information that gets updated in runtime are carried in
|
||||
* a circpad_machine_state_t.
|
||||
*
|
||||
* This struct describes the histograms and parameters of a single
|
||||
* state in the adaptive padding machine. Instances of this struct
|
||||
* exist in global circpad machine definitions that come from torrc
|
||||
* or the consensus.
|
||||
*/
|
||||
typedef struct circpad_state_t {
|
||||
/** If a histogram is used for this state, this specifies the number of bins
|
||||
* of this histogram. Histograms must have at least 2 bins.
|
||||
*
|
||||
* If a delay probability distribution is used for this state, this is set
|
||||
* to 0. */
|
||||
circpad_hist_index_t histogram_len;
|
||||
/** The histogram itself: an array of uint16s of tokens, whose
|
||||
* widths are exponentially spaced, in microseconds */
|
||||
circpad_hist_token_t histogram[CIRCPAD_MAX_HISTOGRAM_LEN];
|
||||
/** Total number of tokens in this histogram. This is a constant and is *not*
|
||||
* decremented every time we spend a token. It's used for initializing and
|
||||
* refilling the histogram. */
|
||||
uint32_t histogram_total_tokens;
|
||||
|
||||
/** Minimum padding delay of this state in microseconds.
|
||||
*
|
||||
* If histograms are used, this is the left (and right) bound of the first
|
||||
* bin (since it has zero width).
|
||||
*
|
||||
* If a delay probability distribution is used, this represents the minimum
|
||||
* delay we can sample from the distribution.
|
||||
*/
|
||||
circpad_delay_t start_usec;
|
||||
|
||||
/** If histograms are used, this is the width of the whole histogram in
|
||||
* microseconds, and it's used to calculate individual bin width.
|
||||
*
|
||||
* If a delay probability distribution is used, this is used as the max
|
||||
* delay we can sample from the distribution.
|
||||
*/
|
||||
circpad_delay_t range_usec;
|
||||
|
||||
/**
|
||||
* Represents a delay probability distribution (aka IAT distribution). It's a
|
||||
* parametrized way of encoding inter-packet delay information in
|
||||
* microseconds. It can be used instead of histograms.
|
||||
*
|
||||
* If it is used, token_removal below must be set to
|
||||
* CIRCPAD_TOKEN_REMOVAL_NONE.
|
||||
*
|
||||
* Start_usec, range_sec, and rtt_estimates are still applied to the
|
||||
* results of sampling from this distribution (range_sec is used as a max).
|
||||
*/
|
||||
circpad_distribution_t iat_dist;
|
||||
|
||||
/**
|
||||
* The length dist is a parameterized way of encoding how long this
|
||||
* state machine runs in terms of sent padding cells or all
|
||||
* sent cells. Values are sampled from this distribution, clamped
|
||||
* to max_len, and then start_len is added to that value.
|
||||
*
|
||||
* It may be specified instead of or in addition to
|
||||
* the infinity bins and bins empty conditions. */
|
||||
circpad_distribution_t length_dist;
|
||||
/** A minimum length value, added to the output of length_dist */
|
||||
uint16_t start_length;
|
||||
/** A cap on the length value that can be sampled from the length_dist */
|
||||
uint64_t max_length;
|
||||
|
||||
/** Should we decrement length when we see a nonpadding packet?
|
||||
* XXX: Are there any machines that actually want to set this to 0? There may
|
||||
* not be. OTOH, it's only a bit.. */
|
||||
unsigned length_includes_nonpadding : 1;
|
||||
|
||||
/**
|
||||
* This is an array that specifies the next state to transition to upon
|
||||
* receipt an event matching the indicated array index.
|
||||
*
|
||||
* This aborts our scheduled packet and switches to the state
|
||||
* corresponding to the index of the array. Tokens are filled upon
|
||||
* this transition.
|
||||
*
|
||||
* States are allowed to transition to themselves, which means re-schedule
|
||||
* a new padding timer. They are also allowed to temporarily "transition"
|
||||
* to the "IGNORE" and "CANCEL" pseudo-states. See #defines below
|
||||
* for details on state behavior and meaning.
|
||||
*/
|
||||
circpad_statenum_t next_state[CIRCPAD_NUM_EVENTS];
|
||||
|
||||
/**
|
||||
* If true, estimate the RTT from this relay to the exit/website and add that
|
||||
* to start_usec for use as the histogram bin 0 start delay.
|
||||
*
|
||||
* Right now this is only supported for relay-side state machines.
|
||||
*/
|
||||
unsigned use_rtt_estimate : 1;
|
||||
|
||||
/** This specifies the token removal strategy to use upon padding and
|
||||
* non-padding activity. */
|
||||
circpad_removal_t token_removal;
|
||||
} circpad_state_t;
|
||||
|
||||
/**
|
||||
* The start state for this machine.
|
||||
*
|
||||
* In the original WTF-PAD, this is only used for transition to/from
|
||||
* the burst state. All other fields are not used. But to simplify the
|
||||
* code we've made it a first-class state. This has no performance
|
||||
* consequences, but may make naive serialization of the state machine
|
||||
* large, if we're not careful about how we represent empty fields.
|
||||
*/
|
||||
#define CIRCPAD_STATE_START 0
|
||||
|
||||
/**
|
||||
* The burst state for this machine.
|
||||
*
|
||||
* In the original Adaptive Padding algorithm and in WTF-PAD
|
||||
* (https://www.freehaven.net/anonbib/cache/ShWa-Timing06.pdf and
|
||||
* https://www.cs.kau.se/pulls/hot/thebasketcase-wtfpad/), the burst
|
||||
* state serves to detect bursts in traffic. This is done by using longer
|
||||
* delays in its histogram, which represent the expected delays between
|
||||
* bursts of packets in the target stream. If this delay expires without a
|
||||
* real packet being sent, the burst state sends a padding packet and then
|
||||
* immediately transitions to the gap state, which is used to generate
|
||||
* a synthetic padding packet train. In this implementation, this transition
|
||||
* needs to be explicitly specified in the burst state's transition events.
|
||||
*
|
||||
* Because of this flexibility, other padding mechanisms can transition
|
||||
* between these two states arbitrarily, to encode other dynamics of
|
||||
* target traffic.
|
||||
*/
|
||||
#define CIRCPAD_STATE_BURST 1
|
||||
|
||||
/**
|
||||
* The gap state for this machine.
|
||||
*
|
||||
* In the original Adaptive Padding algorithm and in WTF-PAD, the gap
|
||||
* state serves to simulate an artificial packet train composed of padding
|
||||
* packets. It does this by specifying much lower inter-packet delays than
|
||||
* the burst state, and transitioning back to itself after padding is sent
|
||||
* if these timers expire before real traffic is sent. If real traffic is
|
||||
* sent, it transitions back to the burst state.
|
||||
*
|
||||
* Again, in this implementation, these transitions must be specified
|
||||
* explicitly, and other transitions are also permitted.
|
||||
*/
|
||||
#define CIRCPAD_STATE_GAP 2
|
||||
|
||||
/**
|
||||
* End is a pseudo-state that causes the machine to go completely
|
||||
* idle, and optionally get torn down (depending on the
|
||||
* value of circpad_machine_spec_t.should_negotiate_end)
|
||||
*
|
||||
* End MUST NOT occupy a slot in the machine state array.
|
||||
*/
|
||||
#define CIRCPAD_STATE_END CIRCPAD_STATENUM_MAX
|
||||
|
||||
/**
|
||||
* "Ignore" is a pseudo-state that means "do not react to this
|
||||
* event".
|
||||
*
|
||||
* "Ignore" MUST NOT occupy a slot in the machine state array.
|
||||
*/
|
||||
#define CIRCPAD_STATE_IGNORE (CIRCPAD_STATENUM_MAX-1)
|
||||
|
||||
/**
|
||||
* "Cancel" is a pseudo-state that means "cancel pending timers,
|
||||
* but remain in your current state".
|
||||
*
|
||||
* Cancel MUST NOT occupy a slot in the machine state array.
|
||||
*/
|
||||
#define CIRCPAD_STATE_CANCEL (CIRCPAD_STATENUM_MAX-2)
|
||||
|
||||
/**
|
||||
* Since we have 3 pseudo-states, the max state array length is
|
||||
* up to one less than cancel's statenum.
|
||||
*/
|
||||
#define CIRCPAD_MAX_MACHINE_STATES (CIRCPAD_STATE_CANCEL-1)
|
||||
|
||||
/**
|
||||
* Mutable padding machine info.
|
||||
*
|
||||
* This structure contains mutable information about a padding
|
||||
* machine. The mutable information must be kept separate because
|
||||
* it exists per-circuit, where as the machines themselves are global.
|
||||
* This separation is done to conserve space in the circuit structure.
|
||||
*
|
||||
* This is the per-circuit state that changes regarding the global state
|
||||
* machine. Some parts of it are optional (ie NULL).
|
||||
*
|
||||
* XXX: Play with layout to minimize space on x64 Linux (most common relay).
|
||||
*/
|
||||
typedef struct circpad_machine_state_t {
|
||||
/** The callback pointer for the padding callbacks.
|
||||
*
|
||||
* These timers stick around the machineinfo until the machineinfo's circuit
|
||||
* is closed, at which point the timer is cancelled. For this reason it's
|
||||
* safe to assume that the machineinfo exists if this timer gets
|
||||
* triggered. */
|
||||
tor_timer_t *padding_timer;
|
||||
|
||||
/** The circuit for this machine */
|
||||
struct circuit_t *on_circ;
|
||||
|
||||
/** A mutable copy of the histogram for the current state.
|
||||
* NULL if remove_tokens is false for that state */
|
||||
circpad_hist_token_t *histogram;
|
||||
/** Length of the above histogram.
|
||||
* XXX: This field *could* be removed at the expense of added
|
||||
* complexity+overhead for reaching back into the immutable machine
|
||||
* state every time we need to inspect the histogram. It's only a byte,
|
||||
* though, so it seemed worth it.
|
||||
*/
|
||||
circpad_hist_index_t histogram_len;
|
||||
/** Remove token from this index upon sending padding */
|
||||
circpad_hist_index_t chosen_bin;
|
||||
|
||||
/** Stop padding/transition if this many cells sent */
|
||||
uint64_t state_length;
|
||||
#define CIRCPAD_STATE_LENGTH_INFINITE UINT64_MAX
|
||||
|
||||
/** A scaled count of padding packets sent, used to limit padding overhead.
|
||||
* When this reaches UINT16_MAX, we cut it and nonpadding_sent in half. */
|
||||
uint16_t padding_sent;
|
||||
/** A scaled count of non-padding packets sent, used to limit padding
|
||||
* overhead. When this reaches UINT16_MAX, we cut it and padding_sent in
|
||||
* half. */
|
||||
uint16_t nonpadding_sent;
|
||||
|
||||
/**
|
||||
* EWMA estimate of the RTT of the circuit from this hop
|
||||
* to the exit end, in microseconds. */
|
||||
circpad_delay_t rtt_estimate_usec;
|
||||
|
||||
/**
|
||||
* The last time we got an event relevant to estimating
|
||||
* the RTT. Monotonic time in microseconds since system
|
||||
* start.
|
||||
*/
|
||||
circpad_time_t last_received_time_usec;
|
||||
|
||||
/**
|
||||
* The time at which we scheduled a non-padding packet,
|
||||
* or selected an infinite delay.
|
||||
*
|
||||
* Monotonic time in microseconds since system start.
|
||||
* This is 0 if we haven't chosen a padding delay.
|
||||
*/
|
||||
circpad_time_t padding_scheduled_at_usec;
|
||||
|
||||
/** What state is this machine in? */
|
||||
circpad_statenum_t current_state;
|
||||
|
||||
/**
|
||||
* True if we have scheduled a timer for padding.
|
||||
*
|
||||
* This is 1 if a timer is pending. It is 0 if
|
||||
* no timer is scheduled. (It can be 0 even when
|
||||
* padding_was_scheduled_at_usec is non-zero).
|
||||
*/
|
||||
unsigned is_padding_timer_scheduled : 1;
|
||||
|
||||
/**
|
||||
* If this is true, we have seen full duplex behavior.
|
||||
* Stop updating the RTT.
|
||||
*/
|
||||
unsigned stop_rtt_update : 1;
|
||||
|
||||
/** Max number of padding machines on each circuit. If changed,
|
||||
* also ensure the machine_index bitwith supports the new size. */
|
||||
#define CIRCPAD_MAX_MACHINES (2)
|
||||
/** Which padding machine index was this for.
|
||||
* (make sure changes to the bitwidth can support the
|
||||
* CIRCPAD_MAX_MACHINES define). */
|
||||
unsigned machine_index : 1;
|
||||
|
||||
} circpad_machine_state_t;
|
||||
|
||||
/** Helper macro to get an actual state machine from a machineinfo */
|
||||
#define CIRCPAD_GET_MACHINE(machineinfo) \
|
||||
((machineinfo)->on_circ->padding_machine[(machineinfo)->machine_index])
|
||||
|
||||
/**
|
||||
* This specifies a particular padding machine to use after negotiation.
|
||||
*
|
||||
* The constants for machine_num_t are in trunnel.
|
||||
* We want to be able to define extra numbers in the consensus/torrc, though.
|
||||
*/
|
||||
typedef uint8_t circpad_machine_num_t;
|
||||
|
||||
/** Global state machine structure from the consensus */
|
||||
typedef struct circpad_machine_spec_t {
|
||||
/** Global machine number */
|
||||
circpad_machine_num_t machine_num;
|
||||
|
||||
/** Which machine index slot should this machine go into in
|
||||
* the array on the circuit_t */
|
||||
unsigned machine_index : 1;
|
||||
|
||||
/** Send a padding negotiate to shut down machine at end state? */
|
||||
unsigned should_negotiate_end : 1;
|
||||
|
||||
// These next three fields are origin machine-only...
|
||||
/** Origin side or relay side */
|
||||
unsigned is_origin_side : 1;
|
||||
|
||||
/** Which hop in the circuit should we send padding to/from?
|
||||
* 1-indexed (ie: hop #1 is guard, #2 middle, #3 exit). */
|
||||
unsigned target_hopnum : 3;
|
||||
|
||||
/** This machine only kills fascists if the following conditions are met. */
|
||||
circpad_machine_conditions_t conditions;
|
||||
|
||||
/** How many padding cells can be sent before we apply overhead limits?
|
||||
* XXX: Note that we can only allow up to 64k of padding cells on an
|
||||
* otherwise quiet circuit. Is this enough? It's 33MB. */
|
||||
uint16_t allowed_padding_count;
|
||||
|
||||
/** Padding percent cap: Stop padding if we exceed this percent overhead.
|
||||
* 0 means no limit. Overhead is defined as percent of total traffic, so
|
||||
* that we can use 0..100 here. This is the same definition as used in
|
||||
* Prop#265. */
|
||||
uint8_t max_padding_percent;
|
||||
|
||||
/** State array: indexed by circpad_statenum_t */
|
||||
circpad_state_t *states;
|
||||
|
||||
/**
|
||||
* Number of states this machine has (ie: length of the states array).
|
||||
* XXX: This field is not needed other than for safety. */
|
||||
circpad_statenum_t num_states;
|
||||
} circpad_machine_spec_t;
|
||||
|
||||
void circpad_new_consensus_params(const networkstatus_t *ns);
|
||||
|
||||
/**
|
||||
* The following are event call-in points that are of interest to
|
||||
* the state machines. They are called during cell processing. */
|
||||
void circpad_deliver_unrecognized_cell_events(struct circuit_t *circ,
|
||||
cell_direction_t dir);
|
||||
void circpad_deliver_sent_relay_cell_events(struct circuit_t *circ,
|
||||
uint8_t relay_command);
|
||||
void circpad_deliver_recognized_relay_cell_events(struct circuit_t *circ,
|
||||
uint8_t relay_command,
|
||||
crypt_path_t *layer_hint);
|
||||
|
||||
/** Cell events are delivered by the above delivery functions */
|
||||
void circpad_cell_event_nonpadding_sent(struct circuit_t *on_circ);
|
||||
void circpad_cell_event_nonpadding_received(struct circuit_t *on_circ);
|
||||
void circpad_cell_event_padding_sent(struct circuit_t *on_circ);
|
||||
void circpad_cell_event_padding_received(struct circuit_t *on_circ);
|
||||
|
||||
/** Internal events are events the machines send to themselves */
|
||||
circpad_decision_t
|
||||
circpad_internal_event_infinity(circpad_machine_state_t *mi);
|
||||
circpad_decision_t
|
||||
circpad_internal_event_bins_empty(circpad_machine_state_t *);
|
||||
circpad_decision_t circpad_internal_event_state_length_up(
|
||||
circpad_machine_state_t *);
|
||||
|
||||
/** Machine creation events are events that cause us to set up or
|
||||
* tear down padding state machines. */
|
||||
void circpad_machine_event_circ_added_hop(struct origin_circuit_t *on_circ);
|
||||
void circpad_machine_event_circ_built(struct origin_circuit_t *circ);
|
||||
void circpad_machine_event_circ_purpose_changed(struct origin_circuit_t *circ);
|
||||
void circpad_machine_event_circ_has_streams(struct origin_circuit_t *circ);
|
||||
void circpad_machine_event_circ_has_no_streams(struct origin_circuit_t *circ);
|
||||
void
|
||||
circpad_machine_event_circ_has_no_relay_early(struct origin_circuit_t *circ);
|
||||
|
||||
void circpad_machines_init(void);
|
||||
void circpad_machines_free(void);
|
||||
|
||||
void circpad_machine_states_init(circpad_machine_spec_t *machine,
|
||||
circpad_statenum_t num_states);
|
||||
|
||||
void circpad_circuit_free_all_machineinfos(struct circuit_t *circ);
|
||||
|
||||
bool circpad_padding_is_from_expected_hop(struct circuit_t *circ,
|
||||
crypt_path_t *from_hop);
|
||||
|
||||
/** Serializaton functions for writing to/from torrc and consensus */
|
||||
char *circpad_machine_spec_to_string(const circpad_machine_spec_t *machine);
|
||||
const circpad_machine_spec_t *circpad_string_to_machine(const char *str);
|
||||
|
||||
/* Padding negotiation between client and middle */
|
||||
signed_error_t circpad_handle_padding_negotiate(struct circuit_t *circ,
|
||||
struct cell_t *cell);
|
||||
signed_error_t circpad_handle_padding_negotiated(struct circuit_t *circ,
|
||||
struct cell_t *cell,
|
||||
crypt_path_t *layer_hint);
|
||||
signed_error_t circpad_negotiate_padding(struct origin_circuit_t *circ,
|
||||
circpad_machine_num_t machine,
|
||||
uint8_t target_hopnum,
|
||||
uint8_t command);
|
||||
bool circpad_padding_negotiated(struct circuit_t *circ,
|
||||
circpad_machine_num_t machine,
|
||||
uint8_t command,
|
||||
uint8_t response);
|
||||
|
||||
MOCK_DECL(circpad_decision_t,
|
||||
circpad_machine_schedule_padding,(circpad_machine_state_t *));
|
||||
|
||||
MOCK_DECL(circpad_decision_t,
|
||||
circpad_machine_spec_transition, (circpad_machine_state_t *mi,
|
||||
circpad_event_t event));
|
||||
|
||||
circpad_decision_t circpad_send_padding_cell_for_callback(
|
||||
circpad_machine_state_t *mi);
|
||||
|
||||
#ifdef CIRCUITPADDING_PRIVATE
|
||||
STATIC circpad_delay_t
|
||||
circpad_machine_sample_delay(circpad_machine_state_t *mi);
|
||||
|
||||
STATIC bool
|
||||
circpad_machine_reached_padding_limit(circpad_machine_state_t *mi);
|
||||
|
||||
STATIC
|
||||
circpad_decision_t circpad_machine_remove_token(circpad_machine_state_t *mi);
|
||||
|
||||
STATIC circpad_delay_t
|
||||
circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi,
|
||||
circpad_hist_index_t bin);
|
||||
|
||||
STATIC const circpad_state_t *
|
||||
circpad_machine_current_state(const circpad_machine_state_t *mi);
|
||||
|
||||
STATIC circpad_hist_index_t circpad_histogram_usec_to_bin(
|
||||
const circpad_machine_state_t *mi,
|
||||
circpad_delay_t us);
|
||||
|
||||
STATIC circpad_machine_state_t *circpad_circuit_machineinfo_new(
|
||||
struct circuit_t *on_circ,
|
||||
int machine_index);
|
||||
STATIC void circpad_machine_remove_higher_token(circpad_machine_state_t *mi,
|
||||
circpad_delay_t target_bin_us);
|
||||
STATIC void circpad_machine_remove_lower_token(circpad_machine_state_t *mi,
|
||||
circpad_delay_t target_bin_us);
|
||||
STATIC void circpad_machine_remove_closest_token(circpad_machine_state_t *mi,
|
||||
circpad_delay_t target_bin_us,
|
||||
bool use_usec);
|
||||
STATIC void circpad_machine_setup_tokens(circpad_machine_state_t *mi);
|
||||
|
||||
MOCK_DECL(STATIC signed_error_t,
|
||||
circpad_send_command_to_hop,(struct origin_circuit_t *circ, uint8_t hopnum,
|
||||
uint8_t relay_command, const uint8_t *payload,
|
||||
ssize_t payload_len));
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
extern smartlist_t *origin_padding_machines;
|
||||
extern smartlist_t *relay_padding_machines;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -35,6 +35,7 @@
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuitstats.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "feature/client/addressmap.h"
|
||||
@ -1419,6 +1420,11 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
|
||||
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
|
||||
hs_dec_rdv_stream_counter(origin_circ);
|
||||
}
|
||||
|
||||
/* If there are no more streams on this circ, tell circpad */
|
||||
if (!origin_circ->p_streams)
|
||||
circpad_machine_event_circ_has_no_streams(origin_circ);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -2586,6 +2592,12 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
|
||||
/* add it into the linked list of streams on this circuit */
|
||||
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.",
|
||||
(unsigned)circ->base_.n_circ_id);
|
||||
|
||||
/* If this is the first stream on this circuit, tell circpad
|
||||
* that streams are attached */
|
||||
if (!circ->p_streams)
|
||||
circpad_machine_event_circ_has_streams(circ);
|
||||
|
||||
/* reset it, so we can measure circ timeouts */
|
||||
ENTRY_TO_CONN(apconn)->timestamp_last_read_allowed = time(NULL);
|
||||
ENTRY_TO_EDGE_CONN(apconn)->next_stream = circ->p_streams;
|
||||
@ -3064,6 +3076,8 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
control_event_circuit_purpose_changed(TO_ORIGIN_CIRCUIT(circ),
|
||||
old_purpose);
|
||||
|
||||
circpad_machine_event_circ_purpose_changed(TO_ORIGIN_CIRCUIT(circ));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "core/or/connection_or.h"
|
||||
#include "core/or/policies.h"
|
||||
@ -3712,6 +3713,10 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
|
||||
/* Link the circuit and the connection crypt path. */
|
||||
conn->cpath_layer = origin_circ->cpath->prev;
|
||||
|
||||
/* If this is the first stream on this circuit, tell circpad */
|
||||
if (!origin_circ->p_streams)
|
||||
circpad_machine_event_circ_has_streams(origin_circ);
|
||||
|
||||
/* Add it into the linked list of p_streams on this circuit */
|
||||
conn->next_stream = origin_circ->p_streams;
|
||||
origin_circ->p_streams = conn;
|
||||
|
@ -207,6 +207,9 @@ struct curve25519_public_key_t;
|
||||
#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39
|
||||
#define RELAY_COMMAND_INTRODUCE_ACK 40
|
||||
|
||||
#define RELAY_COMMAND_PADDING_NEGOTIATE 41
|
||||
#define RELAY_COMMAND_PADDING_NEGOTIATED 42
|
||||
|
||||
/* Reasons why an OR connection is closed. */
|
||||
#define END_OR_CONN_REASON_DONE 1
|
||||
#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */
|
||||
@ -836,6 +839,10 @@ typedef struct protover_summary_flags_t {
|
||||
* service rendezvous point supporting version 3 as seen in proposal 224.
|
||||
* This requires HSRend=2. */
|
||||
unsigned int supports_v3_rendezvous_point: 1;
|
||||
|
||||
/** True iff this router has a protocol list that allows clients to
|
||||
* negotiate link-level padding. Requires Padding>=1. */
|
||||
unsigned int supports_padding : 1;
|
||||
} protover_summary_flags_t;
|
||||
|
||||
typedef struct routerinfo_t routerinfo_t;
|
||||
|
@ -161,6 +161,10 @@ struct origin_circuit_t {
|
||||
* connections to this circuit. */
|
||||
unsigned int unusable_for_new_conns : 1;
|
||||
|
||||
/* If this flag is set (due to padding negotiation failure), we should
|
||||
* not try to negotiate further circuit padding. */
|
||||
unsigned padding_negotiation_failed : 1;
|
||||
|
||||
/**
|
||||
* Tristate variable to guard against pathbias miscounting
|
||||
* due to circuit purpose transitions changing the decision
|
||||
|
@ -39,6 +39,9 @@ static int protocol_list_contains(const smartlist_t *protos,
|
||||
static const struct {
|
||||
protocol_type_t protover_type;
|
||||
const char *name;
|
||||
/* If you add a new protocol here, you probably also want to add
|
||||
* parsing for it in routerstatus_parse_entry_from_string() so that
|
||||
* it is set in routerstatus_t */
|
||||
} PROTOCOL_NAMES[] = {
|
||||
{ PRT_LINK, "Link" },
|
||||
{ PRT_LINKAUTH, "LinkAuth" },
|
||||
@ -49,6 +52,7 @@ static const struct {
|
||||
{ PRT_HSREND, "HSRend" },
|
||||
{ PRT_DESC, "Desc" },
|
||||
{ PRT_MICRODESC, "Microdesc"},
|
||||
{ PRT_PADDING, "Padding"},
|
||||
{ PRT_CONS, "Cons" }
|
||||
};
|
||||
|
||||
@ -396,7 +400,8 @@ protover_get_supported_protocols(void)
|
||||
"LinkAuth=3 "
|
||||
#endif
|
||||
"Microdesc=1-2 "
|
||||
"Relay=1-2";
|
||||
"Relay=1-2 "
|
||||
"Padding=1";
|
||||
}
|
||||
|
||||
/** The protocols from protover_get_supported_protocols(), as parsed into a
|
||||
|
@ -43,6 +43,7 @@ typedef enum protocol_type_t {
|
||||
PRT_DESC,
|
||||
PRT_MICRODESC,
|
||||
PRT_CONS,
|
||||
PRT_PADDING,
|
||||
} protocol_type_t;
|
||||
|
||||
bool protover_contains_long_protocol_names(const char *s);
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "core/or/circuitbuild.h"
|
||||
#include "core/or/circuitlist.h"
|
||||
#include "core/or/circuituse.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "lib/compress/compress.h"
|
||||
#include "app/config/config.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
@ -80,7 +81,6 @@
|
||||
#include "feature/nodelist/describe.h"
|
||||
#include "feature/nodelist/routerlist.h"
|
||||
#include "core/or/scheduler.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
|
||||
#include "core/or/cell_st.h"
|
||||
#include "core/or/cell_queue_st.h"
|
||||
@ -293,7 +293,9 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not recognized. pass it on. */
|
||||
/* not recognized. inform circpad and pass it on. */
|
||||
circpad_deliver_unrecognized_cell_events(circ, cell_direction);
|
||||
|
||||
if (cell_direction == CELL_DIRECTION_OUT) {
|
||||
cell->circ_id = circ->n_circ_id; /* switch it */
|
||||
chan = circ->n_chan;
|
||||
@ -353,11 +355,11 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
* - Encrypt it to the right layer
|
||||
* - Append it to the appropriate cell_queue on <b>circ</b>.
|
||||
*/
|
||||
static int
|
||||
circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
MOCK_IMPL(int,
|
||||
circuit_package_relay_cell, (cell_t *cell, circuit_t *circ,
|
||||
cell_direction_t cell_direction,
|
||||
crypt_path_t *layer_hint, streamid_t on_stream,
|
||||
const char *filename, int lineno)
|
||||
const char *filename, int lineno))
|
||||
{
|
||||
channel_t *chan; /* where to send the cell */
|
||||
|
||||
@ -524,6 +526,8 @@ relay_command_to_string(uint8_t command)
|
||||
case RELAY_COMMAND_INTRODUCE_ACK: return "INTRODUCE_ACK";
|
||||
case RELAY_COMMAND_EXTEND2: return "EXTEND2";
|
||||
case RELAY_COMMAND_EXTENDED2: return "EXTENDED2";
|
||||
case RELAY_COMMAND_PADDING_NEGOTIATE: return "PADDING_NEGOTIATE";
|
||||
case RELAY_COMMAND_PADDING_NEGOTIATED: return "PADDING_NEGOTIATED";
|
||||
default:
|
||||
tor_snprintf(buf, sizeof(buf), "Unrecognized relay command %u",
|
||||
(unsigned)command);
|
||||
@ -577,8 +581,8 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
|
||||
log_debug(LD_OR,"delivering %d cell %s.", relay_command,
|
||||
cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
|
||||
|
||||
if (relay_command == RELAY_COMMAND_DROP)
|
||||
rep_hist_padding_count_write(PADDING_TYPE_DROP);
|
||||
/* Tell circpad we're sending a relay cell */
|
||||
circpad_deliver_sent_relay_cell_events(circ, relay_command);
|
||||
|
||||
/* If we are sending an END cell and this circuit is used for a tunneled
|
||||
* directory request, advance its state. */
|
||||
@ -602,7 +606,9 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ,
|
||||
* one of them. Don't worry about the conn protocol version:
|
||||
* append_cell_to_circuit_queue will fix it up. */
|
||||
cell.command = CELL_RELAY_EARLY;
|
||||
--origin_circ->remaining_relay_early_cells;
|
||||
/* If we're out of relay early cells, tell circpad */
|
||||
if (--origin_circ->remaining_relay_early_cells == 0)
|
||||
circpad_machine_event_circ_has_no_relay_early(origin_circ);
|
||||
log_debug(LD_OR, "Sending a RELAY_EARLY cell; %d remaining.",
|
||||
(int)origin_circ->remaining_relay_early_cells);
|
||||
/* Memorize the command that is sent as RELAY_EARLY cell; helps debug
|
||||
@ -1481,9 +1487,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell circpad that we've recieved a recognized cell */
|
||||
circpad_deliver_recognized_relay_cell_events(circ, rh.command, layer_hint);
|
||||
|
||||
/* either conn is NULL, in which case we've got a control cell, or else
|
||||
* conn points to the recognized stream. */
|
||||
|
||||
if (conn && !connection_state_is_open(TO_CONN(conn))) {
|
||||
if (conn->base_.type == CONN_TYPE_EXIT &&
|
||||
(conn->base_.state == EXIT_CONN_STATE_CONNECTING ||
|
||||
@ -1504,8 +1512,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
|
||||
switch (rh.command) {
|
||||
case RELAY_COMMAND_DROP:
|
||||
rep_hist_padding_count_read(PADDING_TYPE_DROP);
|
||||
// log_info(domain,"Got a relay-level padding cell. Dropping.");
|
||||
/* Already examined in circpad_deliver_recognized_relay_cell_events */
|
||||
return 0;
|
||||
case RELAY_COMMAND_PADDING_NEGOTIATE:
|
||||
circpad_handle_padding_negotiate(circ, cell);
|
||||
return 0;
|
||||
case RELAY_COMMAND_PADDING_NEGOTIATED:
|
||||
if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0)
|
||||
circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
|
||||
return 0;
|
||||
case RELAY_COMMAND_BEGIN:
|
||||
case RELAY_COMMAND_BEGIN_DIR:
|
||||
|
@ -78,6 +78,11 @@ void destroy_cell_queue_append(destroy_cell_queue_t *queue,
|
||||
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
|
||||
MOCK_DECL(int, channel_flush_from_first_active_circuit,
|
||||
(channel_t *chan, int max));
|
||||
MOCK_DECL(int, circuit_package_relay_cell, (cell_t *cell, circuit_t *circ,
|
||||
cell_direction_t cell_direction,
|
||||
crypt_path_t *layer_hint, streamid_t on_stream,
|
||||
const char *filename, int lineno));
|
||||
|
||||
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
|
||||
const char *file, int lineno);
|
||||
#define update_circuit_on_cmux(circ, direction) \
|
||||
|
@ -448,6 +448,8 @@ memoize_protover_summary(protover_summary_flags_t *out,
|
||||
out->supports_v3_rendezvous_point =
|
||||
protocol_list_supports_protocol(protocols, PRT_HSREND,
|
||||
PROTOVER_HS_RENDEZVOUS_POINT_V3);
|
||||
out->supports_padding =
|
||||
protocol_list_supports_protocol(protocols, PRT_PADDING, 1);
|
||||
|
||||
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
|
||||
cached = strmap_set(protover_summary_map, protocols, new_cached);
|
||||
|
@ -37,6 +37,7 @@ hibernating, phase 2:
|
||||
#include "core/or/connection_or.h"
|
||||
#include "feature/control/control.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/defs/time.h"
|
||||
#include "feature/hibernate/hibernate.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "feature/relay/router.h"
|
||||
@ -832,8 +833,6 @@ hibernate_soft_limit_reached(void)
|
||||
return get_accounting_bytes() >= soft_limit;
|
||||
}
|
||||
|
||||
#define TOR_USEC_PER_SEC (1000000)
|
||||
|
||||
/** Called when we get a SIGINT, or when bandwidth soft limit is
|
||||
* reached. Puts us into "loose hibernation": we don't accept new
|
||||
* connections, but we continue handling old ones. */
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "core/mainloop/netstatus.h"
|
||||
#include "core/or/channel.h"
|
||||
#include "core/or/channelpadding.h"
|
||||
#include "core/or/circuitpadding.h"
|
||||
#include "core/or/circuitmux.h"
|
||||
#include "core/or/circuitmux_ewma.h"
|
||||
#include "core/or/circuitstats.h"
|
||||
@ -2116,6 +2117,7 @@ networkstatus_set_current_consensus(const char *consensus,
|
||||
circuit_build_times_new_consensus_params(
|
||||
get_circuit_build_times_mutable(), c);
|
||||
channelpadding_new_consensus_params(c);
|
||||
circpad_new_consensus_params(c);
|
||||
}
|
||||
|
||||
/* Reset the failure count only if this consensus is actually valid. */
|
||||
|
@ -1106,7 +1106,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
|
||||
/** Dummy object that should be unreturnable. Used to ensure that
|
||||
* node_get_protover_summary_flags() always returns non-NULL. */
|
||||
static const protover_summary_flags_t zero_protover_flags = {
|
||||
0,0,0,0,0,0,0
|
||||
0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
/** Return the protover_summary_flags for a given node. */
|
||||
@ -2350,7 +2350,7 @@ compute_frac_paths_available(const networkstatus_t *consensus,
|
||||
const int authdir = authdir_mode_v3(options);
|
||||
|
||||
count_usable_descriptors(num_present_out, num_usable_out,
|
||||
mid, consensus, now, NULL,
|
||||
mid, consensus, now, options->MiddleNodes,
|
||||
USABLE_DESCRIPTOR_ALL);
|
||||
log_debug(LD_NET,
|
||||
"%s: %d present, %d usable",
|
||||
|
@ -3221,6 +3221,8 @@ refresh_all_country_info(void)
|
||||
routerset_refresh_countries(options->EntryNodes);
|
||||
if (options->ExitNodes)
|
||||
routerset_refresh_countries(options->ExitNodes);
|
||||
if (options->MiddleNodes)
|
||||
routerset_refresh_countries(options->MiddleNodes);
|
||||
if (options->ExcludeNodes)
|
||||
routerset_refresh_countries(options->ExcludeNodes);
|
||||
if (options->ExcludeExitNodes)
|
||||
|
@ -528,6 +528,17 @@ crypto_rand_unmocked(char *to, size_t n)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw an unsigned 32-bit integer uniformly at random.
|
||||
*/
|
||||
uint32_t
|
||||
crypto_rand_u32(void)
|
||||
{
|
||||
uint32_t rand;
|
||||
crypto_rand((void*)&rand, sizeof(rand));
|
||||
return rand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pseudorandom integer, chosen uniformly from the values
|
||||
* between 0 and <b>max</b>-1 inclusive. <b>max</b> must be between 1 and
|
||||
|
@ -27,6 +27,7 @@ int crypto_rand_int(unsigned int max);
|
||||
int crypto_rand_int_range(unsigned int min, unsigned int max);
|
||||
uint64_t crypto_rand_uint64_range(uint64_t min, uint64_t max);
|
||||
time_t crypto_rand_time_range(time_t min, time_t max);
|
||||
uint32_t crypto_rand_u32(void);
|
||||
uint64_t crypto_rand_uint64(uint64_t max);
|
||||
double crypto_rand_double(void);
|
||||
struct tor_weak_rng_t;
|
||||
|
@ -2,4 +2,5 @@
|
||||
noinst_HEADERS += \
|
||||
src/lib/defs/dh_sizes.h \
|
||||
src/lib/defs/digest_sizes.h \
|
||||
src/lib/defs/time.h \
|
||||
src/lib/defs/x25519_sizes.h
|
||||
|
23
src/lib/defs/time.h
Normal file
23
src/lib/defs/time.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright (c) 2001, Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_TIME_DEFS_H
|
||||
#define TOR_TIME_DEFS_H
|
||||
|
||||
/**
|
||||
* \file time.h
|
||||
*
|
||||
* \brief Definitions for timing-related constants.
|
||||
**/
|
||||
|
||||
/** How many microseconds per second */
|
||||
#define TOR_USEC_PER_SEC (1000000)
|
||||
/** How many nanoseconds per microsecond */
|
||||
#define TOR_NSEC_PER_USEC (1000)
|
||||
/* How many nanoseconds per millisecond */
|
||||
#define TOR_NSEC_PER_MSEC (1000*1000)
|
||||
|
||||
#endif
|
@ -3,3 +3,5 @@ orconfig.h
|
||||
lib/cc/*.h
|
||||
lib/log/*.h
|
||||
lib/math/*.h
|
||||
lib/testsupport/*.h
|
||||
lib/crypt_ops/*.h
|
||||
|
@ -117,3 +117,28 @@ ENABLE_GCC_WARNING(double-promotion)
|
||||
ENABLE_GCC_WARNING(float-conversion)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* isinf() wrapper for tor */
|
||||
int
|
||||
tor_isinf(double x)
|
||||
{
|
||||
/* Same as above, work around the "double promotion" warnings */
|
||||
#if defined(MINGW_ANY) && GCC_VERSION >= 409
|
||||
#define PROBLEMATIC_FLOAT_CONVERSION_WARNING
|
||||
DISABLE_GCC_WARNING(float-conversion)
|
||||
#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */
|
||||
#if defined(__clang__)
|
||||
#if __has_warning("-Wdouble-promotion")
|
||||
#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING
|
||||
DISABLE_GCC_WARNING(double-promotion)
|
||||
#endif
|
||||
#endif /* defined(__clang__) */
|
||||
return isinf(x);
|
||||
#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
|
||||
ENABLE_GCC_WARNING(double-promotion)
|
||||
#endif
|
||||
#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
|
||||
ENABLE_GCC_WARNING(float-conversion)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -19,5 +19,6 @@ double tor_mathlog(double d) ATTR_CONST;
|
||||
long tor_lround(double d) ATTR_CONST;
|
||||
int64_t tor_llround(double d) ATTR_CONST;
|
||||
int64_t clamp_double_to_int64(double number);
|
||||
int tor_isinf(double x);
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,8 @@ endif
|
||||
|
||||
src_lib_libtor_math_a_SOURCES = \
|
||||
src/lib/math/fp.c \
|
||||
src/lib/math/laplace.c
|
||||
src/lib/math/laplace.c \
|
||||
src/lib/math/prob_distr.c
|
||||
|
||||
|
||||
src_lib_libtor_math_testing_a_SOURCES = \
|
||||
@ -17,4 +18,5 @@ src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||
|
||||
noinst_HEADERS += \
|
||||
src/lib/math/fp.h \
|
||||
src/lib/math/laplace.h
|
||||
src/lib/math/laplace.h \
|
||||
src/lib/math/prob_distr.h
|
||||
|
1717
src/lib/math/prob_distr.c
Normal file
1717
src/lib/math/prob_distr.c
Normal file
File diff suppressed because it is too large
Load Diff
158
src/lib/math/prob_distr.h
Normal file
158
src/lib/math/prob_distr.h
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
/**
|
||||
* \file prob_distr.h
|
||||
*
|
||||
* \brief Header for prob_distr.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_PROB_DISTR_H
|
||||
#define TOR_PROB_DISTR_H
|
||||
|
||||
#include "lib/cc/compat_compiler.h"
|
||||
#include "lib/cc/torint.h"
|
||||
#include "lib/testsupport/testsupport.h"
|
||||
|
||||
/**
|
||||
* Container for distribution parameters for sampling, CDF, &c.
|
||||
*/
|
||||
struct dist {
|
||||
const struct dist_ops *ops;
|
||||
};
|
||||
|
||||
#define DIST_BASE(OPS) { .ops = (OPS) }
|
||||
#define DIST_BASE_TYPED(OPS, OBJ, TYPE) \
|
||||
DIST_BASE((OPS) + 0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
|
||||
|
||||
const char *dist_name(const struct dist *);
|
||||
double dist_sample(const struct dist *);
|
||||
double dist_cdf(const struct dist *, double x);
|
||||
double dist_sf(const struct dist *, double x);
|
||||
double dist_icdf(const struct dist *, double p);
|
||||
double dist_isf(const struct dist *, double p);
|
||||
|
||||
struct dist_ops {
|
||||
const char *name;
|
||||
double (*sample)(const struct dist *);
|
||||
double (*cdf)(const struct dist *, double x);
|
||||
double (*sf)(const struct dist *, double x);
|
||||
double (*icdf)(const struct dist *, double p);
|
||||
double (*isf)(const struct dist *, double p);
|
||||
};
|
||||
|
||||
/* Geometric distribution on positive number of trials before first success */
|
||||
|
||||
struct geometric {
|
||||
struct dist base;
|
||||
double p; /* success probability */
|
||||
};
|
||||
|
||||
extern const struct dist_ops geometric_ops;
|
||||
|
||||
#define GEOMETRIC(OBJ) \
|
||||
DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric)
|
||||
|
||||
/* Pareto distribution */
|
||||
|
||||
struct genpareto {
|
||||
struct dist base;
|
||||
double mu;
|
||||
double sigma;
|
||||
double xi;
|
||||
};
|
||||
|
||||
extern const struct dist_ops genpareto_ops;
|
||||
|
||||
#define GENPARETO(OBJ) \
|
||||
DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto)
|
||||
|
||||
/* Weibull distribution */
|
||||
|
||||
struct weibull {
|
||||
struct dist base;
|
||||
double lambda;
|
||||
double k;
|
||||
};
|
||||
|
||||
extern const struct dist_ops weibull_ops;
|
||||
|
||||
#define WEIBULL(OBJ) \
|
||||
DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull)
|
||||
|
||||
/* Log-logistic distribution */
|
||||
|
||||
struct log_logistic {
|
||||
struct dist base;
|
||||
double alpha;
|
||||
double beta;
|
||||
};
|
||||
|
||||
extern const struct dist_ops log_logistic_ops;
|
||||
|
||||
#define LOG_LOGISTIC(OBJ) \
|
||||
DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic)
|
||||
|
||||
/* Logistic distribution */
|
||||
|
||||
struct logistic {
|
||||
struct dist base;
|
||||
double mu;
|
||||
double sigma;
|
||||
};
|
||||
|
||||
extern const struct dist_ops logistic_ops;
|
||||
|
||||
#define LOGISTIC(OBJ) \
|
||||
DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic)
|
||||
|
||||
/* Uniform distribution */
|
||||
|
||||
struct uniform {
|
||||
struct dist base;
|
||||
double a;
|
||||
double b;
|
||||
};
|
||||
|
||||
extern const struct dist_ops uniform_ops;
|
||||
|
||||
#define UNIFORM(OBJ) \
|
||||
DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform)
|
||||
|
||||
/** Only by unittests */
|
||||
|
||||
#ifdef PROB_DISTR_PRIVATE
|
||||
|
||||
STATIC double logithalf(double p0);
|
||||
STATIC double logit(double p);
|
||||
|
||||
STATIC double random_uniform_01(void);
|
||||
|
||||
STATIC double logistic(double x);
|
||||
STATIC double cdf_logistic(double x, double mu, double sigma);
|
||||
STATIC double sf_logistic(double x, double mu, double sigma);
|
||||
STATIC double icdf_logistic(double p, double mu, double sigma);
|
||||
STATIC double isf_logistic(double p, double mu, double sigma);
|
||||
STATIC double sample_logistic(uint32_t s, double t, double p0);
|
||||
|
||||
STATIC double cdf_log_logistic(double x, double alpha, double beta);
|
||||
STATIC double sf_log_logistic(double x, double alpha, double beta);
|
||||
STATIC double icdf_log_logistic(double p, double alpha, double beta);
|
||||
STATIC double isf_log_logistic(double p, double alpha, double beta);
|
||||
STATIC double sample_log_logistic(uint32_t s, double p0);
|
||||
|
||||
STATIC double cdf_weibull(double x, double lambda, double k);
|
||||
STATIC double sf_weibull(double x, double lambda, double k);
|
||||
STATIC double icdf_weibull(double p, double lambda, double k);
|
||||
STATIC double isf_weibull(double p, double lambda, double k);
|
||||
STATIC double sample_weibull(uint32_t s, double p0, double lambda, double k);
|
||||
|
||||
STATIC double sample_uniform_interval(double p0, double a, double b);
|
||||
|
||||
STATIC double cdf_genpareto(double x, double mu, double sigma, double xi);
|
||||
STATIC double sf_genpareto(double x, double mu, double sigma, double xi);
|
||||
STATIC double icdf_genpareto(double p, double mu, double sigma, double xi);
|
||||
STATIC double isf_genpareto(double p, double mu, double sigma, double xi);
|
||||
STATIC double sample_genpareto(uint32_t s, double p0, double xi);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -83,6 +83,19 @@
|
||||
++var ## _sl_idx) { \
|
||||
var = (sl)->list[var ## _sl_idx];
|
||||
|
||||
/** Iterates over the items in smartlist <b>sl</b> in reverse order, similar to
|
||||
* SMARTLIST_FOREACH_BEGIN
|
||||
*
|
||||
* NOTE: This macro is incompatible with SMARTLIST_DEL_CURRENT.
|
||||
*/
|
||||
#define SMARTLIST_FOREACH_REVERSE_BEGIN(sl, type, var) \
|
||||
STMT_BEGIN \
|
||||
int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \
|
||||
type var; \
|
||||
for (var ## _sl_idx = var ## _sl_len-1; var ## _sl_idx >= 0; \
|
||||
--var ## _sl_idx) { \
|
||||
var = (sl)->list[var ## _sl_idx];
|
||||
|
||||
#define SMARTLIST_FOREACH_END(var) \
|
||||
var = NULL; \
|
||||
(void) var ## _sl_idx; \
|
||||
|
@ -7,6 +7,7 @@ lib/log/*.h
|
||||
lib/subsys/*.h
|
||||
lib/time/*.h
|
||||
lib/wallclock/*.h
|
||||
lib/defs/time.h
|
||||
|
||||
# For load_windows_system_lib.
|
||||
lib/fs/winlib.h
|
@ -787,8 +787,8 @@ monotime_absolute_nsec(void)
|
||||
return monotime_diff_nsec(&initialized_at, &now);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
monotime_absolute_usec(void)
|
||||
MOCK_IMPL(uint64_t,
|
||||
monotime_absolute_usec,(void))
|
||||
{
|
||||
return monotime_absolute_nsec() / 1000;
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ uint64_t monotime_absolute_nsec(void);
|
||||
/**
|
||||
* Return the number of microseconds since the timer system was initialized.
|
||||
*/
|
||||
uint64_t monotime_absolute_usec(void);
|
||||
MOCK_DECL(uint64_t, monotime_absolute_usec,(void));
|
||||
/**
|
||||
* Return the number of milliseconds since the timer system was initialized.
|
||||
*/
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "lib/time/tvdiff.h"
|
||||
|
||||
#include "lib/cc/compat_compiler.h"
|
||||
#include "lib/defs/time.h"
|
||||
#include "lib/log/log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -20,8 +21,6 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define TOR_USEC_PER_SEC 1000000
|
||||
|
||||
/** Return the difference between start->tv_sec and end->tv_sec.
|
||||
* Returns INT64_MAX on overflow and underflow.
|
||||
*/
|
||||
|
@ -46,6 +46,7 @@ pub enum Protocol {
|
||||
LinkAuth,
|
||||
Microdesc,
|
||||
Relay,
|
||||
Padding,
|
||||
}
|
||||
|
||||
impl fmt::Display for Protocol {
|
||||
@ -73,6 +74,7 @@ impl FromStr for Protocol {
|
||||
"LinkAuth" => Ok(Protocol::LinkAuth),
|
||||
"Microdesc" => Ok(Protocol::Microdesc),
|
||||
"Relay" => Ok(Protocol::Relay),
|
||||
"Padding" => Ok(Protocol::Padding),
|
||||
_ => Err(ProtoverError::UnknownProtocol),
|
||||
}
|
||||
}
|
||||
@ -163,7 +165,8 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
|
||||
Link=1-5 \
|
||||
LinkAuth=3 \
|
||||
Microdesc=1-2 \
|
||||
Relay=1-2"
|
||||
Relay=1-2 \
|
||||
Padding=1"
|
||||
)
|
||||
} else {
|
||||
cstr!(
|
||||
@ -176,7 +179,8 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
|
||||
Link=1-5 \
|
||||
LinkAuth=1,3 \
|
||||
Microdesc=1-2 \
|
||||
Relay=1-2"
|
||||
Relay=1-2 \
|
||||
Padding=1"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ TEST_OBJECTS = test.obj test_addr.obj test_channel.obj test_channeltls.obj \
|
||||
test_cell_formats.obj test_relay.obj test_replay.obj \
|
||||
test_channelpadding.obj \
|
||||
test_circuitstats.obj \
|
||||
test_circuitpadding.obj \
|
||||
test_scheduler.obj test_introduce.obj test_hs.obj tinytest.obj
|
||||
|
||||
tinytest.obj: ..\ext\tinytest.c
|
||||
|
@ -101,6 +101,7 @@ src_test_test_SOURCES += \
|
||||
src/test/test_cell_queue.c \
|
||||
src/test/test_channel.c \
|
||||
src/test/test_channelpadding.c \
|
||||
src/test/test_circuitpadding.c \
|
||||
src/test/test_channeltls.c \
|
||||
src/test/test_checkdir.c \
|
||||
src/test/test_circuitlist.c \
|
||||
@ -156,6 +157,7 @@ src_test_test_SOURCES += \
|
||||
src/test/test_periodic_event.c \
|
||||
src/test/test_policy.c \
|
||||
src/test/test_process.c \
|
||||
src/test/test_prob_distr.c \
|
||||
src/test/test_procmon.c \
|
||||
src/test/test_proto_http.c \
|
||||
src/test/test_proto_misc.c \
|
||||
@ -206,6 +208,7 @@ src_test_test_slow_SOURCES += \
|
||||
src/test/test_slow.c \
|
||||
src/test/test_crypto_slow.c \
|
||||
src/test/test_process_slow.c \
|
||||
src/test/test_prob_distr.c \
|
||||
src/test/testing_common.c \
|
||||
src/test/testing_rsakeys.c \
|
||||
src/ext/tinytest.c
|
||||
|
64
src/test/prob_distr_mpfr_ref.c
Normal file
64
src/test/prob_distr_mpfr_ref.c
Normal file
@ -0,0 +1,64 @@
|
||||
/* Copyright 2012-2018, The Tor Project, Inc
|
||||
* See LICENSE for licensing information */
|
||||
|
||||
/** prob_distr_mpfr_ref.c
|
||||
*
|
||||
* Example reference file for GNU MPFR vectors tested in test_prob_distr.c .
|
||||
* Code by Riastradh.
|
||||
*/
|
||||
|
||||
#include <complex.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Must come after <stdio.h> so we get mpfr_printf. */
|
||||
#include <mpfr.h>
|
||||
|
||||
/* gcc -o mpfr prob_distr_mpfr_ref.c -lmpfr -lm */
|
||||
|
||||
/* Computes logit(p) for p = .49999 */
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
mpfr_t p, q, r;
|
||||
mpfr_init(p);
|
||||
mpfr_set_prec(p, 200);
|
||||
mpfr_init(q);
|
||||
mpfr_set_prec(q, 200);
|
||||
mpfr_init(r);
|
||||
mpfr_set_prec(r, 200);
|
||||
mpfr_set_d(p, .49999, MPFR_RNDN);
|
||||
mpfr_set_d(q, 1, MPFR_RNDN);
|
||||
/* r := q - p = 1 - p */
|
||||
mpfr_sub(r, q, p, MPFR_RNDN);
|
||||
/* q := p/r = p/(1 - p) */
|
||||
mpfr_div(q, p, r, MPFR_RNDN);
|
||||
/* r := log(q) = log(p/(1 - p)) */
|
||||
mpfr_log(r, q, MPFR_RNDN);
|
||||
mpfr_printf("mpfr 200-bit\t%.128Rg\n", r);
|
||||
|
||||
/*
|
||||
* Print a double approximation to logit three different ways. All
|
||||
* three agree bit for bit on the libms I tried, with the nextafter
|
||||
* adjustment (which is well within the 10 eps relative error bound
|
||||
* advertised). Apparently I must have used the Goldberg expression
|
||||
* for what I wrote down in the test case.
|
||||
*/
|
||||
printf("mpfr 53-bit\t%.17g\n", nextafter(mpfr_get_d(r, MPFR_RNDN), 0), 0);
|
||||
volatile double p0 = .49999;
|
||||
printf("log1p\t\t%.17g\n", nextafter(-log1p((1 - 2*p0)/p0), 0));
|
||||
volatile double x = (1 - 2*p0)/p0;
|
||||
volatile double xp1 = x + 1;
|
||||
printf("Goldberg\t%.17g\n", -x*log(xp1)/(xp1 - 1));
|
||||
|
||||
/*
|
||||
* Print a bad approximation, using the naive expression, to see a
|
||||
* lot of wrong digits, far beyond the 10 eps relative error attained
|
||||
* by -log1p((1 - 2*p)/p).
|
||||
*/
|
||||
printf("naive\t\t%.17g\n", log(p0/(1 - p0)));
|
||||
|
||||
fflush(stdout);
|
||||
return ferror(stdout);
|
||||
}
|
@ -845,6 +845,7 @@ struct testgroup_t testgroups[] = {
|
||||
{ "channeltls/", channeltls_tests },
|
||||
{ "checkdir/", checkdir_tests },
|
||||
{ "circuitbuild/", circuitbuild_tests },
|
||||
{ "circuitpadding/", circuitpadding_tests },
|
||||
{ "circuitlist/", circuitlist_tests },
|
||||
{ "circuitmux/", circuitmux_tests },
|
||||
{ "circuitstats/", circuitstats_tests },
|
||||
@ -900,6 +901,7 @@ struct testgroup_t testgroups[] = {
|
||||
{ "parsecommon/", parsecommon_tests },
|
||||
{ "periodic-event/" , periodic_event_tests },
|
||||
{ "policy/" , policy_tests },
|
||||
{ "prob_distr/", prob_distr_tests },
|
||||
{ "procmon/", procmon_tests },
|
||||
{ "process/", process_tests },
|
||||
{ "proto/http/", proto_http_tests },
|
||||
|
@ -187,6 +187,7 @@ extern struct testcase_t cell_format_tests[];
|
||||
extern struct testcase_t cell_queue_tests[];
|
||||
extern struct testcase_t channel_tests[];
|
||||
extern struct testcase_t channelpadding_tests[];
|
||||
extern struct testcase_t circuitpadding_tests[];
|
||||
extern struct testcase_t channeltls_tests[];
|
||||
extern struct testcase_t checkdir_tests[];
|
||||
extern struct testcase_t circuitbuild_tests[];
|
||||
@ -242,6 +243,8 @@ extern struct testcase_t parsecommon_tests[];
|
||||
extern struct testcase_t pem_tests[];
|
||||
extern struct testcase_t periodic_event_tests[];
|
||||
extern struct testcase_t policy_tests[];
|
||||
extern struct testcase_t prob_distr_tests[];
|
||||
extern struct testcase_t slow_stochastic_prob_distr_tests[];
|
||||
extern struct testcase_t procmon_tests[];
|
||||
extern struct testcase_t process_tests[];
|
||||
extern struct testcase_t proto_http_tests[];
|
||||
|
2356
src/test/test_circuitpadding.c
Normal file
2356
src/test/test_circuitpadding.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -96,6 +96,30 @@ test_container_smartlist_basic(void *arg)
|
||||
tor_free(v555);
|
||||
}
|
||||
|
||||
/** Test SMARTLIST_FOREACH_REVERSE_BEGIN loop macro */
|
||||
static void
|
||||
test_container_smartlist_foreach_reverse(void *arg)
|
||||
{
|
||||
smartlist_t *sl = smartlist_new();
|
||||
int i;
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* Add integers to smartlist in increasing order */
|
||||
for (i=0;i<100;i++) {
|
||||
smartlist_add(sl, (void*)(uintptr_t)i);
|
||||
}
|
||||
|
||||
/* Pop them out in reverse and test their value */
|
||||
SMARTLIST_FOREACH_REVERSE_BEGIN(sl, void*, k) {
|
||||
i--;
|
||||
tt_ptr_op(k, OP_EQ, (void*)(uintptr_t)i);
|
||||
} SMARTLIST_FOREACH_END(k);
|
||||
|
||||
done:
|
||||
smartlist_free(sl);
|
||||
}
|
||||
|
||||
/** Run unit tests for smartlist-of-strings functionality. */
|
||||
static void
|
||||
test_container_smartlist_strings(void *arg)
|
||||
@ -1281,6 +1305,7 @@ test_container_smartlist_strings_eq(void *arg)
|
||||
struct testcase_t container_tests[] = {
|
||||
CONTAINER_LEGACY(smartlist_basic),
|
||||
CONTAINER_LEGACY(smartlist_strings),
|
||||
CONTAINER_LEGACY(smartlist_foreach_reverse),
|
||||
CONTAINER_LEGACY(smartlist_overlap),
|
||||
CONTAINER_LEGACY(smartlist_digests),
|
||||
CONTAINER_LEGACY(smartlist_join),
|
||||
|
1428
src/test/test_prob_distr.c
Normal file
1428
src/test/test_prob_distr.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@
|
||||
struct testgroup_t testgroups[] = {
|
||||
{ "slow/crypto/", slow_crypto_tests },
|
||||
{ "slow/process/", slow_process_tests },
|
||||
{ "slow/prob_distr/", slow_stochastic_prob_distr_tests },
|
||||
END_OF_GROUPS
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "feature/client/transports.h"
|
||||
#include "lib/crypt_ops/crypto_format.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/defs/time.h"
|
||||
#include "test/test.h"
|
||||
#include "lib/memarea/memarea.h"
|
||||
#include "lib/process/waitpid.h"
|
||||
@ -69,6 +70,28 @@
|
||||
#define INFINITY_DBL ((double)INFINITY)
|
||||
#define NAN_DBL ((double)NAN)
|
||||
|
||||
/** Test the tor_isinf() wrapper */
|
||||
static void
|
||||
test_tor_isinf(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
tt_assert(tor_isinf(INFINITY_DBL));
|
||||
|
||||
tt_assert(!tor_isinf(NAN_DBL));
|
||||
tt_assert(!tor_isinf(DBL_EPSILON));
|
||||
tt_assert(!tor_isinf(DBL_MAX));
|
||||
tt_assert(!tor_isinf(DBL_MIN));
|
||||
|
||||
tt_assert(!tor_isinf(0.0));
|
||||
tt_assert(!tor_isinf(0.1));
|
||||
tt_assert(!tor_isinf(3));
|
||||
tt_assert(!tor_isinf(3.14));
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
/* XXXX this is a minimal wrapper to make the unit tests compile with the
|
||||
* changed tor_timegm interface. */
|
||||
static time_t
|
||||
@ -404,7 +427,6 @@ test_util_time(void *arg)
|
||||
|
||||
/* Assume tv_usec is an unsigned integer until proven otherwise */
|
||||
#define TV_USEC_MAX UINT_MAX
|
||||
#define TOR_USEC_PER_SEC 1000000
|
||||
|
||||
/* Overflows in the result type */
|
||||
|
||||
@ -6182,6 +6204,7 @@ struct testcase_t util_tests[] = {
|
||||
UTIL_TEST(mathlog, 0),
|
||||
UTIL_TEST(fraction, 0),
|
||||
UTIL_TEST(weak_random, 0),
|
||||
{ "tor_isinf", test_tor_isinf, TT_FORK, NULL, NULL },
|
||||
{ "socket_ipv4", test_util_socket, TT_FORK, &passthrough_setup,
|
||||
(void*)"4" },
|
||||
{ "socket_ipv6", test_util_socket, TT_FORK,
|
||||
|
549
src/trunnel/circpad_negotiation.c
Normal file
549
src/trunnel/circpad_negotiation.c
Normal file
@ -0,0 +1,549 @@
|
||||
/* circpad_negotiation.c -- generated by Trunnel v1.5.2.
|
||||
* https://gitweb.torproject.org/trunnel.git
|
||||
* You probably shouldn't edit this file.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "trunnel-impl.h"
|
||||
|
||||
#include "circpad_negotiation.h"
|
||||
|
||||
#define TRUNNEL_SET_ERROR_CODE(obj) \
|
||||
do { \
|
||||
(obj)->trunnel_error_code_ = 1; \
|
||||
} while (0)
|
||||
|
||||
#if defined(__COVERITY__) || defined(__clang_analyzer__)
|
||||
/* If we're running a static analysis tool, we don't want it to complain
|
||||
* that some of our remaining-bytes checks are dead-code. */
|
||||
int circpadnegotiation_deadcode_dummy__ = 0;
|
||||
#define OR_DEADCODE_DUMMY || circpadnegotiation_deadcode_dummy__
|
||||
#else
|
||||
#define OR_DEADCODE_DUMMY
|
||||
#endif
|
||||
|
||||
#define CHECK_REMAINING(nbytes, label) \
|
||||
do { \
|
||||
if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
circpad_negotiate_t *
|
||||
circpad_negotiate_new(void)
|
||||
{
|
||||
circpad_negotiate_t *val = trunnel_calloc(1, sizeof(circpad_negotiate_t));
|
||||
if (NULL == val)
|
||||
return NULL;
|
||||
val->command = CIRCPAD_COMMAND_START;
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Release all storage held inside 'obj', but do not free 'obj'.
|
||||
*/
|
||||
static void
|
||||
circpad_negotiate_clear(circpad_negotiate_t *obj)
|
||||
{
|
||||
(void) obj;
|
||||
}
|
||||
|
||||
void
|
||||
circpad_negotiate_free(circpad_negotiate_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
circpad_negotiate_clear(obj);
|
||||
trunnel_memwipe(obj, sizeof(circpad_negotiate_t));
|
||||
trunnel_free_(obj);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
circpad_negotiate_get_version(const circpad_negotiate_t *inp)
|
||||
{
|
||||
return inp->version;
|
||||
}
|
||||
int
|
||||
circpad_negotiate_set_version(circpad_negotiate_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == 0))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->version = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
circpad_negotiate_get_command(const circpad_negotiate_t *inp)
|
||||
{
|
||||
return inp->command;
|
||||
}
|
||||
int
|
||||
circpad_negotiate_set_command(circpad_negotiate_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == CIRCPAD_COMMAND_START || val == CIRCPAD_COMMAND_STOP))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->command = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
circpad_negotiate_get_machine_type(const circpad_negotiate_t *inp)
|
||||
{
|
||||
return inp->machine_type;
|
||||
}
|
||||
int
|
||||
circpad_negotiate_set_machine_type(circpad_negotiate_t *inp, uint8_t val)
|
||||
{
|
||||
inp->machine_type = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
circpad_negotiate_get_echo_request(const circpad_negotiate_t *inp)
|
||||
{
|
||||
return inp->echo_request;
|
||||
}
|
||||
int
|
||||
circpad_negotiate_set_echo_request(circpad_negotiate_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == 0 || val == 1))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->echo_request = val;
|
||||
return 0;
|
||||
}
|
||||
const char *
|
||||
circpad_negotiate_check(const circpad_negotiate_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return "Object was NULL";
|
||||
if (obj->trunnel_error_code_)
|
||||
return "A set function failed on this object";
|
||||
if (! (obj->version == 0))
|
||||
return "Integer out of bounds";
|
||||
if (! (obj->command == CIRCPAD_COMMAND_START || obj->command == CIRCPAD_COMMAND_STOP))
|
||||
return "Integer out of bounds";
|
||||
if (! (obj->echo_request == 0 || obj->echo_request == 1))
|
||||
return "Integer out of bounds";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
circpad_negotiate_encoded_len(const circpad_negotiate_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
|
||||
if (NULL != circpad_negotiate_check(obj))
|
||||
return -1;
|
||||
|
||||
|
||||
/* Length of u8 version IN [0] */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP] */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 machine_type */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 echo_request IN [0, 1] */
|
||||
result += 1;
|
||||
return result;
|
||||
}
|
||||
int
|
||||
circpad_negotiate_clear_errors(circpad_negotiate_t *obj)
|
||||
{
|
||||
int r = obj->trunnel_error_code_;
|
||||
obj->trunnel_error_code_ = 0;
|
||||
return r;
|
||||
}
|
||||
ssize_t
|
||||
circpad_negotiate_encode(uint8_t *output, const size_t avail, const circpad_negotiate_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
size_t written = 0;
|
||||
uint8_t *ptr = output;
|
||||
const char *msg;
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
const ssize_t encoded_len = circpad_negotiate_encoded_len(obj);
|
||||
#endif
|
||||
|
||||
if (NULL != (msg = circpad_negotiate_check(obj)))
|
||||
goto check_failed;
|
||||
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
#endif
|
||||
|
||||
/* Encode u8 version IN [0] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->version));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->command));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 machine_type */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->machine_type));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 echo_request IN [0, 1] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->echo_request));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
|
||||
trunnel_assert(ptr == output + written);
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
{
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
trunnel_assert((size_t)encoded_len == written);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return written;
|
||||
|
||||
truncated:
|
||||
result = -2;
|
||||
goto fail;
|
||||
check_failed:
|
||||
(void)msg;
|
||||
result = -1;
|
||||
goto fail;
|
||||
fail:
|
||||
trunnel_assert(result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** As circpad_negotiate_parse(), but do not allocate the output
|
||||
* object.
|
||||
*/
|
||||
static ssize_t
|
||||
circpad_negotiate_parse_into(circpad_negotiate_t *obj, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
const uint8_t *ptr = input;
|
||||
size_t remaining = len_in;
|
||||
ssize_t result = 0;
|
||||
(void)result;
|
||||
|
||||
/* Parse u8 version IN [0] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->version = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->version == 0))
|
||||
goto fail;
|
||||
|
||||
/* Parse u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->command = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->command == CIRCPAD_COMMAND_START || obj->command == CIRCPAD_COMMAND_STOP))
|
||||
goto fail;
|
||||
|
||||
/* Parse u8 machine_type */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->machine_type = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
|
||||
/* Parse u8 echo_request IN [0, 1] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->echo_request = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->echo_request == 0 || obj->echo_request == 1))
|
||||
goto fail;
|
||||
trunnel_assert(ptr + remaining == input + len_in);
|
||||
return len_in - remaining;
|
||||
|
||||
truncated:
|
||||
return -2;
|
||||
fail:
|
||||
result = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
circpad_negotiate_parse(circpad_negotiate_t **output, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
ssize_t result;
|
||||
*output = circpad_negotiate_new();
|
||||
if (NULL == *output)
|
||||
return -1;
|
||||
result = circpad_negotiate_parse_into(*output, input, len_in);
|
||||
if (result < 0) {
|
||||
circpad_negotiate_free(*output);
|
||||
*output = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
circpad_negotiated_t *
|
||||
circpad_negotiated_new(void)
|
||||
{
|
||||
circpad_negotiated_t *val = trunnel_calloc(1, sizeof(circpad_negotiated_t));
|
||||
if (NULL == val)
|
||||
return NULL;
|
||||
val->command = CIRCPAD_COMMAND_START;
|
||||
val->response = CIRCPAD_RESPONSE_ERR;
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Release all storage held inside 'obj', but do not free 'obj'.
|
||||
*/
|
||||
static void
|
||||
circpad_negotiated_clear(circpad_negotiated_t *obj)
|
||||
{
|
||||
(void) obj;
|
||||
}
|
||||
|
||||
void
|
||||
circpad_negotiated_free(circpad_negotiated_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
circpad_negotiated_clear(obj);
|
||||
trunnel_memwipe(obj, sizeof(circpad_negotiated_t));
|
||||
trunnel_free_(obj);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
circpad_negotiated_get_version(const circpad_negotiated_t *inp)
|
||||
{
|
||||
return inp->version;
|
||||
}
|
||||
int
|
||||
circpad_negotiated_set_version(circpad_negotiated_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == 0))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->version = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
circpad_negotiated_get_command(const circpad_negotiated_t *inp)
|
||||
{
|
||||
return inp->command;
|
||||
}
|
||||
int
|
||||
circpad_negotiated_set_command(circpad_negotiated_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == CIRCPAD_COMMAND_START || val == CIRCPAD_COMMAND_STOP))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->command = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
circpad_negotiated_get_response(const circpad_negotiated_t *inp)
|
||||
{
|
||||
return inp->response;
|
||||
}
|
||||
int
|
||||
circpad_negotiated_set_response(circpad_negotiated_t *inp, uint8_t val)
|
||||
{
|
||||
if (! ((val == CIRCPAD_RESPONSE_ERR || val == CIRCPAD_RESPONSE_OK))) {
|
||||
TRUNNEL_SET_ERROR_CODE(inp);
|
||||
return -1;
|
||||
}
|
||||
inp->response = val;
|
||||
return 0;
|
||||
}
|
||||
uint8_t
|
||||
circpad_negotiated_get_machine_type(const circpad_negotiated_t *inp)
|
||||
{
|
||||
return inp->machine_type;
|
||||
}
|
||||
int
|
||||
circpad_negotiated_set_machine_type(circpad_negotiated_t *inp, uint8_t val)
|
||||
{
|
||||
inp->machine_type = val;
|
||||
return 0;
|
||||
}
|
||||
const char *
|
||||
circpad_negotiated_check(const circpad_negotiated_t *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return "Object was NULL";
|
||||
if (obj->trunnel_error_code_)
|
||||
return "A set function failed on this object";
|
||||
if (! (obj->version == 0))
|
||||
return "Integer out of bounds";
|
||||
if (! (obj->command == CIRCPAD_COMMAND_START || obj->command == CIRCPAD_COMMAND_STOP))
|
||||
return "Integer out of bounds";
|
||||
if (! (obj->response == CIRCPAD_RESPONSE_ERR || obj->response == CIRCPAD_RESPONSE_OK))
|
||||
return "Integer out of bounds";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
circpad_negotiated_encoded_len(const circpad_negotiated_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
|
||||
if (NULL != circpad_negotiated_check(obj))
|
||||
return -1;
|
||||
|
||||
|
||||
/* Length of u8 version IN [0] */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP] */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 response IN [CIRCPAD_RESPONSE_ERR, CIRCPAD_RESPONSE_OK] */
|
||||
result += 1;
|
||||
|
||||
/* Length of u8 machine_type */
|
||||
result += 1;
|
||||
return result;
|
||||
}
|
||||
int
|
||||
circpad_negotiated_clear_errors(circpad_negotiated_t *obj)
|
||||
{
|
||||
int r = obj->trunnel_error_code_;
|
||||
obj->trunnel_error_code_ = 0;
|
||||
return r;
|
||||
}
|
||||
ssize_t
|
||||
circpad_negotiated_encode(uint8_t *output, const size_t avail, const circpad_negotiated_t *obj)
|
||||
{
|
||||
ssize_t result = 0;
|
||||
size_t written = 0;
|
||||
uint8_t *ptr = output;
|
||||
const char *msg;
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
const ssize_t encoded_len = circpad_negotiated_encoded_len(obj);
|
||||
#endif
|
||||
|
||||
if (NULL != (msg = circpad_negotiated_check(obj)))
|
||||
goto check_failed;
|
||||
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
#endif
|
||||
|
||||
/* Encode u8 version IN [0] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->version));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->command));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 response IN [CIRCPAD_RESPONSE_ERR, CIRCPAD_RESPONSE_OK] */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->response));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
/* Encode u8 machine_type */
|
||||
trunnel_assert(written <= avail);
|
||||
if (avail - written < 1)
|
||||
goto truncated;
|
||||
trunnel_set_uint8(ptr, (obj->machine_type));
|
||||
written += 1; ptr += 1;
|
||||
|
||||
|
||||
trunnel_assert(ptr == output + written);
|
||||
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||
{
|
||||
trunnel_assert(encoded_len >= 0);
|
||||
trunnel_assert((size_t)encoded_len == written);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return written;
|
||||
|
||||
truncated:
|
||||
result = -2;
|
||||
goto fail;
|
||||
check_failed:
|
||||
(void)msg;
|
||||
result = -1;
|
||||
goto fail;
|
||||
fail:
|
||||
trunnel_assert(result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** As circpad_negotiated_parse(), but do not allocate the output
|
||||
* object.
|
||||
*/
|
||||
static ssize_t
|
||||
circpad_negotiated_parse_into(circpad_negotiated_t *obj, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
const uint8_t *ptr = input;
|
||||
size_t remaining = len_in;
|
||||
ssize_t result = 0;
|
||||
(void)result;
|
||||
|
||||
/* Parse u8 version IN [0] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->version = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->version == 0))
|
||||
goto fail;
|
||||
|
||||
/* Parse u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->command = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->command == CIRCPAD_COMMAND_START || obj->command == CIRCPAD_COMMAND_STOP))
|
||||
goto fail;
|
||||
|
||||
/* Parse u8 response IN [CIRCPAD_RESPONSE_ERR, CIRCPAD_RESPONSE_OK] */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->response = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
if (! (obj->response == CIRCPAD_RESPONSE_ERR || obj->response == CIRCPAD_RESPONSE_OK))
|
||||
goto fail;
|
||||
|
||||
/* Parse u8 machine_type */
|
||||
CHECK_REMAINING(1, truncated);
|
||||
obj->machine_type = (trunnel_get_uint8(ptr));
|
||||
remaining -= 1; ptr += 1;
|
||||
trunnel_assert(ptr + remaining == input + len_in);
|
||||
return len_in - remaining;
|
||||
|
||||
truncated:
|
||||
return -2;
|
||||
fail:
|
||||
result = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
circpad_negotiated_parse(circpad_negotiated_t **output, const uint8_t *input, const size_t len_in)
|
||||
{
|
||||
ssize_t result;
|
||||
*output = circpad_negotiated_new();
|
||||
if (NULL == *output)
|
||||
return -1;
|
||||
result = circpad_negotiated_parse_into(*output, input, len_in);
|
||||
if (result < 0) {
|
||||
circpad_negotiated_free(*output);
|
||||
*output = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
195
src/trunnel/circpad_negotiation.h
Normal file
195
src/trunnel/circpad_negotiation.h
Normal file
@ -0,0 +1,195 @@
|
||||
/* circpad_negotiation.h -- generated by Trunnel v1.5.2.
|
||||
* https://gitweb.torproject.org/trunnel.git
|
||||
* You probably shouldn't edit this file.
|
||||
*/
|
||||
#ifndef TRUNNEL_CIRCPAD_NEGOTIATION_H
|
||||
#define TRUNNEL_CIRCPAD_NEGOTIATION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "trunnel.h"
|
||||
|
||||
#define CIRCPAD_COMMAND_STOP 1
|
||||
#define CIRCPAD_COMMAND_START 2
|
||||
#define CIRCPAD_RESPONSE_OK 1
|
||||
#define CIRCPAD_RESPONSE_ERR 2
|
||||
#define CIRCPAD_MACHINE_CIRC_SETUP 1
|
||||
/**
|
||||
* This command tells the relay to alter its min and max netflow
|
||||
* timeout range values, and send padding at that rate (resuming
|
||||
* if stopped). */
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CIRCPAD_NEGOTIATE)
|
||||
struct circpad_negotiate_st {
|
||||
uint8_t version;
|
||||
uint8_t command;
|
||||
/** Machine type is left unbounded because we can specify
|
||||
* new machines in the consensus */
|
||||
uint8_t machine_type;
|
||||
/** If true, send a relay_drop reply.. */
|
||||
uint8_t echo_request;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct circpad_negotiate_st circpad_negotiate_t;
|
||||
/**
|
||||
* This command tells the relay to alter its min and max netflow
|
||||
* timeout range values, and send padding at that rate (resuming
|
||||
* if stopped). */
|
||||
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CIRCPAD_NEGOTIATED)
|
||||
struct circpad_negotiated_st {
|
||||
uint8_t version;
|
||||
uint8_t command;
|
||||
uint8_t response;
|
||||
/** Machine type is left unbounded because we can specify
|
||||
* new machines in the consensus */
|
||||
uint8_t machine_type;
|
||||
uint8_t trunnel_error_code_;
|
||||
};
|
||||
#endif
|
||||
typedef struct circpad_negotiated_st circpad_negotiated_t;
|
||||
/** Return a newly allocated circpad_negotiate with all elements set
|
||||
* to zero.
|
||||
*/
|
||||
circpad_negotiate_t *circpad_negotiate_new(void);
|
||||
/** Release all storage held by the circpad_negotiate in 'victim'. (Do
|
||||
* nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void circpad_negotiate_free(circpad_negotiate_t *victim);
|
||||
/** Try to parse a circpad_negotiate from the buffer in 'input', using
|
||||
* up to 'len_in' bytes from the input buffer. On success, return the
|
||||
* number of bytes consumed and set *output to the newly allocated
|
||||
* circpad_negotiate_t. On failure, return -2 if the input appears
|
||||
* truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t circpad_negotiate_parse(circpad_negotiate_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* circpad_negotiate in 'obj'. On failure, return a negative value.
|
||||
* Note that this value may be an overestimate, and can even be an
|
||||
* underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t circpad_negotiate_encoded_len(const circpad_negotiate_t *obj);
|
||||
/** Try to encode the circpad_negotiate from 'input' into the buffer
|
||||
* at 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t circpad_negotiate_encode(uint8_t *output, size_t avail, const circpad_negotiate_t *input);
|
||||
/** Check whether the internal state of the circpad_negotiate in 'obj'
|
||||
* is consistent. Return NULL if it is, and a short message if it is
|
||||
* not.
|
||||
*/
|
||||
const char *circpad_negotiate_check(const circpad_negotiate_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int circpad_negotiate_clear_errors(circpad_negotiate_t *obj);
|
||||
/** Return the value of the version field of the circpad_negotiate_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiate_get_version(const circpad_negotiate_t *inp);
|
||||
/** Set the value of the version field of the circpad_negotiate_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiate_set_version(circpad_negotiate_t *inp, uint8_t val);
|
||||
/** Return the value of the command field of the circpad_negotiate_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiate_get_command(const circpad_negotiate_t *inp);
|
||||
/** Set the value of the command field of the circpad_negotiate_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiate_set_command(circpad_negotiate_t *inp, uint8_t val);
|
||||
/** Return the value of the machine_type field of the
|
||||
* circpad_negotiate_t in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiate_get_machine_type(const circpad_negotiate_t *inp);
|
||||
/** Set the value of the machine_type field of the circpad_negotiate_t
|
||||
* in 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiate_set_machine_type(circpad_negotiate_t *inp, uint8_t val);
|
||||
/** Return the value of the echo_request field of the
|
||||
* circpad_negotiate_t in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiate_get_echo_request(const circpad_negotiate_t *inp);
|
||||
/** Set the value of the echo_request field of the circpad_negotiate_t
|
||||
* in 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiate_set_echo_request(circpad_negotiate_t *inp, uint8_t val);
|
||||
/** Return a newly allocated circpad_negotiated with all elements set
|
||||
* to zero.
|
||||
*/
|
||||
circpad_negotiated_t *circpad_negotiated_new(void);
|
||||
/** Release all storage held by the circpad_negotiated in 'victim'.
|
||||
* (Do nothing if 'victim' is NULL.)
|
||||
*/
|
||||
void circpad_negotiated_free(circpad_negotiated_t *victim);
|
||||
/** Try to parse a circpad_negotiated from the buffer in 'input',
|
||||
* using up to 'len_in' bytes from the input buffer. On success,
|
||||
* return the number of bytes consumed and set *output to the newly
|
||||
* allocated circpad_negotiated_t. On failure, return -2 if the input
|
||||
* appears truncated, and -1 if the input is otherwise invalid.
|
||||
*/
|
||||
ssize_t circpad_negotiated_parse(circpad_negotiated_t **output, const uint8_t *input, const size_t len_in);
|
||||
/** Return the number of bytes we expect to need to encode the
|
||||
* circpad_negotiated in 'obj'. On failure, return a negative value.
|
||||
* Note that this value may be an overestimate, and can even be an
|
||||
* underestimate for certain unencodeable objects.
|
||||
*/
|
||||
ssize_t circpad_negotiated_encoded_len(const circpad_negotiated_t *obj);
|
||||
/** Try to encode the circpad_negotiated from 'input' into the buffer
|
||||
* at 'output', using up to 'avail' bytes of the output buffer. On
|
||||
* success, return the number of bytes used. On failure, return -2 if
|
||||
* the buffer was not long enough, and -1 if the input was invalid.
|
||||
*/
|
||||
ssize_t circpad_negotiated_encode(uint8_t *output, size_t avail, const circpad_negotiated_t *input);
|
||||
/** Check whether the internal state of the circpad_negotiated in
|
||||
* 'obj' is consistent. Return NULL if it is, and a short message if
|
||||
* it is not.
|
||||
*/
|
||||
const char *circpad_negotiated_check(const circpad_negotiated_t *obj);
|
||||
/** Clear any errors that were set on the object 'obj' by its setter
|
||||
* functions. Return true iff errors were cleared.
|
||||
*/
|
||||
int circpad_negotiated_clear_errors(circpad_negotiated_t *obj);
|
||||
/** Return the value of the version field of the circpad_negotiated_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiated_get_version(const circpad_negotiated_t *inp);
|
||||
/** Set the value of the version field of the circpad_negotiated_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiated_set_version(circpad_negotiated_t *inp, uint8_t val);
|
||||
/** Return the value of the command field of the circpad_negotiated_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiated_get_command(const circpad_negotiated_t *inp);
|
||||
/** Set the value of the command field of the circpad_negotiated_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiated_set_command(circpad_negotiated_t *inp, uint8_t val);
|
||||
/** Return the value of the response field of the circpad_negotiated_t
|
||||
* in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiated_get_response(const circpad_negotiated_t *inp);
|
||||
/** Set the value of the response field of the circpad_negotiated_t in
|
||||
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||
* code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiated_set_response(circpad_negotiated_t *inp, uint8_t val);
|
||||
/** Return the value of the machine_type field of the
|
||||
* circpad_negotiated_t in 'inp'
|
||||
*/
|
||||
uint8_t circpad_negotiated_get_machine_type(const circpad_negotiated_t *inp);
|
||||
/** Set the value of the machine_type field of the
|
||||
* circpad_negotiated_t in 'inp' to 'val'. Return 0 on success; return
|
||||
* -1 and set the error code on 'inp' on failure.
|
||||
*/
|
||||
int circpad_negotiated_set_machine_type(circpad_negotiated_t *inp, uint8_t val);
|
||||
|
||||
|
||||
#endif
|
44
src/trunnel/circpad_negotiation.trunnel
Normal file
44
src/trunnel/circpad_negotiation.trunnel
Normal file
@ -0,0 +1,44 @@
|
||||
/* These are the padding negotiation commands */
|
||||
const CIRCPAD_COMMAND_STOP = 1;
|
||||
const CIRCPAD_COMMAND_START = 2;
|
||||
|
||||
/* Responses to commands */
|
||||
const CIRCPAD_RESPONSE_OK = 1;
|
||||
const CIRCPAD_RESPONSE_ERR = 2;
|
||||
|
||||
/* Built-in machine types */
|
||||
|
||||
/* 1) Machine that obscures circuit setup */
|
||||
const CIRCPAD_MACHINE_CIRC_SETUP = 1;
|
||||
|
||||
/**
|
||||
* This command tells the relay to alter its min and max netflow
|
||||
* timeout range values, and send padding at that rate (resuming
|
||||
* if stopped). */
|
||||
struct circpad_negotiate {
|
||||
u8 version IN [0];
|
||||
u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP];
|
||||
|
||||
/** Machine type is left unbounded because we can specify
|
||||
* new machines in the consensus */
|
||||
u8 machine_type;
|
||||
|
||||
/** If true, send a relay_drop reply.. */
|
||||
// FIXME-MP-AP: Maybe we just say to transition to the first state
|
||||
// here instead.. Also what about delay before responding?
|
||||
u8 echo_request IN [0,1];
|
||||
};
|
||||
|
||||
/**
|
||||
* This command tells the relay to alter its min and max netflow
|
||||
* timeout range values, and send padding at that rate (resuming
|
||||
* if stopped). */
|
||||
struct circpad_negotiated {
|
||||
u8 version IN [0];
|
||||
u8 command IN [CIRCPAD_COMMAND_START, CIRCPAD_COMMAND_STOP];
|
||||
u8 response IN [CIRCPAD_RESPONSE_OK, CIRCPAD_RESPONSE_ERR];
|
||||
|
||||
/** Machine type is left unbounded because we can specify
|
||||
* new machines in the consensus */
|
||||
u8 machine_type;
|
||||
};
|
@ -11,7 +11,8 @@ TRUNNELINPUTS = \
|
||||
src/trunnel/link_handshake.trunnel \
|
||||
src/trunnel/pwbox.trunnel \
|
||||
src/trunnel/channelpadding_negotiation.trunnel \
|
||||
src/trunner/socks5.trunnel
|
||||
src/trunnel/socks5.trunnel \
|
||||
src/trunnel/circpad_negotiation.trunnel
|
||||
|
||||
TRUNNELSOURCES = \
|
||||
src/ext/trunnel/trunnel.c \
|
||||
@ -23,8 +24,9 @@ TRUNNELSOURCES = \
|
||||
src/trunnel/hs/cell_introduce1.c \
|
||||
src/trunnel/hs/cell_rendezvous.c \
|
||||
src/trunnel/channelpadding_negotiation.c \
|
||||
src/trunnel/socks5.c \
|
||||
src/trunnel/netinfo.c
|
||||
src/trunnel/socks5.c \
|
||||
src/trunnel/netinfo.c \
|
||||
src/trunnel/circpad_negotiation.c
|
||||
|
||||
TRUNNELHEADERS = \
|
||||
src/ext/trunnel/trunnel.h \
|
||||
@ -39,7 +41,8 @@ TRUNNELHEADERS = \
|
||||
src/trunnel/hs/cell_rendezvous.h \
|
||||
src/trunnel/channelpadding_negotiation.h \
|
||||
src/trunnel/socks5.h \
|
||||
src/trunnel/netinfo.h
|
||||
src/trunnel/netinfo.h \
|
||||
src/trunnel/circpad_negotiation.h
|
||||
|
||||
src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES)
|
||||
src_trunnel_libor_trunnel_a_CPPFLAGS = \
|
||||
|
Loading…
Reference in New Issue
Block a user