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

Allow to bind to IPv6 address specified by name, not address #2689

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

Conversation

gozdal
Copy link

@gozdal gozdal commented Nov 15, 2021

No description provided.

gunicorn/sock.py Outdated Show resolved Hide resolved
sys.exit(1)
if sock is not None:
listeners.append(sock)
some_sock_succeeded = True
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we bind to all addresses returned from getaddrinfo, or just the first one that succeeds?

Copy link
Author

Choose a reason for hiding this comment

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

I think we should bind to them all, try at least. IIUC getaddrinfo returns the result in unspecified order. It means that one call may return [IPv6 address, IPv4 address] and the next [IPv4 address, IPv6 address]. If binding only to the first one we'd be introducing non-determinism between runs.

gunicorn/sock.py Outdated

listeners.append(sock)
if not some_sock_succeeded:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd like to see some_sock_succeeded moved inside the outermost loop, and an exit if we fail to bind any of the specified bind addresses to at least one of their infos. I think the indentation of this check and the some_sock_succeeded = False should be done for each specified bind address. That would be consistent with the previous behavior.

Copy link
Author

Choose a reason for hiding this comment

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

That would be consistent with the previous behavior.

Indeed, though I wonder if it's the best behavior - if a hostname resolves to both IPv4 and IPv6 or the user passed multiple addresses, failure to bind to any of them results in sys.exit(1).

I guess this could be left in the name of backwards compatibility but doing sys.exit(1) if any bind failed seemed pretty harsh to me.

@gozdal gozdal requested a review from tilgovi December 7, 2021 12:30
@tilgovi tilgovi self-assigned this Jan 23, 2022
@gozdal
Copy link
Author

gozdal commented Aug 5, 2022

@tilgovi can I do something to help getting this merged?

@gozdal
Copy link
Author

gozdal commented Mar 1, 2023

@tilgovi @benoitc
can I do something to help getting this merged?

@benoitc benoitc added this to the 21.0 release milestone May 7, 2023
@tilgovi tilgovi modified the milestones: 21.0, 22.0 Dec 28, 2023
@ddzialak
Copy link
Contributor

ddzialak commented Oct 2, 2024

Rebased and resolved conflicts

@pajod
Copy link
Contributor

pajod commented Oct 3, 2024

(just my commentary, not what is blocking this PR from moving forward)

  • Prior to this change an invalid bind setting (such as a lone dot) went through to Can't connect to error output, and possibly a more specific root cause, such as OverflowError: bind(): port must be 0-65535.
  • After this change you can crash via UnicodeError: encoding with 'idna' codec failed or OverflowError: Python int too large to convert to C long
  • After this change all the bind addresses requested by the user might be skipped over.. leading to a crash wish IndexError: list index out of range in the worker
  • Proposed mitigation:
    • Widen except, add both original and resolved addr in logs.
    • Strictly error out when the user instructed to bind somewhere and that attempt was abandoned.
  • Follow-up idea: Depending on the skip-and-warn or strict-error behavior of this PR, the somewhat confusing behavior when mixing address in config and inheriting existing sockets could be changed to match that design decision in a later PR.

Interesting test cases: ".:0", "[::ffff:b1c:00f]:0", "[::ffff:127.0.0.1]:0", "0:0", "[::]:-1", "invalid.:0", "localhost.:0", "localhost:0", "0:210000000000000000000", "[]:0"

@gozdal
Copy link
Author

gozdal commented Oct 3, 2024

UnicodeError: encoding with 'idna' codec failed

How can you get UnicodeError in this code?

@pajod
Copy link
Contributor

pajod commented Oct 3, 2024

UnicodeError: encoding with 'idna' codec failed

How can you get UnicodeError in this code?

When a typo or incorrect variable expansion produces a host name that fails the sanity checks during conversion to ascii form ("Punycode"), e.g leading dot, consecutive dots, labels exceeding >63 ascii bytes.
I tested on CPython 3.12: gunicorn --bind=.:0 -- app - see my previous comment for more interesting test cases.

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