Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Added test-before-evict discipline in Addrman, feeler connections. #6355
These changes implement countermeasures 3 (feeler connections) and 4 (test-before-evict) suggested in our paper: "Eclipse Attacks on Bitcoin’s Peer-to-Peer Network".
The primary change is the creation of a feeler connection thread. Every 2 minutes this feeler thread launches one feeler connection, increasing the default number of max outgoing connections to 9. Feeler connections are very short lived and disconnect upon verifying the tested host is running bitcoind. Feeler connections exist only to test if the remote host to test is online. The feeler thread pulls the addresses to test from two sources:
Source 1. Tried table collisions.
Source 2. The new table.
See our paper for a full analysis of the benefits of these countermeasures.
We ran an instance with our changes for two days against our in house developed attack code to induce many collisions in the tried table. Under these conditions we used valgrind to look for memory leaks.
As we have made some cosmetic code changes since this test was run we are rerunning this test and will update this pull request when it is finished. We are launching several test nodes.
If you want to test my code, and you don't want to simulate a large number of incoming connections, you need to generate a bunch of collisions that would trigger feeler connections. The way to do this is to reduce the the number of buckets in tried to 1. (That way, every address inserted into tried will have a high probability (at least p=1/64) to be a collision.)
addrman_tests.cpp contains unit tests for the code I added to addrman. As a small side note, because addrman bucket placement depends on a randomly chosen seed (nKey) I needed to
Changes addrman to use the test-before-evict discipline in which an address is to be evicted from the tried table is first tested and if it is still online it is not evicted. Creates a new thread which tests if addresses are online or offline by briefly connecting to them. These short lived connections are referred to as feeler connections. Feeler connections have two purposes: First, to increase the number of addresses in tried, by selecting and connecting to addresses in new. Second, to implement the testing stage of the test-before-evict discipline. Adds tests to provide test coverage for these changes. This change was suggested as Countermeasure 3 and 4 in Eclipse Attacks on Bitcoin’s Peer-to-Peer Network, Ethan Heilman, Alison Kendler, Aviv Zohar, Sharon Goldberg. ePrint Archive Report 2015/263. March 2015.
We ran a node with these changes between July 9th to July 13th. We attempted to connect to our node 1375078 times (not all connections succeeded due to connection exhaustion) from 16384 district IP addresses (256 IPs per group, 64 groups using the unallocated prefix 249\8). Both the output file and valgrind are nominal.
Abstracts from the output:
We are connecting from 249\8 and running on testnet. We can see here bitcoin swapping an offline address for a recently connected address.
@laanwj I've been auditing/fuzzing the existing network code and slowing adding unittests for net/addrman to establish a behavior baseline and make unittesting of this feature easier. See #6720, #7212, #7291, #7696
I'm currently planning on breaking this commit into two commits (feeler connections and test-before-evict) and testing them independently. My current roadmap is:
I have found some other minor bugs in the networking code, I'm trying to figure out if I should prioritize them over this.
e68172e Add test-before-evict discipline to addrman (Ethan Heilman) Pull request description: This change implement countermeasures 3 (test-before-evict) suggested in our paper: ["Eclipse Attacks on Bitcoin’s Peer-to-Peer Network"](http://cs-people.bu.edu/heilman/eclipse/). # Design: A collision occurs when an address, addr1, is being moved to the tried table from the new table, but maps to a position in the tried table which already contains an address (addr2). The current behavior is that addr1 would evict addr2 from the tried table. This change ensures that during a collision, addr1 is not inserted into tried but instead inserted into a buffer (setTriedCollisions). The to-be-evicted address, addr2, is then tested by [a feeler connection](#8282). If addr2 is found to be online, we remove addr1 from the buffer and addr2 is not evicted, on the other hand if addr2 is found be offline it is replaced by addr1. An additional small advantage of this change is that, as no more than ten addresses can be in the test buffer at once, and addresses are only cleared one at a time from the test buffer (at 2 minute intervals), thus an attacker is forced to wait at least two minutes to insert a new address into tried after filling up the test buffer. This rate limits an attacker attempting to launch an eclipse attack. # Risk mitigation: - To prevent this functionality from being used as a DoS vector, we limit the number of addresses which are to be tested to ten. If we have more than ten addresses to test, we drop new addresses being added to tried if they would evict an address. Since the feeler thread only creates one new connection every 2 minutes the additional network overhead is limited. - An address in tried gains immunity from tests for 4 hours after it has been tested or successfully connected to. # Tests: This change includes additional addrman unittests which test this behavior. I ran an instance of this change with a much smaller tried table (2 buckets of 64 addresses) so that collisions were much more likely and observed evictions. ``` 2016-10-27 07:20:26 Swapping 184.108.40.206:8333 for 220.127.116.11:8333 in tried table 2016-10-27 07:20:26 Moving 18.104.22.168:8333 to tried ``` I documented tests we ran against similar earlier versions of this change in #6355. # Security Benefit This is was originally posted in PR #8282 see [this comment for full details](#8282 (comment)). To determine the security benefit of these larger numbers of IPs in the tried table I modeled the attack presented in [Eclipse Attacks on Bitcoin’s Peer-to-Peer Network](https://eprint.iacr.org/2015/263). ![attackergraph40000-10-1000short-line](https://cloud.githubusercontent.com/assets/274814/17366828/372af458-595b-11e6-81e5-2c9f97282305.png) **Default node:** 595 attacker IPs for ~50% attack success. **Default node + test-before-evict:** 620 attacker IPs for ~50% attack success. **Feeler node:** 5540 attacker IPs for ~50% attack success. **Feeler node + test-before-evict:** 8600 attacker IPs for ~50% attack success. The node running feeler connections has 10 times as many online IP addresses in its tried table making an attack 10 times harder (i.e. requiring the an attacker require 10 times as many IP addresses in different /16s). Adding test-before-evict increases resistance of the node by an additional 3000 attacker IP addresses. Below I graph the attack over even greater attacker resources (i.e. more attacker controled IP addresses). Note that test-before-evict maintains some security far longer even against an attacker with 50,000 IPs. If this node had a larger tried table test-before-evict could greatly boost a nodes resistance to eclipse attacks. ![attacker graph long view](https://cloud.githubusercontent.com/assets/274814/17367108/96f46d64-595c-11e6-91cd-edba160598e7.png) Tree-SHA512: fdad4d26aadeaad9bcdc71929b3eb4e1f855b3ee3541fbfbe25dca8d7d0a1667815402db0cb4319db6bd3fcd32d67b5bbc0e12045c4252d62d6239b7d77c4395