1 // Copyright 2023 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/testing.h"
16
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <poll.h>
20 #include <sys/eventfd.h>
21 #include <sys/socket.h>
22
23 #include <cstddef>
24 #include <cstdint>
25 #include <memory>
26 #include <thread>
27 #include <utility>
28
29 #include "absl/base/macros.h"
30 #include "absl/log/check.h"
31 #include "absl/memory/memory.h"
32 #include "absl/status/status.h"
33 #include "absl/strings/string_view.h"
34 #include "sandboxed_api/util/fileops.h"
35 #include "sandboxed_api/util/status_macros.h"
36
37 namespace sandbox2 {
38 namespace {
39
40 using sapi::file_util::fileops::FDCloser;
41
CreateServerSocket(int port,bool ipv6=true)42 absl::StatusOr<FDCloser> CreateServerSocket(int port, bool ipv6 = true) {
43 // Listen to localhost only
44 sockaddr_in6 addr6;
45 sockaddr_in addr4;
46 addr6.sin6_family = AF_INET6;
47 addr4.sin_family = AF_INET;
48 addr4.sin_port = addr6.sin6_port = htons(port);
49 PCHECK(inet_pton(AF_INET, "127.0.0.1", &addr4.sin_addr.s_addr) == 1);
50 PCHECK(inet_pton(AF_INET6, "::1", &addr6.sin6_addr.s6_addr) == 1);
51 sockaddr* addr = ipv6 ? reinterpret_cast<sockaddr*>(&addr6)
52 : reinterpret_cast<sockaddr*>(&addr4);
53 size_t addr_size = ipv6 ? sizeof(addr6) : sizeof(addr4);
54 sapi::file_util::fileops::FDCloser s(
55 socket(addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0));
56 if (s.get() < 0) {
57 return absl::InternalError("socket() failed");
58 }
59 int enable = 1;
60 if (setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) <
61 0) {
62 return absl::InternalError("setsockopt() failed");
63 }
64 if (bind(s.get(), addr, addr_size) < 0) {
65 return absl::InternalError("bind() failed");
66 }
67 if (listen(s.get(), 1) < 0) {
68 return absl::InternalError("listen() failed");
69 }
70 return s;
71 }
72
73 } // namespace
74
75 absl::StatusOr<std::unique_ptr<NetworkProxyTestServer>>
Start(bool ipv6)76 NetworkProxyTestServer::Start(bool ipv6) {
77 static int port = 8085;
78 FDCloser event_fd(eventfd(0, 0));
79 if (event_fd.get() < 0) {
80 return absl::InternalError("eventfd() failed");
81 }
82 SAPI_ASSIGN_OR_RETURN(FDCloser server_socket, CreateServerSocket(port, ipv6));
83 auto server = absl::WrapUnique(new NetworkProxyTestServer(
84 port, std::move(server_socket), std::move(event_fd)));
85 server->Spawn();
86 return server;
87 }
88
Stop()89 void NetworkProxyTestServer::Stop() {
90 if (event_fd_.get() < 0) {
91 return;
92 }
93 uint64_t value = 1;
94 PCHECK(write(event_fd_.get(), &value, sizeof(value)) == sizeof(value));
95 thread_.join();
96 event_fd_.Close();
97 server_socket_.Close();
98 }
99
Run()100 void NetworkProxyTestServer::Run() {
101 struct pollfd pfds[] = {
102 {.fd = server_socket_.get(), .events = POLLIN},
103 {.fd = event_fd_.get(), .events = POLLIN},
104 };
105 do {
106 PCHECK(poll(pfds, ABSL_ARRAYSIZE(pfds), -1) > 0);
107 if (pfds[1].revents & POLLIN) {
108 return;
109 }
110 } while (!(pfds[0].revents & POLLIN));
111 FDCloser client(accept(server_socket_.get(), 0, 0));
112 PCHECK(client.get() >= 0);
113 constexpr absl::string_view kMsg = "Hello World\n";
114 PCHECK(write(client.get(), kMsg.data(), kMsg.size()) == kMsg.size());
115 }
116
Spawn()117 void NetworkProxyTestServer::Spawn() {
118 thread_ = std::thread([this] { Run(); });
119 }
120
121 } // namespace sandbox2
122