diff --git a/test/extensions/filters/listener/original_dst/BUILD b/test/extensions/filters/listener/original_dst/BUILD index 4c2ad41b41ce9..562775fc6cacd 100644 --- a/test/extensions/filters/listener/original_dst/BUILD +++ b/test/extensions/filters/listener/original_dst/BUILD @@ -1,6 +1,8 @@ load( "//bazel:envoy_build_system.bzl", + "envoy_cc_fuzz_test", "envoy_package", + "envoy_proto_library", ) load( "//test/extensions:extensions_build_system.bzl", @@ -20,3 +22,19 @@ envoy_extension_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_proto_library( + name = "original_dst_fuzz_test_proto", + srcs = ["original_dst_fuzz_test.proto"], +) + +envoy_cc_fuzz_test( + name = "original_dst_fuzz_test", + srcs = ["original_dst_fuzz_test.cc"], + corpus = "original_dst_corpus", + deps = [ + ":original_dst_fuzz_test_proto_cc_proto", + "//source/extensions/filters/listener/original_dst:original_dst_lib", + "//test/mocks/network:network_mocks", + ], +) diff --git a/test/extensions/filters/listener/original_dst/original_dst_corpus/invalid_test b/test/extensions/filters/listener/original_dst/original_dst_corpus/invalid_test new file mode 100644 index 0000000000000..a015d2d6e09f5 --- /dev/null +++ b/test/extensions/filters/listener/original_dst/original_dst_corpus/invalid_test @@ -0,0 +1 @@ +address: "hello world" \ No newline at end of file diff --git a/test/extensions/filters/listener/original_dst/original_dst_corpus/ipv4_test b/test/extensions/filters/listener/original_dst/original_dst_corpus/ipv4_test new file mode 100644 index 0000000000000..6a87711c09a63 --- /dev/null +++ b/test/extensions/filters/listener/original_dst/original_dst_corpus/ipv4_test @@ -0,0 +1 @@ +address: "tcp://0.0.0.0:0" \ No newline at end of file diff --git a/test/extensions/filters/listener/original_dst/original_dst_corpus/ipv6_test b/test/extensions/filters/listener/original_dst/original_dst_corpus/ipv6_test new file mode 100644 index 0000000000000..9d8f333019e04 --- /dev/null +++ b/test/extensions/filters/listener/original_dst/original_dst_corpus/ipv6_test @@ -0,0 +1 @@ +address: "tcp://[a:b:c:d::]:0" \ No newline at end of file diff --git a/test/extensions/filters/listener/original_dst/original_dst_corpus/unix_test b/test/extensions/filters/listener/original_dst/original_dst_corpus/unix_test new file mode 100644 index 0000000000000..7df146a6cabd5 --- /dev/null +++ b/test/extensions/filters/listener/original_dst/original_dst_corpus/unix_test @@ -0,0 +1 @@ +address: "unix://tmp/server" \ No newline at end of file diff --git a/test/extensions/filters/listener/original_dst/original_dst_fuzz_test.cc b/test/extensions/filters/listener/original_dst/original_dst_fuzz_test.cc new file mode 100644 index 0000000000000..90ac50f389aab --- /dev/null +++ b/test/extensions/filters/listener/original_dst/original_dst_fuzz_test.cc @@ -0,0 +1,85 @@ +#include "common/network/utility.h" + +#include "extensions/filters/listener/original_dst/original_dst.h" + +#include "test/extensions/filters/listener/original_dst/original_dst_fuzz_test.pb.validate.h" +#include "test/fuzz/fuzz_runner.h" +#include "test/mocks/network/mocks.h" + +#include "gmock/gmock.h" + +namespace Envoy { +namespace Extensions { +namespace ListenerFilters { +namespace OriginalDst { + +class FakeConnectionSocket : public Network::MockConnectionSocket { + const Network::Address::InstanceConstSharedPtr& local_address_; + +public: + ~FakeConnectionSocket() override = default; + + FakeConnectionSocket(const Network::Address::InstanceConstSharedPtr& local_address) + : local_address_(local_address) {} + + const Network::Address::InstanceConstSharedPtr& localAddress() const override { + return local_address_; + } + + Network::Address::Type addressType() const override { return local_address_->type(); } + + absl::optional ipVersion() const override { + if (local_address_->type() != Network::Address::Type::Ip) { + return absl::nullopt; + } + + return local_address_->ip()->version(); + } + + Api::SysCallIntResult getSocketOption(int level, int, void* optval, socklen_t*) const override { + switch (level) { + case SOL_IPV6: + static_cast(optval)->ss_family = AF_INET6; + break; + case SOL_IP: + static_cast(optval)->ss_family = AF_INET; + break; + default: + NOT_REACHED_GCOVR_EXCL_LINE; + } + + return Api::SysCallIntResult{0, 0}; + } +}; + +DEFINE_PROTO_FUZZER( + const envoy::extensions::filters::listener::original_dst::v3::OriginalDstTestCase& input) { + + try { + TestUtility::validate(input); + } catch (const ProtoValidationException& e) { + ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what()); + return; + } + + NiceMock callbacks; + Network::Address::InstanceConstSharedPtr address = nullptr; + + try { + address = Network::Utility::resolveUrl(input.address()); + } catch (const EnvoyException& e) { + ENVOY_LOG_MISC(debug, "EnvoyException: {}", e.what()); + return; + } + + FakeConnectionSocket socket(address); + ON_CALL(callbacks, socket()).WillByDefault(testing::ReturnRef(socket)); + + auto filter = std::make_unique(); + filter->onAccept(callbacks); +} + +} // namespace OriginalDst +} // namespace ListenerFilters +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/filters/listener/original_dst/original_dst_fuzz_test.proto b/test/extensions/filters/listener/original_dst/original_dst_fuzz_test.proto new file mode 100644 index 0000000000000..f6e5e28e2defc --- /dev/null +++ b/test/extensions/filters/listener/original_dst/original_dst_fuzz_test.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package envoy.extensions.filters.listener.original_dst.v3; + +message OriginalDstTestCase { + string address = 2; +} \ No newline at end of file