-
Notifications
You must be signed in to change notification settings - Fork 844
PROXY Protocol transformed to Forwarded HTTP header. #3123
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
Conversation
4693d4a to
ba03be0
Compare
|
FWIW, https://httpoxy.org/ describes a vulnerability with origins around the Proxy header. As a result, in our setup, we always remove the Proxy: header |
|
Proxy protocol and the Proxy header is two different thing. This should solve #1985 |
proxy/ProxyProtocol.cc
Outdated
| @@ -0,0 +1,149 @@ | |||
| /** @file | |||
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.
Do you mean to put ProxyProtocol.cc in the tree twice? Both in proxy and iocore/net.
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.
I had moved the ProxyProtocol.cc from proxy/ into iocore/net, then rebased and sqquash my commits, but somehow it is still in both places. I will fix it now.
| } | ||
| internal_msg_buffer_size = 0; | ||
| } | ||
|
|
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.
I am unclear on why you need to keep a copy of the proxy protocol information in the HttpState object. Is this for future growth. I don't see where this PR makes use of that data.
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 Proxy Protocol info is detected, parsed and stashed into the NetVC object. It is then copied into the State object in HttpTransact::initialize_state_variables_from_request() so that it can be accessed in HttpTransactHeaders::add_forwarded_field_to_request to write the Forwarded: header. Somehow, the changes in HttpTransactHeaders.cc didn't get committed into this PR. Will fix this.
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.
Sorry, I had forgotten about a late change in the code. Instead of waiting until it's time to write the headers out, I use the address received in the Proxy Protocol info and set it as the remote address in NetVConnection::get_remote_addr(). This way all internal references to the remote address use the info from Proxy Protocol.
I do store all of the data received in the Proxy Protocol header, and hope that someday, we can use that data in further enhancements, like a full Proxy Protocol implementation.
|
Generally looks reasonable beyond my two comments above. Would be good to have an autest to exercise this code. |
5c540eb to
a9fd370
Compare
|
[approve ci autest] |
|
[approve ci centos] |
|
[approve ci debian] |
iocore/net/Makefile.am
Outdated
| $(top_builddir)/lib/ts/libtsutil.la \ | ||
| $(top_builddir)/iocore/eventsystem/libinkevent.a \ | ||
| $(top_builddir)/proxy/ParentSelectionStrategy.o | ||
| $(top_builddir)/proxy/ParentSelectionStrategy.o |
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 is this additional white space needed ?
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.
Removed the extranseous space
iocore/net/I_NetVConnection.h
Outdated
|
|
||
| enum ProxyProtocolVersion_t { | ||
| PROXY_VERSION_UNDEFINED, | ||
| PROXY_V1, |
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.
PROXY_ here seems a little ambiguous in this flat name space. Can we make the symbols e.g. PROXY_PROTO_VERSION_UNDEF, PROXY_PROTO_VERSION_1 and PROXY_PROTO_VERSION_2 ? Similar to your name spacing further below (in ProxyProtocolData_t).
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.
That, or make ProxyProtocolVersion an enum class and change the names to UNDEFINED and V1.
| int | ||
| set_proxy_protocol_addr(ProxyProtocolData_t src_or_dst, ts::string_view &ip_port_str) | ||
| { | ||
| int ret = -1; |
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.
Nitpicking, but hell, it's what I do. I much prefer an empty line between these local scope variables, and the 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.
Fixing.
iocore/net/I_NetVConnection.h
Outdated
|
|
||
| enum ProxyProtocolData_t { | ||
| PROXY_PROTO_UNDEFINED, | ||
| PROXY_PROTO_SRC, |
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.
Hmmm, this looked a little odd to me when reading the code. You are really treating this like a boolean in (almost?) all places where it's used? Why not just get rid of this, and have a boolean parameter where needed, like proxo_proto_is_src or some such.
I don't care particularly strongly on it though.
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.
I am converting both of these enums to enum classes, and reducing the names to UNDEFINED, VI, etc. As for the ProxyProtocolData enum, I use this as a sort of switch for the get_ and set_proxy_protocol_addr(). E.g. the intent is to call set_proxy_protocol_src_addr() which sets the SRC or DST flag before calling set_proxy_protocol_src_addr(). If this doesn't work for you guys, I can change it to a simple bool. I was just looking for something I could expand on down the road.
iocore/net/P_NetVConnection.h
Outdated
| TS_INLINE sockaddr const * | ||
| NetVConnection::get_proxy_protocol_addr(ProxyProtocolData_t src_or_dst) | ||
| { | ||
| if (src_or_dst == PROXY_PROTO_SRC) { |
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.
Like, here you are treating this really like a boolean, i.e. you don't check any other possible values of src_or_dst).
iocore/net/I_NetVConnection.h
Outdated
| set_proxy_protocol_addr(ProxyProtocolData_t src_or_dst, ts::string_view &ip_port_str) | ||
| { | ||
| int ret = -1; | ||
| if (src_or_dst == PROXY_PROTO_SRC) { |
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.
Same here, treating it as a boolean, not checking any other values in the enum).
iocore/net/ProxyProtocol.cc
Outdated
| bool | ||
| proxy_protov1_parse(NetVConnection *netvc, char *buf) | ||
| { | ||
| std::string src_addr_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.
Not convinced this is a good use of std::string. Is this in the critical path? I.e. if this happens on every request, makes this a sufficiently large char[] on the stack, and use that. You can use snprintf() into that safely (and I assume the size of these port strings are of known, limited size.
I do feel strongly about this on the critical path, where we avoid using std::string intentionally. If it's not in the critical path, e.g. in some configuration code that only happens infrequent, it's fine.
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.
Heh. This is a great place for TextView. Let me rip out some code for it.
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.
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.
I'm implementing amc's TextView with some minor modifications.
iocore/net/ProxyProtocol.h
Outdated
| const char *const PROXY_V2_CONNECTION_PREFACE = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02"; | ||
|
|
||
| const size_t PROXY_V1_CONNECTION_PREFACE_LEN = strlen(PROXY_V1_CONNECTION_PREFACE); // 5 | ||
| const size_t PROXY_V2_CONNECTION_PREFACE_LEN = strlen(PROXY_V2_CONNECTION_PREFACE); // 13 |
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.
I think this will fail, because there is a nul byte in the source string.
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.
Hard coded the value for V2 since it is part of the "spec".
|
|
||
| typedef struct _ProxyProtocol { | ||
| ProxyProtocolVersion proxy_protocol_version = ProxyProtocolVersion::UNDEFINED; | ||
| uint16_t ip_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.
If @zwoop is going to nitpick, I'll note these should be in_port_t.
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.
A more serious question - you have the port values broken out here, but later you have things like
(ats_is_ip(&pp_info.src_addr) && ats_ip_port_cast(&pp_info.src_addr)
which treats the port as being in the IpEndpoint. Why have src_port and dst_port at all? Are these values different from the port in the IpEndpoint?
iocore/net/P_NetVConnection.h
Outdated
| NetVConnection::get_proxy_protocol_addr(ProxyProtocolData_t src_or_dst) | ||
| { | ||
| if (src_or_dst == PROXY_PROTO_SRC) { | ||
| if ((ats_is_ip(&pp_info.src_addr) && ats_ip_port_cast(&pp_info.src_addr)) || |
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.
Becuause src_addr is an IpEndpoint, this can be done as
if ((pp_info.src_addr.isValid() && pp_info.src_addr.port() != 0) ||
fba3b8c to
a028fc4
Compare
a028fc4 to
f2e4d72
Compare
This allows make -j to build all of these things much efficiently, since it's seen as a single build unit. This is similar to how we already build the plugins/ directory. (cherry picked from commit 09e25db)
(cherry picked from commit 882faa0)
(cherry picked from commit 3b07f26)
(cherry picked from commit d859302)
(cherry picked from commit 77882a6)
(cherry picked from commit 5a759ed)
(cherry picked from commit 652f821)
This change imports yaml-cpp 0.6.2 (into lib/yamlcpp) NOTE: I've removed gtest from it's tree (cherry picked from commit 96592e5)
(cherry picked from commit aa908d1)
(cherry picked from commit b0c1653)
…onversion This is still a WIP (cherry picked from commit 1c189cd)
Fixes coredump when testing in production (cherry picked from commit 77be135)
(cherry picked from commit dff7ded)
(cherry picked from commit aafd3a2)
(cherry picked from commit 7fb12c0)
(cherry picked from commit 8ff51f8)
(cherry picked from commit c9d6099)
|
@reveller is there any progress on this? I'd really like to give it a try. |
…trafficserver into proxy-protocol-submit
|
Please remember to remove Milestone and Projects etc. when you close a PR (and not merging it). |
This update automatically detects a PROXY protocol header that precludes either http or https incoming requests. If the header is available, it is parsed and used internally by ATS as the client IP. If the proxy.config.http.insert_forwarded if configured with the 'for:' field, the Forwarded: HTTP header sent to the origin servers will be populated with the client IP passed through the PROXY protocol header. This will facilitate logging of the proper client IP versus load balancer IP. In addition, the origin servers can now use this IP address for tasks such as authz and authn.