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); |
Qijiang Fan | 6bc59e1 | 2020-11-11 02:51:06 +0900 | [diff] [blame^] | 42 | MulticastForwarder(const MulticastForwarder&) = delete; |
| 43 | MulticastForwarder& operator=(const MulticastForwarder&) = delete; |
| 44 | |
Ben Chan | 4f38650 | 2019-09-20 16:17:59 -0700 | [diff] [blame] | 45 | virtual ~MulticastForwarder() = default; |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 46 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 47 | // Start forwarding multicast packets between the guest's interface |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 48 | // |int_ifname| and the external LAN interface |lan_ifname|. This |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 49 | // only forwards traffic on multicast address |mcast_addr_| or |
| 50 | // |mcast_addr6_| and UDP port |port|. |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 51 | bool AddGuest(const std::string& int_ifname); |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 52 | |
Jason Jeremy Iman | d89b5f5 | 2019-10-24 10:39:17 +0900 | [diff] [blame] | 53 | // Stop forwarding multicast packets between |int_ifname| and |
| 54 | // |lan_ifname_|. |
| 55 | void RemoveGuest(const std::string& int_ifname); |
| 56 | |
Jason Jeremy Iman | a9f85f1 | 2019-11-08 07:53:21 +0900 | [diff] [blame] | 57 | // Rewrite mDNS A records pointing to |guest_ip| so that they point to |
| 58 | // the IPv4 |lan_ip| assigned to physical interface instead, so that Android |
| 59 | // can advertise services to devices on the LAN. This modifies |data|, an |
| 60 | // incoming packet that is |len| long. |
| 61 | static void TranslateMdnsIp(const struct in_addr& lan_ip, |
| 62 | const struct in_addr& guest_ip, |
| 63 | char* data, |
| 64 | ssize_t len); |
| 65 | |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 66 | protected: |
| 67 | // Socket is used to keep track of an fd and its watcher. |
| 68 | struct Socket { |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 69 | Socket(base::ScopedFD fd, |
| 70 | sa_family_t sa_family, |
| 71 | const base::Callback<void(int, sa_family_t)>& callback); |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 72 | base::ScopedFD fd; |
| 73 | std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher; |
Jason Jeremy Iman | 6e8855f | 2019-10-09 12:12:38 +0900 | [diff] [blame] | 74 | }; |
| 75 | |
| 76 | // Bind will create a multicast socket and return its fd. |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 77 | 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] | 78 | |
Jason Jeremy Iman | 5293304 | 2019-10-09 11:53:34 +0900 | [diff] [blame] | 79 | // SendTo sends |data| using a socket bound to |src_port| and |lan_ifname_|. |
| 80 | // If |src_port| is equal to |port_|, we will use |lan_socket_|. Otherwise, |
| 81 | // create a temporary socket. |
| 82 | bool SendTo(uint16_t src_port, |
| 83 | const void* data, |
| 84 | ssize_t len, |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 85 | const struct sockaddr* dst, |
| 86 | socklen_t dst_len); |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 87 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 88 | // SendToGuests will forward packet to all Chrome OS guests' (ARC++, |
| 89 | // Crostini, etc) internal fd using |port|. |
| 90 | // However, if ignore_fd is not 0, it will skip guest with fd = ignore_fd. |
| 91 | bool SendToGuests(const void* data, |
| 92 | ssize_t len, |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 93 | const struct sockaddr* dst, |
| 94 | socklen_t dst_len, |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 95 | int ignore_fd = -1); |
| 96 | |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 97 | std::string lan_ifname_; |
Brian Norris | 0873202 | 2020-01-22 00:30:56 +0000 | [diff] [blame] | 98 | unsigned int port_; |
Jason Jeremy Iman | 97ac56d | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 99 | |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 100 | struct in_addr mcast_addr_; |
| 101 | struct in6_addr mcast_addr6_; |
| 102 | |
| 103 | std::map<sa_family_t, std::unique_ptr<Socket>> lan_socket_; |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 104 | |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 105 | // Mapping from internal interface name to internal sockets. |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 106 | std::map<std::pair<sa_family_t, std::string>, std::unique_ptr<Socket>> |
| 107 | int_sockets_; |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 108 | |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 109 | // 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] | 110 | // IP address. |
Jason Jeremy Iman | 51a94cc | 2020-03-06 14:36:23 +0900 | [diff] [blame] | 111 | std::set<std::pair<sa_family_t, int>> int_fds_; |
Jason Jeremy Iman | f63bc65 | 2019-10-09 12:41:30 +0900 | [diff] [blame] | 112 | |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 113 | private: |
Jason Jeremy Iman | d04ad28 | 2019-10-09 14:15:35 +0900 | [diff] [blame] | 114 | void OnFileCanReadWithoutBlocking(int fd, sa_family_t sa_family); |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 115 | }; |
| 116 | |
Garrick Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 117 | } // namespace patchpanel |
Kevin Cernekee | 95d4ae9 | 2016-06-19 10:26:29 -0700 | [diff] [blame] | 118 | |
Garrick Evans | 3388a03 | 2020-03-24 11:25:55 +0900 | [diff] [blame] | 119 | #endif // PATCHPANEL_MULTICAST_FORWARDER_H_ |