Support dual stack listening

This commit is contained in:
shortcutme 2019-01-23 02:13:13 +01:00
parent 439d2bcf7f
commit 1824363f86
No known key found for this signature in database
GPG key ID: 5B63BAE6CB9613AE
5 changed files with 58 additions and 34 deletions

View file

@ -51,6 +51,7 @@ class ConfigStorage extends Class
options: [ options: [
{title: "IPv4", value: "ipv4"} {title: "IPv4", value: "ipv4"}
{title: "IPv6", value: "ipv6"} {title: "IPv6", value: "ipv6"}
{title: "Dual (IPv4 & IPv6)", value: "dual"}
] ]
description: "Accept incoming peers using IPv4 or IPv6 address. (default: IPv4)" description: "Accept incoming peers using IPv4 or IPv6 address. (default: IPv4)"

View file

@ -1367,7 +1367,7 @@
value: "ipv6" value: "ipv6"
} }
], ],
description: "Accept other peers using IPv4 or IPv6 address. (default: IPv4)" description: "Accept incoming peers using IPv4 or IPv6 address. (default: IPv4)"
}); });
section.items.push({ section.items.push({
key: "fileserver_port", key: "fileserver_port",

View file

@ -237,7 +237,7 @@ class Config(object):
self.parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip') self.parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip')
self.parser.add_argument('--fileserver_port', help='FileServer bind port (0: randomize)', default=0, type=int, metavar='port') self.parser.add_argument('--fileserver_port', help='FileServer bind port (0: randomize)', default=0, type=int, metavar='port')
self.parser.add_argument('--fileserver_port_range', help='FileServer randomization range', default="10000-40000", metavar='port') self.parser.add_argument('--fileserver_port_range', help='FileServer randomization range', default="10000-40000", metavar='port')
self.parser.add_argument('--fileserver_ip_type', help='FileServer ip type', default="ipv4", choices=["ipv4", "ipv6"]) self.parser.add_argument('--fileserver_ip_type', help='FileServer ip type', default="dual", choices=["ipv4", "ipv6", "dual"])
self.parser.add_argument('--ip_local', help='My local ips', default=ip_local, type=int, metavar='ip', nargs='*') self.parser.add_argument('--ip_local', help='My local ips', default=ip_local, type=int, metavar='ip', nargs='*')
self.parser.add_argument('--disable_udp', help='Disable UDP connections', action='store_true') self.parser.add_argument('--disable_udp', help='Disable UDP connections', action='store_true')

View file

@ -32,7 +32,7 @@ class ConnectionServer(object):
self.port = port self.port = port
self.last_connection_id = 1 # Connection id incrementer self.last_connection_id = 1 # Connection id incrementer
self.log = logging.getLogger("ConnServer") self.log = logging.getLogger("ConnServer")
self.port_opened = None self.port_opened = {}
self.peer_blacklist = SiteManager.peer_blacklist self.peer_blacklist = SiteManager.peer_blacklist
self.tor_manager = TorManager(self.ip, self.port) self.tor_manager = TorManager(self.ip, self.port)
@ -42,11 +42,9 @@ class ConnectionServer(object):
self.broken_ssl_ips = {} # Peerids of broken ssl connections self.broken_ssl_ips = {} # Peerids of broken ssl connections
self.ips = {} # Connection by ip self.ips = {} # Connection by ip
self.has_internet = True # Internet outage detection self.has_internet = True # Internet outage detection
self.supported_ip_types = ["ipv4"] # Outgoing ip_type support
if self.isIpv6Supported():
self.supported_ip_types.append("ipv6")
self.stream_server = None self.stream_server = None
self.stream_server_proxy = None
self.running = False self.running = False
self.stat_recv = defaultdict(lambda: defaultdict(int)) self.stat_recv = defaultdict(lambda: defaultdict(int))
@ -61,6 +59,7 @@ class ConnectionServer(object):
self.had_external_incoming = False self.had_external_incoming = False
self.timecorrection = 0.0 self.timecorrection = 0.0
self.pool = Pool(500) # do not accept more than 500 connections
# Bittorrent style peerid # Bittorrent style peerid
self.peer_id = "-UT3530-%s" % CryptHash.random(12, "base64") self.peer_id = "-UT3530-%s" % CryptHash.random(12, "base64")
@ -92,36 +91,15 @@ class ConnectionServer(object):
CryptConnection.manager.crypt_supported, self.supported_ip_types CryptConnection.manager.crypt_supported, self.supported_ip_types
)) ))
try: try:
self.pool = Pool(500) # do not accept more than 500 connections
if helper.getIpType(self.ip) == "ipv6":
sock_address = (self.ip, self.port, 0, 0)
else:
sock_address = (self.ip, self.port)
self.stream_server = StreamServer( self.stream_server = StreamServer(
sock_address, self.handleIncomingConnection, spawn=self.pool, backlog=100 (self.ip, self.port), self.handleIncomingConnection, spawn=self.pool, backlog=100
) )
except Exception, err: except Exception, err:
self.log.info("StreamServer bind error: %s" % err) self.log.info("StreamServer create error: %s" % Debug.formatException(err))
def isIpv6Supported(self):
if helper.getIpType(self.ip) == "ipv6":
return True
# Test if we can connect to ipv6 address
ipv6_testip = "2001:19f0:6c01:e76:5400:1ff:fed6:3eca"
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock.connect((ipv6_testip, 80))
local_ipv6 = sock.getsockname()[0]
if local_ipv6 == "::1":
return False
else:
return True
except Exception as err:
return False
def listen(self): def listen(self):
if self.stream_server_proxy:
gevent.spawn(self.listenProxy)
try: try:
self.stream_server.serve_forever() self.stream_server.serve_forever()
except Exception, err: except Exception, err:

