blob: de5342010ca516f358831ad13b46476f3bb33f90 [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
5#include <arpa/inet.h>
6#include <stdint.h>
7
8#include <base/bind.h>
9#include <base/logging.h>
10#include <base/message_loop/message_loop.h>
11#include <base/time/time.h>
12
13#include "arc-networkd/manager.h"
14
15namespace {
16
17const char kMdnsMcastAddress[] = "224.0.0.251";
18const uint16_t kMdnsPort = 5353;
19const char kSsdpMcastAddress[] = "239.255.255.250";
20const uint16_t kSsdpPort = 1900;
21
22const int kMaxRandomAddressTries = 3;
23
24const int kContainerRetryDelaySeconds = 5;
25const int kMaxContainerRetries = 60;
26
27} // namespace
28
29namespace arc_networkd {
30
31Manager::Manager(const Options& opt) :
32 con_init_tries_(0),
33 int_ifname_(opt.int_ifname),
34 con_ifname_(opt.con_ifname),
35 con_netns_(opt.con_netns) {}
36
37int Manager::OnInit() {
38 arc_ip_config_.reset(new ArcIpConfig(int_ifname_, con_ifname_, con_netns_));
39 CHECK(arc_ip_config_->Init());
40
41 // This needs to execute after DBusDaemon::OnInit().
42 base::MessageLoopForIO::current()->PostTask(
43 FROM_HERE,
44 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()));
45
46 return DBusDaemon::OnInit();
47}
48
49void Manager::InitialSetup() {
50 if (!arc_ip_config_->ContainerInit()) {
51 if (++con_init_tries_ >= kMaxContainerRetries) {
52 LOG(FATAL) << "Container failed to come up";
53 } else {
54 base::MessageLoopForIO::current()->PostDelayedTask(
55 FROM_HERE,
56 base::Bind(&Manager::InitialSetup, weak_factory_.GetWeakPtr()),
57 base::TimeDelta::FromSeconds(kContainerRetryDelaySeconds));
58 }
59 return;
60 }
61
62 shill_client_.reset(new ShillClient(std::move(bus_)));
63 shill_client_->RegisterDefaultInterfaceChangedHandler(
64 base::Bind(&Manager::OnDefaultInterfaceChanged,
65 weak_factory_.GetWeakPtr()));
66}
67
68void Manager::OnDefaultInterfaceChanged(const std::string& ifname) {
69 arc_ip_config_->Clear();
70 neighbor_finder_.reset();
71
72 lan_ifname_ = ifname;
73 if (ifname.empty()) {
74 LOG(INFO) << "Unbinding services";
75 mdns_forwarder_.reset();
76 ssdp_forwarder_.reset();
77 router_finder_.reset();
78 } else {
79 LOG(INFO) << "Binding to interface " << ifname;
80 mdns_forwarder_.reset(new MulticastForwarder());
81 ssdp_forwarder_.reset(new MulticastForwarder());
82 router_finder_.reset(new RouterFinder());
83
84 mdns_forwarder_->Start(int_ifname_,
85 ifname,
86 kMdnsMcastAddress,
87 kMdnsPort,
88 /* allow_stateless */ true);
89 ssdp_forwarder_->Start(int_ifname_,
90 ifname,
91 kSsdpMcastAddress,
92 kSsdpPort,
93 /* allow_stateless */ false);
94
95 router_finder_->Start(ifname,
96 base::Bind(&Manager::OnRouteFound, weak_factory_.GetWeakPtr()));
97 }
98}
99
100void Manager::OnRouteFound(const struct in6_addr& prefix,
101 int prefix_len,
102 const struct in6_addr& router) {
103 if (prefix_len == 64) {
104 char buf[64];
105 LOG(INFO) << "Found IPv6 network "
106 << inet_ntop(AF_INET6, &prefix, buf, sizeof(buf))
107 << "/" << prefix_len
108 << " route "
109 << inet_ntop(AF_INET6, &router, buf, sizeof(buf));
110
111 memcpy(&random_address_, &prefix, sizeof(random_address_));
112 random_address_prefix_len_ = prefix_len;
113 random_address_tries_ = 0;
114
115 ArcIpConfig::GenerateRandom(&random_address_,
116 random_address_prefix_len_);
117
118 neighbor_finder_.reset(new NeighborFinder());
119 neighbor_finder_->Check(lan_ifname_, random_address_,
120 base::Bind(&Manager::OnNeighborCheckResult,
121 weak_factory_.GetWeakPtr()));
122 } else {
123 LOG(INFO) << "No IPv6 connectivity available";
124 }
125}
126
127void Manager::OnNeighborCheckResult(bool found) {
128 if (found) {
129 if (++random_address_tries_ >= kMaxRandomAddressTries) {
130 LOG(WARNING) << "Too many IP collisions, giving up.";
131 return;
132 }
133
134 LOG(INFO) << "Detected IP collision, retrying with a new address";
135 ArcIpConfig::GenerateRandom(&random_address_,
136 random_address_prefix_len_);
137 neighbor_finder_->Check(lan_ifname_, random_address_,
138 base::Bind(&Manager::OnNeighborCheckResult,
139 weak_factory_.GetWeakPtr()));
140 } else {
141 struct in6_addr router;
142
143 if (!ArcIpConfig::GetV6Address(int_ifname_, &router)) {
144 LOG(ERROR) << "Error reading link local address for "
145 << int_ifname_;
146 return;
147 }
148
149 char buf[64];
150 LOG(INFO) << "Setting IPv6 address "
151 << inet_ntop(AF_INET6, &random_address_, buf, sizeof(buf))
152 << "/128 route "
153 << inet_ntop(AF_INET6, &router, buf, sizeof(buf));
154 arc_ip_config_->Set(random_address_, 128, router, lan_ifname_);
155 }
156}
157
158} // namespace arc_networkd