sockcreator_tests.cc 14.1 KB
Newer Older
1
// Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
Michal Vaner's avatar
Michal Vaner committed
2
//
3
4
5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
Michal Vaner's avatar
Michal Vaner committed
6

7
8
#include <config.h>

Michal Vaner's avatar
Michal Vaner committed
9
10
#include "../sockcreator.h"

Michal Vaner's avatar
Michal Vaner committed
11
12
13
#include <util/unittests/fork.h>
#include <util/io/fd.h>

14
#include <boost/lexical_cast.hpp>
Michal Vaner's avatar
Michal Vaner committed
15
16
17
18
#include <gtest/gtest.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
19
#include <arpa/inet.h>
Michal Vaner's avatar
Michal Vaner committed
20
#include <unistd.h>
21
22

#include <iostream>
Michal Vaner's avatar
Michal Vaner committed
23
24
25
26
#include <cstring>
#include <cerrno>

using namespace isc::socket_creator;
Michal Vaner's avatar
Michal Vaner committed
27
28
using namespace isc::util::unittests;
using namespace isc::util::io;
Michal Vaner's avatar
Michal Vaner committed
29

30
31
32
33
34
// The tests check both TCP and UDP sockets on IPv4 and IPv6.
//
// Essentially we need to check all four combinations of TCP/UDP and IPv4/IPv6.
// The different address families (IPv4/IPv6) require different structures to
// hold the address information, and so some common code is in the form of
Josh Soref's avatar
Josh Soref committed
35
// templates (or overloads), parameterized on the structure type.
36
37
38
39
40
//
// The protocol is determined by an integer (SOCK_STREAM or SOCK_DGRAM) so
// cannot be templated in the same way.  Relevant check functions are
// selected manually.

Michal Vaner's avatar
Michal Vaner committed
41
42
namespace {

43
// Set IP-version-specific fields.
Michal Vaner's avatar
Michal Vaner committed
44

45
46
47
48
49
50
51
52
53
54
55
56
void
setAddressFamilyFields(sockaddr_in* address) {
    address->sin_family = AF_INET;
    address->sin_addr.s_addr = INADDR_ANY;
}

void
setAddressFamilyFields(sockaddr_in6* address) {
    address->sin6_family = AF_INET6;
    address->sin6_addr = in6addr_loopback;
}

Andrei Pavel's avatar
Andrei Pavel committed
57
// Socket has been opened, perform a check on it.  The sole argument is the
58
59
// socket descriptor.  The TCP check is the same regardless of the address
// family.  The UDP check requires that the socket address be obtained so
Josh Soref's avatar
Josh Soref committed
60
// is parameterized on the type of structure required to hold the address.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

void
tcpCheck(const int socknum) {
    // Sufficient to be able to listen on the socket.
    EXPECT_EQ(0, listen(socknum, 1));
}

template <typename ADDRTYPE>
void
udpCheck(const int socknum) {
    // UDP testing is more complicated than TCP: send a packet to ourselves and
    // see if it arrives.

    // Get details of the socket so that we can use it as the target of the
    // sendto().
    ADDRTYPE addr;
    memset(&addr, 0, sizeof(addr));
    sockaddr* addr_ptr = reinterpret_cast<sockaddr*>(&addr);
    socklen_t len = sizeof(addr);
    ASSERT_EQ(0, getsockname(socknum, addr_ptr, &len));

    // Send the packet to ourselves and check we receive it.
    ASSERT_EQ(5, sendto(socknum, "test", 5, 0, addr_ptr, sizeof(addr))) <<
        "Send failed with error " << strerror(errno) << " on socket " <<
        socknum;
    char buffer[5];
    ASSERT_EQ(5, recv(socknum, buffer, 5, 0)) <<
        "Recv failed with error " << strerror(errno) << " on socket " <<
        socknum;
    EXPECT_STREQ("test", buffer);
}

// The check function (tcpCheck/udpCheck) is passed as a parameter to the test
94
// code, so provide a convenient typedef.
95
96
typedef void (*socket_check_t)(const int);

Andrei Pavel's avatar
Andrei Pavel committed
97
// Address-family-specific socket checks.
98
99
100
101
102
//
// The first argument is used to select the overloaded check function.
// The other argument is the socket descriptor number.

// IPv4 check
103
void addressFamilySpecificCheck(const sockaddr_in*, const int, const int) {
104
}
105
106

// IPv6 check
107
108
109
void addressFamilySpecificCheck(const sockaddr_in6*, const int socknum,
                                const int socket_type)
{
110
111
    int options;
    socklen_t len = sizeof(options);
112
113
    EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_V6ONLY, &options,
                            &len));
