private IP range checks

When advertising nodes and when establishing connections, private IP
range checks were not done. This could cause private IPs to be
advertised across the network. Also, some of the checks weren't
IPv6-aware.
Fixes Bitmessage#768
This commit is contained in:
mailchuck 2016-01-26 12:04:06 +01:00 committed by Peter Surda
parent 47f1c0c267
commit 4f26bf1059
2 changed files with 41 additions and 28 deletions

View File

@ -490,9 +490,19 @@ class receiveDataThread(threading.Thread):
logger.debug('sending an object.') logger.debug('sending an object.')
self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('object',payload))) self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('object',payload)))
def _checkIPAddress(self, host):
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:])
return self._checkIPv4Address(host[12:], hostStandardFormat)
else:
hostStandardFormat = socket.inet_ntop(socket.AF_INET6, host)
if hostStandardFormat == "":
# This can happen on Windows systems which are not 64-bit compatible
# so let us drop the IPv6 address.
return False
return self._checkIPv6Address(host, hostStandardFormat)
def _checkIPv4Address(self, host, hostStandardFormat): def _checkIPv4Address(self, host, hostStandardFormat):
# print 'hostStandardFormat', hostStandardFormat
if host[0] == '\x7F': # 127/8 if host[0] == '\x7F': # 127/8
logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat)
return False return False
@ -505,7 +515,7 @@ class receiveDataThread(threading.Thread):
if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12
logger.debug('Ignoring IP address in private range:' + hostStandardFormat) logger.debug('Ignoring IP address in private range:' + hostStandardFormat)
return False return False
return True return hostStandardFormat
def _checkIPv6Address(self, host, hostStandardFormat): def _checkIPv6Address(self, host, hostStandardFormat):
if host == ('\x00' * 15) + '\x01': if host == ('\x00' * 15) + '\x01':
@ -517,7 +527,7 @@ class receiveDataThread(threading.Thread):
if (ord(host[0]) & 0xfe) == 0xfc: if (ord(host[0]) & 0xfe) == 0xfc:
logger.debug ('Ignoring unique local address: ' + hostStandardFormat) logger.debug ('Ignoring unique local address: ' + hostStandardFormat)
return False return False
return True return hostStandardFormat
# We have received an addr message. # We have received an addr message.
def recaddr(self, data): def recaddr(self, data):
@ -545,18 +555,8 @@ class receiveDataThread(threading.Thread):
38 * i):20 + lengthOfNumberOfAddresses + (38 * i)]) 38 * i):20 + lengthOfNumberOfAddresses + (38 * i)])
recaddrPort, = unpack('>H', data[36 + lengthOfNumberOfAddresses + ( recaddrPort, = unpack('>H', data[36 + lengthOfNumberOfAddresses + (
38 * i):38 + lengthOfNumberOfAddresses + (38 * i)]) 38 * i):38 + lengthOfNumberOfAddresses + (38 * i)])
if fullHost[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': hostStandardFormat = self._checkIPAddress(fullHost)
ipv4Host = fullHost[12:] if hostStandardFormat is False:
hostStandardFormat = socket.inet_ntop(socket.AF_INET, ipv4Host)
if not self._checkIPv4Address(ipv4Host, hostStandardFormat):
continue
else:
hostStandardFormat = socket.inet_ntop(socket.AF_INET6, fullHost)
if hostStandardFormat == "":
# This can happen on Windows systems which are not 64-bit compatible
# so let us drop the IPv6 address.
continue
if not self._checkIPv6Address(fullHost, hostStandardFormat):
continue continue
timeSomeoneElseReceivedMessageFromThisNode, = unpack('>Q', data[lengthOfNumberOfAddresses + ( timeSomeoneElseReceivedMessageFromThisNode, = unpack('>Q', data[lengthOfNumberOfAddresses + (
38 * i):8 + lengthOfNumberOfAddresses + (38 * i)]) # This is the 'time' value in the received addr message. 64-bit. 38 * i):8 + lengthOfNumberOfAddresses + (38 * i)]) # This is the 'time' value in the received addr message. 64-bit.
@ -744,6 +744,7 @@ class receiveDataThread(threading.Thread):
# in this version message. Let us inform the sendDataThread. # in this version message. Let us inform the sendDataThread.
self.sendDataThreadQueue.put((0, 'setRemoteProtocolVersion', self.remoteProtocolVersion)) self.sendDataThreadQueue.put((0, 'setRemoteProtocolVersion', self.remoteProtocolVersion))
if not isHostInPrivateIPRange(self.peer.host):
with shared.knownNodesLock: with shared.knownNodesLock:
shared.knownNodes[self.streamNumber][shared.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) shared.knownNodes[self.streamNumber][shared.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time())
shared.needToWriteKnownNodesToDisk = True shared.needToWriteKnownNodesToDisk = True

View File

@ -1,6 +1,8 @@
import shared import socket
import sys import sys
import shared
def convertIntToString(n): def convertIntToString(n):
a = __builtins__.hex(n) a = __builtins__.hex(n)
if a[-1:] == 'L': if a[-1:] == 'L':
@ -23,6 +25,16 @@ def signal_handler(signal, frame):
print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.'
def isHostInPrivateIPRange(host): def isHostInPrivateIPRange(host):
if ":" in host: #IPv6
hostAddr = socket.inet_pton(socket.AF_INET6, host)
if hostAddr == ('\x00' * 15) + '\x01':
return False
if hostAddr[0] == '\xFE' and (ord(hostAddr[1]) & 0xc0) == 0x80:
return False
if (ord(hostAddr[0]) & 0xfe) == 0xfc:
return False
pass
else:
if host[:3] == '10.': if host[:3] == '10.':
return True return True
if host[:4] == '172.': if host[:4] == '172.':