Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 1 | // 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 Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 5 | #ifndef PATCHPANEL_MULTICAST_FORWARDER_H_ |
| 6 | #define PATCHPANEL_MULTICAST_FORWARDER_H_ |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 7 | |
| 8 | #include <netinet/ip.h> |
| 9 | #include <sys/socket.h> |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 10 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 11 | #include <map> |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 12 | #include <memory> |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 13 | #include <set> |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 14 | #include <string> |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 15 | #include <utility> |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 16 | |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 17 | #include <base/files/file_descriptor_watcher_posix.h> |
| 18 | #include <base/files/scoped_file.h> |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 19 | #include <base/macros.h> |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 20 | |
Garrick Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 21 | #include "patchpanel/net_util.h" |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 22 | |
Garrick Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 23 | namespace patchpanel { |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 24 | |
Jason Jeremy Iman | 5293304 | 2019-10-09 11:53:34 +0900 | [diff] [blame] | 25 | constexpr uint32_t kMdnsMcastAddress = Ipv4Addr(224, 0, 0, 251); |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 26 | constexpr char kMdnsMcastAddress6[] = "ff02::fb"; |
Jason Jeremy Iman | 5293304 | 2019-10-09 11:53:34 +0900 | [diff] [blame] | 27 | constexpr uint16_t kMdnsPort = 5353; |
| 28 | constexpr uint32_t kSsdpMcastAddress = Ipv4Addr(239, 255, 255, 250); |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 29 | constexpr char kSsdpMcastAddress6[] = "ff02::c"; |
Jason Jeremy Iman | 5293304 | 2019-10-09 11:53:34 +0900 | [diff] [blame] | 30 | constexpr uint16_t kSsdpPort = 1900; |
| 31 | |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 32 | // Listens on a well-known port and forwards multicast messages between |
Jason Jeremy Iman | 5293304 | 2019-10-09 11:53:34 +0900 | [diff] [blame] | 33 | // network interfaces. Handles mDNS, legacy mDNS, and SSDP messages. |
Jason Jeremy Iman | d89b5f5 | 2019-10-24 10:39:17 +0900 | [diff] [blame] | 34 | // MulticastForwarder forwards multicast between 1 physical interface and |
| 35 | // many guest interfaces. |
Hidehiko Abe | de12922 | 2019-08-16 00:55:04 +0900 | [diff] [blame] | 36 | class MulticastForwarder { |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 37 | public: |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 38 | MulticastForwarder(const std::string& lan_ifname, |
| 39 | uint32_t mcast_addr, |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 40 | const std::string& mcast_addr6, |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 41 | uint16_t port); |
Ben Chan | 4f38650 | 2019-09-20 16:17:59 -0700 | [diff] [blame] | 42 | virtual ~MulticastForwarder() = default; |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 43 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 44 | // Start forwarding multicast packets between the guest's interface |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 45 | // |int_ifname| and the external LAN interface |lan_ifname|. This |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 46 | // only forwards traffic on multicast address |mcast_addr_| or |
| 47 | // |mcast_addr6_| and UDP port |port|. |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 48 | bool AddGuest(const std::string& int_ifname); |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 49 | |
Jason Jeremy Iman | d89b5f5 | 2019-10-24 10:39:17 +0900 | [diff] [blame] | 50 | // Stop forwarding multicast packets between |int_ifname| and |
| 51 | // |lan_ifname_|. |
| 52 | void RemoveGuest(const std::string& int_ifname); |
| 53 | |
Jason Jeremy Iman | a9f85f1 | 2019-11-08 07:53:21 +0900 | [diff] [blame] | 54 | // 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 Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 63 | protected: |
| 64 | // Socket is used to keep track of an fd and its watcher. |
| 65 | struct Socket { |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 66 | Socket(base::ScopedFD fd, |
| 67 | sa_family_t sa_family, |
| 68 | const base::Callback<void(int, sa_family_t)>& callback); |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 69 | base::ScopedFD fd; |
| 70 | std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher; |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 71 | }; |
| 72 | |
| 73 | // Bind will create a multicast socket and return its fd. |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 74 | base::ScopedFD Bind(sa_family_t sa_family, const std::string& ifname); |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 75 | |
Jason Jeremy Iman | 5293304 | 2019-10-09 11:53:34 +0900 | [diff] [blame] | 76 | // 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 Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 82 | const struct sockaddr* dst, |
| 83 | socklen_t dst_len); |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 84 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 85 | // 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 Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 90 | const struct sockaddr* dst, |
| 91 | socklen_t dst_len, |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 92 | int ignore_fd = -1); |
| 93 | |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 94 | std::string lan_ifname_; |
Brian Norris | 0873202 | 2020-01-22 00:30:56 +0000 | [diff] [blame] | 95 | unsigned int port_; |
Jason Jeremy Iman | 97ac56d | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 96 | |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 97 | 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 Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 101 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 102 | // Mapping from internal interface name to internal sockets. |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 103 | std::map<std::pair<sa_family_t, std::string>, std::unique_ptr<Socket>> |
| 104 | int_sockets_; |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 105 | |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 106 | // A set of internal file descriptors (guest facing sockets) to its guest |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 107 | // IP address. |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 108 | std::set<std::pair<sa_family_t, int>> int_fds_; |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 109 | |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 110 | private: |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 111 | void OnFileCanReadWithoutBlocking(int fd, sa_family_t sa_family); |
Hidehiko Abe | de12922 | 2019-08-16 00:55:04 +0900 | [diff] [blame] | 112 | |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 113 | DISALLOW_COPY_AND_ASSIGN(MulticastForwarder); |
| 114 | }; |
| 115 | |
Garrick Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 116 | } // namespace patchpanel |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 117 | |
Garrick Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 118 | #endif // PATCHPANEL_MULTICAST_FORWARDER_H_ |