Skip to content
Draft

test #41513

Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 4 additions & 19 deletions source/extensions/filters/udp/dns_filter/dns_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -659,28 +659,13 @@ void DnsFilter::logQuery(const DnsQueryContextPtr& context) {
StreamInfo::StreamInfoImpl stream_info(listener_.dispatcher().timeSource(), connection_info,
StreamInfo::FilterState::LifeSpan::Connection);

// Add DNS-specific information to dynamic metadata
Protobuf::Struct dns_metadata;
auto* fields = dns_metadata.mutable_fields();

// Add query information
if (!context->queries_.empty()) {
const auto& query = context->queries_[0];
(*fields)["query_name"] = ValueUtil::stringValue(absl::StrCat(query->name_));
(*fields)["query_type"] = ValueUtil::stringValue(absl::StrCat(query->type_));
(*fields)["query_class"] = ValueUtil::stringValue(absl::StrCat(query->class_));
}

// Add response information
(*fields)["answer_count"] = ValueUtil::stringValue(absl::StrCat(context->answers_.size()));
(*fields)["response_code"] = ValueUtil::stringValue(absl::StrCat(context->response_code_));
(*fields)["parse_status"] = ValueUtil::stringValue(context->parse_status_ ? "true" : "false");

stream_info.setDynamicMetadata(std::string(DnsFilterName), dns_metadata);
// Create formatter context with DNS query context extension
Formatter::Context formatter_context;
formatter_context.setExtension(*context);

// Log to all configured access loggers
for (const auto& access_log : config_->accessLogs()) {
access_log->log({}, stream_info);
access_log->log(formatter_context, stream_info);
}
}

Expand Down
109 changes: 62 additions & 47 deletions source/extensions/filters/udp/dns_filter/dns_filter_access_log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "source/common/formatter/substitution_format_string.h"
#include "source/common/protobuf/utility.h"
#include "source/extensions/filters/udp/dns_filter/dns_parser.h"

