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).
This commit is contained in:
Nick Mathewson 2011-09-08 11:54:24 -04:00
parent df0da3991c
commit 69d16900aa
5 changed files with 68 additions and 41 deletions

View File

@ -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

View File

@ -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.");

View File

@ -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;
char *cp;
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;
}
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
{

View File

@ -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);

View File

@ -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);
}