dns_filter: disable malformed DNS messages to dns filter#20744
dns_filter: disable malformed DNS messages to dns filter#20744mattklein123 merged 14 commits intoenvoyproxy:mainfrom
Conversation
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
|
/retest |
|
Retrying Azure Pipelines: |
|
/assign @yanjunxiang-google |
pradeepcrao
left a comment
There was a problem hiding this comment.
Thanks so much for taking care of this Boteng!
|
/assign @abaptiste |
| // resource records, where the number of records is specified in the corresponding count field in | ||
| // the header. | ||
|
|
||
| // Parse Answer Records and Additional Resource Records. This is primarily used for tests |
There was a problem hiding this comment.
It's understandable that the DNS client request message should not contain answer records. Just brainstorming, what's the right behavior if it does contain that? Should we simply ignore it? Reading through RFC1035, I don't see any text to describe this situation.
There was a problem hiding this comment.
Good point. RFC1035 is fuzzy and there is no clear statement for this scenario. But I found the RFC1034 6.2.1 query example, and RFC1035 7.3, stating that - Check the header for reasonableness. Discard datagrams which are queries when responses are expected. for response processing. For query we can have the similar process based on the query type. Note, this is not for inverse query. The inverse query type can include the answers with empty questions.
For our dns filter, the parsed answers are not used for the main query logic but only for testing.
| @@ -193,8 +193,11 @@ bool DnsMessageParser::parseDnsObject(DnsQueryContextPtr& context, | |||
| } | |||
There was a problem hiding this comment.
If as below, that we are simply ignoring parsing the Answers/authority/additional RRs in a DNS client request, should we still set these states? Or after parsing questions section, then directly return?
There was a problem hiding this comment.
If as below, that we are simply ignoring parsing the Answers/authority/additional RRs in a DNS client request, should we still set these states? Or after parsing questions section, then directly return?
We should still parse them I believe, because this state machine is to parse header to get the meta data like the number of questions/answers/authority/additional RRs. We can check if the request is expected based the header data, and then data are parsed from buffer like a byte stream.
| return EMPTY_STRING; | ||
| } | ||
|
|
||
| DnsQueryContextPtr DnsResponseValidator::createResponseContext(Network::UdpRecvData& client_request, |
There was a problem hiding this comment.
Is this function is added for test only? And is it to test some testing code, not production code?
I am thinking we should just test createQueryContext().
There was a problem hiding this comment.
This function is to parse the DNS response message, and it is used to verify the response generated by DNS filter, which we want to test. Basically, the query and response are sharing the same message format, this is only to parse and verify the response.
There was a problem hiding this comment.
I understand what you mean now. So, the test is to send a request, get the response and parse the response and verify it is expected. The original code is using createQueryContext() to parse the response since that logic is embedded there. With the new code, createResponseContext is added to specially handle the response. Also, in the real world, Envoy won't parse the response. Only the DNS client who sends the request will parse the response. Thus createResponseContext() is only called in Envoy test code.
With that, I think the only thing I recommend is to add a few new test cases to verify the new logic --- bail out early and return false if answer is detected in query, which you added in createQueryContext()->parseDnsObject().
There was a problem hiding this comment.
More generally, I'm wondering if there is some way to actually replace this custom code with c-ares? I bet there is some way we could pipe the response into c-ares and have it parse it. IMO That would be better than maintaining this code just for testing purposes. Maybe add a TODO around this also?
There was a problem hiding this comment.
Good point, DNS filter only supports A, AAAA, SRV records, so we could use c-ares methods like ares_parse_a_reply, ares_parse_aaaa_reply, and ares_parse_srv_reply.
For now, the answer RRs are parsed by c-ares not the overall message format. This is only for test and validation, IMO it is okay to keep as it is, but will add a TODO.
| requestResponseWithListenerAddress(*listener_address, query, response); | ||
|
|
||
| query_ctx_ = response_parser_->createQueryContext(response, counters_); | ||
| query_ctx_ = response_parser_->createResponseContext(response, counters_); |
There was a problem hiding this comment.
I think the test code should test the production code, which is createQueryContext(). The test code should not test the testing specific code logic. Same as all below.
There was a problem hiding this comment.
Right, the response is already got from the DNS filter, which is from requestResponseWithListenerAddress(*listener_address, query, response). This line is used to verify the response generated by the DNS filter.
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
|
/retest |
|
Retrying Azure Pipelines: |
|
Gentle ping for any comments. |
Signed-off-by: Boteng Yao <boteng@google.com>
|
LGTM |
|
Hi @mattklein123, can someone take a further look and merge this PR? |
mattklein123
left a comment
There was a problem hiding this comment.
Thanks for the cleanup. LGTM with small comments.
/wait
| return EMPTY_STRING; | ||
| } | ||
|
|
||
| DnsQueryContextPtr DnsResponseValidator::createResponseContext(Network::UdpRecvData& client_request, |
There was a problem hiding this comment.
More generally, I'm wondering if there is some way to actually replace this custom code with c-ares? I bet there is some way we could pipe the response into c-ares and have it parse it. IMO That would be better than maintaining this code just for testing purposes. Maybe add a TODO around this also?
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
| ENVOY_LOG( | ||
| debug, | ||
| "One or more of Answers [{}], Authority [{}], and Additional [{}] RRs present in the query." | ||
| "Inverse query is not supported", | ||
| static_cast<int>(context->header_.answers), | ||
| static_cast<int>(context->header_.authority_rrs), | ||
| static_cast<int>(context->header_.additional_rrs)); |
There was a problem hiding this comment.
This is not what I meant (I meant adding a filter stat/metric for this failure case that can be monitored), but if you want to keep that that is fine.
|
Thank you for approving! |
…20744) Signed-off-by: Boteng Yao <boteng@google.com>
<!-- !!!ATTENTION!!! If you are fixing *any* crash or *any* potential security issue, *do not* open a pull request in this repo. Please report the issue via emailing envoy-security@googlegroups.com where the issue will be triaged appropriately. Thank you in advance for helping to keep Envoy secure. !!!ATTENTION!!! For an explanation of how to fill out the fields, please see the relevant section in [PULL_REQUESTS.md](https://github.com/envoyproxy/envoy/blob/main/PULL_REQUESTS.md) --> Commit Message: Additional Description: I believe it is stable now since we conduct a security review and improvement for dns filter like #18651 #20744 #22861 #17479 #34409 #34456 #34490 and so on Risk Level: low Testing: Docs Changes: Release Notes: Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao boteng@google.com
Commit Message: Disable malformed DNS messages to dns parser.
Additional Description: Only allow query message without any Answer, Authority, and Additional RRs to pass the parser check.
Risk Level: Low
Testing: unit test
Docs Changes:
Release Notes: Previously, the parser will return true when client sends a malformed message with question count == 1 and answer count == 1, which is not expected. The new behavior will only accept queries with Question count == 1, and all other Answer RRs count == 0. Otherwise, a format error code will be sent back.
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Fixes commit #PR or SHA]
[Optional Deprecated:]
[Optional API Considerations:]