waitress 1.0a1 doesn't work on linux without internet connectivity (DNS?) #131

Closed
ztane opened this Issue Jul 6, 2016 · 5 comments

Projects

None yet

2 participants

@ztane
ztane commented Jul 6, 2016

I am using:

listen = '127.0.0.1:6543 [::1]:6543'

Now, if I do not have internet connectivity (aeroplane coding mode for example), waitress crashes with:

Traceback (most recent call last):
  File "/.../venv/lib/python3.5/site-packages/waitress/adjustments.py", line 258, in __init__
    socket.AI_PASSIVE | socket.AI_ADDRCONFIG
  File "/usr/lib/python3.5/socket.py", line 732, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -9] Address family for hostname not supported

This even though the reverses for 127.0.0.1 and ::1 are in /etc/hosts, and they are the names that are displayed on the Serving message. That is, if I change them to localhost123 and ip6-localhost123, and I have internet connectivity, waitress displays:

Serving on http://localhost123:6543
Serving on http://ip6-localhost123:6543
@ztane
ztane commented Jul 6, 2016

This is because of AI_ADDRCONFIG:

    If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4 addresses are returned in the list pointed to by res only if the local system has at least one IPv4 address configured,  and  IPv6
    addresses are returned only if the local system has at least one IPv6 address configured.  The loopback address is not considered for this case as valid as a configured address.  This flag is
     useful on, for example, IPv4-only systems, to ensure that getaddrinfo() does not return IPv6 socket addresses that would always fail in connect(2) or bind(2).

and since there is no internet connectivity, no IP address is configured on any other interface except loopback. Perhaps it should be changed so that if AI_ADDRCONFIG fails then either

  • the lookup is tried with AI_NUMERICHOST without AI_ADDRCONFIG,
  • or the lookup itself is tried without AI_ADDRCONFIG, possibly with issuance of a warning or not...
@ztane
ztane commented Jul 6, 2016 edited

Now I believe the correct option should be to drop AI_ADDRCONFIG altogether. The reason for using AI_ADDRCONFIG is to ensure that you're not resolving only IPv6 addresses on a machine that doesn't have IPv6 connection to outside, or IPv4 on a machine with no IPv4 connectivity. Since all of the resolved addresses are bound to, it doesn't matter whether they're only internal. The only case is if you have only IPv6 addressing inside your network with no IPv4 addressing within the network and only IPv4 addressing outside and you're binding by a hostname, or you have IPv6 completely disabled on your system, even on localhost, but getaddrinfo still offering IPv6 address for loopback interface.

@bertjwregeer
Member

I went back and forth on adding AI_ADDRCONFIG. It's probably the wrong thing to do when explicitly requesting localhost (either ::1 or 127.0.0.1) but when using a hostname that is then resolved using getaddrinfo() it is potentially the right thing to do...

For example, on OS X you could set your listen parameter to:

alexandra.network.lan:8080

Where alexandra.network.lan is your local machines name, and a DNS entry that resolves. If the DNS server has stale data due to DHCPv6 not having updated it, it's possible it will return an IPv6 address that is invalid for the machine and attempting to bind() to all results without AI_ADDRCONFIG would do the wrong thing. I'll admit it is an example of a broken local network, but it is an issue I ran into.


At this point, I can agree to dropping AI_ADDRCONFIG, if your local network is misconfigured that's not something I really should try to protect against. I will NOT be adding AI_NUMERICHOST because it disallows the use of hostnames in getaddrfinfo() and I want to allow the user to say listen = localhost:8080 and listen on whatever addresses are returned for that (generally 127.0.0.1 and ::1 unless you are on some flavour of linux that uses ip6-localhost).


Regarding the "Serving on" messages. Those are found by getting the name info for the IP address that is bound to, basically doing a reverse DNS query, including what is in /etc/hosts.

Thanks for your report, will get a fix out by the end of today! Appreciate the testing!

@bertjwregeer bertjwregeer added a commit that closed this issue Jul 7, 2016
@bertjwregeer bertjwregeer Remove AI_ADDRCONFIG
Closes #131
2e5926b
@ztane
ztane commented Jul 7, 2016 edited

Ah, the AI_NUMERICHOST would have been

try:
    addressses = getaddrinfo(...|AI_ADDRCONFIG)
except:
    addresses = getaddrinfo(...|AI_NUMERICHOST)

and let the exception propagate only when both of them fail.

@bertjwregeer
Member

It's not really required though, by default getaddrinfo does the right thing when you pass it a numeric host or non-numeric. Also that still wouldn't support the use case of:

listen = localhost:8080

Because it would fail on theAI_ ADDRCONFIG when the user has no network connectivity, and it isn't a numeric host so it would fail on the AI_NUMERICHOST.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment