Add controller getinfo exit-policy/reject-private

exit-policy/reject-private lists the reject rules added by
ExitPolicyRejectPrivate. This makes it easier for stem to
display exit policies.

Add unit tests for getinfo exit-policy/*.

Completes ticket #17183. Patch by "teor".
This commit is contained in:
teor (Tim Wilson-Brown) 2015-11-16 20:40:17 +11:00 committed by Nick Mathewson
parent 6913bdfcc5
commit 10a6390deb
5 changed files with 425 additions and 227 deletions

View File

@ -0,0 +1,6 @@
o Minor features (exit policies, controllers):
- Add controller getinfo exit-policy/reject-private/[default,relay]
for the reject rules added by ExitPolicyRejectPrivate. This makes
it easier for stem to display exit policies.
- Add unit tests for getinfo exit-policy/*.
Completes ticket #17183. Patch by "teor".

View File

@ -2562,6 +2562,12 @@ static const getinfo_item_t getinfo_items[] = {
"v3 Networkstatus consensus as retrieved from a DirPort."),
ITEM("exit-policy/default", policies,
"The default value appended to the configured exit policy."),
ITEM("exit-policy/reject-private/default", policies,
"The default rules appended to the configured exit policy by"
" ExitPolicyRejectPrivate."),
ITEM("exit-policy/reject-private/relay", policies,
"The relay-specific rules appended to the configured exit policy by"
" ExitPolicyRejectPrivate."),
ITEM("exit-policy/full", policies, "The entire exit policy of onion router"),
ITEM("exit-policy/ipv4", policies, "IPv4 parts of exit policy"),
ITEM("exit-policy/ipv6", policies, "IPv6 parts of exit policy"),

View File

@ -63,17 +63,14 @@ static const char *private_nets[] = {
};
static int policies_parse_exit_policy_internal(
config_line_t *cfg,
smartlist_t **dest,
int ipv6_exit,
int rejectprivate,
uint32_t local_address,
const tor_addr_t *ipv6_local_address,
const tor_addr_t *ipv4_outbound_address,
const tor_addr_t *ipv6_outbound_address,
int reject_interface_addresses,
int reject_configured_port_addresses,
int add_default_policy);
config_line_t *cfg,
smartlist_t **dest,
int ipv6_exit,
int rejectprivate,
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses,
int add_default_policy);
/** Replace all "private" entries in *<b>policy</b> with their expanded
* equivalents. */
@ -868,7 +865,7 @@ addr_policy_intersects(addr_policy_t *a, addr_policy_t *b)
/** Add the exit policy described by <b>more</b> to <b>policy</b>.
*/
static void
STATIC void
append_exit_policy_string(smartlist_t **policy, const char *more)
{
config_line_t tmp;
@ -885,6 +882,9 @@ append_exit_policy_string(smartlist_t **policy, const char *more)
void
addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr)
{
tor_assert(dest);
tor_assert(addr);
addr_policy_t p, *add;
memset(&p, 0, sizeof(p));
p.policy_type = ADDR_POLICY_REJECT;
@ -902,17 +902,68 @@ addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr)
}
/* Is addr public for the purposes of rejection? */
static int
tor_addr_is_public_for_reject(const tor_addr_t *addr)
{
return !tor_addr_is_null(addr) && !tor_addr_is_internal(addr, 0);
}
/* Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed.
* Filter the address, only adding an IPv4 reject rule if ipv4_rules
* is true, and similarly for ipv6_rules. Check each address returns true for
* tor_addr_is_public_for_reject before adding it.
*/
static void
addr_policy_append_reject_addr_filter(smartlist_t **dest,
const tor_addr_t *addr,
int ipv4_rules,
int ipv6_rules)
{
tor_assert(dest);
tor_assert(addr);
/* Only reject IP addresses which are public */
if (tor_addr_is_public_for_reject(addr)) {
/* Reject IPv4 addresses and IPv6 addresses based on the filters */
int is_ipv4 = tor_addr_is_v4(addr);
if ((is_ipv4 && ipv4_rules) || (!is_ipv4 && ipv6_rules)) {
addr_policy_append_reject_addr(dest, addr);
}
}
}
/** Add "reject addr:*" to <b>dest</b>, for each addr in addrs, creating the
* list as needed. */
void
addr_policy_append_reject_addr_list(smartlist_t **dest,
const smartlist_t *addrs)
{
tor_assert(dest);
tor_assert(addrs);
SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, addr) {
addr_policy_append_reject_addr(dest, addr);
} SMARTLIST_FOREACH_END(addr);
}
/** Add "reject addr:*" to <b>dest</b>, for each addr in addrs, creating the
* list as needed. Filter using */
static void
addr_policy_append_reject_addr_list_filter(smartlist_t **dest,
const smartlist_t *addrs,
int ipv4_rules,
int ipv6_rules)
{
tor_assert(dest);
tor_assert(addrs);
SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, addr) {
addr_policy_append_reject_addr_filter(dest, addr, ipv4_rules, ipv6_rules);
} SMARTLIST_FOREACH_END(addr);
}
/** Detect and excise "dead code" from the policy *<b>dest</b>. */
static void
exit_policy_remove_redundancies(smartlist_t *dest)
@ -997,21 +1048,12 @@ exit_policy_remove_redundancies(smartlist_t *dest)
}
}
/* Is addr public for the purposes of rejection? */
static int
tor_addr_is_public_for_reject(const tor_addr_t *addr)
{
return !tor_addr_is_null(addr) && !tor_addr_is_internal(addr, 0);
}
/** Reject private helper for policies_parse_exit_policy_internal: rejects
* publicly routable addresses on this exit relay.
*
* Add reject entries to the linked list *dest:
* - if local_address is non-zero, treat it as a host-order IPv4 address,
* and add an entry that rejects it as a destination.
* - if ipv6_local_address, ipv4_outbound_address, or ipv6_outbound_address
* are non-NULL, add entries that reject them as destinations.
* - if configured_addresses is non-NULL, add entries that reject each
* tor_addr_t* in the list as a destination.
* - if reject_interface_addresses is true, add entries that reject each
* public IPv4 and IPv6 address of each interface on this machine.
* - if reject_configured_port_addresses is true, add entries that reject
@ -1027,60 +1069,16 @@ void
policies_parse_exit_policy_reject_private(
smartlist_t **dest,
int ipv6_exit,
uint32_t local_address,
const tor_addr_t *ipv6_local_address,
const tor_addr_t *ipv4_outbound_address,
const tor_addr_t *ipv6_outbound_address,
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses)
{
tor_assert(dest);
/* Reject our local IPv4 address */
if (local_address) {
tor_addr_t v4_local;
tor_addr_from_ipv4h(&v4_local, local_address);
if (tor_addr_is_public_for_reject(&v4_local)) {
addr_policy_append_reject_addr(dest, &v4_local);
log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject %s:*' for our "
"published IPv4 address", fmt_addr32(local_address));
}
}
/* Reject the outbound IPv4 connection address */
if (ipv4_outbound_address
&& tor_addr_is_public_for_reject(ipv4_outbound_address)) {
addr_policy_append_reject_addr(dest, ipv4_outbound_address);
log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject %s:*' for "
"our outbound IPv4 connection address",
fmt_addr(ipv4_outbound_address));
}
/* If we're not an IPv6 exit, all IPv6 addresses have already been rejected
* by policies_parse_exit_policy_internal */
if (ipv6_exit) {
/* Reject our local IPv6 address */
if (ipv6_local_address != NULL
&& tor_addr_is_public_for_reject(ipv6_local_address)) {
if (tor_addr_is_v4(ipv6_local_address)) {
log_warn(LD_CONFIG, "IPv4 address '%s' provided as our IPv6 local "
"address", fmt_addr(ipv6_local_address));
} else {
addr_policy_append_reject_addr(dest, ipv6_local_address);
log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject [%s]:*' for "
"our published IPv6 address", fmt_addr(ipv6_local_address));
}
}
/* Reject the outbound IPv6 connection address */
if (ipv6_outbound_address
&& tor_addr_is_public_for_reject(ipv6_outbound_address)) {
addr_policy_append_reject_addr(dest, ipv6_outbound_address);
log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject [%s]:*' for "
"our outbound IPv6 connection address",
fmt_addr(ipv6_outbound_address));
}
/* Reject configured addresses, if they are from public netblocks. */
if (configured_addresses) {
addr_policy_append_reject_addr_list_filter(dest, configured_addresses,
1, ipv6_exit);
}
/* Reject configured port addresses, if they are from public netblocks. */
@ -1089,14 +1087,9 @@ policies_parse_exit_policy_reject_private(
SMARTLIST_FOREACH_BEGIN(port_addrs, port_cfg_t *, port) {
/* Only reject IP addresses which are public */
if (!port->is_unix_addr && tor_addr_is_public_for_reject(&port->addr)) {
/* Reject IPv4 addresses. If we are an IPv6 exit, also reject IPv6
* addresses */
if (tor_addr_is_v4(&port->addr) || ipv6_exit) {
addr_policy_append_reject_addr(dest, &port->addr);
}
/* Only reject port IP addresses, not port unix sockets */
if (!port->is_unix_addr) {
addr_policy_append_reject_addr_filter(dest, &port->addr, 1, ipv6_exit);
}
} SMARTLIST_FOREACH_END(port);
}
@ -1107,13 +1100,14 @@ policies_parse_exit_policy_reject_private(
/* Reject public IPv4 addresses on any interface */
public_addresses = get_interface_address6_list(LOG_INFO, AF_INET, 0);
addr_policy_append_reject_addr_list(dest, public_addresses);
addr_policy_append_reject_addr_list_filter(dest, public_addresses, 1, 0);
free_interface_address6_list(public_addresses);
/* Don't look for IPv6 addresses if we're configured as IPv4-only */
if (ipv6_exit) {
/* Reject public IPv6 addresses on any interface */
public_addresses = get_interface_address6_list(LOG_INFO, AF_INET6, 0);
addr_policy_append_reject_addr_list(dest, public_addresses);
addr_policy_append_reject_addr_list_filter(dest, public_addresses, 0, 1);
free_interface_address6_list(public_addresses);
}
}
@ -1149,13 +1143,11 @@ policies_parse_exit_policy_reject_private(
* see router_add_exit_policy.
*/
static int
policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest,
policies_parse_exit_policy_internal(config_line_t *cfg,
smartlist_t **dest,
int ipv6_exit,
int rejectprivate,
uint32_t local_address,
const tor_addr_t *ipv6_local_address,
const tor_addr_t *ipv4_outbound_address,
const tor_addr_t *ipv6_outbound_address,
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses,
int add_default_policy)
@ -1168,10 +1160,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest,
append_exit_policy_string(dest, "reject private:*");
/* Reject IPv4 and IPv6 publicly routable addresses on this exit relay */
policies_parse_exit_policy_reject_private(
dest, ipv6_exit, local_address,
ipv6_local_address,
ipv4_outbound_address,
ipv6_outbound_address,
dest, ipv6_exit,
configured_addresses,
reject_interface_addresses,
reject_configured_port_addresses);
}
@ -1256,12 +1246,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest,
* If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>:
* - prepend an entry that rejects all destinations in all netblocks
* reserved for private use.
* - if local_address is non-zero, treat it as a host-order IPv4 address,
* and prepend an entry that rejects it as a destination.
* - if ipv6_local_address is non-NULL, prepend an entry that rejects it as
* a destination.
* - if reject_interface_addresses is true, prepend entries that reject each
* public IPv4 and IPv6 address of each interface on this machine.
* - prepend entries that reject publicly routable addresses on this exit
* relay by calling policies_parse_exit_policy_internal
*
* If <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set in <b>options</b>, append
* default exit policy entries to <b>result</b> smartlist.
@ -1269,10 +1255,7 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest,
int
policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
exit_policy_parser_cfg_t options,
uint32_t local_address,
const tor_addr_t *ipv6_local_address,
const tor_addr_t *ipv4_outbound_address,
const tor_addr_t *ipv6_outbound_address)
const smartlist_t *configured_addresses)
{
int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0;
int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0;
@ -1280,15 +1263,51 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled,
reject_private,
local_address,
ipv6_local_address,
ipv4_outbound_address,
ipv6_outbound_address,
configured_addresses,
reject_private,
reject_private,
add_default);
}
/** Helper function that adds addr to a smartlist as long as it is non-NULL
* and not tor_addr_is_null(). */
static void
policies_add_addr_to_smartlist(smartlist_t *addr_list, const tor_addr_t *addr)
{
if (addr && !tor_addr_is_null(addr)) {
smartlist_add(addr_list, (void *)addr);
}
}
/** Helper function that adds ipv4h_addr to a smartlist as a tor_addr_t *,
* by converting it to a tor_addr_t and passing it to
* policies_add_addr_to_smartlist. */
static void
policies_add_ipv4h_to_smartlist(smartlist_t *addr_list, uint32_t ipv4h_addr)
{
if (ipv4h_addr) {
tor_addr_t ipv4_tor_addr;
tor_addr_from_ipv4h(&ipv4_tor_addr, ipv4h_addr);
policies_add_addr_to_smartlist(addr_list, (void *)&ipv4_tor_addr);
}
}
/** Helper function that adds or_options->OutboundBindAddressIPv[4|6]_ to a
* smartlist as a tor_addr_t *, as long as or_options is non-NULL,
* by passing them to policies_add_addr_to_smartlist. */
static void
policies_add_outbound_addresses_to_smartlist(smartlist_t *addr_list,
const or_options_t *or_options)
{
if (or_options) {
policies_add_addr_to_smartlist(addr_list,
&or_options->OutboundBindAddressIPv4_);
policies_add_addr_to_smartlist(addr_list,
&or_options->OutboundBindAddressIPv6_);
}
}
/** Parse <b>ExitPolicy</b> member of <b>or_options</b> into <b>result</b>
* smartlist.
* If <b>or_options->IPv6Exit</b> is false, prepend an entry that
@ -1298,11 +1317,13 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
* - prepend an entry that rejects all destinations in all netblocks reserved
* for private use.
* - if local_address is non-zero, treat it as a host-order IPv4 address, and
* prepend an entry that rejects it as a destination.
* - if ipv6_local_address is non-NULL, prepend an entry that rejects it as a
* destination.
* - if reject_interface_addresses is true, prepend entries that reject each
* public IPv4 and IPv6 address of each interface on this machine.
* add it to the list of configured addresses.
* - if ipv6_local_address is non-NULL, and not the null tor_addr_t, add it
* to the list of configured addresses.
* - if or_options->OutboundBindAddressIPv4_ is not the null tor_addr_t, add
* it to the list of configured addresses.
* - if or_options->OutboundBindAddressIPv6_ is not the null tor_addr_t, add
* it to the list of configured addresses.
*
* If <b>or_options->BridgeRelay</b> is false, append entries of default
* Tor exit policy into <b>result</b> smartlist.
@ -1317,13 +1338,17 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options,
smartlist_t **result)
{
exit_policy_parser_cfg_t parser_cfg = 0;
smartlist_t *configured_addresses = smartlist_new();
int rv = 0;
/* Short-circuit for non-exit relays */
if (or_options->ExitRelay == 0) {
append_exit_policy_string(result, "reject *4:*");
append_exit_policy_string(result, "reject *6:*");
return 0;
}
/* Configure the parser */
if (or_options->IPv6Exit) {
parser_cfg |= EXIT_POLICY_IPV6_ENABLED;
}
@ -1336,11 +1361,20 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options,
parser_cfg |= EXIT_POLICY_ADD_DEFAULT;
}
return policies_parse_exit_policy(or_options->ExitPolicy,result,
parser_cfg,local_address,
ipv6_local_address,
&or_options->OutboundBindAddressIPv4_,
&or_options->OutboundBindAddressIPv6_);
/* Add the configured addresses to the tor_addr_t* list */
policies_add_ipv4h_to_smartlist(configured_addresses, local_address);
policies_add_addr_to_smartlist(configured_addresses, ipv6_local_address);
policies_add_outbound_addresses_to_smartlist(configured_addresses,
or_options);
rv = policies_parse_exit_policy(or_options->ExitPolicy, result, parser_cfg,
configured_addresses);
/* We don't need to free the pointers in this list, they are either constant
* or locally scoped. */
smartlist_free(configured_addresses);
return rv;
}
/** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating
@ -2085,6 +2119,49 @@ getinfo_helper_policies(control_connection_t *conn,
(void) errmsg;
if (!strcmp(question, "exit-policy/default")) {
*answer = tor_strdup(DEFAULT_EXIT_POLICY);
} else if (!strcmp(question, "exit-policy/reject-private/default")) {
smartlist_t *private_policy_strings;
const char **priv = private_nets;
private_policy_strings = smartlist_new();
while (*priv != NULL) {
/* IPv6 addresses are in "[]" and contain ":",
* IPv4 addresses are not in "[]" and contain "." */
smartlist_add_asprintf(private_policy_strings, "reject %s:*", *priv);
priv++;
}
*answer = smartlist_join_strings(private_policy_strings,
",", 0, NULL);
SMARTLIST_FOREACH(private_policy_strings, char *, str, tor_free(str));
smartlist_free(private_policy_strings);
} else if (!strcmp(question, "exit-policy/reject-private/relay")) {
const or_options_t *options = get_options();
const routerinfo_t *me = router_get_my_routerinfo();
smartlist_t *private_policy_list = smartlist_new();
smartlist_t *configured_addresses = smartlist_new();
if (!me) {
*errmsg = "router_get_my_routerinfo returned NULL";
return -1;
}
/* Add the configured addresses to the tor_addr_t* list */
policies_add_ipv4h_to_smartlist(configured_addresses, me->addr);
policies_add_addr_to_smartlist(configured_addresses, &me->ipv6_addr);
policies_add_outbound_addresses_to_smartlist(configured_addresses,
options);
policies_parse_exit_policy_reject_private(
&private_policy_list,
options->IPv6Exit,
configured_addresses,
1, 1);
*answer = policy_dump_to_string(private_policy_list, 1, 1);
addr_policy_list_free(private_policy_list);
} else if (!strcmpstart(question, "exit-policy/")) {
const routerinfo_t *me = router_get_my_routerinfo();

View File

@ -44,7 +44,6 @@ addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
int cmp_addr_policies(smartlist_t *a, smartlist_t *b);
MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
(const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
uint16_t port, const node_t *node);
@ -55,17 +54,11 @@ int policies_parse_exit_policy_from_options(
smartlist_t **result);
int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
exit_policy_parser_cfg_t options,
uint32_t local_address,
const tor_addr_t *ipv6_local_address,
const tor_addr_t *ipv4_outbound_address,
const tor_addr_t *ipv6_outbound_address);
const smartlist_t *configured_addresses);
void policies_parse_exit_policy_reject_private(
smartlist_t **dest,
int ipv6_exit,
uint32_t local_address,
const tor_addr_t *ipv6_local_address,
const tor_addr_t *ipv4_outbound_address,
const tor_addr_t *ipv6_outbound_address,
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses);
void policies_exit_policy_append_reject_star(smartlist_t **dest);
@ -99,5 +92,9 @@ addr_policy_result_t compare_tor_addr_to_short_policy(
const tor_addr_t *addr, uint16_t port,
const short_policy_t *policy);
#ifdef POLICIES_PRIVATE
void append_exit_policy_string(smartlist_t **policy, const char *more);
#endif
#endif

View File

@ -6,6 +6,7 @@
#include "config.h"
#include "router.h"
#include "routerparse.h"
#define POLICIES_PRIVATE
#include "policies.h"
#include "test.h"
@ -51,7 +52,7 @@ test_policy_summary_helper(const char *policy_str,
r = policies_parse_exit_policy(&line, &policy,
EXIT_POLICY_IPV6_ENABLED |
EXIT_POLICY_ADD_DEFAULT, 0, NULL, NULL, NULL);
EXIT_POLICY_ADD_DEFAULT, NULL);
tt_int_op(r,OP_EQ, 0);
summary = policy_summarize(policy, AF_INET);
@ -82,7 +83,8 @@ test_policies_general(void *arg)
*policy7 = NULL, *policy8 = NULL, *policy9 = NULL,
*policy10 = NULL, *policy11 = NULL, *policy12 = NULL;
addr_policy_t *p;
tor_addr_t tar;
tor_addr_t tar, tar2;
smartlist_t *addr_list = NULL;
config_line_t line;
smartlist_t *sm = NULL;
char *policy_str = NULL;
@ -117,18 +119,22 @@ test_policies_general(void *arg)
tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy2,
EXIT_POLICY_IPV6_ENABLED |
EXIT_POLICY_REJECT_PRIVATE |
EXIT_POLICY_ADD_DEFAULT, 0,
NULL, NULL, NULL));
EXIT_POLICY_ADD_DEFAULT, NULL));
tt_assert(policy2);
tor_addr_parse(&tar, "[2000::1234]");
tor_addr_from_ipv4h(&tar, 0x0306090cu);
tor_addr_parse(&tar2, "[2000::1234]");
addr_list = smartlist_new();
smartlist_add(addr_list, &tar);
smartlist_add(addr_list, &tar2);
tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy12,
EXIT_POLICY_IPV6_ENABLED |
EXIT_POLICY_REJECT_PRIVATE |
EXIT_POLICY_ADD_DEFAULT,
0x0306090cu, &tar, NULL,
NULL));
addr_list));
smartlist_free(addr_list);
addr_list = NULL;
tt_assert(policy12);
@ -209,15 +215,15 @@ test_policies_general(void *arg)
tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy8,
EXIT_POLICY_IPV6_ENABLED |
EXIT_POLICY_REJECT_PRIVATE |
EXIT_POLICY_ADD_DEFAULT, 0,
NULL, NULL, NULL));
EXIT_POLICY_ADD_DEFAULT,
NULL));
tt_assert(policy8);
tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy9,
EXIT_POLICY_REJECT_PRIVATE |
EXIT_POLICY_ADD_DEFAULT, 0,
NULL, NULL, NULL));
EXIT_POLICY_ADD_DEFAULT,
NULL));
tt_assert(policy9);
@ -271,8 +277,7 @@ test_policies_general(void *arg)
line.next = NULL;
tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy,
EXIT_POLICY_IPV6_ENABLED |
EXIT_POLICY_ADD_DEFAULT, 0,
NULL, NULL, NULL));
EXIT_POLICY_ADD_DEFAULT, NULL));
tt_assert(policy);
//test_streq(policy->string, "accept *:80");
@ -523,118 +528,82 @@ static void
test_policies_reject_exit_address(void *arg)
{
smartlist_t *policy = NULL;
tor_addr_t ipv4_addr;
tor_addr_t ipv6_addr;
tor_addr_t ipv4_addr, ipv6_addr;
smartlist_t *ipv4_list, *ipv6_list, *both_list, *dupl_list;
(void)arg;
tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
/* test that local_address is interpreted as an IPv4 host-order address and
* rejected on an IPv4-only exit */
policies_parse_exit_policy_reject_private(&policy, 0, TEST_IPV4_ADDR, NULL,
NULL, NULL, 0, 0);
ipv4_list = smartlist_new();
ipv6_list = smartlist_new();
both_list = smartlist_new();
dupl_list = smartlist_new();
smartlist_add(ipv4_list, &ipv4_addr);
smartlist_add(both_list, &ipv4_addr);
smartlist_add(dupl_list, &ipv4_addr);
smartlist_add(dupl_list, &ipv4_addr);
smartlist_add(dupl_list, &ipv4_addr);
smartlist_add(ipv6_list, &ipv6_addr);
smartlist_add(both_list, &ipv6_addr);
smartlist_add(dupl_list, &ipv6_addr);
smartlist_add(dupl_list, &ipv6_addr);
/* IPv4-Only Exits */
/* test that IPv4 addresses are rejected on an IPv4-only exit */
policies_parse_exit_policy_reject_private(&policy, 0, ipv4_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that local_address is interpreted as an IPv4 host-order address and
* rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, TEST_IPV4_ADDR, NULL,
NULL, NULL, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that ipv6_local_address is rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, 0, &ipv6_addr, NULL,
NULL, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv6_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that ipv6_local_address is NOT rejected on an IPv4-only exit
/* test that IPv6 addresses are NOT rejected on an IPv4-only exit
* (all IPv6 addresses are rejected by policies_parse_exit_policy_internal
* on IPv4-only exits, so policies_parse_exit_policy_reject_private doesn't
* need to do anything) */
policies_parse_exit_policy_reject_private(&policy, 0, 0, &ipv6_addr, NULL,
NULL, 0, 0);
policies_parse_exit_policy_reject_private(&policy, 0, ipv6_list, 0, 0);
tt_assert(policy == NULL);
done:
addr_policy_list_free(policy);
}
/** Run unit tests for rejecting outbound connection addresses on this
* exit relay using policies_parse_exit_policy_reject_private */
static void
test_policies_reject_outbound_address(void *arg)
{
smartlist_t *policy = NULL;
tor_addr_t ipv4_addr, ipv6_addr;
(void)arg;
tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
/* test that OutboundBindAddressIPv4_ is rejected on an IPv4-only exit */
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, &ipv4_addr,
NULL, 0, 0);
/* test that only IPv4 addresses are rejected on an IPv4-only exit */
policies_parse_exit_policy_reject_private(&policy, 0, both_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that OutboundBindAddressIPv4_ is rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, &ipv4_addr,
NULL, 0, 0);
/* Test that lists with duplicate entries produce the same results */
policies_parse_exit_policy_reject_private(&policy, 0, dupl_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that OutboundBindAddressIPv6_ is rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, NULL,
&ipv6_addr, 0, 0);
/* IPv4/IPv6 Exits */
/* test that IPv4 addresses are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, ipv4_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that IPv6 addresses are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, ipv6_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv6_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that OutboundBindAddressIPv6_ is NOT rejected on an IPv4-only exit
* (all IPv6 addresses are rejected by policies_parse_exit_policy_internal
* on IPv4-only exits, so policies_parse_exit_policy_reject_private doesn't
* need to do anything with IPv6 addresses on IPv4-only exits) */
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL,
&ipv6_addr, 0, 0);
tt_assert(policy == NULL);
/* test that OutboundBindAddressIPv4_ is rejected on an IPv4-only exit,
* but OutboundBindAddressIPv6_ is NOT rejected (all IPv6 addresses are
* rejected by policies_parse_exit_policy_internal on IPv4-only exits, so
* policies_parse_exit_policy_reject_private doesn't need to do anything
* with IPv6 addresses on IPv4-only exits) */
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, &ipv4_addr,
&ipv6_addr, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
/* test that OutboundBindAddressIPv4_ and OutboundBindAddressIPv6_ are
* rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, &ipv4_addr,
&ipv6_addr, 0, 0);
/* test that IPv4 and IPv6 addresses are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, both_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 2);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
@ -642,8 +611,21 @@ test_policies_reject_outbound_address(void *arg)
addr_policy_list_free(policy);
policy = NULL;
done:
/* Test that lists with duplicate entries produce the same results */
policies_parse_exit_policy_reject_private(&policy, 1, dupl_list, 0, 0);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 2);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
tt_assert(test_policy_has_address_helper(policy, &ipv6_addr));
addr_policy_list_free(policy);
policy = NULL;
done:
addr_policy_list_free(policy);
smartlist_free(ipv4_list);
smartlist_free(ipv6_list);
smartlist_free(both_list);
smartlist_free(dupl_list);
}
static smartlist_t *test_configured_ports = NULL;
@ -683,8 +665,7 @@ test_policies_reject_port_address(void *arg)
* policies_parse_exit_policy_internal on IPv4-only exits, so
* policies_parse_exit_policy_reject_private doesn't need to do anything
* with IPv6 addresses on IPv4-only exits) */
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL,
0, 1);
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 1);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr));
@ -692,8 +673,7 @@ test_policies_reject_port_address(void *arg)
policy = NULL;
/* test that IPv4 and IPv6 ports are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, NULL, NULL,
0, 1);
policies_parse_exit_policy_reject_private(&policy, 1, NULL, 0, 1);
tt_assert(policy);
tt_assert(smartlist_len(policy) == 2);
tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr));
@ -728,14 +708,12 @@ test_policies_reject_interface_address(void *arg)
(void)arg;
/* test that no addresses are rejected when none are supplied/requested */
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL,
0, 0);
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 0);
tt_assert(policy == NULL);
/* test that only IPv4 interface addresses are rejected on an IPv4-only exit
*/
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL,
1, 0);
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 1, 0);
if (policy) {
tt_assert(smartlist_len(policy) == smartlist_len(public_ipv4_addrs));
addr_policy_list_free(policy);
@ -744,8 +722,7 @@ test_policies_reject_interface_address(void *arg)
/* test that IPv4 and IPv6 interface addresses are rejected on an IPv4/IPv6
* exit */
policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL,
1, 0);
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 1, 0);
if (policy) {
tt_assert(smartlist_len(policy) == (smartlist_len(public_ipv4_addrs)
+ smartlist_len(public_ipv6_addrs)));
@ -848,13 +825,148 @@ test_dump_exit_policy_to_string(void *arg)
tor_free(ep);
}
static routerinfo_t *mock_desc_routerinfo = NULL;
const routerinfo_t *mock_router_get_my_routerinfo(void)
{
return mock_desc_routerinfo;
}
#define DEFAULT_POLICY_STRING "reject *:*"
#define TEST_IPV4_ADDR (0x02040608)
#define TEST_IPV6_ADDR ("2003::ef01")
static or_options_t mock_options;
static const or_options_t *
mock_get_options(void)
{
return &mock_options;
}
/** Run unit tests for generating summary lines of exit policies */
static void
test_policies_getinfo_helper_policies(void *arg)
{
(void)arg;
int rv = 0;
size_t ipv4_len = 0, ipv6_len = 0;
char *answer = NULL;
const char *errmsg = NULL;
routerinfo_t mock_my_routerinfo;
rv = getinfo_helper_policies(NULL, "exit-policy/default", &answer, &errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/default",
&answer, &errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
memset(&mock_my_routerinfo, 0, sizeof(routerinfo_t));
MOCK(router_get_my_routerinfo, mock_router_get_my_routerinfo);
mock_my_routerinfo.exit_policy = smartlist_new();
mock_desc_routerinfo = &mock_my_routerinfo;
memset(&mock_options, 0, sizeof(or_options_t));
MOCK(get_options, mock_get_options);
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
tt_assert(strlen(answer) == 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv4", &answer,
&errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
ipv4_len = strlen(answer);
tt_assert(ipv4_len == 0 || ipv4_len == strlen(DEFAULT_POLICY_STRING));
tt_assert(ipv4_len == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv6", &answer,
&errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
ipv6_len = strlen(answer);
tt_assert(ipv6_len == 0 || ipv6_len == strlen(DEFAULT_POLICY_STRING));
tt_assert(ipv6_len == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/full", &answer,
&errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
/* It's either empty or it's the default */
tt_assert(strlen(answer) == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
tor_free(answer);
mock_my_routerinfo.addr = TEST_IPV4_ADDR;
tor_addr_parse(&mock_my_routerinfo.ipv6_addr, TEST_IPV6_ADDR);
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "accept *4:*");
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "reject *6:*");
mock_options.IPv6Exit = 1;
tor_addr_from_ipv4h(&mock_options.OutboundBindAddressIPv4_, TEST_IPV4_ADDR);
tor_addr_parse(&mock_options.OutboundBindAddressIPv6_, TEST_IPV6_ADDR);
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv4", &answer,
&errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
ipv4_len = strlen(answer);
tt_assert(ipv4_len > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv6", &answer,
&errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
ipv6_len = strlen(answer);
tt_assert(ipv6_len > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/full", &answer,
&errmsg);
tt_assert(rv == 0);
tt_assert(answer != NULL);
tt_assert(strlen(answer) > 0);
tt_assert(strlen(answer) == ipv4_len + ipv6_len + 1);
tor_free(answer);
done:
tor_free(answer);
UNMOCK(get_options);
UNMOCK(router_get_my_routerinfo);
smartlist_free(mock_my_routerinfo.exit_policy);
}
#undef DEFAULT_POLICY_STRING
#undef TEST_IPV4_ADDR
#undef TEST_IPV6_ADDR
struct testcase_t policy_tests[] = {
{ "router_dump_exit_policy_to_string", test_dump_exit_policy_to_string, 0,
NULL, NULL },
{ "general", test_policies_general, 0, NULL, NULL },
{ "getinfo_helper_policies", test_policies_getinfo_helper_policies, 0, NULL,
NULL },
{ "reject_exit_address", test_policies_reject_exit_address, 0, NULL, NULL },
{ "reject_interface_address", test_policies_reject_interface_address, 0, NULL, NULL },
{ "reject_outbound_address", test_policies_reject_outbound_address, 0, NULL, NULL },
{ "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL },
END_OF_TESTCASES
};