// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "sandboxed_api/sandbox2/network_proxy/server.h" #include #include #include #include #include #include #include #include #include #include #include "absl/memory/memory.h" #include "absl/status/statusor.h" #include "sandboxed_api/util/fileops.h" namespace sandbox2 { namespace file_util = ::sapi::file_util; NetworkProxyServer::NetworkProxyServer(int fd, AllowedHosts* allowed_hosts, pthread_t monitor_thread_id) : violation_occurred_(false), comms_{absl::make_unique(fd)}, fatal_error_(false), monitor_thread_id_(monitor_thread_id), allowed_hosts_(allowed_hosts) {} void NetworkProxyServer::ProcessConnectRequest() { std::vector addr; if (!comms_->RecvBytes(&addr)) { fatal_error_ = true; return; } const struct sockaddr* saddr = reinterpret_cast(addr.data()); // Only IPv4 TCP and IPv6 TCP are supported. if (!((addr.size() == sizeof(sockaddr_in) && saddr->sa_family == AF_INET) || (addr.size() == sizeof(sockaddr_in6) && saddr->sa_family == AF_INET6))) { SendError(EINVAL); return; } if (!allowed_hosts_->IsHostAllowed(saddr)) { NotifyViolation(saddr); return; } int new_socket = socket(saddr->sa_family, SOCK_STREAM, 0); if (new_socket < 0) { SendError(errno); return; } file_util::fileops::FDCloser new_socket_closer(new_socket); int result = connect( new_socket, reinterpret_cast(addr.data()), addr.size()); if (result == 0) { NotifySuccess(); if (!fatal_error_) { if (!comms_->SendFD(new_socket)) { fatal_error_ = true; return; } } } } void NetworkProxyServer::Run() { while (!fatal_error_ && !violation_occurred_.load(std::memory_order_relaxed)) { ProcessConnectRequest(); } LOG(INFO) << "Clean shutdown or error occurred, shutting down NetworkProxyServer"; } void NetworkProxyServer::SendError(int saved_errno) { if (!comms_->SendInt32(saved_errno)) { fatal_error_ = true; } } void NetworkProxyServer::NotifySuccess() { if (!comms_->SendInt32(0)) { fatal_error_ = true; } } void NetworkProxyServer::NotifyViolation(const struct sockaddr* saddr) { if (absl::StatusOr result = AddrToString(saddr); result.ok()) { violation_msg_ = std::move(result).value(); } else { violation_msg_ = std::string(result.status().message()); } violation_occurred_.store(true, std::memory_order_release); pthread_kill(monitor_thread_id_, SIGCHLD); } } // namespace sandbox2