Skip to content
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

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

wanneut
Copy link

@wanneut wanneut commented Mar 14, 2018

Changes proposed there: #1719 .

@wanneut
Copy link
Author

wanneut commented Mar 14, 2018

I don't understand what this should do:

elif netloc == "":

netloc has should always have a value which is set Bind:
if 'PORT' in os.environ:

@@ -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'))]
Copy link
Collaborator

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?

Copy link
Author

@wanneut wanneut Mar 15, 2018

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)

@tilgovi tilgovi self-requested a review March 14, 2018 17:47
@tilgovi
Copy link
Collaborator

tilgovi commented Mar 14, 2018

I don't understand what this should do

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 parse_address?

@tilgovi
Copy link
Collaborator

tilgovi commented Mar 14, 2018

Oh, I'm sorry, that's a good default when we don't automatically default to binding to every interface (PORT is undefined). I don't know what a good default is for the other case. Maybe it's to provide two addresses the way I described before.

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)
Copy link
Collaborator

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?

Copy link
Author

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.

@wanneut
Copy link
Author

wanneut commented Mar 15, 2018

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.
Think there are many gunicorn instances without security measures.
But in is set to that already in config.

@wanneut
Copy link
Author

wanneut commented Mar 15, 2018

So now all test pass. (And I added a view.) I think all cases are handled properly now.

@wanneut
Copy link
Author

wanneut commented Mar 15, 2018

OK, not on Ubuntu Trusty Tahr (from 2014).
The IPv6 entry in /etc/hosts for localhost is missing there.
On debian jessie (from 2015) and stretch all checks pass so it is on CentOS 7 and Ubuntu Bionic Beaver.

@benoitc
Copy link
Owner

benoitc commented Mar 20, 2018

_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.

@wanneut
Copy link
Author

wanneut commented Mar 20, 2018

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/.

@@ -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]

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why replacing that code?

Copy link
Author

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'))]
Copy link
Owner

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?

Copy link
Author

@wanneut wanneut Apr 3, 2018

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.

@benoitc
Copy link
Owner

benoitc commented Apr 1, 2018

mm if ipv6 is not enabled at all on the machine at the kernel level it shouldn’t work normally. i will test anyway

@wanneut
Copy link
Author

wanneut commented Apr 3, 2018

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.

@wanneut
Copy link
Author

wanneut commented Apr 18, 2018

I think the TOXENV=lint check is broken.

@tilgovi
Copy link
Collaborator

tilgovi commented Apr 26, 2018

@wanneut why are some of the test cases commented out?

@wanneut
Copy link
Author

wanneut commented Apr 27, 2018

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.
Yesterday there was a release of an new Ubuntu LTS version. So may the testing environment is updated and the tests can be used again.
Another option would be to replace localhost by a "real" domain but this would require a working Internet connection for testing. I don't know if that is wanted.
So I just commented them out and hoped that someone else, who reads it decides what to do.
Btw.: I thought about testing the protocol specific localhost addresses but this is even worse for testing on different OSes. On some they are named ip4-loopback and ip6-loopback on some localhost4 on some localhost-v4 on some there are only the v6 specific and the v4 specific missing...

@tilgovi
Copy link
Collaborator

tilgovi commented Apr 27, 2018

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.

@wanneut
Copy link
Author

wanneut commented May 3, 2018

The tests passed on my debian PC with. They did never pass in the testing environment.

@wanneut
Copy link
Author

wanneut commented Jun 12, 2018

Is anybody still following this?

@tilgovi
Copy link
Collaborator

tilgovi commented Jun 14, 2018

@wanneut thanks for the nudge. I'll try to pick this up.

@tilgovi tilgovi self-assigned this Jun 14, 2018
@tilgovi
Copy link
Collaborator

tilgovi commented Jan 22, 2019

I'll pick this up again for the next cycle after R20. Sorry for the delay and thank you for your patience and efforts.

@rivimey
Copy link

rivimey commented Sep 28, 2020

bump - is this still relevant? I'm interested in getting gunicorn listening on ipv6 for a dual-family host.

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

Successfully merging this pull request may close these issues.

5 participants