114
    EXPECT_NE(0, options);
115
116
117
118
    if (socket_type == SOCK_DGRAM) {
    // Some more checks for UDP - MTU
#ifdef IPV6_USE_MIN_MTU        /* RFC 3542, not too common yet*/
        // use minimum MTU
Jelte Jansen's avatar
Jelte Jansen committed
119
120
        EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
                                &options, &len)) << strerror(errno);
121
        EXPECT_NE(0, options);
122
#else
123
124
125
126
127
128
        // We do not check for the IPV6_MTU, because while setting works (eg.
        // the packets are fragmented correctly), the getting does not. If
        // we try to getsockopt it, an error complaining it can't be accessed
        // on unconnected socket is returned. If we try to connect it, the
        // MTU of the interface is returned, not the one we set. So we live
        // in belief it works because we examined the packet dump.
129
130
131
132
133
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
        // Turned off Path MTU discovery on IPv6/UDP sockets?
        EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
                                &options, &len)) << strerror(errno);
        EXPECT_EQ(IPV6_PMTUDISC_DONT, options);
134
#endif
135
136
#endif
    }
137
}
138

139
140
141
142
143
// Just ignore the fd and pretend success. We close invalid fds in the tests.
int
closeIgnore(int) {
    return (0);
}
144
145
146

// Generic version of the socket test.  It creates the socket and checks that
// it is a valid descriptor.  The family-specific check functions are called
Josh Soref's avatar
Josh Soref committed
147
// to check that the socket is valid.  The function is parameterized according
148
149
150
151
152
153
154
155
156
157
158
159
160
// to the structure used to hold the address.
//
// Arguments:
// socket_type Type of socket to create (SOCK_DGRAM or SOCK_STREAM)
// socket_check Associated check function - udpCheck() or tcpCheck()
template <typename ADDRTYPE>
void testAnyCreate(int socket_type, socket_check_t socket_check) {

    // Create the socket.
    ADDRTYPE addr;
    memset(&addr, 0, sizeof(addr));
    setAddressFamilyFields(&addr);
    sockaddr* addr_ptr = reinterpret_cast<sockaddr*>(&addr);
161
162
    const int socket = getSock(socket_type, addr_ptr, sizeof(addr),
                               closeIgnore);
163
164
165
166
167
168
169
170
171
172
173
174
175
    ASSERT_GE(socket, 0) << "Couldn't create socket: failed with " <<
        "return code " << socket << " and error " << strerror(errno);

    // Perform socket-type-specific testing.
    socket_check(socket);

    // Do address-family-independent
    int options;
    socklen_t len = sizeof(options);
    EXPECT_EQ(0, getsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &options, &len));
    EXPECT_NE(0, options);

    // ...and the address-family specific tests.
176
    addressFamilySpecificCheck(&addr, socket, socket_type);
177
178
179
180
181
182
183

    // Tidy up and exit.
    EXPECT_EQ(0, close(socket));
}


// Several tests to ensure we can create the sockets.
Michal Vaner's avatar
Michal Vaner committed
184
TEST(get_sock, udp4_create) {
185
    testAnyCreate<sockaddr_in>(SOCK_DGRAM, udpCheck<sockaddr_in>);
Michal Vaner's avatar
Michal Vaner committed
186
187
188
}

