diff --git a/src/Config.py b/src/Config.py index 4738a8be..c5ebf060 100644 --- a/src/Config.py +++ b/src/Config.py @@ -212,7 +212,8 @@ class Config(object): self.parser.add_argument('--workers', help='Download workers per site', default=5, type=int, metavar='workers') self.parser.add_argument('--fileserver_ip', help='FileServer bind address', default="*", metavar='ip') - self.parser.add_argument('--fileserver_port', help='FileServer bind port', default=15441, 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('--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') diff --git a/src/Connection/ConnectionServer.py b/src/Connection/ConnectionServer.py index e6c04dd9..84cef96e 100644 --- a/src/Connection/ConnectionServer.py +++ b/src/Connection/ConnectionServer.py @@ -61,22 +61,25 @@ class ConnectionServer(object): ) sys.exit(0) - if port: # Listen server on a port - self.pool = Pool(500) # do not accept more than 500 connections - self.stream_server = StreamServer( - (ip.replace("*", "0.0.0.0"), port), self.handleIncomingConnection, spawn=self.pool, backlog=100 - ) - if request_handler: - self.handleRequest = request_handler + if request_handler: + self.handleRequest = request_handler def start(self): self.running = True CryptConnection.manager.loadCerts() + if not self.port: + self.log.info("No port found, not binding") + return False + self.log.debug("Binding to: %s:%s, (msgpack: %s), supported crypt: %s" % ( self.ip, self.port, ".".join(map(str, msgpack.version)), CryptConnection.manager.crypt_supported) ) try: + self.pool = Pool(500) # do not accept more than 500 connections + self.stream_server = StreamServer( + (self.ip, self.port), self.handleIncomingConnection, spawn=self.pool, backlog=100 + ) self.stream_server.serve_forever() # Start normal connection server except Exception, err: self.log.info("StreamServer bind error, must be running already: %s" % err) diff --git a/src/File/FileServer.py b/src/File/FileServer.py index b76467c9..65882bbd 100644 --- a/src/File/FileServer.py +++ b/src/File/FileServer.py @@ -3,6 +3,7 @@ import urllib2 import re import time import random +import socket import gevent @@ -20,10 +21,21 @@ from Plugin import PluginManager class FileServer(ConnectionServer): def __init__(self, ip=config.fileserver_ip, port=config.fileserver_port): - ConnectionServer.__init__(self, ip, port, self.handleRequest) - self.site_manager = SiteManager.site_manager self.log = logging.getLogger("FileServer") + ip = ip.replace("*", "0.0.0.0") + + should_use_random_port = port == 0 or config.tor == "always" + if should_use_random_port: + port_range_from, port_range_to = map(int, config.fileserver_port_range.split("-")) + port = self.getRandomPort(ip, port_range_from, port_range_to) + config.fileserver_port = port + if not port: + raise Exception("Can't find bindable port") + if not config.tor == "always": + config.saveValue("fileserver_port", port) # Save random port value for next restart + + ConnectionServer.__init__(self, ip, port, self.handleRequest) if config.ip_external: # Ip external defined in arguments self.port_opened = True @@ -36,6 +48,28 @@ class FileServer(ConnectionServer): self.files_parsing = {} self.ui_server = None + def getRandomPort(self, ip, port_range_from, port_range_to): + self.log.info("Getting random port in range %s-%s..." % (port_range_from, port_range_to)) + tried = [] + for bind_retry in range(100): + port = random.randint(port_range_from, port_range_to) + if port in tried: + continue + tried.append(port) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.bind((ip, port)) + success = True + except Exception as err: + self.log.warning("Error binding to port %s: %s" % (port, err)) + success = False + sock.close() + if success: + return port + else: + time.sleep(0.1) + return False + # Handle request to fileserver def handleRequest(self, connection, message): if config.verbose: