1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "sandboxed_api/sandbox2/network_proxy/server.h"
16
17 #include <netinet/in.h>
18 #include <signal.h>
19 #include <sys/socket.h>
20 #include <sys/types.h>
21
22 #include <atomic>
23 #include <cerrno>
24 #include <cstdint>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29
30 #include "absl/functional/any_invocable.h"
31 #include "absl/log/log.h"
32 #include "absl/status/status.h"
33 #include "absl/status/statusor.h"
34 #include "sandboxed_api/sandbox2/comms.h"
35 #include "sandboxed_api/sandbox2/network_proxy/filtering.h"
36 #include "sandboxed_api/util/fileops.h"
37
38 namespace sandbox2 {
39
40 namespace file_util = ::sapi::file_util;
41
NetworkProxyServer(int fd,AllowedHosts * allowed_hosts,absl::AnyInvocable<void ()> notify_violation_fn)42 NetworkProxyServer::NetworkProxyServer(
43 int fd, AllowedHosts* allowed_hosts,
44 absl::AnyInvocable<void()> notify_violation_fn)
45 : violation_occurred_(false),
46 comms_(std::make_unique<Comms>(fd)),
47 fatal_error_(false),
48 notify_violation_fn_(std::move(notify_violation_fn)),
49 allowed_hosts_(allowed_hosts) {}
50
ProcessConnectRequest()51 void NetworkProxyServer::ProcessConnectRequest() {
52 std::vector<uint8_t> addr;
53 if (!comms_->RecvBytes(&addr)) {
54 fatal_error_ = true;
55 return;
56 }
57
58 const struct sockaddr* saddr = reinterpret_cast<const sockaddr*>(addr.data());
59
60 // Only IPv4 TCP and IPv6 TCP are supported.
61 if (!((addr.size() == sizeof(sockaddr_in) && saddr->sa_family == AF_INET) ||
62 (addr.size() == sizeof(sockaddr_in6) &&
63 saddr->sa_family == AF_INET6))) {
64 SendError(EINVAL);
65 return;
66 }
67
68 if (!allowed_hosts_->IsHostAllowed(saddr)) {
69 NotifyViolation(saddr);
70 return;
71 }
72
73 int new_socket = socket(saddr->sa_family, SOCK_STREAM, 0);
74 if (new_socket < 0) {
75 SendError(errno);
76 return;
77 }
78
79 file_util::fileops::FDCloser new_socket_closer(new_socket);
80
81 int result = connect(
82 new_socket, reinterpret_cast<const sockaddr*>(addr.data()), addr.size());
83
84 if (result < 0) {
85 SendError(errno);
86 return;
87 }
88
89 NotifySuccess();
90 if (!fatal_error_ && !comms_->SendFD(new_socket)) {
91 fatal_error_ = true;
92 return;
93 }
94 }
95
Run()96 void NetworkProxyServer::Run() {
97 while (!fatal_error_ &&
98 !violation_occurred_.load(std::memory_order_relaxed)) {
99 ProcessConnectRequest();
100 }
101 LOG(INFO)
102 << "Clean shutdown or error occurred, shutting down NetworkProxyServer";
103 }
104
SendError(int saved_errno)105 void NetworkProxyServer::SendError(int saved_errno) {
106 if (!comms_->SendInt32(saved_errno)) {
107 fatal_error_ = true;
108 }
109 }
110
NotifySuccess()111 void NetworkProxyServer::NotifySuccess() {
112 if (!comms_->SendInt32(0)) {
113 fatal_error_ = true;
114 }
115 }
116
NotifyViolation(const struct sockaddr * saddr)117 void NetworkProxyServer::NotifyViolation(const struct sockaddr* saddr) {
118 if (absl::StatusOr<std::string> result = AddrToString(saddr); result.ok()) {
119 violation_msg_ = std::move(result).value();
120 } else {
121 violation_msg_ = std::string(result.status().message());
122 }
123 violation_occurred_.store(true, std::memory_order_release);
124 notify_violation_fn_();
125 }
126
127 } // namespace sandbox2
128