-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue #1719: resolving hostnames for bind #1723
base: master
Are you sure you want to change the base?
Conversation
gunicorn/config.py: using getaddrinfo gunicorn/util.py accept lists gunicorn/sock.py more general family handeling.
@@ -538,9 +538,9 @@ class Bind(Setting): | |||
validator = validate_list_string | |||
|
|||
if 'PORT' in os.environ: | |||
default = ['0.0.0.0:{0}'.format(os.environ.get('PORT'))] | |||
default = ['[::]:{0}'.format(os.environ.get('PORT'))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least on my machine, this returns only IPv6 addresses from socket.getaddrinfo()
. Since this is a list, maybe we want to give it two entries so Gunicorn binds to IPv4 and IPv6 by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you bind to :: you will listen to any address (IPv4 and IPv6) as long the IPV6_V6ONLY flag is not set.
In fact :: could be written as ::0.0.0.0 which is already the IPv4-compatible address for 0.0.0.0. (Older version of ::FFFF:0.0.0.0)
I think it is just being safe and not relying on the config code to set it. However, on my machine, an empty host does what I wanted from the default config where I commented: >>> socket.getaddrinfo('', 80, proto=socket.IPPROTO_TCP)
[(<AddressFamily.AF_INET6: 30>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('::1', 80, 0, 0)), (<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('127.0.0.1', 80))] So maybe the right default is the empty string and we don't need to handle it specially in |
Oh, I'm sorry, that's a good default when we don't automatically default to binding to every interface ( |
gunicorn/sock.py
Outdated
@@ -166,7 +159,8 @@ def create_sockets(conf, log, fds=None): | |||
for fd in fds: | |||
sock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM) | |||
sock_name = sock.getsockname() | |||
sock_type = _sock_type(sock_name) | |||
sockinfo = (sock.family, sock.type, sock.proto, '', socket.getsockname()) | |||
sock_type = _sock_type(sockinfo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you pass a tuple here? _sock_type()
only uses the first element of the tuple sockinfo
. Can't we just pass sock.family
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done so before. But I can change that.
I don't think that 0.0.0.0 is a good default. localhost is much better. I don't like programs witch listen to the world by default while it is very common to configure them insecure. |
So now all test pass. (And I added a view.) I think all cases are handled properly now. |
OK, not on Ubuntu Trusty Tahr (from 2014). |
_One question I have twith this PR is how it will work with OSes that doesn't support or have not been started with IPV6 support. I do think we still need to make sure ipv6 is supported on the OS somehow. |
I think it works perfect. It just binds to IPv4. Only some tests fail. Tried a view examples on a VM with disabled IPv6 in /proc/sys/net/. |
gunicorn/config.py
Outdated
@@ -122,7 +122,11 @@ def worker_class(self): | |||
@property | |||
def address(self): | |||
s = self.settings['bind'].get() | |||
return [util.parse_address(_compat.bytes_to_str(bind)) for bind in s] | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why replacing that code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was described at the beginning. It can handle only one address.
@@ -534,9 +538,9 @@ class Bind(Setting): | |||
validator = validate_list_string | |||
|
|||
if 'PORT' in os.environ: | |||
default = ['0.0.0.0:{0}'.format(os.environ.get('PORT'))] | |||
default = ['[::]:{0}'.format(os.environ.get('PORT'))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about the machine that doesn't support or has not been installed with ipv6 support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The older version dosn't work on IPv6 installations at all.
This version, works everywhere (IPv4 like IPv6) exempt of some obscure Linux-configurations (I think there are not many other OSes where something can be done.), where someone explicitly removed IPv6 support. I think such users should know how to specify another bind address.
If someone shoots himself into his foot he should not wonder if it hurts.
Gunicorn requires Python 2 (which is newer than IPv6.) multithreading and several other things which are much more uncommon than IPv6.
At the end you have to decide what your defaults are.
I mean what about installations with disabled IPv4? It is deprecated for 20 years now. Time to turn it off? IPv6 is compatible to it. So it shouldn't be needed any more. The new code could handle that.
mm if ipv6 is not enabled at all on the machine at the kernel level it shouldn’t work normally. i will test anyway |
It works not if you set the PORT environment variable but no bind-address. The defaults work. If you set a IPv4 bind-address it woks also. |
I think the TOXENV=lint check is broken. |
@wanneut why are some of the test cases commented out? |
On almost all OSes (even older ones) localhost resolves to ::1 and 127.0.0.1. So I used this to test an address that is known to be dual stack. But this seems not to be true for Ubuntu Trusty Tahr. Since this is the environment where the tests are executed I commented them out. |
If these tests passed before, they should pass now, unless behavior has changed. Where the behavior has changed deliberately, can we update the tests to show what the new expectation is? I would love to get this merged. |
The tests passed on my debian PC with. They did never pass in the testing environment. |
Is anybody still following this? |
@wanneut thanks for the nudge. I'll try to pick this up. |
I'll pick this up again for the next cycle after R20. Sorry for the delay and thank you for your patience and efforts. |
bump - is this still relevant? I'm interested in getting gunicorn listening on ipv6 for a dual-family host. |
Changes proposed there: #1719 .