blob: 961cfbf09655617ae303fd7a1f05fb198ab507b1 [file] [log] [blame]
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07001// Copyright 2016 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Garrick Evans3388a032020-03-24 11:25:55 +09005#ifndef PATCHPANEL_MULTICAST_FORWARDER_H_
6#define PATCHPANEL_MULTICAST_FORWARDER_H_
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07007
8#include <netinet/ip.h>
9#include <sys/socket.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070010
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +090011#include <map>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070012#include <memory>
Jason Jeremy Iman51a94cc2020-03-06 14:36:23 +090013#include <set>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070014#include <string>
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090015#include <utility>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070016
Jason Jeremy Iman6e8855f2019-10-09 12:12:38 +090017#include <base/files/file_descriptor_watcher_posix.h>
18#include <base/files/scoped_file.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070019#include <base/macros.h>
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070020
Garrick Evans3388a032020-03-24 11:25:55 +090021#include "patchpanel/net_util.h"
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070022
Garrick Evans3388a032020-03-24 11:25:55 +090023namespace patchpanel {
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070024
Jason Jeremy Iman52933042019-10-09 11:53:34 +090025constexpr uint32_t kMdnsMcastAddress = Ipv4Addr(224, 0, 0, 251);
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090026constexpr char kMdnsMcastAddress6[] = "ff02::fb";
Jason Jeremy Iman52933042019-10-09 11:53:34 +090027constexpr uint16_t kMdnsPort = 5353;
28constexpr uint32_t kSsdpMcastAddress = Ipv4Addr(239, 255, 255, 250);
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090029constexpr char kSsdpMcastAddress6[] = "ff02::c";
Jason Jeremy Iman52933042019-10-09 11:53:34 +090030constexpr uint16_t kSsdpPort = 1900;
31
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070032// Listens on a well-known port and forwards multicast messages between
Jason Jeremy Iman52933042019-10-09 11:53:34 +090033// network interfaces. Handles mDNS, legacy mDNS, and SSDP messages.
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090034// MulticastForwarder forwards multicast between 1 physical interface and
35// many guest interfaces.
Hidehiko Abede129222019-08-16 00:55:04 +090036class MulticastForwarder {
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070037 public:
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +090038 MulticastForwarder(const std::string& lan_ifname,
39 uint32_t mcast_addr,
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090040 const std::string& mcast_addr6,
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +090041 uint16_t port);
Ben Chan4f386502019-09-20 16:17:59 -070042 virtual ~MulticastForwarder() = default;
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070043
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +090044 // Start forwarding multicast packets between the guest's interface
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070045 // |int_ifname| and the external LAN interface |lan_ifname|. This
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090046 // only forwards traffic on multicast address |mcast_addr_| or
47 // |mcast_addr6_| and UDP port |port|.
Jason Jeremy Iman51a94cc2020-03-06 14:36:23 +090048 bool AddGuest(const std::string& int_ifname);
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070049
Jason Jeremy Imand89b5f52019-10-24 10:39:17 +090050 // Stop forwarding multicast packets between |int_ifname| and
51 // |lan_ifname_|.
52 void RemoveGuest(const std::string& int_ifname);
53
Jason Jeremy Imana9f85f12019-11-08 07:53:21 +090054 // Rewrite mDNS A records pointing to |guest_ip| so that they point to
55 // the IPv4 |lan_ip| assigned to physical interface instead, so that Android
56 // can advertise services to devices on the LAN. This modifies |data|, an
57 // incoming packet that is |len| long.
58 static void TranslateMdnsIp(const struct in_addr& lan_ip,
59 const struct in_addr& guest_ip,
60 char* data,
61 ssize_t len);
62
Jason Jeremy Iman6e8855f2019-10-09 12:12:38 +090063 protected:
64 // Socket is used to keep track of an fd and its watcher.
65 struct Socket {
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090066 Socket(base::ScopedFD fd,
67 sa_family_t sa_family,
68 const base::Callback<void(int, sa_family_t)>& callback);
Jason Jeremy Iman6e8855f2019-10-09 12:12:38 +090069 base::ScopedFD fd;
70 std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher;
Jason Jeremy Iman6e8855f2019-10-09 12:12:38 +090071 };
72
73 // Bind will create a multicast socket and return its fd.
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090074 base::ScopedFD Bind(sa_family_t sa_family, const std::string& ifname);
Jason Jeremy Iman6e8855f2019-10-09 12:12:38 +090075
Jason Jeremy Iman52933042019-10-09 11:53:34 +090076 // SendTo sends |data| using a socket bound to |src_port| and |lan_ifname_|.
77 // If |src_port| is equal to |port_|, we will use |lan_socket_|. Otherwise,
78 // create a temporary socket.
79 bool SendTo(uint16_t src_port,
80 const void* data,
81 ssize_t len,
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090082 const struct sockaddr* dst,
83 socklen_t dst_len);
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070084
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +090085 // SendToGuests will forward packet to all Chrome OS guests' (ARC++,
86 // Crostini, etc) internal fd using |port|.
87 // However, if ignore_fd is not 0, it will skip guest with fd = ignore_fd.
88 bool SendToGuests(const void* data,
89 ssize_t len,
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090090 const struct sockaddr* dst,
91 socklen_t dst_len,
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +090092 int ignore_fd = -1);
93
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070094 std::string lan_ifname_;
Brian Norris08732022020-01-22 00:30:56 +000095 unsigned int port_;
Jason Jeremy Iman97ac56d2019-10-09 14:15:35 +090096
Jason Jeremy Imand04ad282019-10-09 14:15:35 +090097 struct in_addr mcast_addr_;
98 struct in6_addr mcast_addr6_;
99
100 std::map<sa_family_t, std::unique_ptr<Socket>> lan_socket_;
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700101
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +0900102 // Mapping from internal interface name to internal sockets.
Jason Jeremy Imand04ad282019-10-09 14:15:35 +0900103 std::map<std::pair<sa_family_t, std::string>, std::unique_ptr<Socket>>
104 int_sockets_;
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +0900105
Jason Jeremy Iman51a94cc2020-03-06 14:36:23 +0900106 // A set of internal file descriptors (guest facing sockets) to its guest
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +0900107 // IP address.
Jason Jeremy Iman51a94cc2020-03-06 14:36:23 +0900108 std::set<std::pair<sa_family_t, int>> int_fds_;
Jason Jeremy Imanf63bc652019-10-09 12:41:30 +0900109
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700110 private:
Jason Jeremy Imand04ad282019-10-09 14:15:35 +0900111 void OnFileCanReadWithoutBlocking(int fd, sa_family_t sa_family);
Hidehiko Abede129222019-08-16 00:55:04 +0900112
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700113 DISALLOW_COPY_AND_ASSIGN(MulticastForwarder);
114};
115
Garrick Evans3388a032020-03-24 11:25:55 +0900116} // namespace patchpanel
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700117
Garrick Evans3388a032020-03-24 11:25:55 +0900118#endif // PATCHPANEL_MULTICAST_FORWARDER_H_