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 <pthread.h>
19 #include <signal.h>
20 #include <sys/socket.h>
21 #include <sys/types.h>
22
23 #include <atomic>
24 #include <cerrno>
25 #include <cstdint>
26 #include <memory>
27 #include <string>
28 #include <utility>
29 #include <vector>
30
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,pthread_t monitor_thread_id)42 NetworkProxyServer::NetworkProxyServer(int fd, AllowedHosts* allowed_hosts,
43 pthread_t monitor_thread_id)
44 : violation_occurred_(false),
45 comms_(std::make_unique<Comms>(fd)),
46 fatal_error_(false),
47 monitor_thread_id_(monitor_thread_id),
48 allowed_hosts_(allowed_hosts) {}
49
ProcessConnectRequest()50 void NetworkProxyServer::ProcessConnectRequest() {
51 std::vector<uint8_t> addr;
52 if (!comms_->RecvBytes(&addr)) {
53 fatal_error_ = true;
54 return;
55 }
56
57 const struct sockaddr* saddr = reinterpret_cast<const sockaddr*>(addr.data());
58
59 // Only IPv4 TCP and IPv6 TCP are supported.
60 if (!((addr.size() == sizeof(sockaddr_in) && saddr->sa_family == AF_INET) ||
61 (addr.size() == sizeof(sockaddr_in6) &&
62 saddr->sa_family == AF_INET6))) {
63 SendError(EINVAL);
64 return;
65 }
66
67 if (!allowed_hosts_->IsHostAllowed(saddr)) {
68 NotifyViolation(saddr);
69 return;
70 }
71
72 int new_socket = socket(saddr->sa_family, SOCK_STREAM, 0);
73 if (new_socket < 0) {
74 SendError(errno);
75 return;
76 }
77
78 file_util::fileops::FDCloser new_socket_closer(new_socket);
79
80 int result = connect(
81 new_socket, reinterpret_cast<const sockaddr*>(addr.data()), addr.size());
82
83 if (result < 0) {
84 SendError(errno);
85 return;
86 }
87
88 NotifySuccess();
89 if (!fatal_error_ && !comms_->SendFD(new_socket)) {
90 fatal_error_ = true;
91 return;
92 }
93 }
94
Run()95 void NetworkProxyServer::Run() {
96 while (!fatal_error_ &&
97 !violation_occurred_.load(std::memory_order_relaxed)) {
98 ProcessConnectRequest();
99 }
100 LOG(INFO)
101 << "Clean shutdown or error occurred, shutting down NetworkProxyServer";
102 }
103
SendError(int saved_errno)104 void NetworkProxyServer::SendError(int saved_errno) {
105 if (!comms_->SendInt32(saved_errno)) {
106 fatal_error_ = true;
107 }
108 }
109
NotifySuccess()110 void NetworkProxyServer::NotifySuccess() {
111 if (!comms_->SendInt32(0)) {
112 fatal_error_ = true;
113 }
114 }
115
NotifyViolation(const struct sockaddr * saddr)116 void NetworkProxyServer::NotifyViolation(const struct sockaddr* saddr) {
117 if (absl::StatusOr<std::string> result = AddrToString(saddr); result.ok()) {
118 violation_msg_ = std::move(result).value();
119 } else {
120 violation_msg_ = std::string(result.status().message());
121 }
122 violation_occurred_.store(true, std::memory_order_release);
123 pthread_kill(monitor_thread_id_, SIGCHLD);
124 }
125
126 } // namespace sandbox2
127