Skip to content

Conversation

@gmaxwell
Copy link
Contributor

This is a simplified re-do of closed pull #3088.

This patch eliminates the privacy and reliability problematic use
of centralized web services for discovering the node's addresses
for advertisement.

The Bitcoin protocol already allows your peers to tell you what
IP they think you have, but this data isn't trustworthy since
they could lie. So the challenge is using it without creating a
DOS vector.

To accomplish this we adopt an approach similar to the one used
by P2Pool: If we're announcing and don't have a better address
discovered (e.g. via UPNP) or configured we just announce to
each peer the address that peer told us. Since peers could
already replace, forge, or drop our address messages this cannot
create a new vulnerability... but if even one of our peers is
giving us a good address we'll eventually make a useful
advertisement.

We also may randomly use the peer-provided address for the
daily rebroadcast even if we otherwise have a seemingly routable
address, just in case we've been misconfigured (e.g. by UPNP).

To avoid privacy problems, we only do these things if discovery
is enabled.

@gmaxwell
Copy link
Contributor Author

I've tested this (and variations of it) for a while and I'm happy with it. I think its reasonably simple now and avoids moving much of anything around.

The testing I performed was two fold, I ran an instrumented copy that logged its announcements and saw it making both types of announcements.

I also ran a node behind nat (with a port forward) which hasn't had bitcoin running on it recently without UPNP or other ways of discovering an IP and confirmed that it eventually gained inbound connections.

@gmaxwell gmaxwell added this to the 0.10.0 milestone Oct 28, 2014
@TheBlueMatt
Copy link
Contributor

Can we change the help text on -discover to say something like "Do not rumor your address except as provided by -localip"? (and, more broadly, do we really want a flag for this? It is some strange depend-on-my-peer-not-rumoring-my-address benchmark, when we really should just use fListen?)

src/main.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of this we only clear setAddrKnown when we're listening, which I dont think was intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gah. good catch. I added that at the last minute "oh why bother taking the vnodes lock when we're not going to do anything with it."

@gmaxwell
Copy link
Contributor Author

Can we change the help text on -discover to say something like "Do not rumor your address except as provided by -localip"? (and, more broadly, do we really want a flag for this? It is some strange depend-on-my-peer-not-rumoring-my-address benchmark, when we really should just use fListen?)

Consider, when you're listening to torHS you want listen=1 but you certantly don't want discovery of any type. (capturing that, one of the extra changes I made here was making proxy also imply no discovery but it still should be settable). Beyond hoping that your peers won't disrespect your wishes, it can avoid rumoring incorrect data when your outbound connections don't match your inbound. (p2pool has no way to control what addresses get rumored and this has broken things for at least a couple people).

@ghost
Copy link

ghost commented Oct 29, 2014

I think there is some clown out there who is addr messaging for everyone who connects to him

There's a number of clients on the network that do absolutely stupid things with the IP address in the handshake and addr messages. One piece of software returns ::1 for everything, another returns a 0.0.0.0, another makes up random IP addresses for their peers. I don't know what software they are, because two pretend to be a /Satoshi/ client (Satoshi seems to be the new Mozilla/5.0), and the other returns null for the human readable version name.

It's likely not a problem for this patch, just be aware that even the big players are writing horribly broken code that doesn't even attempt to conform to the p2p network the core client does.

@gmaxwell
Copy link
Contributor Author

Yea, this patch doesn't assume the peers are non-evil, much less assuming they aren't conventionally broken.

@laanwj laanwj added the P2P label Oct 29, 2014
@gmaxwell
Copy link
Contributor Author

@TheBlueMatt see updates

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does AdvertizeLocal still qualify for the previous comment ("used when scores of local addresses may have changed")?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only indirectly. Previously it invoked readvertisement more frequently, potentially triggered by external events. With this change we only advertise on connect and on a timer... if the scores change it'll influence what we advertise, but no longer directly triggers it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is advertise intentionally misspelled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not misspelled. advertize is EN_US and that was the name previously.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, I've never seen it spelled with a 'z' even in EN_US, but it appears Google agrees.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this change do we ever advertize our Tor hidden service address? I've added logging to my test node that listens both on Tor and plainnet, both external addresses appear as SeenLocal

2014-11-08 12:56:48 SeenLocal: xx.xx.xx.xx:8333
2014-11-08 12:57:05 SeenLocal: xxx.onion:8333

However, it always advertizes the IPv4 address

2014-11-08 09:15:21 AdvertizeLocal: advertizing address xx.xx.xx.xx:8333

(maybe this can be avoided using discover=0, and providing externalips, but I explicitly disabled those to test this code)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resason you're seen-localing it is becasue peers who already know it are connecting inbound to you. Since outbound HS peers can never seen your HS address it can't be discovered, and must be configured with externalips.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - so when providing externalips, it will advertise the HS address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; for two reasons: one is because externalips disables discover, the other is because if you enable discover it still mosty uses the traditional address source (what it would have used if discover were distabled) if it has one that it thinks is routable.

@spinza
Copy link

spinza commented Oct 30, 2014

Does this pull request also resolve issue #48 ?

@gmaxwell
Copy link
Contributor Author

@spinza the substance of #48 was mostly solved by the prior heartbeating changes. But this will improve the loss of inbound connections after your IP changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this rationale fits. Proxies aren't always for privacy. More importantly: is there a reason not to default discover to false always?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If proxy is set complex things are happening with your networking and discovery is much more likely not useful.

Defaulting to discover false would break listening for every host behind NAT by default, precisely those users who are least likely to set things right.

Avoiding it when proxy is set helps minimize unwanted surprises without gratitious breakage (afer all, we already disabling listening in that case).

@gmaxwell
Copy link
Contributor Author

gmaxwell commented Nov 4, 2014

@luke-jr updated

@luke-jr
Copy link
Member

luke-jr commented Nov 4, 2014

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ACK commit 5fd28b94e57d14f81bc63717c99e3e7ca7316b75 : Looked over the code, without fully understanding the logic behind it, and tested that the correct external IP does get advertised properly in an IPv4-only behind-NAT-without-UPnP scenario.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQQcBAEBCAAGBQJUWTUnAAoJEL0ClCQh9IifY1wf/R8eYEiWbT4/WbhgpnD1BuKR
2r5GuMoSsTFe5opSJSIl7zpwviY4sdD+itZ7UiDlAjqbXdFeJ5MtmzY5gQA9KoXL
keWmcsv9hxg7zf2/OntPScMb4X44JtgaQiUZ9DtRpBLT6ZsSIE0BzKO+YYNEYt4K
fAvapwJd++qHbiCEfTBY3Bap4P93A8xyEM/zpfs9Fd805rLj4qzULG4a6Xl+i4s3
djkKKpTweTiX/auO21loimzzFPLeQ/Vdypd4U3in2MQ7ylSgW81QI0wsoga9BlO4
+RQDRxB7lRa1prqWGg5uQx61M+7kaq93HI18b1MmcWf34XwQ3rdLz/jjuRaawLNt
46mPTfvnyXPlLTxyvP4fOOPUT+JomjcOj2dYqR7iKUQL4S1bYSsPKiDsZOE7XlAt
opAcdSqpU2Zg746cTDb/xREWsgXT5Je0lxhTfTdT1bx9eQHBum23wS2KvTs/UXEn
ELNGQ/NfXfSlJIIxxUTBCMRDeBWYU5ycATMg1ABayITbJiCaM5RtyaRduhUdNKJk
xWO7uzz/HbbuIfVOGYJ4mV/x16NFkGQ0ysfZlzBwrxzxxqlzblhcwpY8B8zyx356
cnYKrvR7v20XQHfy1drW4RI7NjMlSIjD7mpSAILyYmEEBi56X+MLV7RjaT1kzuSs
TimyVqekC4H+/afzaKlHpxtok9Tj8C0RMI/JySCtzeKetl3emO9b9C+iYivgdhH8
vH4nYJZKYDjMzGiB1RzMitSE95lV7jDVohAJoGVahSqjMMHWluhx7Or0qJfzQFwz
2FaFnFliHFoo6Mz1fxYS6JuBJ3ZbQ6aSWTg5oTx4LKJQ4YYL/X9OfEZX+ROz1z7q
Gaqu6NWN01oNIcdCKI2c0mTGzPdVwOLlbXHMby4DQhBphPEkCEoHfLAGFqY/p8Oz
bkeRXK2IAkrCviVaQXyzCNQygv7q0k9ryDO9DGYQFr4WN2CDhJ0Aawba7enOm2GG
lliUH4vYSm0ZKSeJcuqC2KFyvEpgMjvK/jFySJdj0ji1t98S8CR8bxM4GVrKNjD7
NB6JzGI9QoLevFEe0YcTTz2eVdNZftiqBXyC1fw8c+7o+gBrG+wXKpfWNxGGb+Gu
tjH8zq0EHV04A6gOj+WGvezshvGynfmYQTpHSL8lUrgcr+aoV1RoCww2fBSr1GgV
/vS4DV5LOGxqCAwWWRxiy7x7V1e2na9sBP3oMVdoW2pWajjeFfe7iZRCctM/rt2E
4AZgRh5sgrnJb+o+88EyKRzAkQ1yuj2s2ncIlwRzKEmGZFF6HwMQCWYMy9TaAqzr
Ylt8v3AovtokW9tTgkPseGXLWwWtpajerq0VpVojPgF6vxlQ4lA4YY/0JpffXrc=
=Ee+E
-----END PGP SIGNATURE-----

@laanwj
Copy link
Member

