blob: abe0f2b42c1f1ceffdadfe7d176f8de2c729a782 [file] [log] [blame]
Taoyu Liba04fe32020-01-14 13:19:35 +09001// Copyright 2020 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.
Stephen Barber7e24d3d2020-02-07 11:02:14 -08004#include <unistd.h>
Taoyu Liba04fe32020-01-14 13:19:35 +09005
6#include <base/bind.h>
7#include <base/command_line.h>
8#include <base/files/scoped_file.h>
9#include <base/macros.h>
10#include <brillo/daemons/daemon.h>
11
Garrick Evans3388a032020-03-24 11:25:55 +090012#include "patchpanel/minijailed_process_runner.h"
13#include "patchpanel/ndproxy.h"
Taoyu Liba04fe32020-01-14 13:19:35 +090014
Garrick Evans3388a032020-03-24 11:25:55 +090015void OnSocketReadReady(patchpanel::NDProxy* proxy, int fd) {
Taoyu Liba04fe32020-01-14 13:19:35 +090016 proxy->ReadAndProcessOneFrame(fd);
17}
18
Hugo Benichi3994ea22021-01-12 09:46:05 +090019void OnGuestIpDiscovery(patchpanel::MinijailedProcessRunner* runner,
Taoyu Liba04fe32020-01-14 13:19:35 +090020 const std::string& ifname,
21 const std::string& ip6addr) {
Hugo Benichi3994ea22021-01-12 09:46:05 +090022 if (runner->ip6("route", "replace", {ip6addr + "/128", "dev", ifname}) != 0)
Taoyu Liba04fe32020-01-14 13:19:35 +090023 LOG(WARNING) << "Failed to setup the IPv6 route for interface " << ifname;
Taoyu Liba04fe32020-01-14 13:19:35 +090024}
25
26// Stand-alone daemon to proxy ND frames between a pair of interfaces
27// Usage: ndproxyd $physical_ifname $guest_ifname
28int main(int argc, char* argv[]) {
29 base::CommandLine::Init(argc, argv);
30 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
31 base::CommandLine::StringVector args = cl->GetArgs();
32 if (args.size() < 2) {
33 LOG(ERROR) << "Missing command line arguments; exiting";
34 return EXIT_FAILURE;
35 }
36
37 brillo::Daemon daemon;
38
Garrick Evans3388a032020-03-24 11:25:55 +090039 patchpanel::MinijailedProcessRunner runner;
Garrick Evans8e8e3472020-01-23 14:03:50 +090040 char accept_ra_sysctl_cmd[40] = {0};
41 snprintf(accept_ra_sysctl_cmd, sizeof(accept_ra_sysctl_cmd),
42 "net.ipv6.conf.%s.accept_ra", args[0].c_str());
43 if (runner.sysctl_w(accept_ra_sysctl_cmd, "2") != 0) {
Taoyu Liba04fe32020-01-14 13:19:35 +090044 LOG(ERROR) << "Failed to enable " << accept_ra_sysctl_cmd << ".";
45 return EXIT_FAILURE;
46 }
Garrick Evans8e8e3472020-01-23 14:03:50 +090047 if (runner.sysctl_w("net.ipv6.conf.all.forwarding", "1") != 0) {
Taoyu Liba04fe32020-01-14 13:19:35 +090048 LOG(ERROR) << "Failed to enable net.ipv6.conf.all.forwarding.";
49 return EXIT_FAILURE;
50 }
Taoyu Liba04fe32020-01-14 13:19:35 +090051
Garrick Evans3388a032020-03-24 11:25:55 +090052 patchpanel::NDProxy proxy;
Taoyu Liba04fe32020-01-14 13:19:35 +090053 if (!proxy.Init()) {
54 PLOG(ERROR) << "Failed to initialize NDProxy internal state";
55 return EXIT_FAILURE;
56 }
Stephen Barber7e24d3d2020-02-07 11:02:14 -080057
58 // Crostini depends on another daemon (LXD) creating the guest bridge
59 // interface. This can take a few seconds, so retry if necessary.
60 bool added_interfaces = false;
61 for (int i = 0; i < 10; i++) {
Taoyu Li7dca19a2020-03-16 16:27:07 +090062 if (proxy.AddInterfacePair(args[0], args[1])) {
Stephen Barber7e24d3d2020-02-07 11:02:14 -080063 added_interfaces = true;
64 break;
65 }
66 usleep(1000 * 1000 /* 1 second */);
67 }
68 if (!added_interfaces) {
69 LOG(ERROR) << "Network interfaces " << args[0] << " and " << args[1]
70 << " could not be added; do they exist?";
71 return EXIT_FAILURE;
72 }
73
Taoyu Liba04fe32020-01-14 13:19:35 +090074 proxy.RegisterOnGuestIpDiscoveryHandler(
Hugo Benichi3994ea22021-01-12 09:46:05 +090075 base::Bind(&OnGuestIpDiscovery, &runner));
Taoyu Liba04fe32020-01-14 13:19:35 +090076
Garrick Evans3388a032020-03-24 11:25:55 +090077 base::ScopedFD fd = patchpanel::NDProxy::PreparePacketSocket();
Taoyu Liba04fe32020-01-14 13:19:35 +090078 if (!fd.is_valid()) {
79 PLOG(ERROR) << "Failed to initialize data socket";
80 return EXIT_FAILURE;
81 }
82
83 std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher =
84 base::FileDescriptorWatcher::WatchReadable(
85 fd.get(), base::Bind(&OnSocketReadReady, &proxy, fd.get()));
86
87 return daemon.Run();
88}