TEST(get_sock, tcp4_create) {
189
    testAnyCreate<sockaddr_in>(SOCK_STREAM, tcpCheck);
Michal Vaner's avatar
Michal Vaner committed
190
191
}

192
193
194
195
196
197
#ifdef HAVE_BROKEN_GET_IPV6_USE_MIN_MTU
TEST(get_sock, DISABLED_udp6_create)
#else
TEST(get_sock, udp6_create)
#endif
{
198
    testAnyCreate<sockaddr_in6>(SOCK_DGRAM, udpCheck<sockaddr_in6>);
Michal Vaner's avatar
Michal Vaner committed
199
200
201
}

TEST(get_sock, tcp6_create) {
202
    testAnyCreate<sockaddr_in6>(SOCK_STREAM, tcpCheck);
Michal Vaner's avatar
Michal Vaner committed
203
204
}

205
206
bool close_called(false);

207
208
209
// You can use it as a close mockup. If you care about checking if it was really
// called, you can use the close_called variable. But set it to false before the
// test.
210
211
212
213
214
215
int closeCall(int socket) {
    close(socket);
    close_called = true;
    return (0);
}

216
217
// Ask the get_sock function for some nonsense and test if it is able to report
// an error.
Michal Vaner's avatar
Michal Vaner committed
218
TEST(get_sock, fail_with_nonsense) {
219
220
    sockaddr addr;
    memset(&addr, 0, sizeof(addr));
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    close_called = false;
    ASSERT_EQ(-1, getSock(0, &addr, sizeof addr, closeCall));
    ASSERT_FALSE(close_called); // The "socket" call should have failed already
}

// Bind should have failed here
TEST(get_sock, fail_with_bind) {
    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = 1;
    // No host should have this address on the interface, so it should not be
    // possible to bind it.
    addr.sin_addr.s_addr = inet_addr("192.0.2.1");
    close_called = false;
    ASSERT_EQ(-2, getSock(SOCK_STREAM, reinterpret_cast<sockaddr*>(&addr),
                          sizeof addr, closeCall));
    ASSERT_TRUE(close_called); // The "socket" call should have failed already
Michal Vaner's avatar
Michal Vaner committed
239
240
}

241
242
243
244
// The main run() function in the socket creator takes three functions to
// get the socket, send information to it, and close it.  These allow for
// alternatives to the system functions to be used for testing.

