Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
proxy protocol: new feature auto-detect proxy protocol #18951
proxy protocol: new feature auto-detect proxy protocol #18951
Changes from 24 commits
278ce7e
121e87d
2d43ae3
de6b7f2
3a36695
409f94c
ae19e1f
ed4fb54
bcc7aef
8c87bcd
4aa520e
91c9a1b
c45ecc7
4259f1a
2b4a89a
f105c3d
6a0d49b
f47232f
fa9746a
a37ad43
6f19883
0927000
b5cbfc1
a7ef68f
9495853
ffb56d1
ac2982f
2a66a01
c9e086f
af6f88d
7f17660
59206da
b416242
4e4638a
354a365
86ad288
899f199
887d0bc
a23ac5f
6075b67
4d6f75f
2cb4526
1667461
a0c977f
85706e6
c86edef
6031151
a09bb1b
cfeda5a
5a660a0
e92a8a4
84cdc32
f3d65e9
b2d467e
45e9c24
056f74f
39e7b50
392124e
307df1c
5c50e23
36bbfa2
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
Please add a link to the new config setting.
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.
addressed in 392124e
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.
Can you make this into a switch/case on
read_state
? Then the compiler can warn if not all cases are handled.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.
addressed in 392124e
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.
Your handling decides to skip the filter if not enough data is read; that's not correct. Everytime some data comes in, look at what we have, and determine whether this is defintely proxy proto v1, definately v2, definitely neither, or not-yet-determined (needs more data to decide).
/wait
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.
Sounds like we are saying the same case https://github.com/envoyproxy/envoy/pull/18951/files#r747243218
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 for I didn't describe the case clearly.
Write it as test case as below
The test will fail with below:
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.
see #18951 (comment)
I'm not sure we can actually tell the difference between your case and the case provided above. If we receive a small amount of bytes off the initial
recv
we can be in either situation; I can change handling this scenario to a hard error, so that both of these cases see error rather than passing through a potentially valid proxy protocol request.We could put
recv
in a loop withMSG_PEEK
until we have enough bytes, but there's no guarantee there will ever be enough bytes and waiting for timeout is also bad for the initial use case.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.
What I'm thinking is if only see the first byte is a 'P', then we are looking for more bytes to ensure it is a proxy protocol. Not intent changing to a hard error.
You are right, timeout is bad. It sounds like a choice. We can choice to believe after first byte 'P', there still can be a proxy protocol. Or we choice to believe after first byte 'P', it can't be a proxy protocol.
So I guess the question should be 'how much chance the healthcheck request is similar to proxy proxy signature?' If there is rarely chance the first few bytes of healthcheck is same with proxy signature, then I would choose to look more bytes to ensure it is proxy signature or not.
Anyway, let's see others opinion. I'm ok if people think this case doesn't important.
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 just realized that If we are going to fix the case I said, then we probably need to fix it with the way @ggreenway said at #18951 (comment)
"I think you need to fix this case. You may have to restructure the code such that no bytes are read (without MSG_PEEK) until we've decided 100% whether this is a proxy header or not."
And I feel that will touch the windows MSG_PEEK issue, we have to wait for the fix #18900.
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.
Agreed, the PR as currently written does not read any bytes (without
MSG_PEEK
) until we know for sure whether or not this is proxy protocol.Why do we have to wait for #18900? We already use
MSG_PEEK
in this filter, and further the codepath added here is only hit if a user opts-in to the new feature. I'm only being slightly pushy because I have a customer chomping at the bits for this (eager user for feature).Thanks and looking forward to your response.
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.
@mattklein123 can you weigh in here and provide direction? I believe we should try and make forward progress here instead of waiting on another PR dependency #18900 which adds support for a required feature on Windows. I'm assuming we can add a feature for an OS and later on support it for other OS/distros/environments since this is opt in?
We would like to upstream this feature asap instead of patching it in private so any help is appreciated.
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.
Can someone summarize what needs deciding on please?
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.
Quick summary: this new feature would require doing MSG_PEEK to determine whether to proceed or not. The filter did not previously need to do this. On Windows, there isn't edge-triggered event support so this results in the connection having a read event on every event loop.
I don't think we can make a change that breaks Windows. It is a supported platform.
The fix for Windows is in the works. After that, this PR could proceed.
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.
Yes, that is fine. The problem is that this change would break an existing feature on windows, until the other PR is merged.
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.
OK sounds good, let's just finish the other PR.
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.
it should be
((nread < PROXY_PROTO_V2_SIGNATURE_LEN || memcmp(buf_, PROXY_PROTO_V2_SIGNATURE, nread)) && memcmp(buf_, PROXY_PROTO_V1_SIGNATURE, nread))
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.
this is actually fine as is. the first if statement in this block ensures that by the time we get here we know
nread
>=PROXY_PROTO_V1_SIGNATURE_LEN
. then in this if statement thenread < PROXY_PROTO_V2_SIGNATURE_LEN
case short-circuits if needed, so in the secondmemcmp
we knownread
>=PROXY_PROTO_V2_SIGNATURE_LEN
. in short, we knownread
is >= both signature lengths before we domemcmp
with the signature, and we want to check at most the signature lengthif it helps with readability I'm happy to add
std::min
onnread
and the signature lengths, but I do not think there is a logic error hereThere 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, you are right.
I was based on the logic we want to exam more bytes.
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.
const
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.
Maybe we can test the v2 case here, otherwise, I didn't see a difference between the previous test case, both of them are going to skip the header in the first bytes.
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 don't think we can, this test is for separate logic (it ensures we have this check) while the test prior ensures that we have this check
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.
Also worth testing a case that we have correct v1 or v2 header signature, but invalid data in the rest of header, then ensure we disconnect the connection, and not let the connection passthrough.
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.
addressed in 6031151
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.
nit, useless space line
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.
addressed in 1667461
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.
We should test the case of the first write is not full v1 protocol signature, like just one char 'P'
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.
Addressed in 6a0d49b
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 actually not sure this is possible simultaneously with the fragmented/partial protocol without the possibility for false positive, e.g.
this is why in the initial implementation I required that the initial read from
recv
have enough bytes available on the initialMSG_PEEK
to make the determination on the v1/v2 proxy header.We can leave the PR as it is (or perhaps preferably throw a hard error if we consumed some bytes and then realize we had a false positive?) with the understanding that there could be false positives on identifying proxy protocol, additionally with the understanding that this is quite rare and will not likely happen in practice (except perhaps for single byte reads of
P
and HTTP POST/PUT request?). In exchange, we get support for fragmented/partial reads. Thoughts?Also willing to go back to my original version (before 6a0d49b which addresses the initial concern with partial reads) which addresses the potential false positive here
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 not following. How would the filter consume the
P
only?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.
Running the test above, we do
recv
withMSG_PEEK
and just getP
here.Then before we continue the loop, we read that byte for real (no
MSG_PEEK
) here. Thus when we do our secondrecv
and we getBOGUS
we have already consumedP
. We correctly identify that the request is not proxy protocol, but the request forwarded upstream has a missing byte(s) (in this case, justP
).The only way I see to avoid false positives identifying the header and always send the correct response up the filter chain is to require that the initial
MSG_PEEK
has enough bytes to detect v1/v2 header (at most 16, which seems reasonable for this opt-in only codepath)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.
Oh, I see.
I think you need to fix this case. You may have to restructure the code such that no bytes are read (without MSG_PEEK) until we've decided 100% whether this is a proxy header or not.
I think it's probably good enough to look for either
PROXY_PROTO_V1_SIGNATURE
orPROXY_PROTO_V2_SIGNATURE
. If the connections starts with either of those, but then doesn't have a valid full proxy protocol header, abort the connection as we currently do. If the connection starts with bytes that match neither of those signatures, and the new option is enabled, don'tread()
any bytes and continue the filter chain. Will that work?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 it will work. Implemented in 6f19883 and 0927000