blob: 74205f338c74ec97d247b76cf2abbd7336c2080d [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
Kevin Cernekee4e62cc12016-12-03 11:50:53 -08005#include "arc-networkd/manager.h"
6
Kevin Cernekee95d4ae92016-06-19 10:26:29 -07007#include <arpa/inet.h>
8#include <stdint.h>
9
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080010#include <utility>
11
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070012#include <base/bind.h>
13#include <base/logging.h>
14#include <base/message_loop/message_loop.h>
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080015#include <brillo/minijail/minijail.h>
16
17#include "arc-networkd/ipc.pb.h"
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070018
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070019namespace {
20
21const char kMdnsMcastAddress[] = "224.0.0.251";
22const uint16_t kMdnsPort = 5353;
23const char kSsdpMcastAddress[] = "239.255.255.250";
24const uint16_t kSsdpPort = 1900;
25
26const int kMaxRandomAddressTries = 3;
27
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080028const char kUnprivilegedUser[] = "arc-networkd";
29const uint64_t kManagerCapMask = CAP_TO_MASK(CAP_NET_RAW);
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070030
31} // namespace
32
33namespace arc_networkd {
34
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080035Manager::Manager(const Options& opt, std::unique_ptr<HelperProcess> ip_helper)
Kevin Cernekee73e09202017-06-17 20:55:09 -070036 : int_ifname_(opt.int_ifname),
37 mdns_ipaddr_(opt.mdns_ipaddr),
38 con_ifname_(opt.con_ifname) {
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080039 ip_helper_ = std::move(ip_helper);
40}
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070041
42int Manager::OnInit() {
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080043 // Run with minimal privileges.
44 brillo::Minijail* m = brillo::Minijail::GetInstance();
45 struct minijail* jail = m->New();
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070046
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080047 // Most of these return void, but DropRoot() can fail if the user/group
48 // does not exist.
49 CHECK(m->DropRoot(jail, kUnprivilegedUser, kUnprivilegedUser));
50 m->UseCapabilities(jail, kManagerCapMask);
51 m->Enter(jail);
52 m->Destroy(jail);
53
54 // Handle subprocess lifecycle.
55 process_reaper_.Register(this);
56 process_reaper_.WatchForChild(FROM_HERE,
57 ip_helper_->pid(),
58 base::Bind(&Manager::OnSubprocessExited,
59 weak_factory_.GetWeakPtr(),
60 ip_helper_->pid()));
61
62 // This needs to execute after DBusDaemon::OnInit() creates bus_.
Eric Caruso9ce54182018-01-04 11:19:47 -080063 base::MessageLoopForIO::current()->task_runner()->PostTask(
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070064 FROM_HERE,
65 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
66
67 return DBusDaemon::OnInit();
68}
69
70void Manager::InitialSetup() {
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070071 shill_client_.reset(new ShillClient(std::move(bus_)));
72 shill_client_->RegisterDefaultInterfaceChangedHandler(
73 base::Bind(&Manager::OnDefaultInterfaceChanged,
74 weak_factory_.GetWeakPtr()));
75}
76
77void Manager::OnDefaultInterfaceChanged(const std::string& ifname) {
Kevin Cernekee27bcaa62016-12-03 11:16:26 -080078 ClearArcIp();
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070079 neighbor_finder_.reset();
80
81 lan_ifname_ = ifname;
82 if (ifname.empty()) {
83 LOG(INFO) << "Unbinding services";
84 mdns_forwarder_.reset();
85 ssdp_forwarder_.reset();
86 router_finder_.reset();
Kevin Cernekee31a3d902017-07-11 16:46:39 -070087 DisableInbound();
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070088 } else {
89 LOG(INFO) << "Binding to interface " << ifname;
90 mdns_forwarder_.reset(new MulticastForwarder());
91 ssdp_forwarder_.reset(new MulticastForwarder());
92 router_finder_.reset(new RouterFinder());
93
94 mdns_forwarder_->Start(int_ifname_,
95 ifname,
Kevin Cernekee73e09202017-06-17 20:55:09 -070096 mdns_ipaddr_,
Kevin Cernekee95d4ae92016-06-19 10:26:29 -070097 kMdnsMcastAddress,
98 kMdnsPort,
99 /* allow_stateless */ true);
100 ssdp_forwarder_->Start(int_ifname_,
101 ifname,
Kevin Cernekee73e09202017-06-17 20:55:09 -0700102 /* mdns_ipaddr */ "",
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700103 kSsdpMcastAddress,
104 kSsdpPort,
105 /* allow_stateless */ false);
106
107 router_finder_->Start(ifname,
108 base::Bind(&Manager::OnRouteFound, weak_factory_.GetWeakPtr()));
Kevin Cernekee31a3d902017-07-11 16:46:39 -0700109 EnableInbound(ifname);
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700110 }
111}
112
113void Manager::OnRouteFound(const struct in6_addr& prefix,
114 int prefix_len,
115 const struct in6_addr& router) {
116 if (prefix_len == 64) {
117 char buf[64];
118 LOG(INFO) << "Found IPv6 network "
119 << inet_ntop(AF_INET6, &prefix, buf, sizeof(buf))
120 << "/" << prefix_len
121 << " route "
122 << inet_ntop(AF_INET6, &router, buf, sizeof(buf));
123
124 memcpy(&random_address_, &prefix, sizeof(random_address_));
125 random_address_prefix_len_ = prefix_len;
126 random_address_tries_ = 0;
127
128 ArcIpConfig::GenerateRandom(&random_address_,
129 random_address_prefix_len_);
130
131 neighbor_finder_.reset(new NeighborFinder());
132 neighbor_finder_->Check(lan_ifname_, random_address_,
133 base::Bind(&Manager::OnNeighborCheckResult,
134 weak_factory_.GetWeakPtr()));
135 } else {
136 LOG(INFO) << "No IPv6 connectivity available";
137 }
138}
139
140void Manager::OnNeighborCheckResult(bool found) {
141 if (found) {
142 if (++random_address_tries_ >= kMaxRandomAddressTries) {
143 LOG(WARNING) << "Too many IP collisions, giving up.";
144 return;
145 }
146
147 LOG(INFO) << "Detected IP collision, retrying with a new address";
148 ArcIpConfig::GenerateRandom(&random_address_,
149 random_address_prefix_len_);
150 neighbor_finder_->Check(lan_ifname_, random_address_,
151 base::Bind(&Manager::OnNeighborCheckResult,
152 weak_factory_.GetWeakPtr()));
153 } else {
154 struct in6_addr router;
155
156 if (!ArcIpConfig::GetV6Address(int_ifname_, &router)) {
157 LOG(ERROR) << "Error reading link local address for "
158 << int_ifname_;
159 return;
160 }
161
162 char buf[64];
163 LOG(INFO) << "Setting IPv6 address "
164 << inet_ntop(AF_INET6, &random_address_, buf, sizeof(buf))
165 << "/128 route "
166 << inet_ntop(AF_INET6, &router, buf, sizeof(buf));
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800167
168 // Set up new ARC IPv6 address, NDP, and forwarding rules.
169 IpHelperMessage outer_msg;
170 SetArcIp* inner_msg = outer_msg.mutable_set_arc_ip();
171 inner_msg->set_prefix(&random_address_, sizeof(struct in6_addr));
172 inner_msg->set_prefix_len(128);
173 inner_msg->set_router(&router, sizeof(struct in6_addr));
174 inner_msg->set_lan_ifname(lan_ifname_);
175 ip_helper_->SendMessage(outer_msg);
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700176 }
177}
178
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800179void Manager::ClearArcIp() {
180 IpHelperMessage msg;
181 msg.set_clear_arc_ip(true);
182 ip_helper_->SendMessage(msg);
183}
184
Kevin Cernekee31a3d902017-07-11 16:46:39 -0700185void Manager::EnableInbound(const std::string& lan_ifname) {
186 IpHelperMessage msg;
187 msg.set_enable_inbound(lan_ifname);
188 ip_helper_->SendMessage(msg);
189}
190
191void Manager::DisableInbound() {
192 IpHelperMessage msg;
193 msg.set_disable_inbound(true);
194 ip_helper_->SendMessage(msg);
195}
196
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800197void Manager::OnShutdown(int* exit_code) {
198 ClearArcIp();
Kevin Cernekee31a3d902017-07-11 16:46:39 -0700199 DisableInbound();
Kevin Cernekee27bcaa62016-12-03 11:16:26 -0800200}
201
202void Manager::OnSubprocessExited(pid_t pid, const siginfo_t& info) {
203 LOG(FATAL) << "Subprocess " << pid << " exited unexpectedly";
204}
205
Kevin Cernekee95d4ae92016-06-19 10:26:29 -0700206} // namespace arc_networkd