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

resolving hostnames for bind #1719

Open
wanneut opened this issue Mar 9, 2018 · 8 comments
Open

resolving hostnames for bind #1719

wanneut opened this issue Mar 9, 2018 · 8 comments

Comments

@wanneut
Copy link

wanneut commented Mar 9, 2018

gunicorn takes a list of hostnames, checks for everyone if it is a IPv6 address and if it is not, it binds to the IPv4 address of the hostname.
The relevant parts are:

return [util.parse_address(_compat.bytes_to_str(bind)) for bind in s]

if util.is_ipv6(addr[0]):

socket.inet_pton(socket.AF_INET6, addr)

This makes two wrong assumptions:

  • Every hostname has exact one IP-address.
  • A hostname can not resolve to an IPv6 address.

Even for the most common example localhost this assumptions are not true:
localhost resolves on the most systems to ::1 and 127.0.0.1. But gunicorn binds only to 127.0.0.1 (the first IPv4 address)
If a standards-compliant software tries to connect to gunicorn on localhost it will at first try to connect to ::1 and only after that times out to 127.0.0.1.
So most of my clients disable IPv6 to make gunicorn react faster…

A much better approach would be to loop over all results of getaddrinfo and just bind to whatever family it returns:
https://docs.python.org/2.5/lib/socket-example.html

@tilgovi
Copy link
Collaborator

tilgovi commented Mar 10, 2018

Thank you for reporting this issue! If you would like to make a PR, I'd be happy to review it with you.

@tilgovi
Copy link
Collaborator

tilgovi commented Mar 10, 2018

It seems like we might have to change that first comprehension to complex comprehension and have parse_address yield one or multiple addresses. I am open to other approaches, but that seems the least invasive.

@wanneut
Copy link
Author

wanneut commented Mar 12, 2018

Tried to make a nicer approach to handle different family types there https://github.com/wanneut/gunicorn
But there is still a little work to do. (Some former tests fail, because they are still using is_ipv6... And I still don't understand how you close sockets.)
I am not that fit in python programming. Can you have a look?

@tilgovi
Copy link
Collaborator

tilgovi commented Mar 12, 2018

@wanneut I took a look and left some style comments, but I like your approach! I won't be able to look at tests until later today, but this is great. Thank you. You should be able to close sockets with .close().

@tilgovi
Copy link
Collaborator

tilgovi commented Mar 12, 2018

We also have a helper in gunicorn.util to close a socket and catch any error when you don't care about errors.

@wanneut
Copy link
Author

wanneut commented Mar 14, 2018

I start adopting the tests.

@gozdal
Copy link

gozdal commented Nov 12, 2021

I've stumbled upon exact this problem and see that the old PR was abandoned. I've created a minimal change which allows gunicorn to listen on IPv6 addresses specified as hostnames. Unfortunately the GitHub check on AppVeyor seems to be broken currently. Not sure how I could proceed with this #2689, @tilgovi maybe you can advise?

@gozdal
Copy link

gozdal commented Nov 12, 2021

I've run the tests locally and they seem to pass (apart from pylint, although it's not something broken by this PR)

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

No branches or pull requests

3 participants