Line data Source code
1 : #include <fcntl.h>
2 : #include <sys/stat.h>
3 : #include <unistd.h>
4 :
5 : #include <cerrno>
6 : #include <string>
7 :
8 : #include "envoy/network/socket.h"
9 :
10 : #include "source/common/api/os_sys_calls_impl.h"
11 : #include "source/common/network/address_impl.h"
12 :
13 : #if defined(__ANDROID_API__) && __ANDROID_API__ < 24
14 : #pragma clang diagnostic push
15 : #pragma clang diagnostic ignored "-Wold-style-cast"
16 : namespace android {
17 : #include "third_party/android/ifaddrs-android.h"
18 : } // namespace android
19 : #pragma clang diagnostic pop
20 : #endif
21 :
22 : namespace Envoy {
23 : namespace Api {
24 :
25 1317 : SysCallIntResult OsSysCallsImpl::bind(os_fd_t sockfd, const sockaddr* addr, socklen_t addrlen) {
26 1317 : const int rc = ::bind(sockfd, addr, addrlen);
27 1317 : return {rc, rc != -1 ? 0 : errno};
28 1317 : }
29 :
30 0 : SysCallIntResult OsSysCallsImpl::chmod(const std::string& path, mode_t mode) {
31 0 : const int rc = ::chmod(path.c_str(), mode);
32 0 : return {rc, rc != -1 ? 0 : errno};
33 0 : }
34 :
35 : SysCallIntResult OsSysCallsImpl::ioctl(os_fd_t sockfd, unsigned long request, void* argp,
36 0 : unsigned long, void*, unsigned long, unsigned long*) {
37 0 : const int rc = ::ioctl(sockfd, request, argp);
38 0 : return {rc, rc != -1 ? 0 : errno};
39 0 : }
40 :
41 9959 : SysCallIntResult OsSysCallsImpl::close(os_fd_t fd) {
42 9959 : const int rc = ::close(fd);
43 9959 : return {rc, rc != -1 ? 0 : errno};
44 9959 : }
45 :
46 478 : SysCallSizeResult OsSysCallsImpl::writev(os_fd_t fd, const iovec* iov, int num_iov) {
47 478 : const ssize_t rc = ::writev(fd, iov, num_iov);
48 478 : return {rc, rc != -1 ? 0 : errno};
49 478 : }
50 :
51 4396 : SysCallSizeResult OsSysCallsImpl::readv(os_fd_t fd, const iovec* iov, int num_iov) {
52 4396 : const ssize_t rc = ::readv(fd, iov, num_iov);
53 4396 : return {rc, rc != -1 ? 0 : errno};
54 4396 : }
55 :
56 : SysCallSizeResult OsSysCallsImpl::pwrite(os_fd_t fd, const void* buffer, size_t length,
57 0 : off_t offset) const {
58 0 : const ssize_t rc = ::pwrite(fd, buffer, length, offset);
59 0 : return {rc, rc != -1 ? 0 : errno};
60 0 : }
61 :
62 : SysCallSizeResult OsSysCallsImpl::pread(os_fd_t fd, void* buffer, size_t length,
63 0 : off_t offset) const {
64 0 : const ssize_t rc = ::pread(fd, buffer, length, offset);
65 0 : return {rc, rc != -1 ? 0 : errno};
66 0 : }
67 :
68 4383 : SysCallSizeResult OsSysCallsImpl::send(os_fd_t socket, void* buffer, size_t length, int flags) {
69 4383 : const ssize_t rc = ::send(socket, buffer, length, flags);
70 4383 : return {rc, rc != -1 ? 0 : errno};
71 4383 : }
72 :
73 2403 : SysCallSizeResult OsSysCallsImpl::recv(os_fd_t socket, void* buffer, size_t length, int flags) {
74 2403 : const ssize_t rc = ::recv(socket, buffer, length, flags);
75 2403 : return {rc, rc != -1 ? 0 : errno};
76 2403 : }
77 :
78 420 : SysCallSizeResult OsSysCallsImpl::recvmsg(os_fd_t sockfd, msghdr* msg, int flags) {
79 420 : const ssize_t rc = ::recvmsg(sockfd, msg, flags);
80 420 : return {rc, rc != -1 ? 0 : errno};
81 420 : }
82 :
83 : SysCallIntResult OsSysCallsImpl::recvmmsg(os_fd_t sockfd, struct mmsghdr* msgvec, unsigned int vlen,
84 84 : int flags, struct timespec* timeout) {
85 84 : #if ENVOY_MMSG_MORE
86 84 : const int rc = ::recvmmsg(sockfd, msgvec, vlen, flags, timeout);
87 84 : return {rc, errno};
88 : #else
89 : UNREFERENCED_PARAMETER(sockfd);
90 : UNREFERENCED_PARAMETER(msgvec);
91 : UNREFERENCED_PARAMETER(vlen);
92 : UNREFERENCED_PARAMETER(flags);
93 : UNREFERENCED_PARAMETER(timeout);
94 : return {false, EOPNOTSUPP};
95 : #endif
96 84 : }
97 :
98 0 : bool OsSysCallsImpl::supportsMmsg() const {
99 0 : #if ENVOY_MMSG_MORE
100 0 : return true;
101 : #else
102 : return false;
103 : #endif
104 0 : }
105 :
106 0 : bool OsSysCallsImpl::supportsUdpGro() const {
107 : #if !defined(__linux__)
108 : return false;
109 : #else
110 0 : static const bool is_supported = [] {
111 0 : int fd = ::socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
112 0 : if (fd < 0) {
113 0 : return false;
114 0 : }
115 0 : int val = 1;
116 0 : bool result = (0 == ::setsockopt(fd, IPPROTO_UDP, UDP_GRO, &val, sizeof(val)));
117 0 : ::close(fd);
118 0 : return result;
119 0 : }();
120 0 : return is_supported;
121 0 : #endif
122 0 : }
123 :
124 0 : bool OsSysCallsImpl::supportsUdpGso() const {
125 : #if !defined(__linux__)
126 : return false;
127 : #else
128 0 : static const bool is_supported = [] {
129 0 : int fd = ::socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
130 0 : if (fd < 0) {
131 0 : return false;
132 0 : }
133 0 : int optval;
134 0 : socklen_t optlen = sizeof(optval);
135 0 : bool result = (0 <= ::getsockopt(fd, IPPROTO_UDP, UDP_SEGMENT, &optval, &optlen));
136 0 : ::close(fd);
137 0 : return result;
138 0 : }();
139 0 : return is_supported;
140 0 : #endif
141 0 : }
142 :
143 0 : bool OsSysCallsImpl::supportsIpTransparent(Network::Address::IpVersion ip_version) const {
144 : #if !defined(__linux__)
145 : UNREFERENCED_PARAMETER(ip_version);
146 : return false;
147 : #else
148 : // The linux kernel supports IP_TRANSPARENT by following patch(starting from v2.6.28) :
149 : // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/ipv4/ip_sockglue.c?id=f5715aea4564f233767ea1d944b2637a5fd7cd2e
150 : //
151 : // The linux kernel supports IPV6_TRANSPARENT by following patch(starting from v2.6.37) :
152 : // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/ipv6/ipv6_sockglue.c?id=6c46862280c5f55eda7750391bc65cd7e08c7535
153 : //
154 : // So, almost recent linux kernel supports both IP_TRANSPARENT and IPV6_TRANSPARENT options.
155 : // But there are also has ipv4 only or ipv6 only scenarios.
156 : //
157 : // And these socket options need CAP_NET_ADMIN capability to be applied.
158 : // The CAP_NET_ADMIN capability should be applied by root user before call this function.
159 :
160 0 : static constexpr auto transparent_supported = [](int family) {
161 0 : auto opt_tp = family == AF_INET ? ENVOY_SOCKET_IP_TRANSPARENT : ENVOY_SOCKET_IPV6_TRANSPARENT;
162 0 : int fd = ::socket(family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
163 0 : if (fd < 0) {
164 0 : return false;
165 0 : }
166 0 : int val = 1;
167 0 : bool result = (0 == ::setsockopt(fd, opt_tp.level(), opt_tp.option(), &val, sizeof(val)));
168 0 : ::close(fd);
169 0 : return result;
170 0 : };
171 : // Check ipv4 case
172 0 : static const bool ipv4_is_supported = transparent_supported(AF_INET);
173 : // Check ipv6 case
174 0 : static const bool ipv6_is_supported = transparent_supported(AF_INET6);
175 0 : return ip_version == Network::Address::IpVersion::v4 ? ipv4_is_supported : ipv6_is_supported;
176 0 : #endif
177 0 : }
178 :
179 0 : bool OsSysCallsImpl::supportsMptcp() const {
180 : #if !defined(__linux__)
181 : return false;
182 : #else
183 0 : int fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP);
184 0 : if (fd < 0) {
185 0 : return false;
186 0 : }
187 :
188 0 : ::close(fd);
189 0 : return true;
190 0 : #endif
191 0 : }
192 :
193 0 : SysCallIntResult OsSysCallsImpl::ftruncate(int fd, off_t length) {
194 0 : const int rc = ::ftruncate(fd, length);
195 0 : return {rc, rc != -1 ? 0 : errno};
196 0 : }
197 :
198 : SysCallPtrResult OsSysCallsImpl::mmap(void* addr, size_t length, int prot, int flags, int fd,
199 0 : off_t offset) {
200 0 : void* rc = ::mmap(addr, length, prot, flags, fd, offset);
201 0 : return {rc, rc != MAP_FAILED ? 0 : errno};
202 0 : }
203 :
204 111 : SysCallIntResult OsSysCallsImpl::stat(const char* pathname, struct stat* buf) {
205 111 : const int rc = ::stat(pathname, buf);
206 111 : return {rc, rc != -1 ? 0 : errno};
207 111 : }
208 :
209 0 : SysCallIntResult OsSysCallsImpl::fstat(os_fd_t fd, struct stat* buf) {
210 0 : const int rc = ::fstat(fd, buf);
211 0 : return {rc, rc != -1 ? 0 : errno};
212 0 : }
213 :
214 : SysCallIntResult OsSysCallsImpl::setsockopt(os_fd_t sockfd, int level, int optname,
215 3958 : const void* optval, socklen_t optlen) {
216 3958 : const int rc = ::setsockopt(sockfd, level, optname, optval, optlen);
217 3958 : return {rc, rc != -1 ? 0 : errno};
218 3958 : }
219 :
220 : SysCallIntResult OsSysCallsImpl::getsockopt(os_fd_t sockfd, int level, int optname, void* optval,
221 1178 : socklen_t* optlen) {
222 1178 : const int rc = ::getsockopt(sockfd, level, optname, optval, optlen);
223 1178 : return {rc, rc != -1 ? 0 : errno};
224 1178 : }
225 :
226 5206 : SysCallSocketResult OsSysCallsImpl::socket(int domain, int type, int protocol) {
227 5206 : const os_fd_t rc = ::socket(domain, type, protocol);
228 5206 : return {rc, SOCKET_VALID(rc) ? 0 : errno};
229 5206 : }
230 :
231 668 : SysCallSizeResult OsSysCallsImpl::sendmsg(os_fd_t fd, const msghdr* message, int flags) {
232 668 : const int rc = ::sendmsg(fd, message, flags);
233 668 : return {rc, rc != -1 ? 0 : errno};
234 668 : }
235 :
236 2125 : SysCallIntResult OsSysCallsImpl::getsockname(os_fd_t sockfd, sockaddr* addr, socklen_t* addrlen) {
237 2125 : const int rc = ::getsockname(sockfd, addr, addrlen);
238 2125 : return {rc, rc != -1 ? 0 : errno};
239 2125 : }
240 :
241 0 : SysCallIntResult OsSysCallsImpl::gethostname(char* name, size_t length) {
242 0 : const int rc = ::gethostname(name, length);
243 0 : return {rc, rc != -1 ? 0 : errno};
244 0 : }
245 :
246 0 : SysCallIntResult OsSysCallsImpl::getpeername(os_fd_t sockfd, sockaddr* name, socklen_t* namelen) {
247 0 : const int rc = ::getpeername(sockfd, name, namelen);
248 0 : return {rc, rc != -1 ? 0 : errno};
249 0 : }
250 :
251 91 : SysCallIntResult OsSysCallsImpl::setsocketblocking(os_fd_t sockfd, bool blocking) {
252 91 : const int flags = ::fcntl(sockfd, F_GETFL, 0);
253 91 : int rc;
254 91 : if (flags == -1) {
255 0 : return {-1, errno};
256 0 : }
257 91 : if (blocking) {
258 91 : rc = ::fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK);
259 91 : } else {
260 0 : rc = ::fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
261 0 : }
262 91 : return {rc, rc != -1 ? 0 : errno};
263 91 : }
264 :
265 1328 : SysCallIntResult OsSysCallsImpl::connect(os_fd_t sockfd, const sockaddr* addr, socklen_t addrlen) {
266 1328 : const int rc = ::connect(sockfd, addr, addrlen);
267 1328 : return {rc, rc != -1 ? 0 : errno};
268 1328 : }
269 :
270 0 : SysCallIntResult OsSysCallsImpl::open(const char* pathname, int flags) const {
271 0 : const int rc = ::open(pathname, flags);
272 0 : return {rc, rc != -1 ? 0 : errno};
273 0 : }
274 :
275 0 : SysCallIntResult OsSysCallsImpl::open(const char* pathname, int flags, mode_t mode) const {
276 0 : const int rc = ::open(pathname, flags, mode);
277 0 : return {rc, rc != -1 ? 0 : errno};
278 0 : }
279 :
280 0 : SysCallIntResult OsSysCallsImpl::unlink(const char* pathname) const {
281 0 : const int rc = ::unlink(pathname);
282 0 : return {rc, rc != -1 ? 0 : errno};
283 0 : }
284 :
285 : SysCallIntResult OsSysCallsImpl::linkat(os_fd_t olddirfd, const char* oldpath, os_fd_t newdirfd,
286 0 : const char* newpath, int flags) const {
287 0 : const int rc = ::linkat(olddirfd, oldpath, newdirfd, newpath, flags);
288 0 : return {rc, rc != -1 ? 0 : errno};
289 0 : }
290 :
291 0 : SysCallIntResult OsSysCallsImpl::mkstemp(char* tmplate) const {
292 0 : const int rc = ::mkstemp(tmplate);
293 0 : return {rc, rc != -1 ? 0 : errno};
294 0 : }
295 :
296 2 : bool OsSysCallsImpl::supportsAllPosixFileOperations() const { return true; }
297 :
298 252 : SysCallIntResult OsSysCallsImpl::shutdown(os_fd_t sockfd, int how) {
299 252 : const int rc = ::shutdown(sockfd, how);
300 252 : return {rc, rc != -1 ? 0 : errno};
301 252 : }
302 :
303 3224 : SysCallIntResult OsSysCallsImpl::socketpair(int domain, int type, int protocol, os_fd_t sv[2]) {
304 3224 : const int rc = ::socketpair(domain, type, protocol, sv);
305 3224 : return {rc, rc != -1 ? 0 : errno};
306 3224 : }
307 :
308 607 : SysCallIntResult OsSysCallsImpl::listen(os_fd_t sockfd, int backlog) {
309 607 : const int rc = ::listen(sockfd, backlog);
310 607 : return {rc, rc != -1 ? 0 : errno};
311 607 : }
312 :
313 0 : SysCallSizeResult OsSysCallsImpl::write(os_fd_t sockfd, const void* buffer, size_t length) {
314 0 : const ssize_t rc = ::write(sockfd, buffer, length);
315 0 : return {rc, rc != -1 ? 0 : errno};
316 0 : }
317 :
318 18 : SysCallSocketResult OsSysCallsImpl::duplicate(os_fd_t oldfd) {
319 18 : const int rc = ::dup(oldfd);
320 18 : return {rc, rc != -1 ? 0 : errno};
321 18 : }
322 :
323 2612 : SysCallSocketResult OsSysCallsImpl::accept(os_fd_t sockfd, sockaddr* addr, socklen_t* addrlen) {
324 2612 : os_fd_t rc;
325 :
326 2612 : #if defined(__linux__)
327 2612 : rc = ::accept4(sockfd, addr, addrlen, SOCK_NONBLOCK);
328 : // If failed with EINVAL try without flags
329 2612 : if (rc >= 0 || errno != EINVAL) {
330 2612 : return {rc, rc != -1 ? 0 : errno};
331 2612 : }
332 0 : #endif
333 :
334 0 : rc = ::accept(sockfd, addr, addrlen);
335 0 : if (rc >= 0) {
336 0 : setsocketblocking(rc, false);
337 0 : }
338 :
339 0 : return {rc, rc != -1 ? 0 : errno};
340 2612 : }
341 :
342 : SysCallBoolResult OsSysCallsImpl::socketTcpInfo([[maybe_unused]] os_fd_t sockfd,
343 1315 : [[maybe_unused]] EnvoyTcpInfo* tcp_info) {
344 1315 : #ifdef TCP_INFO
345 1315 : struct tcp_info unix_tcp_info;
346 1315 : socklen_t len = sizeof(unix_tcp_info);
347 1315 : auto result = ::getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &unix_tcp_info, &len);
348 1315 : if (!SOCKET_FAILURE(result)) {
349 1315 : tcp_info->tcpi_rtt = std::chrono::microseconds(unix_tcp_info.tcpi_rtt);
350 :
351 1315 : const uint64_t mss = (unix_tcp_info.tcpi_snd_mss > 0) ? unix_tcp_info.tcpi_snd_mss : 1460;
352 : // Convert packets to bytes.
353 1315 : tcp_info->tcpi_snd_cwnd = unix_tcp_info.tcpi_snd_cwnd * mss;
354 1315 : }
355 1315 : return {!SOCKET_FAILURE(result), !SOCKET_FAILURE(result) ? 0 : errno};
356 0 : #endif
357 :
358 0 : return {false, EOPNOTSUPP};
359 1315 : }
360 :
361 98 : bool OsSysCallsImpl::supportsGetifaddrs() const { return true; }
362 :
363 98 : SysCallIntResult OsSysCallsImpl::getifaddrs([[maybe_unused]] InterfaceAddressVector& interfaces) {
364 : #if defined(__ANDROID_API__) && __ANDROID_API__ < 24
365 : struct android::ifaddrs* ifaddr;
366 : struct android::ifaddrs* ifa;
367 :
368 : const int rc = android::getifaddrs(&ifaddr);
369 : if (rc == -1) {
370 : return {rc, errno};
371 : }
372 :
373 : for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
374 : if (ifa->ifa_addr == nullptr) {
375 : continue;
376 : }
377 :
378 : if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) {
379 : const sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
380 : size_t ss_len =
381 : ifa->ifa_addr->sa_family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
382 : StatusOr<Network::Address::InstanceConstSharedPtr> address =
383 : Network::Address::addressFromSockAddr(*ss, ss_len, ifa->ifa_addr->sa_family == AF_INET6);
384 : if (address.ok()) {
385 : interfaces.emplace_back(ifa->ifa_name, ifa->ifa_flags, *address);
386 : }
387 : }
388 : }
389 :
390 : if (ifaddr) {
391 : android::freeifaddrs(ifaddr);
392 : }
393 : return {rc, 0};
394 : #else
395 98 : struct ifaddrs* ifaddr;
396 98 : struct ifaddrs* ifa;
397 :
398 98 : const int rc = ::getifaddrs(&ifaddr);
399 98 : if (rc == -1) {
400 0 : return {rc, errno};
401 0 : }
402 :
403 686 : for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
404 588 : if (ifa->ifa_addr == nullptr) {
405 0 : continue;
406 0 : }
407 :
408 588 : if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) {
409 392 : const sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
410 392 : size_t ss_len =
411 392 : ifa->ifa_addr->sa_family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
412 392 : StatusOr<Network::Address::InstanceConstSharedPtr> address =
413 392 : Network::Address::addressFromSockAddr(*ss, ss_len, ifa->ifa_addr->sa_family == AF_INET6);
414 392 : if (address.ok()) {
415 392 : interfaces.emplace_back(ifa->ifa_name, ifa->ifa_flags, *address);
416 392 : }
417 392 : }
418 588 : }
419 :
420 98 : if (ifaddr) {
421 98 : ::freeifaddrs(ifaddr);
422 98 : }
423 :
424 98 : return {rc, 0};
425 98 : #endif
426 98 : }
427 :
428 : SysCallIntResult OsSysCallsImpl::getaddrinfo(const char* node, const char* service,
429 1029 : const addrinfo* hints, addrinfo** res) {
430 1029 : const int rc = ::getaddrinfo(node, service, hints, res);
431 1029 : return {rc, errno};
432 1029 : }
433 :
434 0 : void OsSysCallsImpl::freeaddrinfo(addrinfo* res) { ::freeaddrinfo(res); }
435 :
436 : } // namespace Api
437 : } // namespace Envoy
|