mirror of
https://github.com/alexta69/metube.git
synced 2026-09-21 21:45:04 +00:00
fix: accept HOST=* so IPv6 users get a dual-stack bind (closes #795)
aiohttp hands HOST straight to getaddrinfo, which has no notion of a '*' wildcard: the lookup fails and MeTube dies at startup on an opaque DNS error. '*' is nevertheless what people reach for when they want to serve both IP stacks -- it is the answer given on #795 -- while the value that actually does it, an empty string, is undiscoverable. asyncio expands an empty host to one listening socket per address family, so map '*' onto it. Verified against the real stack: '' -> [('0.0.0.0', p), ('::', p, 0, 0)] '0.0.0.0' -> [('0.0.0.0', p)] '::' -> [('::', p, 0, 0)] '*' -> gaierror (before this change) The README claimed the 0.0.0.0 default was "all interfaces", which is only true of IPv4; document the three modes instead. Note that '::' is IPv6-only whatever the host's bindv6only says, because asyncio always sets IPV6_V6ONLY on the sockets it binds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+15
-1
@@ -113,6 +113,18 @@ class Config:
|
||||
sys.exit(1)
|
||||
setattr(self, k, v in ('true', 'True', 'on', '1'))
|
||||
|
||||
# aiohttp hands HOST straight to getaddrinfo, which has no notion of a
|
||||
# '*' wildcard: the lookup fails and takes the server down at startup
|
||||
# with an opaque DNS error. '*' is nevertheless what people reach for
|
||||
# when they want to serve both IP stacks, while the value that actually
|
||||
# does it -- an empty string, which asyncio expands to one listening
|
||||
# socket per address family -- is undiscoverable. Accept '*' as the
|
||||
# spelling for "every interface, both stacks". Note that '::' on its own
|
||||
# is IPv6-only regardless of the host's bindv6only setting, because
|
||||
# asyncio always sets IPV6_V6ONLY on the sockets it binds.
|
||||
if self.HOST.strip() == '*':
|
||||
self.HOST = ''
|
||||
|
||||
if not self.URL_PREFIX.endswith('/'):
|
||||
self.URL_PREFIX += '/'
|
||||
|
||||
@@ -1386,7 +1398,9 @@ def isAccessLogEnabled():
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.getLogger().setLevel(parseLogLevel(config.LOGLEVEL) or logging.INFO)
|
||||
log.info(f"Listening on {config.HOST}:{config.PORT}")
|
||||
# An empty HOST binds every interface on both stacks; print the '*' spelling
|
||||
# that selects it rather than a bare ':8081'.
|
||||
log.info(f"Listening on {config.HOST or '*'}:{config.PORT}")
|
||||
|
||||
|
||||
# Auto-detect cookie file on startup
|
||||
|
||||
Reference in New Issue
Block a user