Restrict outbound connections on network groups
Logic borrowed from bitcoin, see CNetAddr::GetGroup() in src/netaddress.cpp Simplified, so may not work fully identically but for our purposes it's good enough. Won't connect to more than one host from a /16 subnet on IPv4 and a /32 subnet on IPv6.
This commit is contained in:
parent
7e1f1d2604
commit
2a165380bb
|
@ -71,6 +71,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
|||
# packet/connection from a local IP
|
||||
self.local = False
|
||||
self.pendingUpload = RandomTrackingDict()
|
||||
# canonical identifier of network group
|
||||
self.network_group = None
|
||||
|
||||
def bm_proto_reset(self):
|
||||
"""Reset the bitmessage object parser"""
|
||||
|
|
|
@ -229,6 +229,7 @@ class BMConnectionPool(object):
|
|||
|
||||
def loop(self): # pylint: disable=too-many-branches,too-many-statements
|
||||
"""Main Connectionpool's loop"""
|
||||
# pylint: disable=too-many-locals
|
||||
# defaults to empty loop if outbound connections are maxed
|
||||
spawnConnections = False
|
||||
acceptConnections = True
|
||||
|
@ -297,6 +298,19 @@ class BMConnectionPool(object):
|
|||
# don't connect to self
|
||||
if chosen in state.ownAddresses:
|
||||
continue
|
||||
# don't connect to the hosts from the same
|
||||
# network group, defense against sibyl attacks
|
||||
host_network_group = protocol.network_group(
|
||||
chosen.host)
|
||||
same_group = False
|
||||
for j in self.outboundConnections.values():
|
||||
if host_network_group == j.network_group:
|
||||
same_group = True
|
||||
if chosen.host == j.destination.host:
|
||||
knownnodes.decreaseRating(chosen)
|
||||
break
|
||||
if same_group:
|
||||
continue
|
||||
|
||||
try:
|
||||
if chosen.host.endswith(".onion") and Proxy.onion_proxy:
|
||||
|
|
|
@ -84,6 +84,7 @@ class TCPConnection(BMProto, TLSDispatcher):
|
|||
)
|
||||
except socket.error:
|
||||
pass # it's probably a hostname
|
||||
self.network_group = protocol.network_group(self.destination.host)
|
||||
ObjectTracker.__init__(self) # pylint: disable=non-parent-init-called
|
||||
self.bm_proto_reset()
|
||||
self.set_state("bm_header", expectBytes=protocol.Header.size)
|
||||
|
|
|
@ -105,6 +105,34 @@ def networkType(host):
|
|||
return 'IPv6'
|
||||
|
||||
|
||||
def network_group(host):
|
||||
"""Canonical identifier of network group
|
||||
simplified, borrowed from
|
||||
GetGroup() in src/netaddresses.cpp in bitcoin core"""
|
||||
if not isinstance(host, str):
|
||||
return None
|
||||
network_type = networkType(host)
|
||||
try:
|
||||
raw_host = encodeHost(host)
|
||||
except socket.error:
|
||||
return host
|
||||
if network_type == 'IPv4':
|
||||
decoded_host = checkIPv4Address(raw_host[12:], True)
|
||||
if decoded_host:
|
||||
# /16 subnet
|
||||
return raw_host[12:14]
|
||||
elif network_type == 'IPv6':
|
||||
decoded_host = checkIPv6Address(raw_host, True)
|
||||
if decoded_host:
|
||||
# /32 subnet
|
||||
return raw_host[0:12]
|
||||
else:
|
||||
# just host, e.g. for tor
|
||||
return host
|
||||
# global network type group for local, private, unroutable
|
||||
return network_type
|
||||
|
||||
|
||||
def checkIPAddress(host, private=False):
|
||||
"""Returns hostStandardFormat if it is a valid IP address, otherwise returns False"""
|
||||
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
||||
|
|
39
src/tests/test_networkgroup.py
Normal file
39
src/tests/test_networkgroup.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
"""
|
||||
Test for network group
|
||||
"""
|
||||
import unittest
|
||||
|
||||
|
||||
class TestNetworkGroup(unittest.TestCase):
|
||||
"""
|
||||
Test case for network group
|
||||
"""
|
||||
def test_network_group(self):
|
||||
"""Test various types of network groups"""
|
||||
from pybitmessage.protocol import network_group
|
||||
|
||||
test_ip = '1.2.3.4'
|
||||
self.assertEqual('\x01\x02', network_group(test_ip))
|
||||
|
||||
test_ip = '127.0.0.1'
|
||||
self.assertEqual('IPv4', network_group(test_ip))
|
||||
|
||||
test_ip = '0102:0304:0506:0708:090A:0B0C:0D0E:0F10'
|
||||
self.assertEqual(
|
||||
'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C',
|
||||
network_group(test_ip))
|
||||
|
||||
test_ip = 'bootstrap8444.bitmessage.org'
|
||||
self.assertEqual(
|
||||
'bootstrap8444.bitmessage.org',
|
||||
network_group(test_ip))
|
||||
|
||||
test_ip = 'quzwelsuziwqgpt2.onion'
|
||||
self.assertEqual(
|
||||
test_ip,
|
||||
network_group(test_ip))
|
||||
|
||||
test_ip = None
|
||||
self.assertEqual(
|
||||
None,
|
||||
network_group(test_ip))
|
Reference in New Issue
Block a user