245
// Replacement getSock() function.
246
247
248
249
250
251
252
253
254
255
256
257
258
// The return value indicates the result of checks and is encoded.  Using LSB
// bit numbering (least-significant bit is bit 0) then:
//
// bit 0: 1 if "type" is known, 0 otherwise
// bit 1: 1 for UDP, 0 for TCP
// bit 2: 1 if address family is known, 0 otherwise
// bit 3: 1 for IPv6, 0 for IPv4
// bit 4: 1 if port passed was valid
//
// Other possible return values are:
//
// -1: The simulated bind() call has failed
// -2: The simulated socket() call has failed
Michal Vaner's avatar
Michal Vaner committed
259
int
260
261
getSockDummy(const int type, struct sockaddr* addr, const socklen_t,
             const close_t) {
262
263
264
265
    int result = 0;
    int port = 0;

    // Validate type field
Michal Vaner's avatar
Michal Vaner committed
266
    switch (type) {
Michal Vaner's avatar
Michal Vaner committed
267
        case SOCK_STREAM:
268
            result |= 0x01;
Michal Vaner's avatar
Michal Vaner committed
269
            break;
270

Michal Vaner's avatar
Michal Vaner committed
271
        case SOCK_DGRAM:
272
            result |= 0x03;
Michal Vaner's avatar
Michal Vaner committed
273
274
            break;
    }
275
276

    // Validate address family
Michal Vaner's avatar
Michal Vaner committed
277
    switch (addr->sa_family) {
Michal Vaner's avatar
Michal Vaner committed
278
        case AF_INET:
279
280
            result |= 0x04;
            port = reinterpret_cast<sockaddr_in*>(addr)->sin_port;
Michal Vaner's avatar
Michal Vaner committed
281
            break;
282

Michal Vaner's avatar
Michal Vaner committed
283
        case AF_INET6:
284
285
            result |= 0x0C;
            port = reinterpret_cast<sockaddr_in6*>(addr)->sin6_port;
Michal Vaner's avatar
Michal Vaner committed
286
287
            break;
    }
288
289
290
291

    // The port should be 0xffff. If it's not, we change the result.
    // The port of 0xbbbb means bind should fail and 0xcccc means
    // socket should fail.
Michal Vaner's avatar
Michal Vaner committed
292
    if (port != 0xffff) {
Michal Vaner's avatar
Michal Vaner committed
293
        errno = 0;
Michal Vaner's avatar
Michal Vaner committed
294
        if (port == 0xbbbb) {
295
            return (-2);
Michal Vaner's avatar
Michal Vaner committed
296
        } else if (port == 0xcccc) {
297
            return (-1);
Michal Vaner's avatar
Michal Vaner committed
298
        } else {
299
            result |= 0x10;
Michal Vaner's avatar
Michal Vaner committed
300
301
        }
    }
302
    return (result);
Michal Vaner's avatar
Michal Vaner committed
303
304
}

305
// Dummy send function - return data (the result of getSock()) to the destination.
Michal Vaner's avatar
Michal Vaner committed
306
int
307
send_FdDummy(const int destination, const int what) {
308
    // Make sure it is 1 byte so we know the length. We do not use more during
Andrei Pavel's avatar
Andrei Pavel committed
309
    // the test anyway.  And even with the LS byte, we can distinguish between
310
311
312
313
    // the different results.
    const char fd_data = what & 0xff;
    const bool status = write_data(destination, &fd_data, sizeof(fd_data));
    return (status ? 0 : -1);
Michal Vaner's avatar
Michal Vaner committed
314
315
}

316
317
318
319
// Generic test that it works, with various inputs and outputs.
// It uses different functions to create the socket and send it and pass
// data to it and check it returns correct data back, to see if the run()
// parses the commands correctly.
320
321
322
323
324
void runTest(const char* input_data, const size_t input_size,
             const char* output_data, const size_t output_size,
             bool should_succeed = true,
             const close_t test_close = closeIgnore,
             const send_fd_t send_fd = send_FdDummy)
Michal Vaner's avatar
Michal Vaner committed
325
{
326
327
    // Prepare the input feeder and output checker processes.  The feeder
    // process sends data from the client to run() and the checker process
Stephen Morris's avatar
Stephen Morris committed
328
    // reads the response and checks it against the expected response.
329
    int input_fd = 0;
330
    const pid_t input = provide_input(&input_fd, input_data, input_size);
Michal Vaner's avatar
Michal Vaner committed
331
    ASSERT_NE(-1, input) << "Couldn't start input feeder";
332
333

    int output_fd = 0;
334
    const pid_t output = check_output(&output_fd, output_data, output_size);
Michal Vaner's avatar
Michal Vaner committed
335
    ASSERT_NE(-1, output) << "Couldn't start output checker";
336

Michal Vaner's avatar
Michal Vaner committed
337
    // Run the body
Stephen Morris's avatar
Stephen Morris committed
338
    if (should_succeed) {
339
        EXPECT_NO_THROW(run(input_fd, output_fd, getSockDummy, send_fd,
Stephen Morris's avatar
Stephen Morris committed
340
341
                            test_close));
    } else {
342
        EXPECT_THROW(run(input_fd, output_fd, getSockDummy, send_fd,
Stephen Morris's avatar
Stephen Morris committed
343
344
345
                         test_close), isc::socket_creator::SocketCreatorError);
    }

Michal Vaner's avatar
Michal Vaner committed
346
347
348
    // Close the pipes
    close(input_fd);
    close(output_fd);
349

Michal Vaner's avatar
Michal Vaner committed
350
351
352
353
354
    // Check the subprocesses say everything is OK too
    EXPECT_TRUE(process_ok(input));
    EXPECT_TRUE(process_ok(output));
}

