gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/connect_external.cc (about) 1 // Copyright 2019 The gVisor Authors. 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 // http://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 <errno.h> 16 #include <stdlib.h> 17 #include <sys/socket.h> 18 #include <sys/un.h> 19 20 #include <cstring> 21 #include <string> 22 #include <tuple> 23 24 #include "gmock/gmock.h" 25 #include "gtest/gtest.h" 26 #include "test/util/file_descriptor.h" 27 #include "test/util/fs_util.h" 28 #include "test/util/socket_util.h" 29 #include "test/util/test_util.h" 30 31 // This file contains tests specific to connecting to host UDS managed outside 32 // the sandbox / test. 33 // 34 // A set of ultity sockets will be created externally in $TEST_UDS_TREE and 35 // $TEST_UDS_ATTACH_TREE for these tests to interact with. 36 37 namespace gvisor { 38 namespace testing { 39 40 namespace { 41 42 struct ProtocolSocket { 43 int protocol; 44 std::string name; 45 }; 46 47 // Parameter is (socket root dir, ProtocolSocket). 48 using GoferStreamSeqpacketTest = 49 ::testing::TestWithParam<std::tuple<std::string, ProtocolSocket>>; 50 51 // Connect to a socket and verify that write/read work. 52 // 53 // An "echo" socket doesn't work for dgram sockets because our socket is 54 // unnamed. The server thus has no way to reply to us. 55 TEST_P(GoferStreamSeqpacketTest, Echo) { 56 std::string env; 57 ProtocolSocket proto; 58 std::tie(env, proto) = GetParam(); 59 60 char* val = getenv(env.c_str()); 61 ASSERT_NE(val, nullptr); 62 std::string root(val); 63 64 FileDescriptor sock = 65 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, proto.protocol, 0)); 66 67 std::string socket_path = JoinPath(root, proto.name, "echo"); 68 69 struct sockaddr_un addr = {}; 70 addr.sun_family = AF_UNIX; 71 memcpy(addr.sun_path, socket_path.c_str(), socket_path.length()); 72 73 ASSERT_THAT(connect(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), 74 sizeof(addr)), 75 SyscallSucceeds()); 76 77 constexpr int kBufferSize = 64; 78 char send_buffer[kBufferSize]; 79 memset(send_buffer, 'a', sizeof(send_buffer)); 80 81 ASSERT_THAT(WriteFd(sock.get(), send_buffer, sizeof(send_buffer)), 82 SyscallSucceedsWithValue(sizeof(send_buffer))); 83 84 char recv_buffer[kBufferSize]; 85 ASSERT_THAT(ReadFd(sock.get(), recv_buffer, sizeof(recv_buffer)), 86 SyscallSucceedsWithValue(sizeof(recv_buffer))); 87 ASSERT_EQ(0, memcmp(send_buffer, recv_buffer, sizeof(send_buffer))); 88 } 89 90 // It is not possible to connect to a bound but non-listening socket. 91 TEST_P(GoferStreamSeqpacketTest, NonListening) { 92 std::string env; 93 ProtocolSocket proto; 94 std::tie(env, proto) = GetParam(); 95 96 char* val = getenv(env.c_str()); 97 ASSERT_NE(val, nullptr); 98 std::string root(val); 99 100 FileDescriptor sock = 101 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, proto.protocol, 0)); 102 103 std::string socket_path = JoinPath(root, proto.name, "nonlistening"); 104 105 struct sockaddr_un addr = {}; 106 addr.sun_family = AF_UNIX; 107 memcpy(addr.sun_path, socket_path.c_str(), socket_path.length()); 108 109 ASSERT_THAT(connect(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), 110 sizeof(addr)), 111 SyscallFailsWithErrno(ECONNREFUSED)); 112 } 113 114 INSTANTIATE_TEST_SUITE_P( 115 StreamSeqpacket, GoferStreamSeqpacketTest, 116 ::testing::Combine( 117 // Test access via standard path and attach point. 118 ::testing::Values("TEST_UDS_TREE", "TEST_UDS_ATTACH_TREE"), 119 ::testing::Values(ProtocolSocket{SOCK_STREAM, "stream"}, 120 ProtocolSocket{SOCK_SEQPACKET, "seqpacket"}))); 121 122 // Parameter is socket root dir. 123 using GoferDgramTest = ::testing::TestWithParam<std::string>; 124 125 // Connect to a socket and verify that write works. 126 // 127 // An "echo" socket doesn't work for dgram sockets because our socket is 128 // unnamed. The server thus has no way to reply to us. 129 TEST_P(GoferDgramTest, Null) { 130 std::string env = GetParam(); 131 char* val = getenv(env.c_str()); 132 ASSERT_NE(val, nullptr); 133 std::string root(val); 134 135 FileDescriptor sock = 136 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, SOCK_DGRAM, 0)); 137 138 std::string socket_path = JoinPath(root, "dgram/null"); 139 140 struct sockaddr_un addr = {}; 141 addr.sun_family = AF_UNIX; 142 memcpy(addr.sun_path, socket_path.c_str(), socket_path.length()); 143 144 ASSERT_THAT(connect(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), 145 sizeof(addr)), 146 SyscallSucceeds()); 147 148 constexpr int kBufferSize = 64; 149 char send_buffer[kBufferSize]; 150 memset(send_buffer, 'a', sizeof(send_buffer)); 151 152 ASSERT_THAT(WriteFd(sock.get(), send_buffer, sizeof(send_buffer)), 153 SyscallSucceedsWithValue(sizeof(send_buffer))); 154 } 155 156 INSTANTIATE_TEST_SUITE_P(Dgram, GoferDgramTest, 157 // Test access via standard path and attach point. 158 ::testing::Values("TEST_UDS_TREE", 159 "TEST_UDS_ATTACH_TREE")); 160 161 } // namespace 162 163 } // namespace testing 164 } // namespace gvisor