blob: 79dca18683d5a1fc657af6b54c7ded1777504bba [file] [log] [blame]
Garrick Evans49879532018-12-03 13:15:36 +09001// Copyright 2018 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
5#include "arc/network/device.h"
6
Garrick Evansf4a93292019-03-13 14:19:43 +09007#include <arpa/inet.h>
8#include <sys/socket.h>
Garrick Evans49879532018-12-03 13:15:36 +09009#include <sys/types.h>
10
11#include <map>
Garrick Evansf4a93292019-03-13 14:19:43 +090012#include <utility>
Garrick Evans49879532018-12-03 13:15:36 +090013
14#include <base/bind.h>
Garrick Evansf4a93292019-03-13 14:19:43 +090015#include <base/lazy_instance.h>
Garrick Evans49879532018-12-03 13:15:36 +090016#include <base/logging.h>
Long Cheng494fc982019-09-24 19:09:03 +000017#include <base/strings/stringprintf.h>
Garrick Evans49879532018-12-03 13:15:36 +090018
Long Chenge4c86762019-09-24 18:52:40 +000019#include "arc/network/arc_ip_config.h"
Hugo Benichi2ac4d072019-05-28 14:51:23 +090020#include "arc/network/net_util.h"
Garrick Evans49879532018-12-03 13:15:36 +090021
22namespace arc_networkd {
23
Garrick Evansd2bb8502019-02-20 15:59:35 +090024// These are used to identify which ARC++ data path should be used when setting
25// up the Android device.
26const char kAndroidDevice[] = "arc0";
27const char kAndroidLegacyDevice[] = "android";
Garrick Evans49879532018-12-03 13:15:36 +090028
29namespace {
Long Cheng494fc982019-09-24 19:09:03 +000030
Hugo Benichi2ac4d072019-05-28 14:51:23 +090031constexpr uint32_t kMdnsMcastAddress = Ipv4Addr(224, 0, 0, 251);
Garrick Evansf4a93292019-03-13 14:19:43 +090032constexpr uint16_t kMdnsPort = 5353;
Hugo Benichi2ac4d072019-05-28 14:51:23 +090033constexpr uint32_t kSsdpMcastAddress = Ipv4Addr(239, 255, 255, 250);
Garrick Evansf4a93292019-03-13 14:19:43 +090034constexpr uint16_t kSsdpPort = 1900;
Long Cheng494fc982019-09-24 19:09:03 +000035
Garrick Evansf4a93292019-03-13 14:19:43 +090036constexpr int kMaxRandomAddressTries = 3;
Long Cheng494fc982019-09-24 19:09:03 +000037
38std::string MacAddressToString(const MacAddress& addr) {
39 return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1],
40 addr[2], addr[3], addr[4], addr[5]);
41}
42
Garrick Evans49879532018-12-03 13:15:36 +090043} // namespace
44
Garrick Evansf4a93292019-03-13 14:19:43 +090045Device::Config::Config(const std::string& host_ifname,
46 const std::string& guest_ifname,
47 const MacAddress& guest_mac_addr,
48 std::unique_ptr<Subnet> ipv4_subnet,
49 std::unique_ptr<SubnetAddress> host_ipv4_addr,
50 std::unique_ptr<SubnetAddress> guest_ipv4_addr)
51 : host_ifname_(host_ifname),
52 guest_ifname_(guest_ifname),
53 guest_mac_addr_(guest_mac_addr),
54 ipv4_subnet_(std::move(ipv4_subnet)),
55 host_ipv4_addr_(std::move(host_ipv4_addr)),
56 guest_ipv4_addr_(std::move(guest_ipv4_addr)) {}
57
Garrick Evans428e4762018-12-11 15:18:42 +090058Device::Device(const std::string& ifname,
Garrick Evansf4a93292019-03-13 14:19:43 +090059 std::unique_ptr<Device::Config> config,
Long Cheng994dfd32019-09-24 18:50:27 +000060 const Device::Options& options,
61 const MessageSink& msg_sink)
Garrick Evansf4a93292019-03-13 14:19:43 +090062 : ifname_(ifname),
63 config_(std::move(config)),
64 options_(options),
Long Cheng494fc982019-09-24 19:09:03 +000065 msg_sink_(msg_sink) {
Garrick Evansf4a93292019-03-13 14:19:43 +090066 DCHECK(config_);
Long Chenge4c86762019-09-24 18:52:40 +000067 if (msg_sink_.is_null())
68 return;
69
70 DeviceMessage msg;
71 msg.set_dev_ifname(ifname_);
72 auto* dev_config = msg.mutable_dev_config();
73 FillProto(dev_config);
74 msg_sink_.Run(msg);
75}
76
77Device::~Device() {
78 if (msg_sink_.is_null())
79 return;
80
81 DeviceMessage msg;
82 msg.set_dev_ifname(ifname_);
83 msg.set_teardown(true);
84 msg_sink_.Run(msg);
Garrick Evans49879532018-12-03 13:15:36 +090085}
86
Long Cheng994dfd32019-09-24 18:50:27 +000087void Device::FillProto(DeviceConfig* msg) const {
88 msg->set_br_ifname(config_->host_ifname());
89 msg->set_br_ipv4(IPv4AddressToString(config_->host_ipv4_addr()));
90 msg->set_arc_ifname(config_->guest_ifname());
91 msg->set_arc_ipv4(IPv4AddressToString(config_->guest_ipv4_addr()));
92 msg->set_mac_addr(MacAddressToString(config_->guest_mac_addr()));
93
94 msg->set_fwd_multicast(options_.fwd_multicast);
95 msg->set_find_ipv6_routes(options_.find_ipv6_routes);
96}
97
Garrick Evans894abc22019-06-07 10:49:02 +090098Device::Config& Device::config() const {
99 CHECK(config_);
100 return *config_.get();
101}
Garrick Evansd2bb8502019-02-20 15:59:35 +0900102
Garrick Evansac982ea2019-07-19 09:05:09 +0900103void Device::Enable(const std::string& ifname) {
Long Cheng494fc982019-09-24 19:09:03 +0000104 // If operating in legacy single network mode, enable inbound traffic to ARC
105 // from the interface.
106 // TODO(b/77293260) Also enable inbound traffic rules specific to the input
107 // physical interface in multinetworking mode.
108 if (ifname_ == kAndroidLegacyDevice) {
109 LOG(INFO) << "Binding interface " << ifname << " to device " << ifname_;
110 legacy_lan_ifname_ = ifname;
111
112 if (!msg_sink_.is_null()) {
113 DeviceMessage msg;
114 msg.set_dev_ifname(ifname_);
115 msg.set_enable_inbound_ifname(legacy_lan_ifname_);
116 msg_sink_.Run(msg);
117 }
118 }
Garrick Evansac982ea2019-07-19 09:05:09 +0900119
Garrick Evansf4a93292019-03-13 14:19:43 +0900120 if (options_.fwd_multicast) {
Garrick Evans894abc22019-06-07 10:49:02 +0900121 if (!mdns_forwarder_) {
122 LOG(INFO) << "Enabling mDNS forwarding for device " << ifname_;
123 auto mdns_fwd = std::make_unique<MulticastForwarder>();
124 if (mdns_fwd->Start(config_->host_ifname(), ifname,
125 config_->guest_ipv4_addr(), kMdnsMcastAddress,
126 kMdnsPort,
127 /* allow_stateless */ true)) {
128 mdns_forwarder_ = std::move(mdns_fwd);
129 } else {
130 LOG(WARNING) << "mDNS forwarder could not be started on " << ifname_;
131 }
Hugo Benichidcce1142019-06-17 10:52:15 +0900132 }
Garrick Evansf4a93292019-03-13 14:19:43 +0900133
Garrick Evans894abc22019-06-07 10:49:02 +0900134 if (!ssdp_forwarder_) {
135 LOG(INFO) << "Enabling SSDP forwarding for device " << ifname_;
136 auto ssdp_fwd = std::make_unique<MulticastForwarder>();
137 if (ssdp_fwd->Start(config_->host_ifname(), ifname, htonl(INADDR_ANY),
138 kSsdpMcastAddress, kSsdpPort,
139 /* allow_stateless */ false)) {
140 ssdp_forwarder_ = std::move(ssdp_fwd);
141 } else {
142 LOG(WARNING) << "SSDP forwarder could not be started on " << ifname_;
143 }
Hugo Benichidcce1142019-06-17 10:52:15 +0900144 }
Garrick Evans428e4762018-12-11 15:18:42 +0900145 }
Garrick Evans49879532018-12-03 13:15:36 +0900146
Garrick Evans894abc22019-06-07 10:49:02 +0900147 if (options_.find_ipv6_routes && !router_finder_) {
Long Cheng494fc982019-09-24 19:09:03 +0000148 LOG(INFO) << "Enabling IPV6 route finding for device " << ifname_;
Garrick Evans428e4762018-12-11 15:18:42 +0900149 router_finder_.reset(new RouterFinder());
150 router_finder_->Start(
Hugo Benichiee787ff2019-05-20 16:42:42 +0900151 ifname, base::Bind(&Device::OnRouteFound, weak_factory_.GetWeakPtr()));
Garrick Evans428e4762018-12-11 15:18:42 +0900152 }
Garrick Evans49879532018-12-03 13:15:36 +0900153}
154
155void Device::Disable() {
Long Chenge4c86762019-09-24 18:52:40 +0000156 LOG(INFO) << "Disabling device " << ifname_;
157
158 neighbor_finder_.reset();
159 router_finder_.reset();
160 ssdp_forwarder_.reset();
161 mdns_forwarder_.reset();
162
163 if (msg_sink_.is_null())
164 return;
165
166 // Clear IPv6 info, if necessary.
167 if (options_.find_ipv6_routes) {
168 DeviceMessage msg;
169 msg.set_dev_ifname(ifname_);
170 msg.set_clear_arc_ip(true);
171 msg_sink_.Run(msg);
Garrick Evans49879532018-12-03 13:15:36 +0900172 }
Garrick Evans49879532018-12-03 13:15:36 +0900173
Long Cheng494fc982019-09-24 19:09:03 +0000174 // Disable inbound traffic.
175 // TODO(b/77293260) Also disable inbound traffic rules in multinetworking
176 // mode.
177 if (ifname_ == kAndroidLegacyDevice && !legacy_lan_ifname_.empty()) {
178 LOG(INFO) << "Unbinding interface " << legacy_lan_ifname_ << " from device "
179 << ifname_;
180 legacy_lan_ifname_.clear();
Garrick Evansac982ea2019-07-19 09:05:09 +0900181
Long Cheng494fc982019-09-24 19:09:03 +0000182 DeviceMessage msg;
183 msg.set_dev_ifname(ifname_);
184 msg.set_disable_inbound(true);
185 msg_sink_.Run(msg);
186 }
187}
Garrick Evansac982ea2019-07-19 09:05:09 +0900188
Garrick Evans49879532018-12-03 13:15:36 +0900189void Device::OnRouteFound(const struct in6_addr& prefix,
190 int prefix_len,
191 const struct in6_addr& router) {
Long Chenge4c86762019-09-24 18:52:40 +0000192 const std::string& ifname =
193 legacy_lan_ifname_.empty() ? ifname_ : legacy_lan_ifname_;
194
195 if (prefix_len == 64) {
196 LOG(INFO) << "Found IPv6 network on iface " << ifname << " route=" << prefix
197 << "/" << prefix_len << ", gateway=" << router;
198
199 memcpy(&random_address_, &prefix, sizeof(random_address_));
200 random_address_prefix_len_ = prefix_len;
201 random_address_tries_ = 0;
202
203 ArcIpConfig::GenerateRandom(&random_address_, random_address_prefix_len_);
204
205 neighbor_finder_.reset(new NeighborFinder());
206 neighbor_finder_->Check(
207 ifname, random_address_,
208 base::Bind(&Device::OnNeighborCheckResult, weak_factory_.GetWeakPtr()));
209 } else {
210 LOG(INFO) << "No IPv6 connectivity available on " << ifname;
Garrick Evans49879532018-12-03 13:15:36 +0900211 }
212}
213
214void Device::OnNeighborCheckResult(bool found) {
Long Chenge4c86762019-09-24 18:52:40 +0000215 const std::string& ifname =
216 legacy_lan_ifname_.empty() ? ifname_ : legacy_lan_ifname_;
217
Garrick Evans49879532018-12-03 13:15:36 +0900218 if (found) {
Long Chenge4c86762019-09-24 18:52:40 +0000219 if (++random_address_tries_ >= kMaxRandomAddressTries) {
220 LOG(WARNING) << "Too many IP collisions, giving up.";
Garrick Evans49879532018-12-03 13:15:36 +0900221 return;
222 }
223
Long Chenge4c86762019-09-24 18:52:40 +0000224 struct in6_addr previous_address = random_address_;
225 ArcIpConfig::GenerateRandom(&random_address_, random_address_prefix_len_);
Garrick Evans49879532018-12-03 13:15:36 +0900226
227 LOG(INFO) << "Detected IP collision for " << previous_address
Long Chenge4c86762019-09-24 18:52:40 +0000228 << ", retrying with new address " << random_address_;
Garrick Evans49879532018-12-03 13:15:36 +0900229
230 neighbor_finder_->Check(
Long Chenge4c86762019-09-24 18:52:40 +0000231 ifname, random_address_,
Garrick Evans49879532018-12-03 13:15:36 +0900232 base::Bind(&Device::OnNeighborCheckResult, weak_factory_.GetWeakPtr()));
Long Chenge4c86762019-09-24 18:52:40 +0000233 } else {
234 struct in6_addr router;
Garrick Evans6467aba2019-07-25 11:22:50 +0900235
Long Chenge4c86762019-09-24 18:52:40 +0000236 if (!ArcIpConfig::GetV6Address(config_->host_ifname(), &router)) {
237 LOG(ERROR) << "Error reading link local address for "
238 << config_->host_ifname();
239 return;
240 }
Garrick Evans6467aba2019-07-25 11:22:50 +0900241
Long Chenge4c86762019-09-24 18:52:40 +0000242 LOG(INFO) << "Setting IPv6 address " << random_address_
243 << "/128, gateway=" << router << " on " << ifname;
244
245 // Set up new ARC IPv6 address, NDP, and forwarding rules.
246 if (!msg_sink_.is_null()) {
247 DeviceMessage msg;
248 msg.set_dev_ifname(ifname_);
249 SetArcIp* setup_msg = msg.mutable_set_arc_ip();
250 setup_msg->set_prefix(&random_address_, sizeof(struct in6_addr));
251 setup_msg->set_prefix_len(128);
252 setup_msg->set_router(&router, sizeof(struct in6_addr));
253 setup_msg->set_lan_ifname(ifname);
254 msg_sink_.Run(msg);
255 }
256 }
Garrick Evans49879532018-12-03 13:15:36 +0900257}
258
Hugo Benichiee787ff2019-05-20 16:42:42 +0900259std::ostream& operator<<(std::ostream& stream, const Device& device) {
Long Chenge4c86762019-09-24 18:52:40 +0000260 stream << "{ ifname: " << device.ifname_;
261 if (!device.legacy_lan_ifname_.empty())
262 stream << ", legacy_lan_ifname: " << device.legacy_lan_ifname_;
263 stream << ", bridge_ifname: " << device.config_->host_ifname()
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900264 << ", bridge_ipv4_addr: "
265 << device.config_->host_ipv4_addr_->ToCidrString()
266 << ", guest_ifname: " << device.config_->guest_ifname()
267 << ", guest_ipv4_addr: "
268 << device.config_->guest_ipv4_addr_->ToCidrString()
269 << ", guest_mac_addr: "
Hugo Benichiee787ff2019-05-20 16:42:42 +0900270 << MacAddressToString(device.config_->guest_mac_addr())
Hugo Benichibd8ec4d2019-05-28 12:52:49 +0900271 << ", fwd_multicast: " << device.options_.fwd_multicast
272 << ", find_ipv6_routes: " << device.options_.find_ipv6_routes << '}';
Hugo Benichiee787ff2019-05-20 16:42:42 +0900273 return stream;
274}
275
Garrick Evans49879532018-12-03 13:15:36 +0900276} // namespace arc_networkd