355
356

// Check it terminates successfully when asked to.
Michal Vaner's avatar
Michal Vaner committed
357
TEST(run, terminate) {
358
    runTest("T", 1, NULL, 0);
Michal Vaner's avatar
Michal Vaner committed
359
360
}

361
// Check it rejects incorrect input.
Michal Vaner's avatar
Michal Vaner committed
362
TEST(run, bad_input) {
363
    runTest("XXX", 3, "FI", 2, false);
Michal Vaner's avatar
Michal Vaner committed
364
365
}

366
// Check it correctly parses query stream to create sockets.
Michal Vaner's avatar
Michal Vaner committed
367
TEST(run, sockets) {
368
    runTest(
369
370
371
372
373
374
375
376
377
        // Commands:
        "SU4\xff\xff\0\0\0\0"   // IPv4 UDP socket, port 0xffffff, address 0.0.0.0
        "ST4\xff\xff\0\0\0\0"   // IPv4 TCP socket, port 0xffffff, address 0.0.0.0
        "ST6\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                                // IPv6 UDP socket, port 0xffffff, address ::
        "SU6\xff\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
                                // IPv6 TCP socket, port 0xffffff, address ::
        "T",                    // ... and terminate
        9 + 9 + 21 + 21 + 1,    // Length of command string
378
        "S\x07S\x05S\x0dS\x0f", // Response ("S" + LS byte of getSock() return)
379
        8);                     // Length of response
Michal Vaner's avatar
Michal Vaner committed
380
381
}

382
383

// Check if failures of get_socket are handled correctly.
Michal Vaner's avatar
Michal Vaner committed
384
TEST(run, bad_sockets) {
385
386
387
388
389
390
391
392
    // We need to construct the answer, but it depends on int length.  We expect
    // two failure answers in this test, each answer comprising two characters
    // followed by the (int) errno value.
    char result[2 * (2 + sizeof(int))];

    // We expect the errno parts to be zero but the characters to depend on the
    // exact failure.
    memset(result, 0, sizeof(result));
Michal Vaner's avatar
Michal Vaner committed
393
    strcpy(result, "EB");
394
395
    strcpy(result + 2 + sizeof(int), "ES");

Michal Vaner's avatar
Michal Vaner committed
396
    // Run the test
397
    runTest(
398
399
400
401
402
        "SU4\xbb\xbb\0\0\0\0"   // Port number will trigger simulated bind() fail
        "SU4\xcc\xcc\0\0\0\0"   // Port number will trigger simulated socket() fail
        "T",                    // Terminate
        19,                     // Length of command string
        result, sizeof(result));
Michal Vaner's avatar
Michal Vaner committed
403
404
}

405
// A close that fails.  (This causes an abort.)
406
int
407
closeFail(int) {
408
409
410
411
    return (-1);
}

TEST(run, cant_close) {
412
413
414
    runTest("SU4\xff\xff\0\0\0\0", 9,
            "S\x07", 2,
            false, closeFail);
415
416
}

417
418
419
// A send of the file descriptor that fails.  In this case we expect the client
// to receive the "S" indicating that the descriptor is being sent and nothing
// else.  This causes an abort.
420
int
421
sendFDFail(const int, const int) {
422
423
424
425
    return (FD_SYSTEM_ERROR);
}

TEST(run, cant_send_fd) {
426
427
428
    runTest("SU4\xff\xff\0\0\0\0", 9,
            "S", 1,
            false, closeIgnore, sendFDFail);
429
430
}

431
}   // Anonymous namespace