Skip to content

dns_filter: disable malformed DNS messages to dns filter#20744

Merged
mattklein123 merged 14 commits intoenvoyproxy:mainfrom
botengyao:dnsparserfix
Apr 21, 2022
Merged

dns_filter: disable malformed DNS messages to dns filter#20744
mattklein123 merged 14 commits intoenvoyproxy:mainfrom
botengyao:dnsparserfix

Conversation

@botengyao
Copy link
Copy Markdown
Member

@botengyao botengyao commented Apr 8, 2022

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:]

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>
@repokitteh-read-only
Copy link
Copy Markdown

As a reminder, PRs marked as draft will not be automatically assigned reviewers,
or be handled by maintainer-oncall triage.

Please mark your PR as ready when you want it to be reviewed!

🐱

Caused by: #20744 was opened by botengyao.

see: more, trace.

@botengyao botengyao marked this pull request as ready for review April 8, 2022 20:51
@botengyao botengyao requested a review from mattklein123 as a code owner April 8, 2022 20:51
@botengyao botengyao changed the title dns_filter: disable malformed DNS messages to dns parser dns_filter: disable malformed DNS messages to dns filter Apr 8, 2022
Signed-off-by: Boteng Yao <boteng@google.com>
@botengyao
Copy link
Copy Markdown
Member Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #20744 (comment) was created by @botengyao.

see: more, trace.

@yanjunxiang-google
Copy link
Copy Markdown
Contributor

/assign @yanjunxiang-google

Copy link
Copy Markdown
Contributor

@pradeepcrao pradeepcrao left a comment

Choose a reason for hiding this comment

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

Thanks so much for taking care of this Boteng!

Comment thread source/extensions/filters/udp/dns_filter/dns_parser.cc Outdated
Comment thread test/extensions/filters/udp/dns_filter/dns_filter_test_utils.cc Outdated
Comment thread test/extensions/filters/udp/dns_filter/dns_filter_test_utils.h Outdated
Comment thread test/extensions/filters/udp/dns_filter/dns_filter_integration_test.cc Outdated
Comment thread test/extensions/filters/udp/dns_filter/dns_filter_test.cc Outdated
@yanjunxiang-google
Copy link
Copy Markdown
Contributor

/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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member Author

@botengyao botengyao Apr 13, 2022

Choose a reason for hiding this comment

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

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,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SG

return EMPTY_STRING;
}

DnsQueryContextPtr DnsResponseValidator::createResponseContext(Network::UdpRecvData& client_request,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Member Author

@botengyao botengyao Apr 20, 2022

Choose a reason for hiding this comment

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

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

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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>
@botengyao
Copy link
Copy Markdown
Member Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #20744 (comment) was created by @botengyao.

see: more, trace.

@botengyao
Copy link
Copy Markdown
Member Author

Gentle ping for any comments.

Comment thread source/extensions/filters/udp/dns_filter/dns_parser.cc
Signed-off-by: Boteng Yao <boteng@google.com>
@yanjunxiang-google
Copy link
Copy Markdown
Contributor

LGTM

@botengyao
Copy link
Copy Markdown
Member Author

Hi @mattklein123, can someone take a further look and merge this PR?

@mattklein123 mattklein123 self-assigned this Apr 20, 2022
Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks for the cleanup. LGTM with small comments.

/wait

Comment thread source/extensions/filters/udp/dns_filter/dns_parser.cc Outdated
return EMPTY_STRING;
}

DnsQueryContextPtr DnsResponseValidator::createResponseContext(Network::UdpRecvData& client_request,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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>
Comment on lines +199 to +205
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));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

@botengyao
Copy link
Copy Markdown
Member Author

Thank you for approving!

@mattklein123 mattklein123 merged commit 02f28f4 into envoyproxy:main Apr 21, 2022
ravenblackx pushed a commit to ravenblackx/envoy that referenced this pull request Jun 8, 2022
mattklein123 pushed a commit that referenced this pull request Dec 11, 2024
<!--
!!!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants