diff --git a/docs/ENVIRONMENT.rst b/docs/ENVIRONMENT.rst index d730b35..cd7872c 100644 --- a/docs/ENVIRONMENT.rst +++ b/docs/ENVIRONMENT.rst @@ -85,8 +85,11 @@ These environment variables are optional: * **HOST** - The host that the TCP and SSL servers will use. Defaults to - `localhost`. Set to blank to listen on all addresses (IPv4 and IPv6). + The host or IP address that the TCP and SSL servers will use when + binding listening sockets. Defaults to `localhost`. To listen on + multiple specific addresses specify a comma-separated list. Set to + an empty string to listen on all available interfaces (likely both + IPv4 and IPv6). * **TCP_PORT** diff --git a/server/controller.py b/server/controller.py index 2f17773..3d0541a 100644 --- a/server/controller.py +++ b/server/controller.py @@ -305,12 +305,13 @@ class Controller(util.LoggedClass): self.state = self.LISTENING env = self.env + host = env.cs_host() if env.tcp_port is not None: - await self.start_server('TCP', env.host, env.tcp_port) + await self.start_server('TCP', host, env.tcp_port) if env.ssl_port is not None: sslc = ssl.SSLContext(ssl.PROTOCOL_TLS) sslc.load_cert_chain(env.ssl_certfile, keyfile=env.ssl_keyfile) - await self.start_server('SSL', env.host, env.ssl_port, ssl=sslc) + await self.start_server('SSL', host, env.ssl_port, ssl=sslc) async def notify(self): '''Notify sessions about height changes and touched addresses.''' diff --git a/server/env.py b/server/env.py index a002549..cd2d0e9 100644 --- a/server/env.py +++ b/server/env.py @@ -183,3 +183,12 @@ class Env(lib_util.LoggedClass): import uvloop return uvloop.EventLoopPolicy() raise self.Error('unknown event loop policy "{}"'.format(policy)) + + def cs_host(self): + '''Returns the 'host' argument to pass to asyncio's create_server + call. The result can be a single host name string, a list of + host name strings, or an empty string to bind to all interfaces.''' + result = self.host.split(',') + if len(result) == 1: + result = result[0] + return result diff --git a/server/peers.py b/server/peers.py index 287efe1..2b67c37 100644 --- a/server/peers.py +++ b/server/peers.py @@ -562,7 +562,12 @@ class PeerManager(util.LoggedClass): else: create_connection = self.loop.create_connection - local_addr = (self.env.host, None) if self.env.host else None + # Use our listening Host/IP for outgoing connections so our + # peers see the correct source. + host = self.env.cs_host() + if isinstance(host, list): + host = host[0] + local_addr = (host, None) if host else None protocol_factory = partial(PeerSession, peer, self, kind) coro = create_connection(protocol_factory, peer.host, port, ssl=sslc, diff --git a/tests/server/test_env.py b/tests/server/test_env.py index da4923f..315ee86 100644 --- a/tests/server/test_env.py +++ b/tests/server/test_env.py @@ -94,6 +94,12 @@ def test_CACHE_MB(): def test_HOST(): assert_default('HOST', 'host', 'localhost') + os.environ['HOST'] = '' + e = Env() + assert e.cs_host() == '' + os.environ['HOST'] = '192.168.0.1,23.45.67.89' + e = Env() + assert e.cs_host() == ['192.168.0.1', '23.45.67.89'] def test_REORG_LIMIT(): assert_integer('REORG_LIMIT', 'reorg_limit', lib_coins.Bitcoin.REORG_LIMIT)