| // 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. |
| |
| #include "patchpanel/multicast_proxy.h" |
| |
| #include <sysexits.h> |
| |
| #include <utility> |
| |
| #include "patchpanel/minijailed_process_runner.h" |
| |
| namespace patchpanel { |
| |
| MulticastProxy::MulticastProxy(base::ScopedFD control_fd) |
| : msg_dispatcher_(std::move(control_fd)) { |
| msg_dispatcher_.RegisterFailureHandler(base::Bind( |
| &MulticastProxy::OnParentProcessExit, weak_factory_.GetWeakPtr())); |
| |
| msg_dispatcher_.RegisterDeviceMessageHandler( |
| base::Bind(&MulticastProxy::OnDeviceMessage, weak_factory_.GetWeakPtr())); |
| } |
| |
| int MulticastProxy::OnInit() { |
| // Prevent the main process from sending us any signals. |
| if (setsid() < 0) { |
| PLOG(ERROR) << "Failed to created a new session with setsid; exiting"; |
| return EX_OSERR; |
| } |
| |
| EnterChildProcessJail(); |
| return Daemon::OnInit(); |
| } |
| |
| void MulticastProxy::Reset() { |
| mdns_fwds_.clear(); |
| ssdp_fwds_.clear(); |
| bcast_fwds_.clear(); |
| } |
| |
| void MulticastProxy::OnParentProcessExit() { |
| LOG(ERROR) << "Quitting because the parent process died"; |
| Reset(); |
| Quit(); |
| } |
| |
| void MulticastProxy::OnDeviceMessage(const DeviceMessage& msg) { |
| const std::string& dev_ifname = msg.dev_ifname(); |
| if (dev_ifname.empty()) { |
| LOG(DFATAL) << "Received DeviceMessage w/ empty dev_ifname"; |
| return; |
| } |
| |
| auto mdns_fwd = mdns_fwds_.find(dev_ifname); |
| auto ssdp_fwd = ssdp_fwds_.find(dev_ifname); |
| auto bcast_fwd = bcast_fwds_.find(dev_ifname); |
| |
| if (!msg.has_teardown()) { |
| // Start multicast forwarders. |
| if (mdns_fwd == mdns_fwds_.end()) { |
| LOG(INFO) << "Enabling mDNS forwarding for device " << dev_ifname; |
| auto fwd = std::make_unique<MulticastForwarder>( |
| dev_ifname, kMdnsMcastAddress, kMdnsMcastAddress6, kMdnsPort); |
| mdns_fwd = mdns_fwds_.emplace(dev_ifname, std::move(fwd)).first; |
| } |
| |
| LOG(INFO) << "Starting mDNS forwarding between " << dev_ifname << " and " |
| << msg.br_ifname(); |
| if (!mdns_fwd->second->AddGuest(msg.br_ifname())) { |
| LOG(WARNING) << "mDNS forwarder could not be started between " |
| << dev_ifname << " and " << msg.br_ifname(); |
| } |
| |
| if (ssdp_fwd == ssdp_fwds_.end()) { |
| LOG(INFO) << "Enabling SSDP forwarding for device " << dev_ifname; |
| auto fwd = std::make_unique<MulticastForwarder>( |
| dev_ifname, kSsdpMcastAddress, kSsdpMcastAddress6, kSsdpPort); |
| ssdp_fwd = ssdp_fwds_.emplace(dev_ifname, std::move(fwd)).first; |
| } |
| |
| LOG(INFO) << "Starting SSDP forwarding between " << dev_ifname << " and " |
| << msg.br_ifname(); |
| if (!ssdp_fwd->second->AddGuest(msg.br_ifname())) { |
| LOG(WARNING) << "SSDP forwarder could not be started on " << dev_ifname |
| << " and " << msg.br_ifname(); |
| } |
| |
| if (bcast_fwd == bcast_fwds_.end()) { |
| LOG(INFO) << "Enabling broadcast forwarding for device " << dev_ifname; |
| auto fwd = std::make_unique<BroadcastForwarder>(dev_ifname); |
| bcast_fwd = bcast_fwds_.emplace(dev_ifname, std::move(fwd)).first; |
| } |
| |
| LOG(INFO) << "Starting broadcast forwarding between " << dev_ifname |
| << " and " << msg.br_ifname(); |
| if (!bcast_fwd->second->AddGuest(msg.br_ifname())) { |
| LOG(WARNING) << "Broadcast forwarder could not be started on " |
| << dev_ifname << " and " << msg.br_ifname(); |
| } |
| |
| return; |
| } |
| |
| if (msg.has_br_ifname()) { |
| // A bridge interface is removed. |
| if (mdns_fwd != mdns_fwds_.end()) { |
| LOG(INFO) << "Disabling mDNS forwarding between " << dev_ifname << " and " |
| << msg.br_ifname(); |
| mdns_fwd->second->RemoveGuest(msg.br_ifname()); |
| } |
| if (ssdp_fwd != ssdp_fwds_.end()) { |
| LOG(INFO) << "Disabling SSDP forwarding between " << dev_ifname << " and " |
| << msg.br_ifname(); |
| ssdp_fwd->second->RemoveGuest(msg.br_ifname()); |
| } |
| if (bcast_fwd != bcast_fwds_.end()) { |
| LOG(INFO) << "Disabling broadcast forwarding between " << dev_ifname |
| << " and " << msg.br_ifname(); |
| bcast_fwd->second->RemoveGuest(msg.br_ifname()); |
| } |
| return; |
| } |
| |
| // A physical interface is removed. |
| if (mdns_fwd != mdns_fwds_.end()) { |
| LOG(INFO) << "Disabling mDNS forwarding for physical interface " |
| << dev_ifname; |
| mdns_fwds_.erase(mdns_fwd); |
| } |
| if (ssdp_fwd != ssdp_fwds_.end()) { |
| LOG(INFO) << "Disabling SSDP forwarding for physical interface " |
| << dev_ifname; |
| ssdp_fwds_.erase(ssdp_fwd); |
| } |
| if (bcast_fwd != bcast_fwds_.end()) { |
| LOG(INFO) << "Disabling broadcast forwarding for physical interface " |
| << dev_ifname; |
| bcast_fwds_.erase(bcast_fwd); |
| } |
| } |
| |
| } // namespace patchpanel |