#include "absl/container/flat_hash_map.h"
#include "absl/strings/str_cat.h"
Expand All @@ -13,66 +14,32 @@ namespace DnsFilter {

namespace {

constexpr absl::string_view DnsFilterMetadataNamespace = "envoy.filters.udp.dns_filter";

/**
* FormatterProvider for DNS-specific fields from dynamic metadata.
* All DNS fields are stored as strings in metadata for simpler formatting.
* FormatterProvider for DNS-specific fields from DnsQueryContext.
*/
class DnsFormatterProvider : public Formatter::FormatterProvider {
public:
using FieldExtractor = std::function<absl::optional<std::string>(const StreamInfo::StreamInfo&)>;
using FieldExtractor =
std::function<absl::optional<std::string>(const Formatter::Context&, const StreamInfo::StreamInfo&)>;

DnsFormatterProvider(FieldExtractor field_extractor)
: field_extractor_(std::move(field_extractor)) {}

// FormatterProvider
absl::optional<std::string>
formatWithContext(const Formatter::Context&,
formatWithContext(const Formatter::Context& context,
const StreamInfo::StreamInfo& stream_info) const override {
return field_extractor_(stream_info);
return field_extractor_(context, stream_info);
}

Protobuf::Value formatValueWithContext(const Formatter::Context&,
Protobuf::Value formatValueWithContext(const Formatter::Context& context,
const StreamInfo::StreamInfo& stream_info) const override {
const auto str = field_extractor_(stream_info);
const auto str = field_extractor_(context, stream_info);
return str.has_value() ? ValueUtil::stringValue(str.value()) : ValueUtil::nullValue();
}

private:
const FieldExtractor field_extractor_;
};

/**
* Helper to extract string field from DNS filter dynamic metadata.
*/
absl::optional<std::string> getDnsMetadataString(const StreamInfo::StreamInfo& stream_info,
absl::string_view field_name) {
const auto& metadata = stream_info.dynamicMetadata().filter_metadata();
const auto filter_it = metadata.find(DnsFilterMetadataNamespace);
if (filter_it == metadata.end()) {
return absl::nullopt;
}

const auto& fields = filter_it->second.fields();
const auto field_it = fields.find(field_name);
if (field_it == fields.end()) {
return absl::nullopt;
}

if (field_it->second.kind_case() == Protobuf::Value::kStringValue) {
return field_it->second.string_value();
}
return absl::nullopt;
}

/**
* Helper to create a provider function for a given DNS metadata field name.
*/
Formatter::FormatterProviderPtr makeDnsFieldProvider(absl::string_view field_name) {
return std::make_unique<DnsFormatterProvider>(
[field_name = std::string(field_name)](const StreamInfo::StreamInfo& stream_info)
-> absl::optional<std::string> { return getDnsMetadataString(stream_info, field_name); });
}

/**
Expand Down Expand Up @@ -102,27 +69,75 @@ class DnsFilterCommandParser : public Formatter::CommandParser {
{
{"QUERY_NAME",
[](absl::string_view, absl::optional<size_t>) -> Formatter::FormatterProviderPtr {
return makeDnsFieldProvider("query_name");
return std::make_unique<DnsFormatterProvider>(

Choose a reason for hiding this comment

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

is it possible to dedup this logic by extracting to method?

[](const Formatter::Context& ctx, const StreamInfo::StreamInfo&)
-> absl::optional<std::string> {
const auto dns_ctx = ctx.typedExtension<DnsQueryContext>();
if (!dns_ctx.has_value() || dns_ctx->queries_.empty()) {
return absl::nullopt;
}
return absl::StrCat(dns_ctx->queries_[0]->name_);
});
}},
{"QUERY_TYPE",
[](absl::string_view, absl::optional<size_t>) -> Formatter::FormatterProviderPtr {
return makeDnsFieldProvider("query_type");
return std::make_unique<DnsFormatterProvider>(
[](const Formatter::Context& ctx, const StreamInfo::StreamInfo&)
-> absl::optional<std::string> {
const auto dns_ctx = ctx.typedExtension<DnsQueryContext>();
if (!dns_ctx.has_value() || dns_ctx->queries_.empty()) {
return absl::nullopt;
}
return absl::StrCat(dns_ctx->queries_[0]->type_);
});
}},
{"QUERY_CLASS",
[](absl::string_view, absl::optional<size_t>) -> Formatter::FormatterProviderPtr {
return makeDnsFieldProvider("query_class");
return std::make_unique<DnsFormatterProvider>(
[](const Formatter::Context& ctx, const StreamInfo::StreamInfo&)
-> absl::optional<std::string> {
const auto dns_ctx = ctx.typedExtension<DnsQueryContext>();
if (!dns_ctx.has_value() || dns_ctx->queries_.empty()) {
return absl::nullopt;
}
return absl::StrCat(dns_ctx->queries_[0]->class_);
});
}},
{"ANSWER_COUNT",
[](absl::string_view, absl::optional<size_t>) -> Formatter::FormatterProviderPtr {
return makeDnsFieldProvider("answer_count");
return std::make_unique<DnsFormatterProvider>(
[](const Formatter::Context& ctx, const StreamInfo::StreamInfo&)
-> absl::optional<std::string> {
const auto dns_ctx = ctx.typedExtension<DnsQueryContext>();
if (!dns_ctx.has_value()) {
return absl::nullopt;
}
return absl::StrCat(dns_ctx->answers_.size());
});
}},
{"RESPONSE_CODE",
[](absl::string_view, absl::optional<size_t>) -> Formatter::FormatterProviderPtr {
return makeDnsFieldProvider("response_code");
return std::make_unique<DnsFormatterProvider>(
[](const Formatter::Context& ctx, const StreamInfo::StreamInfo&)
-> absl::optional<std::string> {
const auto dns_ctx = ctx.typedExtension<DnsQueryContext>();
if (!dns_ctx.has_value()) {
return absl::nullopt;
}
return absl::StrCat(dns_ctx->response_code_);
});
}},
{"PARSE_STATUS",
[](absl::string_view, absl::optional<size_t>) -> Formatter::FormatterProviderPtr {
return makeDnsFieldProvider("parse_status");
return std::make_unique<DnsFormatterProvider>(
[](const Formatter::Context& ctx, const StreamInfo::StreamInfo&)
-> absl::optional<std::string> {
const auto dns_ctx = ctx.typedExtension<DnsQueryContext>();
if (!dns_ctx.has_value()) {
return absl::nullopt;
}
return dns_ctx->parse_status_ ? "true" : "false";
});
}},
});
}
Expand Down
3 changes: 2 additions & 1 deletion source/extensions/filters/udp/dns_filter/dns_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "envoy/buffer/buffer.h"
#include "envoy/common/platform.h"
#include "envoy/common/random_generator.h"
#include "envoy/formatter/http_formatter_context.h"
#include "envoy/network/address.h"
#include "envoy/network/dns.h"
#include "envoy/network/listener.h"
Expand Down Expand Up @@ -184,7 +185,7 @@ PACKED_STRUCT(struct DnsHeader {
/**
* DnsQueryContext contains all the data necessary for responding to a query from a given client.
*/
class DnsQueryContext {
class DnsQueryContext : public Formatter::HttpFormatterContext::Extension {
public:
DnsQueryContext(Network::Address::InstanceConstSharedPtr local,
Network::Address::InstanceConstSharedPtr peer, DnsParserCounters& counters,
Expand Down
Loading
Loading