commit 69d16900aaf1d54b44d2b28514a09873154c63d3
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Sep 8 11:54:24 2011 -0400
Refactor addressmap_match_superdomains and representation of wildcards
In this new representation for wildcarded addresses, there are no
longer any 'magic addresses': rather, "a.b c.d", "*.a.b c.d" and
"*.a.b *.c.d" are all represented by a mapping from "a.b" to "c.d". we
now distinguish them by setting bits in the addressmap_entry_t
structure, where src_wildcard is set if the source address had a
wildcard, and dst_wildcard is set if the target address had a
wildcard.
This lets the case where "*.a.b *.c.d" or "*.a.b c.d" remap the
address "a.b" get handled trivially, and lets us simplify and improve
the addressmap_match_superdomains implementation: we can now have it
run in O(parts of address) rather than O(entries in addressmap).
---
src/or/circuituse.c | 2 +-
src/or/config.c | 24 ++++++++-----
src/or/connection_edge.c | 80 ++++++++++++++++++++++++++++-----------------
src/or/connection_edge.h | 3 +-
src/or/control.c | 2 +-
5 files changed, 69 insertions(+), 42 deletions(-)
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index f7f080d..fc252c9 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1676,7 +1676,7 @@ consider_recording_trackhost(const entry_connection_t *conn,
addressmap_register(conn->socks_request->address, new_address,
time(NULL) + options->TrackHostExitsExpire,
- ADDRMAPSRC_TRACKEXIT);
+ ADDRMAPSRC_TRACKEXIT,0,0);
}
/** Attempt to attach the connection <b>conn</b> to <b>circ</b>, and send a
diff --git a/src/or/config.c b/src/or/config.c
index 1d42413..ef54dcb 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -4459,6 +4459,7 @@ config_register_addressmaps(const or_options_t *options)
addressmap_clear_configured();
elts = smartlist_create();
for (opt = options->AddressMap; opt; opt = opt->next) {
+ int from_wildcard = 0, to_wildcard = 0;
smartlist_split_string(elts, opt->value, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
if (smartlist_len(elts) < 2) {
@@ -4476,27 +4477,32 @@ config_register_addressmaps(const or_options_t *options)
goto cleanup;
}
- /* Remove leading asterisk in expressions of type: '*.example.com' */
- if (!strncmp(from,"*.",2))
- from++;
- if (!strncmp(to,"*.",2))
- to++;
+ /* Detect asterisks in expressions of type: '*.example.com' */
+ if (!strncmp(from,"*.",2)) {
+ from += 2;
+ from_wildcard = 1;
+ }
+ if (!strncmp(to,"*.",2)) {
+ to += 2;
+ to_wildcard = 1;
+ }
- if (to[0] == '.' && from[0] != '.') {
+ if (to_wildcard && !from_wildcard) {
log_warn(LD_CONFIG,
"Skipping invalid argument '%s' to MapAddress: "
"can only use wildcard (i.e. '*.') if 'from' address "
- "uses wildcard also", to);
+ "uses wildcard also", opt->value);
goto cleanup;
}
if (address_is_invalid_destination(to, 1)) {
log_warn(LD_CONFIG,
- "Skipping invalid argument '%s' to MapAddress", to);
+ "Skipping invalid argument '%s' to MapAddress", opt->value);
goto cleanup;
}
- addressmap_register(from, tor_strdup(to), 0, ADDRMAPSRC_TORRC);
+ addressmap_register(from, tor_strdup(to), 0, ADDRMAPSRC_TORRC,
+ from_wildcard, to_wildcard);
if (smartlist_len(elts) > 2)
log_warn(LD_CONFIG,"Ignoring extra arguments to MapAddress.");
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 284b320..f7b2411 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -789,12 +789,18 @@ connection_ap_detach_retriable(entry_connection_t *conn,
* the configuration file, "1" for mappings set from the control
* interface, and other values for DNS and TrackHostExit mappings that can
* expire.)
+ *
+ * A mapping may be 'wildcarded'. If "src_wildcard" is true, then
+ * any address that ends with a . followed by the key for this entry will
+ * get remapped by it. If "dst_wildcard" is also true, then only the
+ * matching suffix of such addresses will get replaced by new_address.
*/
typedef struct {
char *new_address;
time_t expires;
addressmap_entry_source_t source:3;
- int is_wildcard:1;
+ unsigned src_wildcard:1;
+ unsigned dst_wildcard:1;
short num_resolve_failures;
} addressmap_entry_t;
@@ -1041,33 +1047,32 @@ addressmap_free_all(void)
/** Try to find a match for AddressMap expressions that use
* wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
* '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
- * Returns the matching entry in AddressMap or 0 if no match is found.
- * For expressions such as '*.c.d *.e.f' the <b>address</b> 'a.c.d' will
- * get truncated to 'a' before we return the matching AddressMap entry.
+ * Return the matching entry in AddressMap or NULL if no match is found.
+ * For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
+ * to 'a' before we return the matching AddressMap entry.
+ *
+ * This function does not handle the case where a pattern of the form "*.c.d"
+ * matches the address c.d -- that's done by the main addressmap_rewrite
+ * function.
*/
static addressmap_entry_t *
addressmap_match_superdomains(char *address)
{
- strmap_iter_t *iter;
- const char *key;
- void *_val;
addressmap_entry_t *val;
- char *matched_domains = NULL;
-
- for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
- strmap_iter_get(iter, &key, &_val);
- val = _val;
- if (key[0] == '.') {
- if (!strcasecmpend(address, key) || !strcasecmp(address, &key[1])) {
- matched_domains = strstr(address, key);
- if (val->is_wildcard && matched_domains)
- *matched_domains = '\0';
- return val;
- }
+ char *cp;
+
+ cp = address;
+ while ((cp = strchr(cp, '.'))) {
+ /* cp now points to a suffix of address that begins with a . */
+ val = strmap_get_lc(addressmap, cp+1);
+ if (val && val->src_wildcard) {
+ if (val->dst_wildcard)
+ *cp = '\0';
+ return val;
}
- iter = strmap_iter_next(addressmap,iter);
+ ++cp;
}
- return 0;
+ return NULL;
}
/** Look at address, and rewrite it until it doesn't want any
@@ -1098,11 +1103,12 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out)
}
cp = tor_strdup(escaped_safe_str_client(address));
- if (ent->is_wildcard)
- strlcpy(address + strlen(address), ent->new_address,
- (maxlen - strlen(address)));
- else
+ if (ent->dst_wildcard) {
+ strlcat(address, ".", maxlen);
+ strlcat(address, ent->new_address, maxlen);
+ } else {
strlcpy(address, ent->new_address, maxlen);
+ }
log_info(LD_APP, "Addressmap: rewriting %s to %s",
cp, escaped_safe_str_client(address));
@@ -1174,13 +1180,26 @@ addressmap_have_mapping(const char *address, int update_expiry)
*
* If <b>new_address</b> is NULL, or equal to <b>address</b>, remove
* any mappings that exist from <b>address</b>.
- */
+ *
+ * If <b>wildcard_addr</b> is true, then the mapping will match any address
+ * equal to <b>address</b>, or any address ending with a period followed by
+ * <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
+ * both true, the mapping will rewrite addresses that end with
+ * ".<b>address</b>" into ones that end with ".<b>new_address</b>."
+ *
+ * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
+ * not set. */
void
addressmap_register(const char *address, char *new_address, time_t expires,
- addressmap_entry_source_t source)
+ addressmap_entry_source_t source,
+ const int wildcard_addr,
+ const int wildcard_new_addr)
{
addressmap_entry_t *ent;
+ if (wildcard_new_addr)
+ tor_assert(wildcard_addr);
+
ent = strmap_get(addressmap, address);
if (!new_address || !strcasecmp(address,new_address)) {
/* Remove the mapping, if any. */
@@ -1217,7 +1236,8 @@ addressmap_register(const char *address, char *new_address, time_t expires,
ent->expires = expires==2 ? 1 : expires;
ent->num_resolve_failures = 0;
ent->source = source;
- ent->is_wildcard = (new_address[0] == '.') ? 1 : 0;
+ ent->src_wildcard = wildcard_addr ? 1 : 0;
+ ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
safe_str_client(address),
@@ -1302,7 +1322,7 @@ client_dns_set_addressmap_impl(const char *address, const char *name,
"%s", name);
}
addressmap_register(extendedaddress, tor_strdup(extendedval),
- time(NULL) + ttl, ADDRMAPSRC_DNS);
+ time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
}
/** Record the fact that <b>address</b> resolved to <b>val</b>.
@@ -1554,7 +1574,7 @@ addressmap_register_virtual_address(int type, char *new_address)
log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
if (vent_needs_to_be_added)
strmap_set(virtaddress_reversemap, new_address, vent);
- addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP);
+ addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
#if 0
{
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index 830667e..47c9c45 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -78,7 +78,8 @@ int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out);
int addressmap_have_mapping(const char *address, int update_timeout);
void addressmap_register(const char *address, char *new_address,
- time_t expires, addressmap_entry_source_t source);
+ time_t expires, addressmap_entry_source_t source,
+ int address_wildcard, int new_address_wildcard);
int parse_virtual_addr_network(const char *val, int validate_only,
char **msg);
int client_dns_incr_failures(const char *address);
diff --git a/src/or/control.c b/src/or/control.c
index f852659..ce37aca 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1331,7 +1331,7 @@ handle_control_mapaddress(control_connection_t *conn, uint32_t len,
smartlist_add(reply, ans);
}
} else {
- addressmap_register(from, tor_strdup(to), 1, ADDRMAPSRC_CONTROLLER);
+ addressmap_register(from, tor_strdup(to), 1, ADDRMAPSRC_CONTROLLER,0,0);
tor_snprintf(ans, anslen, "250-%s", line);
smartlist_add(reply, ans);
}