patchpanel: directly write to /proc/sys/net/
This patch changes patchpanel to not interact with /proc/sys/net runtime
configuration through /usr/sbin/sysctl but instead directly writing to a
fixed set of files in /proc/sys/net.
After the device has booted, reading the following /proc/sys path
returns the expected content:
localhost ~ # cat /proc/sys/net/ipv4/ip_forward
1
localhost ~ # cat /proc/sys/net/ipv4/ip_local_port_range
32768 47103
localhost ~ # cat /proc/sys/net/ipv6/conf/all/forwarding
1
BUG=b:178980566
TEST=Unit tests. Flashed rammus, checked that /proc/sys/net
configuration on the host happens as expected, checked that ndproxyd
starts correctly.
Change-Id: I1cfa71c3ccd88bdfd89c81b5a75b0c0912b39c72
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2738499
Tested-by: Hugo Benichi <hugobenichi@google.com>
Commit-Queue: Hugo Benichi <hugobenichi@google.com>
Reviewed-by: Garrick Evans <garrick@chromium.org>
diff --git a/patchpanel/system.cc b/patchpanel/system.cc
index f802b82..b971206 100644
--- a/patchpanel/system.cc
+++ b/patchpanel/system.cc
@@ -4,8 +4,43 @@
#include "patchpanel/system.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <base/files/scoped_file.h>
+
namespace patchpanel {
+namespace {
+
+// /proc/sys/ paths and fragments used for System::SysNetSet
+// Defines the local port range that is used by TCP and UDP traffic to choose
+// the local port (IPv4 and IPv6).
+constexpr const char kSysNetIPLocalPortRangePath[] =
+ "/proc/sys/net/ipv4/ip_local_port_range";
+// Enables/Disables IPv4 forwarding between interfaces.
+constexpr const char kSysNetIPv4ForwardingPath[] =
+ "/proc/sys/net/ipv4/ip_forward";
+// /proc/sys path for controlling connection tracking helper modules
+constexpr const char kSysNetConntrackHelperPath[] =
+ "/proc/sys/net/netfilter/nf_conntrack_helper";
+// Prefix for IPv4 interface configuration.
+constexpr const char kSysNetIPv4ConfPrefix[] = "/proc/sys/net/ipv4/conf/";
+// Suffix for allowing localhost as a source or destination when routing IPv4.
+constexpr const char kSysNetIPv4RouteLocalnetSuffix[] = "/route_localnet";
+// Enables/Disables IPv6 forwarding between interfaces.
+constexpr const char kSysNetIPv6ForwardingPath[] =
+ "/proc/sys/net/ipv6/conf/all/forwarding";
+// Prefix for IPv6 interface configuration.
+constexpr const char kSysNetIPv6ConfPrefix[] = "/proc/sys/net/ipv6/conf/";
+// Suffix for accepting Router Advertisements on an interface and
+// autoconfiguring it with IPv6 parameters.
+constexpr const char kSysNetIPv6AcceptRaSuffix[] = "/accept_ra";
+
+} // namespace
+
int System::Ioctl(int fd, ioctl_req_t request, const char* argp) {
return ioctl(fd, request, argp);
}
@@ -22,4 +57,53 @@
return Ioctl(fd, request, reinterpret_cast<const char*>(route));
}
+bool System::SysNetSet(SysNet target,
+ const std::string& content,
+ const std::string& iface) {
+ std::string path;
+ switch (target) {
+ case SysNet::IPv4Forward:
+ return Write(kSysNetIPv4ForwardingPath, content);
+ case SysNet::IPLocalPortRange:
+ return Write(kSysNetIPLocalPortRangePath, content);
+ case SysNet::IPv4RouteLocalnet:
+ if (iface.empty()) {
+ LOG(ERROR) << "IPv4LocalPortRange requires a valid interface";
+ return false;
+ }
+ return Write(
+ kSysNetIPv4ConfPrefix + iface + kSysNetIPv4RouteLocalnetSuffix,
+ content);
+ case SysNet::IPv6Forward:
+ return Write(kSysNetIPv6ForwardingPath, content);
+ case SysNet::IPv6AcceptRA:
+ if (iface.empty()) {
+ LOG(ERROR) << "IPv6AcceptRA requires a valid interface";
+ return false;
+ }
+ return Write(kSysNetIPv6ConfPrefix + iface + kSysNetIPv6AcceptRaSuffix,
+ content);
+ case ConntrackHelper:
+ return Write(kSysNetConntrackHelperPath, content);
+ default:
+ LOG(ERROR) << "Unknown SysNet value " << target;
+ return false;
+ }
+}
+
+bool System::Write(const std::string& path, const std::string& content) {
+ base::ScopedFD fd(open(path.c_str(), O_WRONLY | O_TRUNC | O_CLOEXEC));
+ if (!fd.is_valid()) {
+ PLOG(ERROR) << "Failed to open " << path;
+ return false;
+ }
+
+ if (write(fd.get(), content.c_str(), content.size()) != content.size()) {
+ PLOG(ERROR) << "Failed to write \"" << content << "\" to " << path;
+ return false;
+ }
+
+ return true;
+}
+
} // namespace patchpanel