Skip to content

Conversation

@reveller
Copy link
Contributor

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.

@reveller reveller added the Core label Feb 14, 2018
@reveller reveller added this to the 8.0.0 milestone Feb 14, 2018
@reveller reveller self-assigned this Feb 14, 2018
@reveller reveller force-pushed the proxy-protocol-submit branch 3 times, most recently from 4693d4a to ba03be0 Compare February 15, 2018 02:15
@mlibbey
Copy link
Contributor

mlibbey commented Feb 15, 2018

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

@shukitchan
Copy link
Contributor

Proxy protocol and the Proxy header is two different thing.
This is a really long-awaited feature. Thanks.

This should solve #1985

@@ -0,0 +1,149 @@
/** @file
Copy link
Member

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.

Copy link
Contributor Author

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;
}

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

@shinrich
Copy link
Member

Generally looks reasonable beyond my two comments above. Would be good to have an autest to exercise this code.

@reveller reveller force-pushed the proxy-protocol-submit branch 3 times, most recently from 5c540eb to a9fd370 Compare February 22, 2018 23:30
@apache apache deleted a comment from reveller Mar 3, 2018
@zwoop
Copy link
Contributor

zwoop commented Mar 3, 2018

[approve ci autest]

@apache apache deleted a comment from reveller Mar 3, 2018
@reveller
Copy link
Contributor Author

reveller commented Mar 5, 2018

[approve ci centos]

@bryancall
Copy link
Contributor

[approve ci debian]

shinrich
shinrich previously approved these changes Mar 12, 2018
zwoop
zwoop previously requested changes Apr 3, 2018
$(top_builddir)/lib/ts/libtsutil.la \
$(top_builddir)/iocore/eventsystem/libinkevent.a \
$(top_builddir)/proxy/ParentSelectionStrategy.o
$(top_builddir)/proxy/ParentSelectionStrategy.o
Copy link
Contributor

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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the extranseous space


enum ProxyProtocolVersion_t {
PROXY_VERSION_UNDEFINED,
PROXY_V1,
Copy link
Contributor

@zwoop zwoop Apr 3, 2018

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

Copy link
Member

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;
Copy link
Contributor

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 ;-).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixing.


enum ProxyProtocolData_t {
PROXY_PROTO_UNDEFINED,
PROXY_PROTO_SRC,
Copy link
Contributor

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.

Copy link
Contributor Author

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.

TS_INLINE sockaddr const *
NetVConnection::get_proxy_protocol_addr(ProxyProtocolData_t src_or_dst)
{
if (src_or_dst == PROXY_PROTO_SRC) {
Copy link
Contributor

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

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) {
Copy link
Contributor

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

bool
proxy_protov1_parse(NetVConnection *netvc, char *buf)
{
std::string src_addr_port;
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Member

@SolidWallOfCode SolidWallOfCode Apr 9, 2018

Choose a reason for hiding this comment

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

I got a bit carried away, but here a suggested version of ProxyProtocol.cc which addresses @zwoop 's concern. This doesn't update ssl_has_proxy_v1 but the same sort of changes would be reasonable (e.g., not copying out of the IOBuffer twice).

Copy link
Contributor Author

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.

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
Copy link
Member

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.

Copy link
Contributor Author

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;
Copy link
Member

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.

Copy link
Member

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?

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

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) ||

@SolidWallOfCode SolidWallOfCode changed the title PROXY Protocol transformed to Forwarded HTTP heder. PROXY Protocol transformed to Forwarded HTTP header. Apr 13, 2018
@reveller reveller force-pushed the proxy-protocol-submit branch 2 times, most recently from fba3b8c to a028fc4 Compare April 20, 2018 21:09
@reveller reveller dismissed zwoop’s stale review April 20, 2018 21:15

New submission

@reveller reveller force-pushed the proxy-protocol-submit branch from a028fc4 to f2e4d72 Compare April 20, 2018 23:43
zwoop and others added 21 commits June 12, 2018 14:14
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)
… new/delete"

This reverts commit 79682c4.

(cherry picked from commit 3430a69)
(cherry picked from commit d859302)
This was broke by: 4e62375 Remove Congestion Control Feature

(cherry picked from commit ff85139)
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)
…onversion

This is still a WIP

(cherry picked from commit 1c189cd)
Fixes coredump when testing in production

(cherry picked from commit 77be135)
@calavera
Copy link
Contributor

@reveller is there any progress on this? I'd really like to give it a try.

@SolidWallOfCode
Copy link
Member

@calavera I think this one is dead, check out #3958.

@reveller
Copy link
Contributor Author

@calavera and @zonestc, please see new PRs for this functionality:

#3958
#3956

I am closing this old PR.

@reveller reveller closed this Jul 16, 2018
@zwoop
Copy link
Contributor

zwoop commented Jul 28, 2018

Please remember to remove Milestone and Projects etc. when you close a PR (and not merging it).

@zwoop zwoop removed this from the 9.0.0 milestone Jul 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.