laanwj commented Nov 5, 2014

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Tested ACK 5fd28b94e57d14f81bc63717c99e3e7ca7316b75
I've tested w/ a host behind NAT, upnp=0, discover=1, it advertizes the right IP
Also tested with discover=0 and no externalip, no advertizing of local addresses happens (as expected)
Reviewed the code and the logic makes sense to me
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAEBCgAGBQJUWfrPAAoJEHSBCwEjRsmm0pYH/3BcQvSe93wEyh0AgRnjyQVy
W2qoTeC9orNA6sr709S1xOmgjKbAEgPDXScqAdDnYkYWuL4CuXEjn6lrQ+O/5Vl5
AM9DG6jlrTz7RVkbXt1knPsWNTs7nHAwZWFHWeq2XwrPdQH5QG//EJys8wb6DJ2O
0AsXpqer/GbHOUGusye4tCQSL+kNSD10fMfG581VVXMVzgjc1zMsDm386N5qPjWJ
PMoD7fmqZe5xDiMa2tJZ0tXcNSl10/Iz4jNwO7zZaNQMDDs131YWLcc7Cz7LVTVG
z51kBFy8Wt25+1qhLsjsRs4gmMTxaKuu/6XL0dUtaGwxSDf2Iz2YQ9bPjJaQx50=
=UWK5
-----END PGP SIGNATURE-----

@gmaxwell
Copy link
Contributor Author

gmaxwell commented Nov 7, 2014

Does anyone feel this is waiting on anything else?

src/net.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the address a peer tells us be not good if we're running on a non-standard port?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The peer can't tell us anything about the port we're listning on, (E.g. you connect out to some peer and they see the source port as some random number).... we're already behind address translation. Seemed more conservative to skip in this case.

@sipa
Copy link
Member

sipa commented Nov 7, 2014

utACK, with a few nits.

This is a simplified re-do of closed pull #3088.

This patch eliminates the privacy and reliability problematic use
of centralized web services for discovering the node's addresses
for advertisement.

The Bitcoin protocol already allows your peers to tell you what
IP they think you have, but this data isn't trustworthy since
they could lie. So the challenge is using it without creating a
DOS vector.

To accomplish this we adopt an approach similar to the one used
by P2Pool: If we're announcing and don't have a better address
discovered (e.g. via UPNP) or configured we just announce to
each peer the address that peer told us. Since peers could
already replace, forge, or drop our address messages this cannot
create a new vulnerability... but if even one of our peers is
giving us a good address we'll eventually make a useful
advertisement.

We also may randomly use the peer-provided address for the
daily rebroadcast even if we otherwise have a seemingly routable
address, just in case we've been misconfigured (e.g. by UPNP).

To avoid privacy problems, we only do these things if discovery
is enabled.
@gmaxwell
Copy link
Contributor Author

gmaxwell commented Nov 7, 2014

@sipa adjusted except for the nLastRebroadcast. I think you were misreading it there. Can you confirm?

On the disabling it when using a non-default port, any of the other ACKers have an opinion? I think it could go either way. Avoiding running it seemed more conservative to me, but there are cases where if we require the default port it would fail to discover an address that would be useful... when you're behind nat on a non-standard port and managed to map the ports 1:1, and where the old discovery code would have worked. So I've changed it.

@laanwj
Copy link
Member

laanwj commented Nov 11, 2014

@gmaxwell I'd say it's still useful to be able to discover external IP changes even if not using the default port. Throughout the code, bitcoind assumes that it knows the port where it's listening on.

The edge case here would be a) behind NAT b) manually forwarded port c) external port is different from internal port. But in that case bitcoind has no way of discovering what the external port is for advertising, so this code won't make a difference. I don't think we can handle that case at all right now (even -externalip can't take a port).

@gmaxwell
Copy link
Contributor Author

@laanwj Okay, great. (I did change it so that it doesn't require the default port anymore).

@laanwj laanwj merged commit 845c86d into bitcoin:master Nov 12, 2014
laanwj added a commit that referenced this pull request Nov 12, 2014
845c86d Do not use third party services for IP detection. (Gregory Maxwell)
ghost pushed a commit to blacknet-ninja/blackcoin-old that referenced this pull request Nov 27, 2014
It was removed in bitcoin/bitcoin#5161

Conflicts:
	doc/coding.md
laanwj added a commit that referenced this pull request Jan 20, 2015
No longer necessary since #5161 / 845c86d.
rnicoll pushed a commit to rnicoll/dogecoin that referenced this pull request Feb 15, 2015
rnicoll pushed a commit to rnicoll/dogecoin that referenced this pull request Jun 11, 2015
rnicoll pushed a commit to rnicoll/dogecoin that referenced this pull request Jun 21, 2015
reddink pushed a commit to reddcoin-project/reddcoin-3.10 that referenced this pull request May 27, 2020
It was removed in bitcoin#5161

(cherry picked from commit be4ac91)
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants