blob: b421a2d8f58e2fc39a20fea709720f3fb4a1f47e [file] [log] [blame]
// Copyright 2020 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.
#ifndef PATCHPANEL_BROADCAST_FORWARDER_H_
#define PATCHPANEL_BROADCAST_FORWARDER_H_
#include <sys/socket.h>
#include <sys/types.h>
#include <map>
#include <memory>
#include <string>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/macros.h>
#include <shill/net/rtnl_listener.h>
#include <shill/net/rtnl_message.h>
#include "patchpanel/net_util.h"
#include "patchpanel/shill_client.h"
namespace patchpanel {
constexpr uint32_t kBcastAddr = Ipv4Addr(255, 255, 255, 255);
// Listens to broadcast messages sent by applications and forwards them between
// network interfaces of host and guest.
// BroadcastForwarder assumes that guest addresses, including broadcast and
// netmask, are constant.
class BroadcastForwarder {
public:
explicit BroadcastForwarder(const std::string& dev_ifname);
BroadcastForwarder(const BroadcastForwarder&) = delete;
BroadcastForwarder& operator=(const BroadcastForwarder&) = delete;
virtual ~BroadcastForwarder() = default;
// Starts listening to RTNL IPv4 address events.
void Init();
// Starts or stops forwarding broadcast packets to and from a downstream
// guest on network interface |br_ifname|.
bool AddGuest(const std::string& br_ifname);
void RemoveGuest(const std::string& br_ifname);
// Receives a broadcast packet from the network or from a guest and forwards
// it.
void OnFileCanReadWithoutBlocking(int fd);
// Callback from RTNetlink listener, invoked when the lan interface IPv4
// address is changed.
void AddrMsgHandler(const shill::RTNLMessage& msg);
protected:
// Socket is used to keep track of an fd and its watcher.
// It also stores addresses corresponding to the interface it is bound to.
struct Socket {
base::ScopedFD fd;
std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher;
uint32_t addr;
uint32_t broadaddr;
uint32_t netmask;
};
// Bind will create a broadcast socket and return its fd.
// This is used for sending broadcasts.
virtual base::ScopedFD Bind(const std::string& ifname, uint16_t port);
// BindRaw will create a broadcast socket that listens to all IP packets.
// It filters the packets to only broadcast packets that is sent by
// applications.
// This is used to listen on broadcasts.
virtual base::ScopedFD BindRaw(const std::string& ifname);
// SendToNetwork sends |data| using a socket bound to |src_port| and
// |dev_ifname_| using a temporary socket.
bool SendToNetwork(uint16_t src_port,
const void* data,
ssize_t len,
const struct sockaddr_in& dst);
// SendToGuests will forward the broadcast packet to all Chrome OS guests'
// (ARC++, Crostini, etc) internal fd.
bool SendToGuests(const void* ip_pkt,
ssize_t len,
const struct sockaddr_in& dst);
// Wrapper around libc recvmsg, allowing override in fuzzer tests.
virtual ssize_t ReceiveMessage(int fd, struct msghdr* msg);
// Wrapper around libc sendto, allowing override in fuzzer tests.
virtual ssize_t SendTo(int fd,
const void* buffer,
size_t buffer_len,
const struct sockaddr_in* dst_addr);
virtual std::unique_ptr<Socket> CreateSocket(base::ScopedFD fd,
uint32_t addr,
uint32_t broadaddr,
uint32_t netmask);
private:
// Listens for RTMGRP_IPV4_IFADDR messages and invokes AddrMsgHandler.
std::unique_ptr<shill::RTNLListener> addr_listener_;
// Name of the physical interface that this forwarder is bound to.
const std::string dev_ifname_;
// IPv4 socket bound by this forwarder onto |dev_ifname_|.
std::unique_ptr<Socket> dev_socket_;
// Mapping from guest bridge interface name to its sockets.
std::map<std::string, std::unique_ptr<Socket>> br_sockets_;
base::WeakPtrFactory<BroadcastForwarder> weak_factory_{this};
};
} // namespace patchpanel
#endif // PATCHPANEL_BROADCAST_FORWARDER_H_