Line data Source code
1 : /* Copyright (c) 2001 Matej Pfajfar.
2 : * Copyright (c) 2001-2004, Roger Dingledine.
3 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 : * Copyright (c) 2007-2021, The Tor Project, Inc. */
5 : /* See LICENSE for licensing information */
6 :
7 : /**
8 : * \file addressmap.c
9 : *
10 : * \brief The addressmap module manages the processes by which we rewrite
11 : * addresses in client requess. It handles the MapAddress controller and
12 : * torrc commands, and the TrackHostExits feature, and the client-side DNS
13 : * cache (deprecated).
14 : */
15 :
16 : #define ADDRESSMAP_PRIVATE
17 :
18 : #include "lib/crypt_ops/crypto_rand.h"
19 :
20 : #include "core/or/or.h"
21 : #include "feature/client/addressmap.h"
22 : #include "core/or/circuituse.h"
23 : #include "app/config/config.h"
24 : #include "core/or/connection_edge.h"
25 : #include "feature/control/control_events.h"
26 : #include "feature/nodelist/nodelist.h"
27 : #include "feature/nodelist/routerset.h"
28 :
29 : #include "core/or/entry_connection_st.h"
30 :
31 : /** A client-side struct to remember requests to rewrite addresses
32 : * to new addresses. These structs are stored in the hash table
33 : * "addressmap" below.
34 : *
35 : * There are 5 ways to set an address mapping:
36 : * - A MapAddress command from the controller [permanent]
37 : * - An AddressMap directive in the torrc [permanent]
38 : * - When a TrackHostExits torrc directive is triggered [temporary]
39 : * - When a DNS resolve succeeds [temporary]
40 : * - When a DNS resolve fails [temporary]
41 : *
42 : * When an addressmap request is made but one is already registered,
43 : * the new one is replaced only if the currently registered one has
44 : * no "new_address" (that is, it's in the process of DNS resolve),
45 : * or if the new one is permanent (expires==0 or 1).
46 : *
47 : * (We overload the 'expires' field, using "0" for mappings set via
48 : * the configuration file, "1" for mappings set from the control
49 : * interface, and other values for DNS and TrackHostExit mappings that can
50 : * expire.)
51 : *
52 : * A mapping may be 'wildcarded'. If "src_wildcard" is true, then
53 : * any address that ends with a . followed by the key for this entry will
54 : * get remapped by it. If "dst_wildcard" is also true, then only the
55 : * matching suffix of such addresses will get replaced by new_address.
56 : */
57 : typedef struct {
58 : char *new_address;
59 : time_t expires;
60 : addressmap_entry_source_bitfield_t source:3;
61 : unsigned src_wildcard:1;
62 : unsigned dst_wildcard:1;
63 : short num_resolve_failures;
64 : } addressmap_entry_t;
65 :
66 : /** Entry for mapping addresses to which virtual address we mapped them to. */
67 : typedef struct {
68 : char *ipv4_address;
69 : char *ipv6_address;
70 : char *hostname_address;
71 : } virtaddress_entry_t;
72 :
73 : /** A hash table to store client-side address rewrite instructions. */
74 : static strmap_t *addressmap=NULL;
75 :
76 : /**
77 : * Table mapping addresses to which virtual address, if any, we
78 : * assigned them to.
79 : *
80 : * We maintain the following invariant: if [A,B] is in
81 : * virtaddress_reversemap, then B must be a virtual address, and [A,B]
82 : * must be in addressmap. We do not require that the converse hold:
83 : * if it fails, then we could end up mapping two virtual addresses to
84 : * the same address, which is no disaster.
85 : **/
86 : static strmap_t *virtaddress_reversemap=NULL;
87 :
88 : /** Initialize addressmap. */
89 : void
90 269 : addressmap_init(void)
91 : {
92 269 : addressmap = strmap_new();
93 269 : virtaddress_reversemap = strmap_new();
94 269 : }
95 :
96 : #define addressmap_ent_free(ent) \
97 : FREE_AND_NULL(addressmap_entry_t, addressmap_ent_free_, (ent))
98 :
99 : /** Free the memory associated with the addressmap entry <b>_ent</b>. */
100 : static void
101 40 : addressmap_ent_free_(addressmap_entry_t *ent)
102 : {
103 40 : if (!ent)
104 : return;
105 :
106 40 : tor_free(ent->new_address);
107 40 : tor_free(ent);
108 : }
109 :
110 : static void
111 24 : addressmap_ent_free_void(void *ent)
112 : {
113 24 : addressmap_ent_free_(ent);
114 24 : }
115 :
116 : #define addressmap_virtaddress_ent_free(ent) \
117 : FREE_AND_NULL(virtaddress_entry_t, addressmap_virtaddress_ent_free_, (ent))
118 :
119 : /** Free storage held by a virtaddress_entry_t* entry in <b>_ent</b>. */
120 : static void
121 13 : addressmap_virtaddress_ent_free_(virtaddress_entry_t *ent)
122 : {
123 13 : if (!ent)
124 : return;
125 13 : tor_free(ent->ipv4_address);
126 13 : tor_free(ent->ipv6_address);
127 13 : tor_free(ent->hostname_address);
128 13 : tor_free(ent);
129 : }
130 :
131 : static void
132 13 : addressmap_virtaddress_ent_free_void(void *ent)
133 : {
134 13 : addressmap_virtaddress_ent_free_(ent);
135 13 : }
136 :
137 : /** Remove <b>address</b> (which must map to <b>ent</b>) from the
138 : * virtual address map. */
139 : static void
140 16 : addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
141 : {
142 32 : if (ent && ent->new_address &&
143 16 : address_is_in_virtual_range(ent->new_address)) {
144 0 : virtaddress_entry_t *ve =
145 0 : strmap_get(virtaddress_reversemap, ent->new_address);
146 : /*log_fn(LOG_NOTICE,"remove reverse mapping for %s",ent->new_address);*/
147 0 : if (ve) {
148 0 : if (!strcmp(address, ve->ipv4_address))
149 0 : tor_free(ve->ipv4_address);
150 0 : if (!strcmp(address, ve->ipv6_address))
151 0 : tor_free(ve->ipv6_address);
152 0 : if (!strcmp(address, ve->hostname_address))
153 0 : tor_free(ve->hostname_address);
154 0 : if (!ve->ipv4_address && !ve->ipv6_address && !ve->hostname_address) {
155 0 : tor_free(ve);
156 0 : strmap_remove(virtaddress_reversemap, ent->new_address);
157 : }
158 : }
159 : }
160 16 : }
161 :
162 : /** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
163 : * client address maps, and then free it. */
164 : static void
165 16 : addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
166 : {
167 16 : addressmap_virtaddress_remove(address, ent);
168 16 : addressmap_ent_free(ent);
169 16 : }
170 :
171 : /** Unregister all TrackHostExits mappings from any address to
172 : * *.exitname.exit. */
173 : void
174 0 : clear_trackexithost_mappings(const char *exitname)
175 : {
176 0 : char *suffix = NULL;
177 0 : if (!addressmap || !exitname)
178 0 : return;
179 0 : tor_asprintf(&suffix, ".%s.exit", exitname);
180 0 : tor_strlower(suffix);
181 :
182 0 : STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
183 0 : if (ent->source == ADDRMAPSRC_TRACKEXIT &&
184 0 : !strcmpend(ent->new_address, suffix)) {
185 0 : addressmap_ent_remove(address, ent);
186 0 : MAP_DEL_CURRENT(address);
187 : }
188 0 : } STRMAP_FOREACH_END;
189 :
190 0 : tor_free(suffix);
191 : }
192 :
193 : /** Remove all TRACKEXIT mappings from the addressmap for which the target
194 : * host is unknown or no longer allowed, or for which the source address
195 : * is no longer in trackexithosts. */
196 : void
197 0 : addressmap_clear_excluded_trackexithosts(const or_options_t *options)
198 : {
199 0 : const routerset_t *allow_nodes = options->ExitNodes;
200 0 : const routerset_t *exclude_nodes = options->ExcludeExitNodesUnion_;
201 :
202 0 : if (!addressmap)
203 : return;
204 0 : if (routerset_is_empty(allow_nodes))
205 : allow_nodes = NULL;
206 0 : if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
207 : return;
208 :
209 0 : STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
210 0 : size_t len;
211 0 : const char *target = ent->new_address, *dot;
212 0 : char *nodename;
213 0 : const node_t *node;
214 :
215 0 : if (!target) {
216 : /* DNS resolving in progress */
217 0 : continue;
218 0 : } else if (strcmpend(target, ".exit")) {
219 : /* Not a .exit mapping */
220 0 : continue;
221 0 : } else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
222 : /* Not a trackexit mapping. */
223 0 : continue;
224 : }
225 0 : len = strlen(target);
226 0 : if (len < 6)
227 0 : continue; /* malformed. */
228 0 : dot = target + len - 6; /* dot now points to just before .exit */
229 0 : while (dot > target && *dot != '.')
230 0 : dot--;
231 0 : if (*dot == '.') dot++;
232 0 : nodename = tor_strndup(dot, len-5-(dot-target));
233 0 : node = node_get_by_nickname(nodename, NNF_NO_WARN_UNNAMED);
234 0 : tor_free(nodename);
235 0 : if (!node ||
236 0 : (allow_nodes && !routerset_contains_node(allow_nodes, node)) ||
237 0 : routerset_contains_node(exclude_nodes, node) ||
238 0 : !hostname_in_track_host_exits(options, address)) {
239 : /* We don't know this one, or we want to be rid of it. */
240 0 : addressmap_ent_remove(address, ent);
241 0 : MAP_DEL_CURRENT(address);
242 : }
243 0 : } STRMAP_FOREACH_END;
244 : }
245 :
246 : /** Return true iff <b>address</b> is one that we are configured to
247 : * automap on resolve according to <b>options</b>. */
248 : int
249 8 : addressmap_address_should_automap(const char *address,
250 : const or_options_t *options)
251 : {
252 8 : const smartlist_t *suffix_list = options->AutomapHostsSuffixes;
253 :
254 8 : if (!suffix_list)
255 : return 0;
256 :
257 19 : SMARTLIST_FOREACH_BEGIN(suffix_list, const char *, suffix) {
258 18 : if (!strcmp(suffix, "."))
259 : return 1;
260 14 : if (!strcasecmpend(address, suffix))
261 : return 1;
262 11 : } SMARTLIST_FOREACH_END(suffix);
263 : return 0;
264 : }
265 :
266 : /** Remove all AUTOMAP mappings from the addressmap for which the
267 : * source address no longer matches AutomapHostsSuffixes, which is
268 : * no longer allowed by AutomapHostsOnResolve, or for which the
269 : * target address is no longer in the virtual network. */
270 : void
271 0 : addressmap_clear_invalid_automaps(const or_options_t *options)
272 : {
273 0 : int clear_all = !options->AutomapHostsOnResolve;
274 0 : const smartlist_t *suffixes = options->AutomapHostsSuffixes;
275 :
276 0 : if (!addressmap)
277 : return;
278 :
279 0 : if (!suffixes)
280 0 : clear_all = 1; /* This should be impossible, but let's be sure. */
281 :
282 0 : STRMAP_FOREACH_MODIFY(addressmap, src_address, addressmap_entry_t *, ent) {
283 0 : int remove_this = clear_all;
284 0 : if (ent->source != ADDRMAPSRC_AUTOMAP)
285 0 : continue; /* not an automap mapping. */
286 :
287 0 : if (!remove_this) {
288 0 : remove_this = ! addressmap_address_should_automap(src_address, options);
289 : }
290 :
291 0 : if (!remove_this && ! address_is_in_virtual_range(ent->new_address))
292 : remove_this = 1;
293 :
294 0 : if (remove_this) {
295 0 : addressmap_ent_remove(src_address, ent);
296 0 : MAP_DEL_CURRENT(src_address);
297 : }
298 0 : } STRMAP_FOREACH_END;
299 : }
300 :
301 : /** Remove all entries from the addressmap that were set via the
302 : * configuration file or the command line. */
303 : void
304 30 : addressmap_clear_configured(void)
305 : {
306 30 : addressmap_get_mappings(NULL, 0, 0, 0);
307 30 : }
308 :
309 : /** Remove all entries from the addressmap that are set to expire, ever. */
310 : void
311 0 : addressmap_clear_transient(void)
312 : {
313 0 : addressmap_get_mappings(NULL, 2, TIME_MAX, 0);
314 0 : }
315 :
316 : /** Clean out entries from the addressmap cache that were
317 : * added long enough ago that they are no longer valid.
318 : */
319 : void
320 0 : addressmap_clean(time_t now)
321 : {
322 0 : addressmap_get_mappings(NULL, 2, now, 0);
323 0 : }
324 :
325 : /** Free all the elements in the addressmap, and free the addressmap
326 : * itself. */
327 : void
328 253 : addressmap_free_all(void)
329 : {
330 253 : strmap_free(addressmap, addressmap_ent_free_void);
331 253 : addressmap = NULL;
332 :
333 253 : strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free_void);
334 253 : virtaddress_reversemap = NULL;
335 253 : }
336 :
337 : /** Try to find a match for AddressMap expressions that use
338 : * wildcard notation such as '*.c.d *.e.f' (so 'a.c.d' will map to 'a.e.f') or
339 : * '*.c.d a.b.c' (so 'a.c.d' will map to a.b.c).
340 : * Return the matching entry in AddressMap or NULL if no match is found.
341 : * For expressions such as '*.c.d *.e.f', truncate <b>address</b> 'a.c.d'
342 : * to 'a' before we return the matching AddressMap entry.
343 : *
344 : * This function does not handle the case where a pattern of the form "*.c.d"
345 : * matches the address c.d -- that's done by the main addressmap_rewrite
346 : * function.
347 : */
348 : static addressmap_entry_t *
349 100 : addressmap_match_superdomains(char *address)
350 : {
351 100 : addressmap_entry_t *val;
352 100 : char *cp;
353 :
354 100 : cp = address;
355 220 : while ((cp = strchr(cp, '.'))) {
356 : /* cp now points to a suffix of address that begins with a . */
357 159 : val = strmap_get_lc(addressmap, cp+1);
358 159 : if (val && val->src_wildcard) {
359 39 : if (val->dst_wildcard)
360 5 : *cp = '\0';
361 39 : return val;
362 : }
363 : ++cp;
364 : }
365 : return NULL;
366 : }
367 :
368 : /** Look at address, and rewrite it until it doesn't want any
369 : * more rewrites; but don't get into an infinite loop.
370 : * Don't write more than maxlen chars into address. Return true if the
371 : * address changed; false otherwise. Set *<b>expires_out</b> to the
372 : * expiry time of the result, or to <b>time_max</b> if the result does
373 : * not expire.
374 : *
375 : * If <b>exit_source_out</b> is non-null, we set it as follows. If we the
376 : * address starts out as a non-exit address, and we remap it to an .exit
377 : * address at any point, then set *<b>exit_source_out</b> to the
378 : * address_entry_source_t of the first such rule. Set *<b>exit_source_out</b>
379 : * to ADDRMAPSRC_NONE if there is no such rewrite, or if the original address
380 : * was a .exit.
381 : */
382 : int
383 74 : addressmap_rewrite(char *address, size_t maxlen,
384 : unsigned flags,
385 : time_t *expires_out,
386 : addressmap_entry_source_t *exit_source_out)
387 : {
388 74 : addressmap_entry_t *ent;
389 74 : int rewrites;
390 74 : time_t expires = TIME_MAX;
391 74 : addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
392 74 : char *addr_orig = tor_strdup(address);
393 74 : char *log_addr_orig = NULL;
394 :
395 : /* We use a loop here to limit the total number of rewrites we do,
396 : * so that we can't hit an infinite loop. */
397 223 : for (rewrites = 0; rewrites < 16; rewrites++) {
398 146 : int exact_match = 0;
399 146 : log_addr_orig = tor_strdup(escaped_safe_str_client(address));
400 :
401 : /* First check to see if there's an exact match for this address */
402 146 : ent = strmap_get(addressmap, address);
403 :
404 146 : if (!ent || !ent->new_address) {
405 : /* And if we don't have an exact match, try to check whether
406 : * we have a pattern-based match.
407 : */
408 100 : ent = addressmap_match_superdomains(address);
409 : } else {
410 46 : if (ent->src_wildcard && !ent->dst_wildcard &&
411 1 : !strcasecmp(address, ent->new_address)) {
412 : /* This is a rule like "rewrite *.example.com to example.com", and we
413 : * just got "example.com". Instead of calling it an infinite loop,
414 : * call it complete. */
415 0 : goto done;
416 : }
417 : exact_match = 1;
418 : }
419 :
420 146 : if (!ent || !ent->new_address) {
421 : /* We still have no match at all. We're done! */
422 61 : goto done;
423 : }
424 :
425 : /* Check whether the flags we were passed tell us not to use this
426 : * mapping. */
427 85 : switch (ent->source) {
428 8 : case ADDRMAPSRC_DNS:
429 : {
430 8 : sa_family_t f;
431 8 : tor_addr_t tmp;
432 8 : f = tor_addr_parse(&tmp, ent->new_address);
433 8 : if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS))
434 6 : goto done;
435 5 : else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
436 3 : goto done;
437 : }
438 2 : break;
439 69 : case ADDRMAPSRC_CONTROLLER:
440 : case ADDRMAPSRC_TORRC:
441 69 : if (!(flags & AMR_FLAG_USE_MAPADDRESS))
442 0 : goto done;
443 : break;
444 8 : case ADDRMAPSRC_AUTOMAP:
445 8 : if (!(flags & AMR_FLAG_USE_AUTOMAP))
446 4 : goto done;
447 : break;
448 0 : case ADDRMAPSRC_TRACKEXIT:
449 0 : if (!(flags & AMR_FLAG_USE_TRACKEXIT))
450 0 : goto done;
451 : break;
452 0 : case ADDRMAPSRC_NONE:
453 : default:
454 0 : log_warn(LD_BUG, "Unknown addrmap source value %d. Ignoring it.",
455 : (int) ent->source);
456 0 : goto done;
457 : }
458 :
459 : /* Now fill in the address with the new address. That might be via
460 : * appending some new stuff to the end, or via just replacing it. */
461 75 : if (ent->dst_wildcard && !exact_match) {
462 5 : strlcat(address, ".", maxlen);
463 5 : strlcat(address, ent->new_address, maxlen);
464 : } else {
465 70 : strlcpy(address, ent->new_address, maxlen);
466 : }
467 :
468 : /* Is this now a .exit address? If so, remember where we got it.*/
469 81 : if (!strcmpend(address, ".exit") &&
470 12 : strcmpend(addr_orig, ".exit") &&
471 : exit_source == ADDRMAPSRC_NONE) {
472 6 : exit_source = ent->source;
473 : }
474 :
475 75 : log_info(LD_APP, "Addressmap: rewriting %s to %s",
476 : log_addr_orig, escaped_safe_str_client(address));
477 75 : if (ent->expires > 1 && ent->expires < expires)
478 : expires = ent->expires;
479 :
480 75 : tor_free(log_addr_orig);
481 : }
482 3 : log_warn(LD_CONFIG,
483 : "Loop detected: we've rewritten %s 16 times! Using it as-is.",
484 : escaped_safe_str_client(address));
485 : /* it's fine to rewrite a rewrite, but don't loop forever */
486 :
487 74 : done:
488 74 : tor_free(addr_orig);
489 74 : tor_free(log_addr_orig);
490 74 : if (exit_source_out)
491 51 : *exit_source_out = exit_source;
492 74 : if (expires_out)
493 74 : *expires_out = expires;
494 74 : return (rewrites > 0);
495 : }
496 :
497 : /** If we have a cached reverse DNS entry for the address stored in the
498 : * <b>maxlen</b>-byte buffer <b>address</b> (typically, a dotted quad) then
499 : * rewrite to the cached value and return 1. Otherwise return 0. Set
500 : * *<b>expires_out</b> to the expiry time of the result, or to <b>time_max</b>
501 : * if the result does not expire. */
502 : int
503 1 : addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags,
504 : time_t *expires_out)
505 : {
506 1 : char *s, *cp;
507 1 : addressmap_entry_t *ent;
508 1 : int r = 0;
509 : {
510 1 : sa_family_t f;
511 1 : tor_addr_t tmp;
512 1 : f = tor_addr_parse(&tmp, address);
513 1 : if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS))
514 1 : return 0;
515 0 : else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
516 : return 0;
517 : /* FFFF we should reverse-map virtual addresses even if we haven't
518 : * enabled DNS caching. */
519 : }
520 :
521 0 : tor_asprintf(&s, "REVERSE[%s]", address);
522 0 : ent = strmap_get(addressmap, s);
523 0 : if (ent) {
524 0 : cp = tor_strdup(escaped_safe_str_client(ent->new_address));
525 0 : log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
526 : escaped_safe_str_client(s), cp);
527 0 : tor_free(cp);
528 0 : strlcpy(address, ent->new_address, maxlen);
529 0 : r = 1;
530 : }
531 :
532 0 : if (expires_out)
533 0 : *expires_out = (ent && ent->expires > 1) ? ent->expires : TIME_MAX;
534 :
535 0 : tor_free(s);
536 0 : return r;
537 : }
538 :
539 : /** Return 1 if <b>address</b> is already registered, else return 0. If address
540 : * is already registered, and <b>update_expires</b> is non-zero, then update
541 : * the expiry time on the mapping with update_expires if it is a
542 : * mapping created by TrackHostExits. */
543 : int
544 6 : addressmap_have_mapping(const char *address, int update_expiry)
545 : {
546 6 : addressmap_entry_t *ent;
547 6 : if (!(ent=strmap_get_lc(addressmap, address)))
548 : return 0;
549 0 : if (update_expiry && ent->source==ADDRMAPSRC_TRACKEXIT)
550 0 : ent->expires=time(NULL) + update_expiry;
551 : return 1;
552 : }
553 :
554 : /** Register a request to map <b>address</b> to <b>new_address</b>,
555 : * which will expire on <b>expires</b> (or 0 if never expires from
556 : * config file, 1 if never expires from controller, 2 if never expires
557 : * (virtual address mapping) from the controller.)
558 : *
559 : * <b>new_address</b> should be a newly dup'ed string, which we'll use or
560 : * free as appropriate. We will leave <b>address</b> alone.
561 : *
562 : * If <b>wildcard_addr</b> is true, then the mapping will match any address
563 : * equal to <b>address</b>, or any address ending with a period followed by
564 : * <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
565 : * both true, the mapping will rewrite addresses that end with
566 : * ".<b>address</b>" into ones that end with ".<b>new_address</b>".
567 : *
568 : * If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
569 : * <b>address</b> and <b>wildcard_addr</b> is equal to
570 : * <b>wildcard_new_addr</b>, remove any mappings that exist from
571 : * <b>address</b>.
572 : *
573 : * It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
574 : * not set. */
575 : void
576 41 : addressmap_register(const char *address, char *new_address, time_t expires,
577 : addressmap_entry_source_t source,
578 : const int wildcard_addr,
579 : const int wildcard_new_addr, uint64_t stream_id)
580 : {
581 41 : addressmap_entry_t *ent;
582 :
583 41 : if (wildcard_new_addr)
584 4 : tor_assert(wildcard_addr);
585 :
586 41 : ent = strmap_get(addressmap, address);
587 41 : if (!new_address || (!strcasecmp(address,new_address) &&
588 : wildcard_addr == wildcard_new_addr)) {
589 : /* Remove the mapping, if any. */
590 0 : tor_free(new_address);
591 0 : if (ent) {
592 0 : addressmap_ent_remove(address,ent);
593 0 : strmap_remove(addressmap, address);
594 : }
595 0 : return;
596 : }
597 41 : if (!ent) { /* make a new one and register it */
598 40 : ent = tor_malloc_zero(sizeof(addressmap_entry_t));
599 40 : strmap_set(addressmap, address, ent);
600 1 : } else if (ent->new_address) { /* we need to clean up the old mapping. */
601 1 : if (expires > 1) {
602 0 : log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
603 : "since it's already mapped to '%s'",
604 : safe_str_client(address),
605 : safe_str_client(new_address),
606 : safe_str_client(ent->new_address));
607 0 : tor_free(new_address);
608 0 : return;
609 : }
610 1 : if (address_is_in_virtual_range(ent->new_address) &&
611 : expires != 2) {
612 : /* XXX This isn't the perfect test; we want to avoid removing
613 : * mappings set from the control interface _as virtual mapping */
614 0 : addressmap_virtaddress_remove(address, ent);
615 : }
616 1 : tor_free(ent->new_address);
617 : } /* else { we have an in-progress resolve with no mapping. } */
618 :
619 41 : ent->new_address = new_address;
620 41 : ent->expires = expires==2 ? 1 : expires;
621 41 : ent->num_resolve_failures = 0;
622 41 : ent->source = source;
623 41 : ent->src_wildcard = wildcard_addr ? 1 : 0;
624 41 : ent->dst_wildcard = wildcard_new_addr ? 1 : 0;
625 :
626 41 : log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
627 : safe_str_client(address),
628 : safe_str_client(ent->new_address));
629 41 : control_event_address_mapped(address, ent->new_address,
630 : expires, NULL, 1, stream_id);
631 : }
632 :
633 : /** An attempt to resolve <b>address</b> failed at some OR.
634 : * Increment the number of resolve failures we have on record
635 : * for it, and then return that number.
636 : */
637 : int
638 0 : client_dns_incr_failures(const char *address)
639 : {
640 0 : addressmap_entry_t *ent = strmap_get(addressmap, address);
641 0 : if (!ent) {
642 0 : ent = tor_malloc_zero(sizeof(addressmap_entry_t));
643 0 : ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE;
644 0 : strmap_set(addressmap,address,ent);
645 : }
646 0 : if (ent->num_resolve_failures < SHRT_MAX)
647 0 : ++ent->num_resolve_failures; /* don't overflow */
648 0 : log_info(LD_APP, "Address %s now has %d resolve failures.",
649 : safe_str_client(address),
650 : ent->num_resolve_failures);
651 0 : return ent->num_resolve_failures;
652 : }
653 :
654 : /** If <b>address</b> is in the client DNS addressmap, reset
655 : * the number of resolve failures we have on record for it.
656 : * This is used when we fail a stream because it won't resolve:
657 : * otherwise future attempts on that address will only try once.
658 : */
659 : void
660 0 : client_dns_clear_failures(const char *address)
661 : {
662 0 : addressmap_entry_t *ent = strmap_get(addressmap, address);
663 0 : if (ent)
664 0 : ent->num_resolve_failures = 0;
665 0 : }
666 :
667 : /** Record the fact that <b>address</b> resolved to <b>name</b>.
668 : * We can now use this in subsequent streams via addressmap_rewrite()
669 : * so we can more correctly choose an exit that will allow <b>address</b>.
670 : *
671 : * If <b>exitname</b> is defined, then append the addresses with
672 : * ".exitname.exit" before registering the mapping.
673 : *
674 : * If <b>ttl</b> is nonnegative, the mapping will be valid for
675 : * <b>ttl</b>seconds; otherwise, we use the default.
676 : */
677 : static void
678 0 : client_dns_set_addressmap_impl(entry_connection_t *for_conn,
679 : const char *address, const char *name,
680 : const char *exitname,
681 : int ttl)
682 : {
683 0 : char *extendedaddress=NULL, *extendedval=NULL;
684 0 : uint64_t stream_id = 0;
685 :
686 0 : tor_assert(address);
687 0 : tor_assert(name);
688 :
689 0 : if (for_conn) {
690 0 : stream_id = ENTRY_TO_CONN(for_conn)->global_identifier;
691 : }
692 :
693 0 : if (ttl<0)
694 : ttl = DEFAULT_DNS_TTL;
695 : else
696 0 : ttl = clip_dns_ttl(ttl);
697 :
698 0 : if (exitname) {
699 : /* XXXX fails to ever get attempts to get an exit address of
700 : * google.com.digest[=~]nickname.exit; we need a syntax for this that
701 : * won't make strict RFC952-compliant applications (like us) barf. */
702 0 : tor_asprintf(&extendedaddress,
703 : "%s.%s.exit", address, exitname);
704 0 : tor_asprintf(&extendedval,
705 : "%s.%s.exit", name, exitname);
706 : } else {
707 0 : tor_asprintf(&extendedaddress,
708 : "%s", address);
709 0 : tor_asprintf(&extendedval,
710 : "%s", name);
711 : }
712 0 : addressmap_register(extendedaddress, extendedval,
713 0 : time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0, stream_id);
714 0 : tor_free(extendedaddress);
715 0 : }
716 :
717 : /** Record the fact that <b>address</b> resolved to <b>val</b>.
718 : * We can now use this in subsequent streams via addressmap_rewrite()
719 : * so we can more correctly choose an exit that will allow <b>address</b>.
720 : *
721 : * If <b>exitname</b> is defined, then append the addresses with
722 : * ".exitname.exit" before registering the mapping.
723 : *
724 : * If <b>ttl</b> is nonnegative, the mapping will be valid for
725 : * <b>ttl</b>seconds; otherwise, we use the default.
726 : */
727 : void
728 2 : client_dns_set_addressmap(entry_connection_t *for_conn,
729 : const char *address,
730 : const tor_addr_t *val,
731 : const char *exitname,
732 : int ttl)
733 : {
734 2 : tor_addr_t addr_tmp;
735 2 : char valbuf[TOR_ADDR_BUF_LEN];
736 :
737 2 : tor_assert(address);
738 2 : tor_assert(val);
739 :
740 2 : if (tor_addr_parse(&addr_tmp, address) >= 0)
741 2 : return; /* If address was an IP address already, don't add a mapping. */
742 :
743 1 : if (tor_addr_family(val) == AF_INET) {
744 1 : if (! for_conn->entry_cfg.cache_ipv4_answers)
745 : return;
746 0 : } else if (tor_addr_family(val) == AF_INET6) {
747 0 : if (! for_conn->entry_cfg.cache_ipv6_answers)
748 : return;
749 : }
750 :
751 0 : if (! tor_addr_to_str(valbuf, val, sizeof(valbuf), 1))
752 : return;
753 :
754 0 : client_dns_set_addressmap_impl(for_conn, address, valbuf, exitname, ttl);
755 : }
756 :
757 : /** Add a cache entry noting that <b>address</b> (ordinarily a dotted quad)
758 : * resolved via a RESOLVE_PTR request to the hostname <b>v</b>.
759 : *
760 : * If <b>exitname</b> is defined, then append the addresses with
761 : * ".exitname.exit" before registering the mapping.
762 : *
763 : * If <b>ttl</b> is nonnegative, the mapping will be valid for
764 : * <b>ttl</b>seconds; otherwise, we use the default.
765 : */
766 : void
767 0 : client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
768 : const char *address, const char *v,
769 : const char *exitname,
770 : int ttl)
771 : {
772 0 : char *s = NULL;
773 : {
774 0 : tor_addr_t tmp_addr;
775 0 : sa_family_t f = tor_addr_parse(&tmp_addr, address);
776 0 : if ((f == AF_INET && ! for_conn->entry_cfg.cache_ipv4_answers) ||
777 0 : (f == AF_INET6 && ! for_conn->entry_cfg.cache_ipv6_answers))
778 0 : return;
779 : }
780 0 : tor_asprintf(&s, "REVERSE[%s]", address);
781 0 : client_dns_set_addressmap_impl(for_conn, s, v, exitname, ttl);
782 0 : tor_free(s);
783 : }
784 :
785 : /* By default, we hand out 127.192.0.1 through 127.254.254.254.
786 : * These addresses should map to localhost, so even if the
787 : * application accidentally tried to connect to them directly (not
788 : * via Tor), it wouldn't get too far astray.
789 : *
790 : * These options are configured by parse_virtual_addr_network().
791 : */
792 :
793 : static virtual_addr_conf_t virtaddr_conf_ipv4;
794 : static virtual_addr_conf_t virtaddr_conf_ipv6;
795 :
796 : /** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
797 : * it's a valid set of virtual addresses to hand out in response to MAPADDRESS
798 : * requests. Return 0 on success; set *msg (if provided) to a newly allocated
799 : * string and return -1 on failure. If validate_only is false, sets the
800 : * actual virtual address range to the parsed value. */
801 : int
802 875 : parse_virtual_addr_network(const char *val, sa_family_t family,
803 : int validate_only,
804 : char **msg)
805 : {
806 875 : const int ipv6 = (family == AF_INET6);
807 875 : tor_addr_t addr;
808 875 : maskbits_t bits;
809 875 : const int max_prefix_bits = ipv6 ? 104 : 16;
810 875 : virtual_addr_conf_t *conf = ipv6 ? &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
811 :
812 875 : if (!val || val[0] == '\0') {
813 0 : if (msg)
814 0 : tor_asprintf(msg, "Value not present (%s) after VirtualAddressNetwork%s",
815 : val?"Empty":"NULL", ipv6?"IPv6":"");
816 0 : return -1;
817 : }
818 875 : if (tor_addr_parse_mask_ports(val, 0, &addr, &bits, NULL, NULL) < 0) {
819 2 : if (msg)
820 3 : tor_asprintf(msg, "Error parsing VirtualAddressNetwork%s %s",
821 : ipv6?"IPv6":"", val);
822 2 : return -1;
823 : }
824 873 : if (tor_addr_family(&addr) != family) {
825 0 : if (msg)
826 0 : tor_asprintf(msg, "Incorrect address type for VirtualAddressNetwork%s",
827 : ipv6?"IPv6":"");
828 0 : return -1;
829 : }
830 : #if 0
831 : if (port_min != 1 || port_max != 65535) {
832 : if (msg)
833 : tor_asprintf(msg, "Can't specify ports on VirtualAddressNetwork%s",
834 : ipv6?"IPv6":"");
835 : return -1;
836 : }
837 : #endif /* 0 */
838 :
839 873 : if (bits > max_prefix_bits) {
840 0 : if (msg)
841 0 : tor_asprintf(msg, "VirtualAddressNetwork%s expects a /%d "
842 : "network or larger",ipv6?"IPv6":"", max_prefix_bits);
843 0 : return -1;
844 : }
845 :
846 873 : if (validate_only)
847 : return 0;
848 :
849 18 : tor_addr_copy(&conf->addr, &addr);
850 18 : conf->bits = bits;
851 :
852 18 : return 0;
853 : }
854 :
855 : /**
856 : * Return true iff <b>addr</b> is likely to have been returned by
857 : * client_dns_get_unused_address.
858 : **/
859 : int
860 39 : address_is_in_virtual_range(const char *address)
861 : {
862 39 : tor_addr_t addr;
863 39 : tor_assert(address);
864 39 : if (!strcasecmpend(address, ".virtual")) {
865 : return 1;
866 39 : } else if (tor_addr_parse(&addr, address) >= 0) {
867 13 : const virtual_addr_conf_t *conf = (tor_addr_family(&addr) == AF_INET6) ?
868 : &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
869 13 : if (tor_addr_compare_masked(&addr, &conf->addr, conf->bits, CMP_EXACT)==0)
870 2 : return 1;
871 : }
872 : return 0;
873 : }
874 :
875 : /** Return a random address conforming to the virtual address configuration
876 : * in <b>conf</b>.
877 : */
878 : STATIC void
879 5629 : get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
880 : {
881 5629 : uint8_t tmp[4];
882 5629 : const uint8_t *addr_bytes;
883 5629 : uint8_t bytes[16];
884 5629 : const int ipv6 = tor_addr_family(&conf->addr) == AF_INET6;
885 5629 : const int total_bytes = ipv6 ? 16 : 4;
886 :
887 5629 : tor_assert(conf->bits <= total_bytes * 8);
888 :
889 : /* Set addr_bytes to the bytes of the virtual network, in host order */
890 5629 : if (ipv6) {
891 2314 : addr_bytes = tor_addr_to_in6_addr8(&conf->addr);
892 : } else {
893 3315 : set_uint32(tmp, tor_addr_to_ipv4n(&conf->addr));
894 3315 : addr_bytes = tmp;
895 : }
896 :
897 : /* Get an appropriate number of random bytes. */
898 5629 : crypto_rand((char*)bytes, total_bytes);
899 :
900 : /* Now replace the first "conf->bits" bits of 'bytes' with addr_bytes*/
901 5629 : if (conf->bits >= 8)
902 3581 : memcpy(bytes, addr_bytes, conf->bits / 8);
903 5629 : if (conf->bits & 7) {
904 3849 : uint8_t mask = 0xff >> (conf->bits & 7);
905 3849 : bytes[conf->bits/8] &= mask;
906 3849 : bytes[conf->bits/8] |= addr_bytes[conf->bits/8] & ~mask;
907 : }
908 :
909 5629 : if (ipv6)
910 2314 : tor_addr_from_ipv6_bytes(addr_out, bytes);
911 : else
912 3315 : tor_addr_from_ipv4n(addr_out, get_uint32(bytes));
913 :
914 5629 : tor_assert(tor_addr_compare_masked(addr_out, &conf->addr,
915 : conf->bits, CMP_EXACT)==0);
916 5629 : }
917 :
918 : /** Return a newly allocated string holding an address of <b>type</b>
919 : * (one of RESOLVED_TYPE_{IPV4|IPV6|HOSTNAME}) that has not yet been
920 : * mapped, and that is very unlikely to be the address of any real host.
921 : *
922 : * May return NULL if we have run out of virtual addresses.
923 : */
924 : static char *
925 18 : addressmap_get_virtual_address(int type)
926 : {
927 18 : char buf[64];
928 18 : tor_assert(addressmap);
929 :
930 18 : if (type == RESOLVED_TYPE_HOSTNAME) {
931 4 : char rand_bytes[10];
932 4 : do {
933 4 : crypto_rand(rand_bytes, sizeof(rand_bytes));
934 4 : base32_encode(buf,sizeof(buf),rand_bytes,sizeof(rand_bytes));
935 4 : strlcat(buf, ".virtual", sizeof(buf));
936 4 : } while (strmap_get(addressmap, buf));
937 3 : return tor_strdup(buf);
938 15 : } else if (type == RESOLVED_TYPE_IPV4 || type == RESOLVED_TYPE_IPV6) {
939 15 : const int ipv6 = (type == RESOLVED_TYPE_IPV6);
940 15 : const virtual_addr_conf_t *conf = ipv6 ?
941 : &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
942 :
943 : /* Don't try more than 1000 times. This gives us P < 1e-9 for
944 : * failing to get a good address so long as the address space is
945 : * less than ~97.95% full. That's always going to be true under
946 : * sensible circumstances for an IPv6 /10, and it's going to be
947 : * true for an IPv4 /10 as long as we've handed out less than
948 : * 4.08 million addresses. */
949 15 : uint32_t attempts = 1000;
950 :
951 15 : tor_addr_t addr;
952 :
953 1022 : while (attempts--) {
954 1021 : get_random_virtual_addr(conf, &addr);
955 :
956 1021 : if (!ipv6) {
957 : /* Don't hand out any .0 or .255 address. */
958 1011 : const uint32_t a = tor_addr_to_ipv4h(&addr);
959 1011 : if ((a & 0xff) == 0 || (a & 0xff) == 0xff)
960 2 : continue;
961 : }
962 :
963 1019 : tor_addr_to_str(buf, &addr, sizeof(buf), 1);
964 1019 : if (!strmap_get(addressmap, buf)) {
965 : /* XXXX This code is to make sure I didn't add an undecorated version
966 : * by mistake. I hope it's needless. */
967 14 : char tmp[TOR_ADDR_BUF_LEN];
968 14 : tor_addr_to_str(tmp, &addr, sizeof(tmp), 0);
969 14 : if (strmap_get(addressmap, tmp)) {
970 : // LCOV_EXCL_START
971 : log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.",
972 : buf, tmp);
973 : continue;
974 : // LCOV_EXCL_STOP
975 : }
976 :
977 14 : return tor_strdup(buf);
978 : }
979 : }
980 1 : log_warn(LD_CONFIG, "Ran out of virtual addresses!");
981 1 : return NULL;
982 : } else {
983 : // LCOV_EXCL_START
984 : log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
985 : return NULL;
986 : // LCOV_EXCL_STOP
987 : }
988 : }
989 :
990 : /** A controller has requested that we map some address of type
991 : * <b>type</b> to the address <b>new_address</b>. Choose an address
992 : * that is unlikely to be used, and map it, and return it in a newly
993 : * allocated string. If another address of the same type is already
994 : * mapped to <b>new_address</b>, try to return a copy of that address.
995 : *
996 : * The string in <b>new_address</b> may be freed or inserted into a map
997 : * as appropriate. May return NULL if are out of virtual addresses.
998 : **/
999 : const char *
1000 21 : addressmap_register_virtual_address(int type, char *new_address)
1001 : {
1002 21 : char **addrp;
1003 21 : virtaddress_entry_t *vent;
1004 21 : int vent_needs_to_be_added = 0;
1005 :
1006 21 : tor_assert(new_address);
1007 21 : tor_assert(addressmap);
1008 21 : tor_assert(virtaddress_reversemap);
1009 :
1010 21 : vent = strmap_get(virtaddress_reversemap, new_address);
1011 21 : if (!vent) {
1012 14 : vent = tor_malloc_zero(sizeof(virtaddress_entry_t));
1013 14 : vent_needs_to_be_added = 1;
1014 : }
1015 :
1016 21 : if (type == RESOLVED_TYPE_IPV4)
1017 11 : addrp = &vent->ipv4_address;
1018 10 : else if (type == RESOLVED_TYPE_IPV6)
1019 7 : addrp = &vent->ipv6_address;
1020 : else
1021 3 : addrp = &vent->hostname_address;
1022 :
1023 21 : if (*addrp) {
1024 3 : addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
1025 3 : if (ent && ent->new_address &&
1026 3 : !strcasecmp(new_address, ent->new_address)) {
1027 3 : tor_free(new_address);
1028 3 : tor_assert(!vent_needs_to_be_added);
1029 3 : return *addrp;
1030 : } else {
1031 0 : log_warn(LD_BUG,
1032 : "Internal confusion: I thought that '%s' was mapped to by "
1033 : "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
1034 : safe_str_client(new_address),
1035 : safe_str_client(*addrp),
1036 : safe_str_client(*addrp),
1037 : ent?safe_str_client(ent->new_address):"(nothing)");
1038 : }
1039 : }
1040 :
1041 18 : tor_free(*addrp);
1042 18 : *addrp = addressmap_get_virtual_address(type);
1043 18 : if (!*addrp) {
1044 1 : tor_free(vent);
1045 1 : tor_free(new_address);
1046 1 : return NULL;
1047 : }
1048 17 : log_info(LD_APP, "Registering map from %s to %s", *addrp, new_address);
1049 17 : if (vent_needs_to_be_added)
1050 13 : strmap_set(virtaddress_reversemap, new_address, vent);
1051 17 : addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0, 0);
1052 :
1053 : /* FFFF register corresponding reverse mapping. */
1054 :
1055 : #if 0
1056 : {
1057 : /* Try to catch possible bugs */
1058 : addressmap_entry_t *ent;
1059 : ent = strmap_get(addressmap, *addrp);
1060 : tor_assert(ent);
1061 : tor_assert(!strcasecmp(ent->new_address,new_address));
1062 : vent = strmap_get(virtaddress_reversemap, new_address);
1063 : tor_assert(vent);
1064 : tor_assert(!strcasecmp(*addrp,
1065 : (type == RESOLVED_TYPE_IPV4) ?
1066 : vent->ipv4_address : vent->hostname_address));
1067 : log_info(LD_APP, "Map from %s to %s okay.",
1068 : safe_str_client(*addrp),
1069 : safe_str_client(new_address));
1070 : }
1071 : #endif /* 0 */
1072 :
1073 17 : return *addrp;
1074 : }
1075 :
1076 : /** Return 1 if <b>address</b> has funny characters in it like colons. Return
1077 : * 0 if it's fine, or if we're configured to allow it anyway. <b>client</b>
1078 : * should be true if we're using this address as a client; false if we're
1079 : * using it as a server.
1080 : */
1081 : int
1082 28 : address_is_invalid_destination(const char *address, int client)
1083 : {
1084 28 : if (client) {
1085 22 : if (get_options()->AllowNonRFC953Hostnames)
1086 : return 0;
1087 : } else {
1088 6 : if (get_options()->ServerDNSAllowNonRFC953Hostnames)
1089 : return 0;
1090 : }
1091 :
1092 : /* It might be an IPv6 address! */
1093 : {
1094 28 : tor_addr_t a;
1095 28 : if (tor_addr_parse(&a, address) >= 0)
1096 9 : return 0;
1097 : }
1098 :
1099 371 : while (*address) {
1100 353 : if (TOR_ISALNUM(*address) ||
1101 35 : *address == '-' ||
1102 1 : *address == '.' ||
1103 : *address == '_') /* Underscore is not allowed, but Windows does it
1104 : * sometimes, just to thumb its nose at the IETF. */
1105 352 : ++address;
1106 : else
1107 : return 1;
1108 : }
1109 : return 0;
1110 : }
1111 :
1112 : /** Iterate over all address mappings which have expiry times between
1113 : * min_expires and max_expires, inclusive. If sl is provided, add an
1114 : * "old-addr new-addr expiry" string to sl for each mapping, omitting
1115 : * the expiry time if want_expiry is false. If sl is NULL, remove the
1116 : * mappings.
1117 : */
1118 : void
1119 30 : addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
1120 : time_t max_expires, int want_expiry)
1121 : {
1122 30 : strmap_iter_t *iter;
1123 30 : const char *key;
1124 30 : void *val_;
1125 30 : addressmap_entry_t *val;
1126 :
1127 30 : if (!addressmap)
1128 17 : addressmap_init();
1129 :
1130 46 : for (iter = strmap_iter_init(addressmap); !strmap_iter_done(iter); ) {
1131 16 : strmap_iter_get(iter, &key, &val_);
1132 16 : val = val_;
1133 16 : if (val->expires >= min_expires && val->expires <= max_expires) {
1134 16 : if (!sl) {
1135 16 : iter = strmap_iter_next_rmv(addressmap,iter);
1136 16 : addressmap_ent_remove(key, val);
1137 16 : continue;
1138 0 : } else if (val->new_address) {
1139 0 : const char *src_wc = val->src_wildcard ? "*." : "";
1140 0 : const char *dst_wc = val->dst_wildcard ? "*." : "";
1141 0 : if (want_expiry) {
1142 0 : if (val->expires < 3 || val->expires == TIME_MAX)
1143 0 : smartlist_add_asprintf(sl, "%s%s %s%s NEVER",
1144 : src_wc, key, dst_wc, val->new_address);
1145 : else {
1146 0 : char isotime[ISO_TIME_LEN+1];
1147 0 : format_iso_time(isotime, val->expires);
1148 0 : smartlist_add_asprintf(sl, "%s%s %s%s \"%s\"",
1149 : src_wc, key, dst_wc, val->new_address,
1150 : isotime);
1151 : }
1152 : } else {
1153 0 : smartlist_add_asprintf(sl, "%s%s %s%s",
1154 : src_wc, key, dst_wc, val->new_address);
1155 : }
1156 : }
1157 : }
1158 0 : iter = strmap_iter_next(addressmap,iter);
1159 : }
1160 30 : }
|