Skip to content

Added support for proxy protocol v2.#2912

Closed
apollo13 wants to merge 7 commits into
benoitc:masterfrom
apollo13:proxy-v2
Closed

Added support for proxy protocol v2.#2912
apollo13 wants to merge 7 commits into
benoitc:masterfrom
apollo13:proxy-v2

Conversation

@apollo13
Copy link
Copy Markdown
Contributor

@apollo13 apollo13 commented Jan 2, 2023

This PR adds support for proxy protocol v2 (v1 keeps working as well): https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

Additionally I did rewrite the BytesIO usage to bytearray, the code becomes simpler imo because we can just keep a buffer around and resize it as needed.

Comment thread gunicorn/http/message.py Outdated
Comment thread gunicorn/http/message.py
@apollo13
Copy link
Copy Markdown
Contributor Author

apollo13 commented Jan 27, 2023 via email

@frittentheke
Copy link
Copy Markdown

Very cool to have this feature!

Comment thread gunicorn/http/message.py
"""
if not self.cfg.proxy_protocol:
return False
return
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A docstring above still says "... else False".

And why did you decide change False to None?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is no longer needed. Previously the code checked the return value based on this and then changed behavior. Now the proxy protocol parsing is fully "transparent" and leaves the streams in a usable state for follow up. Will adjust the comment in a follow up commit.

Comment thread gunicorn/http/message.py Outdated
if ver_cmd & 0xF == 0x00:
return # LOCAL command, do not change source addr

if fam == 0x11: # TCPv4
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How about to make constants with meaningful names for 0x11 and so on instead comments? Or enum.IntFlag?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sounds like a plan, will see what I can come up with.

Comment thread gunicorn/http/message.py
s_addr, d_addr, s_port, d_port = struct.unpack(fmt, body)
except struct.error as e:
raise InvalidProxyHeader("cannot unpack %r: %s" % (body, e))
s_addr = str(ip_class(s_addr))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is it needed? - converting str -> ipaddress -> str. Why just not use str representation as is?

If it is needed for validation then where is the error handling?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

s_addr is never really a string but either an 4-byte integer (ipv4 case) or a 16-byte integer (ipv6 case). Those are "narrow" binary representations of the addresses and not directly usable. So this code is turning the address into something human readable.

As for validation errors: How much do we want to trust the trusted proxies to send the correct data? :D

@benoitc benoitc added this to the 21.0 milestone May 11, 2023
@apollo13
Copy link
Copy Markdown
Contributor Author

Hi @sirkonst and @benoitc -- sorry for the late reply; I have lost track here. I'll update and address the comments today. In the meantime it would be great if you could review #2913, due to the bugs in Unreader (at least if I understood the purpose of it correctly) I was not able to utilize it in this PR properly.

@apollo13
Copy link
Copy Markdown
Contributor Author

I think I have addressed all comments, as far as I can see the linting errors are coming from other files. Let me know what you think.

@tilgovi tilgovi modified the milestones: 21.0, 22.0 Dec 28, 2023
@benoitc benoitc closed this Jan 23, 2026
@benoitc
Copy link
Copy Markdown
Owner

benoitc commented Jan 23, 2026

sorry , didn't intent to close this . I will take care of this change in coming release

@benoitc benoitc reopened this Jan 23, 2026
benoitc added a commit that referenced this pull request Jan 23, 2026
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.

Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6

Backwards compatible: --proxy-protocol alone (or True) maps to "auto".

Closes #2912
benoitc added a commit that referenced this pull request Jan 23, 2026
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.

Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6

Backwards compatible: --proxy-protocol alone (or True) maps to "auto".

Closes #2912
benoitc added a commit that referenced this pull request Jan 23, 2026
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.

Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6

Backwards compatible: --proxy-protocol alone (or True) maps to "auto".

Closes #2912
benoitc added a commit that referenced this pull request Jan 23, 2026
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.

Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6

Backwards compatible: --proxy-protocol alone (or True) maps to "auto".

Closes #2912
benoitc added a commit that referenced this pull request Jan 23, 2026
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.

Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6

Backwards compatible: --proxy-protocol alone (or True) maps to "auto".

Closes #2912
benoitc added a commit that referenced this pull request Jan 23, 2026
Extend --proxy-protocol to accept version values (off, v1, v2, auto) instead
of being boolean-only. This allows explicit control over which PROXY protocol
versions are accepted.

Changes:
- Add InvalidProxyHeader exception for v2 binary header errors
- Add validate_proxy_protocol() validator with backwards compatibility
- Update ProxyProtocol setting with nargs="?" and const="auto"
- Add PROXY v2 constants (PP_V2_SIGNATURE, PPCommand, PPFamily, PPProtocol)
- Add _parse_proxy_protocol_v1() and _parse_proxy_protocol_v2() methods
- Update both sync (message.py) and async (asgi/message.py) parsers
- Add hex escape handling in treq.py for v2 binary test data
- Add test cases for v2 TCPv4 and TCPv6

Backwards compatible: --proxy-protocol alone (or True) maps to "auto".

Closes #2912
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