We propose this optional change, to improve the accuracy of IPv6 address
detection from directory documents.
Directory servers use is_local_addr() to detect if the requesting tor
instance is on the same local network. If it is, the directory server does
not include the X-Your-Address-Is HTTP header in directory documents.
Currently, is_local_addr() checks for:
an internal IPv4 or IPv6 address, or
the same IPv4 /24 as the directory server.
We propose also checking for:
the same IPv6 /48 as the directory server.
We choose /48 because it is typically the smallest network in the global
IPv6 routing tables, and it was previously the recommended per-customer
network block. (See [RFC 6177: IPv6 End Site Address Assignment].)
Tor currently uses:
IPv4 /8 and IPv6 /16 for port summaries,
IPv4 /16 and IPv6 /32 for path selection (avoiding relays in the same
network block).
I assume we check the first 48 bits (so that's the third argument), and use CMP_EXACT (fourth argument).
is_local_addr() already takes in an address pointer, which gives us the address we are checking. Now we need the IPv6 address of the local system (that would be the second argument). How exactly can I get that?
Hmmm. It looks like we don't currently have an equivalent to last_resolved_address for IPv6. It's usually set by resolve_my_address(), but that one doesn't have an IPv6 equivalent either.
I suppose we could generalize resolve_my_address() to take a address family, but that function is already pretty complex.
Another option is to declare an IPv6 equivalent for last_resolved_address, but don't actually have anything set it yet. Then in a separate ticket, we can write the code that sets it.
I just fixed the ticket description formatting so it's more readable, and added some standard ticket fields.
Trac: Sponsor: N/Ato Sponsor55-can Milestone: N/Ato Tor: 0.4.4.x-final Description: " We propose this optional change, to improve the accuracy of IPv6 address
detection from directory documents.
Directory servers use is_local_addr() to detect if the requesting tor
instance is on the same local network. If it is, the directory server does
not include the X-Your-Address-Is HTTP header in directory documents.
Currently, is_local_addr() checks for:
* an internal IPv4 or IPv6 address, or
* the same IPv4 /24 as the directory server.
We propose also checking for:
* the same IPv6 /48 as the directory server.
We choose /48 because it is typically the smallest network in the global
IPv6 routing tables, and it was previously the recommended per-customer
network block. (See [RFC 6177: IPv6 End Site Address Assignment].)
We propose this optional change, to improve the accuracy of IPv6 address
detection from directory documents.
Directory servers use is_local_addr() to detect if the requesting tor
instance is on the same local network. If it is, the directory server does
not include the X-Your-Address-Is HTTP header in directory documents.
Currently, is_local_addr() checks for:
an internal IPv4 or IPv6 address, or
the same IPv4 /24 as the directory server.
We propose also checking for:
the same IPv6 /48 as the directory server.
We choose /48 because it is typically the smallest network in the global
IPv6 routing tables, and it was previously the recommended per-customer
network block. (See [RFC 6177: IPv6 End Site Address Assignment].)
Tor currently uses:
IPv4 /8 and IPv6 /16 for port summaries,
IPv4 /16 and IPv6 /32 for path selection (avoiding relays in the same
network block).
Hmmm. It looks like we don't currently have an equivalent to last_resolved_address for IPv6. It's usually set by resolve_my_address(), but that one doesn't have an IPv6 equivalent either.
I suppose we could generalize resolve_my_address() to take a address family, but that function is already pretty complex.
Another option is to declare an IPv6 equivalent for last_resolved_address, but don't actually have anything set it yet. Then in a separate ticket, we can write the code that sets it.
Once we finish implementing the essential parts of proposal 312, last_resolved_address and resolve_my_address() will support IPv6.
Any thoughts here, teor?
In the meantime, we can use the published IPv6 address of the relay, router_get_my_routerinfo()->ipv6_addr.
Before using router_get_my_routerinfo()->ipv6_addr, we should check:
router_get_my_routerinfo() is not NULL
tor_addr_is_valid(router_get_my_routerinfo()->ipv6_addr) is true
Current code changes on commit afbf854ee1ef17622748ec4878e8929df8c9dc0c:
// includes added#include "feature/relay/router.h"/** Return true iff <b>addr</b> is judged to be on the same network as us, or * on a private network. */MOCK_IMPL(int,is_local_addr, (const tor_addr_t *addr)){ /* Check for an internal IPv4 or IPv6 address */ if (tor_addr_is_internal(addr, 0)) return 1; /* Check whether ip is on the same /24 as we are. */ if (get_options()->EnforceDistinctSubnets == 0) return 0; if (tor_addr_family(addr) == AF_INET) { uint32_t ip = tor_addr_to_ipv4h(addr); /* It's possible that this next check will hit before the first time * resolve_my_address actually succeeds. (For clients, it is likely that * resolve_my_address will never be called at all). In those cases, * last_resolved_addr will be 0, and so checking to see whether ip is on * the same /24 as last_resolved_addr will be the same as checking whether * it was on net 0, which is already done by tor_addr_is_internal. */ if ((last_resolved_addr & (uint32_t)0xffffff00ul) == (ip & (uint32_t)0xffffff00ul)) return 1; } /* Check for the same IPv6 /48 as the directory server */ if (tor_addr_family(addr) == AF_INET6) { if (router_get_my_routerinfo() && tor_addr_is_valid(router_get_my_routerinfo()->ipv6_addr, true)) { return tor_addr_compare_masked(addr->addr, router_get_my_routerinfo()->ipv6_addr, 48, CMP_EXACT); } } return 0;}
Here is the error I am getting:
tor ) make test-network$CHUTNEY_PATH was not set.Assuming test-network.sh will find ./../chutney CC src/app/config/src_core_libtor_app_testing_a-config.osrc/app/config/config.c: In function ‘is_local_addr__real’:src/app/config/config.c:3024:83: error: dereferencing pointer to incomplete type ‘routerinfo_t {aka const struct routerinfo_t}’ _addr_is_valid(router_get_my_routerinfo()->ipv6_addr, true)) { ^~src/app/config/config.c:3025:38: error: incompatible type for argument 1 of ‘tor_addr_compare_masked’ return tor_addr_compare_masked(addr->addr, router_get_my_routerinfo()->ipv6_addr, 48, CMP_EXACT); ^~~~In file included from ./src/core/or/or.h:53:0, from src/app/config/config.c:65:./src/lib/net/address.h:249:5: note: expected ‘const tor_addr_t * {aka const struct tor_addr_t *}’ but argument is of type ‘const union <anonymous>’ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, ^~~~~~~~~~~~~~~~~~~~~~~Makefile:13398: recipe for target 'src/app/config/src_core_libtor_app_testing_a-config.o' failedmake[1]: *** [src/app/config/src_core_libtor_app_testing_a-config.o] Error 1Makefile:21570: recipe for target 'test-network' failedmake: *** [test-network] Error 2
Looks like the only declaration I have found for router_get_my_routerinfo was this code in router.h:
"dereferencing pointer to incomplete type" means that there isn't a definition for the structure in scope. you might need to add an #include for the header that defines routerinfo_t. That's in a header called feature/nodelist/routerinfo_st.h
// includes#include "feature/relay/router.h"#include "feature/nodelist/routerinfo_st.h"// modified function/** Return true iff <b>addr</b> is judged to be on the same network as us, or * on a private network. */MOCK_IMPL(int,is_local_addr, (const tor_addr_t *addr)){ /* Check for an internal IPv4 or IPv6 address */ if (tor_addr_is_internal(addr, 0)) return 1; /* Check whether ip is on the same /24 as we are. */ if (get_options()->EnforceDistinctSubnets == 0) return 0; if (tor_addr_family(addr) == AF_INET) { uint32_t ip = tor_addr_to_ipv4h(addr); /* It's possible that this next check will hit before the first time * resolve_my_address actually succeeds. (For clients, it is likely that * resolve_my_address will never be called at all). In those cases, * last_resolved_addr will be 0, and so checking to see whether ip is on * the same /24 as last_resolved_addr will be the same as checking whether * it was on net 0, which is already done by tor_addr_is_internal. */ if ((last_resolved_addr & (uint32_t)0xffffff00ul) == (ip & (uint32_t)0xffffff00ul)) return 1; } /* Check for the same IPv6 /48 as the directory server */ if (tor_addr_family(addr) == AF_INET6) { if (router_get_my_routerinfo() && tor_addr_is_valid(&(router_get_my_routerinfo()->ipv6_addr), true)) { return tor_addr_compare_masked(addr, &(router_get_my_routerinfo()->ipv6_addr), 48, CMP_EXACT); } } return 0;}
The error is quite interesting now:
tor ) make test-network$CHUTNEY_PATH was not set.Assuming test-network.sh will find ./../chutneyRunning IPv4 flavors: bridges+hs-v23.ping6 ::1 or ping ::1 succeeded, running IPv6 flavors: single-onion-v23-ipv6-md.FAIL: bridges+hs-v23cat: '/home/seneca/Documents/outreachy/tor/../chutney/net/nodes/*/info.log': No such file or directoryFAIL: single-onion-v23-ipv6-mdcat: '/home/seneca/Documents/outreachy/tor/../chutney/net/nodes/*/info.log': No such file or directoryLog and result files are available in ./test_network_log.Makefile:21723: recipe for target 'test-network-results' failedmake[1]: *** [test-network-results] Error 1Makefile:21570: recipe for target 'test-network' failedmake: *** [test-network] Error 2tor ) wc -l test_network_log/* 670 test_network_log/bridges+hs-v23.log 4 test_network_log/bridges+hs-v23.trs 599 test_network_log/single-onion-v23-ipv6-md.log 4 test_network_log/single-onion-v23-ipv6-md.trs 1277 total
Hi Neel, please check if other people are working on tickets before you assign them to yourself. (And please only assign yourself tickets if you're actively working on them.)
That's true, but we should open another ticket to fix the issue with tor_addr_is_valid(). Because that issue is not relevant to this ticket.
Here's why:
It doesn't make any sense to compare an all-zeroes IPv6 address to see if it's on the same network as another address. So we should pass "false" for "for_listening".
And all-zeroes addresses never reach this code, because they are excluded by tor_addr_is_internal() at the start of the function.
current code changes in config.c
…
The error is quite interesting now:
{{{
tor ) make test-network
$CHUTNEY_PATH was not set.
Assuming test-network.sh will find ./../chutney
Running IPv4 flavors: bridges+hs-v23.
ping6 ::1 or ping ::1 succeeded, running IPv6 flavors: single-onion-v23-ipv6-md.
FAIL: bridges+hs-v23
cat: '/home/seneca/Documents/outreachy/tor/../chutney/net/nodes//info.log': No such file or directory
FAIL: single-onion-v23-ipv6-md
cat: '/home/seneca/Documents/outreachy/tor/../chutney/net/nodes//info.log': No such file or directory
Log and result files are available in ./test_network_log.
Makefile:21723: recipe for target 'test-network-results' failed
make[1]: *** [test-network-results] Error 1
Makefile:21570: recipe for target 'test-network' failed
make: *** [test-network] Error 2
tor ) wc -l test_network_log/*
670 test_network_log/bridges+hs-v23.log
4 test_network_log/bridges+hs-v23.trs
599 test_network_log/single-onion-v23-ipv6-md.log
4 test_network_log/single-onion-v23-ipv6-md.trs
1277 total
}}}
Please tell me if you want me to attach the logs.
Yes, we need to see the detailed logs to help you.
It looks like tor is crashing, but I can't see why that's happening.
Then we can be sure we are all seeing the same code. And we also have continuous integration (CI) set up to test the code. So we will all see the same logs. And the same code reviews :-)
Hm, that looks like it could be a start, but there's going to be a problem to the extent that router_get_my_routerinfo() might not actually work from the unit tests: it requires that there actually exists a routerinfo, which clients don't have. Maybe there is a better way to get one or more ipv6 addresses to test with -- how about tor_addr_parse()?