View file

@ -1,9 +1,11 @@
import logging import logging
import time import time
import random import random
import socket
import gevent import gevent
import gevent.pool import gevent.pool
from gevent.server import StreamServer
import util import util
from util import helper from util import helper
@ -13,6 +15,7 @@ from Peer import PeerPortchecker
from Site import SiteManager from Site import SiteManager
from Connection import ConnectionServer from Connection import ConnectionServer
from Plugin import PluginManager from Plugin import PluginManager
from Debug import Debug
@PluginManager.acceptPlugins @PluginManager.acceptPlugins
@ -23,7 +26,12 @@ class FileServer(ConnectionServer):
self.portchecker = PeerPortchecker.PeerPortchecker(self) self.portchecker = PeerPortchecker.PeerPortchecker(self)
self.log = logging.getLogger("FileServer") self.log = logging.getLogger("FileServer")
self.ip_type = ip_type self.ip_type = ip_type
if ip_type == "ipv6":
self.supported_ip_types = ["ipv4"] # Outgoing ip_type support
if helper.getIpType(ip) == "ipv6" or self.isIpv6Supported():
self.supported_ip_types.append("ipv6")
if ip_type == "ipv6" or (ip_type == "dual" and "ipv6" in self.supported_ip_types):
ip = ip.replace("*", "::") ip = ip.replace("*", "::")
else: else:
ip = ip.replace("*", "0.0.0.0") ip = ip.replace("*", "0.0.0.0")
@ -42,14 +50,22 @@ class FileServer(ConnectionServer):
ConnectionServer.__init__(self, ip, port, self.handleRequest) ConnectionServer.__init__(self, ip, port, self.handleRequest)
if ip_type == "dual" and ip == "::":
# Also bind to ipv4 addres in dual mode
try:
self.log.debug("Binding proxy to %s:%s" % ("::", self.port))
self.stream_server_proxy = StreamServer(
("0.0.0.0", self.port), self.handleIncomingConnection, spawn=self.pool, backlog=100
)
except Exception, err:
self.log.info("StreamServer proxy create error: %s" % Debug.formatException(err))
self.port_opened = {} self.port_opened = {}
if config.ip_external: # Ip external defined in arguments if config.ip_external: # Ip external defined in arguments
self.port_opened[helper.getIpType(config.ip_external)] = True self.port_opened[helper.getIpType(config.ip_external)] = True
SiteManager.peer_blacklist.append((config.ip_external, self.port)) # Add myself to peer blacklist SiteManager.peer_blacklist.append((config.ip_external, self.port)) # Add myself to peer blacklist
else:
self.port_opened = None # Check it later
self.sites = {} self.sites = {}
self.last_request = time.time() self.last_request = time.time()
self.files_parsing = {} self.files_parsing = {}
@ -78,6 +94,35 @@ class FileServer(ConnectionServer):
time.sleep(0.1) time.sleep(0.1)
return False return False
def isIpv6Supported(self):
# Test if we can connect to ipv6 address
ipv6_testip = "2001:19f0:6c01:e76:5400:1ff:fed6:3eca"
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
sock.connect((ipv6_testip, 80))
local_ipv6 = sock.getsockname()[0]
if local_ipv6 == "::1":
self.log.debug("IPv6 not supported, no local IPv6 address")
return False
else:
self.log.debug("IPv6 supported on IP %s" % local_ipv6)
return True
except socket.error as err:
self.log.error("IPv6 not supported: %s" % err)
return False
except Exception as err:
self.log.error("IPv6 check error: %s" % err)
return False
def listenProxy(self):
try:
self.stream_server_proxy.serve_forever()
except Exception, err:
if err.errno == 98: # Address already in use error
self.log.debug("StreamServer proxy listen error: %s" % err)
else:
self.log.info("StreamServer proxy listen error: %s" % err)
# Handle request to fileserver # Handle request to fileserver
def handleRequest(self, connection, message): def handleRequest(self, connection, message):
if config.verbose: if config.verbose: