blob: 44e81da9fe1c93b881be4cdfb68c8a7b17ef5570 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "patchpanel/multicast_forwarder.h"
#include <net/if.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "patchpanel/net_util.h"
namespace patchpanel {
constexpr const struct in_addr kLanIp = {.s_addr = Ipv4Addr(192, 168, 1, 1)};
constexpr const struct in_addr kGuestIp = {.s_addr = Ipv4Addr(100, 115, 92, 2)};
namespace {
// Test class that overrides MulticastForwarder's sending and receive functions
// with stubs.
class TestMulticastForwarder : public MulticastForwarder {
public:
TestMulticastForwarder(const std::string& lan_ifname,
uint32_t mcast_addr,
const std::string& mcast_addr6,
uint16_t port)
: MulticastForwarder(lan_ifname, mcast_addr, mcast_addr6, port) {}
TestMulticastForwarder(const TestMulticastForwarder&) = delete;
TestMulticastForwarder& operator=(const TestMulticastForwarder&) = delete;
~TestMulticastForwarder() = default;
base::ScopedFD Bind(sa_family_t sa_family,
const std::string& ifname) override {
// Make a real socket to satisfy ScopedFD's checks.
int fd = socket(sa_family, SOCK_DGRAM, 0);
fds.push_back(fd);
return base::ScopedFD(fd);
}
std::unique_ptr<MulticastForwarder::Socket> CreateSocket(
base::ScopedFD fd, sa_family_t sa_family) override {
auto socket = std::make_unique<Socket>();
socket->fd = std::move(fd);
return socket;
}
bool SendTo(uint16_t src_port,
const void* data,
ssize_t len,
const struct sockaddr* dst,
socklen_t dst_len) override {
return true;
}
bool SendToGuests(const void* data,
ssize_t len,
const struct sockaddr* dst,
socklen_t dst_len,
int ignore_fd) override {
return true;
}
ssize_t Receive(int fd,
char* buffer,
size_t buffer_size,
struct sockaddr* src_addr,
socklen_t* addrlen) override {
*addrlen = std::min(src_sockaddr.size(), (size_t)*addrlen);
if (*addrlen > 0) {
memcpy(src_addr, src_sockaddr.data(), *addrlen);
}
buffer_size = std::min(payload.size(), buffer_size);
if (buffer_size > 0) {
memcpy(buffer, payload.data(), buffer_size);
}
src_addr->sa_family = sa_family;
return true;
}
std::vector<int> fds;
sa_family_t sa_family;
std::vector<uint8_t> src_sockaddr;
std::vector<uint8_t> payload;
};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Turn off logging.
logging::SetMinLogLevel(logging::LOGGING_FATAL);
// Copy the input data so that TranslateMdnsIp can mutate it.
char* payload = new char[size];
memcpy(payload, data, size);
MulticastForwarder::TranslateMdnsIp(kLanIp, kGuestIp, payload, size);
delete[] payload;
FuzzedDataProvider provider(data, size);
std::string lan_ifname = provider.ConsumeRandomLengthString(IFNAMSIZ - 1);
std::string guest_ifname1 = provider.ConsumeRandomLengthString(IFNAMSIZ - 1);
std::string guest_ifname2 = provider.ConsumeRandomLengthString(IFNAMSIZ - 1);
uint32_t mcast_addr = provider.ConsumeIntegral<uint32_t>();
struct in6_addr ipv6_addr;
memset(&ipv6_addr, 0, sizeof(ipv6_addr));
std::vector<uint8_t> ipv6_addr_bytes =
provider.ConsumeBytes<uint8_t>(sizeof(ipv6_addr.s6_addr));
std::copy(ipv6_addr_bytes.begin(), ipv6_addr_bytes.end(), ipv6_addr.s6_addr);
std::string mcast_addr6 = IPv6AddressToString(ipv6_addr);
TestMulticastForwarder mcast_forwarder(lan_ifname, mcast_addr, mcast_addr6,
kMdnsPort);
mcast_forwarder.Init();
mcast_forwarder.AddGuest(guest_ifname1);
mcast_forwarder.AddGuest(guest_ifname2);
int fd_index =
provider.ConsumeIntegralInRange<int>(0, mcast_forwarder.fds.size() - 1);
int fd = mcast_forwarder.fds[fd_index];
if (provider.ConsumeBool()) {
mcast_forwarder.sa_family = AF_INET;
mcast_forwarder.src_sockaddr =
provider.ConsumeBytes<uint8_t>(sizeof(struct sockaddr_in));
} else {
mcast_forwarder.sa_family = AF_INET6;
mcast_forwarder.src_sockaddr =
provider.ConsumeBytes<uint8_t>(sizeof(struct sockaddr_in6));
}
mcast_forwarder.payload = provider.ConsumeRemainingBytes<uint8_t>();
mcast_forwarder.OnFileCanReadWithoutBlocking(fd, mcast_forwarder.sa_family);
return 0;
}
} // namespace
} // namespace patchpanel