Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  *
     16  * sock_diag_test.cpp - unit tests for SockDiag.cpp
     17  */
     18 
     19 #include <arpa/inet.h>
     20 #include <netinet/in.h>
     21 #include <linux/inet_diag.h>
     22 
     23 #include <gtest/gtest.h>
     24 
     25 #include "NetdConstants.h"
     26 #include "SockDiag.h"
     27 
     28 
     29 #define NUM_SOCKETS 500
     30 
     31 
     32 class SockDiagTest : public ::testing::Test {
     33 };
     34 
     35 uint16_t bindAndListen(int s) {
     36     for (int i = 0; i < 10; i++) {
     37         uint16_t port = 1024 + arc4random_uniform(0xffff - 1024);
     38         sockaddr_in6 sin6 = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
     39         if (bind(s, (sockaddr *) &sin6, sizeof(sin6)) == 0) {
     40             listen(s, 1);
     41             return port;
     42         }
     43     }
     44     close(s);
     45     return 0;
     46 }
     47 
     48 const char *tcpStateName(uint8_t state) {
     49     static const char *states[] = {
     50         "???",
     51         "TCP_ESTABLISHED",
     52         "TCP_SYN_SENT",
     53         "TCP_SYN_RECV",
     54         "TCP_FIN_WAIT1",
     55         "TCP_FIN_WAIT2",
     56         "TCP_TIME_WAIT",
     57         "TCP_CLOSE",
     58         "TCP_CLOSE_WAIT",
     59         "TCP_LAST_ACK",
     60         "TCP_LISTEN",
     61         "TCP_CLOSING",
     62         "TCP_NEW_SYN_RECV",
     63     };
     64     return states[(state < ARRAY_SIZE(states)) ? state : 0];
     65 }
     66 
     67 TEST_F(SockDiagTest, TestDump) {
     68     int v4socket = socket(AF_INET, SOCK_STREAM, 0);
     69     int v6socket = socket(AF_INET6, SOCK_STREAM, 0);
     70     int listensocket = socket(AF_INET6, SOCK_STREAM, 0);
     71     ASSERT_NE(-1, v4socket) << "Failed to open IPv4 socket";
     72     ASSERT_NE(-1, v6socket) << "Failed to open IPv6 socket";
     73     ASSERT_NE(-1, listensocket) << "Failed to open listen socket";
     74 
     75     uint16_t port = bindAndListen(listensocket);
     76     ASSERT_NE(0, port) << "Can't bind to server port";
     77 
     78     // Connect to loopback.
     79     sockaddr_in server4 = { .sin_family = AF_INET, .sin_port = htons(port) };
     80     sockaddr_in6 server6 = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
     81     ASSERT_EQ(0, connect(v4socket, (sockaddr *) &server4, sizeof(server4)))
     82         << "IPv4 connect failed: " << strerror(errno);
     83     ASSERT_EQ(0, connect(v6socket, (sockaddr *) &server6, sizeof(server6)))
     84         << "IPv6 connect failed: " << strerror(errno);
     85 
     86     sockaddr_in6 client46, client6;
     87     socklen_t clientlen = std::max(sizeof(client46), sizeof(client6));
     88     int accepted4 = accept(listensocket, (sockaddr *) &client46, &clientlen);
     89     int accepted6 = accept(listensocket, (sockaddr *) &client6, &clientlen);
     90     ASSERT_NE(-1, accepted4);
     91     ASSERT_NE(-1, accepted6);
     92 
     93     int v4SocketsSeen = 0;
     94     bool seenclient46 = false;
     95     bool seenNull = false;
     96     char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
     97 
     98     fprintf(stderr, "Ports:\n  server=%d. client46=%d, client6=%d\n",
     99             port, ntohs(client46.sin6_port), ntohs(client6.sin6_port));
    100 
    101     auto checkIPv4Dump = [&] (uint8_t /* proto */, const inet_diag_msg *msg) {
    102         if (msg == nullptr) {
    103             EXPECT_FALSE(seenNull);
    104             seenNull = true;
    105             return 0;
    106         }
    107         EXPECT_EQ(htonl(INADDR_LOOPBACK), msg->id.idiag_src[0]);
    108         v4SocketsSeen++;
    109         seenclient46 |= (msg->id.idiag_sport == client46.sin6_port);
    110         inet_ntop(AF_INET, msg->id.idiag_src, src, sizeof(src));
    111         inet_ntop(AF_INET, msg->id.idiag_src, dst, sizeof(dst));
    112         fprintf(stderr, "  v4 %s:%d -> %s:%d %s\n",
    113                 src, htons(msg->id.idiag_sport),
    114                 dst, htons(msg->id.idiag_dport),
    115                 tcpStateName(msg->idiag_state));
    116         return 0;
    117     };
    118 
    119     int v6SocketsSeen = 0;
    120     bool seenClient6 = false, seenServer46 = false, seenServer6 = false;
    121 
    122     auto checkIPv6Dump = [&] (uint8_t /* proto */, const inet_diag_msg *msg) {
    123         if (msg == nullptr) {
    124             EXPECT_FALSE(seenNull);
    125             seenNull = true;
    126             return 0;
    127         }
    128         struct in6_addr *saddr = (struct in6_addr *) msg->id.idiag_src;
    129         EXPECT_TRUE(
    130             IN6_IS_ADDR_LOOPBACK(saddr) ||
    131             (IN6_IS_ADDR_V4MAPPED(saddr) && saddr->s6_addr32[3] == htonl(INADDR_LOOPBACK)));
    132         v6SocketsSeen++;
    133         seenClient6 |= (msg->id.idiag_sport == client6.sin6_port);
    134         seenServer46 |= (msg->id.idiag_sport == htons(port));
    135         seenServer6 |= (msg->id.idiag_sport == htons(port));
    136         inet_ntop(AF_INET6, msg->id.idiag_src, src, sizeof(src));
    137         inet_ntop(AF_INET6, msg->id.idiag_src, dst, sizeof(dst));
    138         fprintf(stderr, "  v6 [%s]:%d -> [%s]:%d %s\n",
    139                 src, htons(msg->id.idiag_sport),
    140                 dst, htons(msg->id.idiag_dport),
    141                 tcpStateName(msg->idiag_state));
    142         return 0;
    143     };
    144 
    145     SockDiag sd;
    146     ASSERT_TRUE(sd.open()) << "Failed to open SOCK_DIAG socket";
    147 
    148     seenNull = false;
    149     int ret = sd.sendDumpRequest(IPPROTO_TCP, AF_INET, "127.0.0.1");
    150     ASSERT_EQ(0, ret) << "Failed to send IPv4 dump request: " << strerror(-ret);
    151     fprintf(stderr, "Sent IPv4 dump\n");
    152     sd.readDiagMsg(IPPROTO_TCP, checkIPv4Dump);
    153     EXPECT_GE(v4SocketsSeen, 1);
    154     EXPECT_TRUE(seenclient46);
    155     EXPECT_FALSE(seenServer46);
    156 
    157     seenNull = false;
    158     ret = sd.sendDumpRequest(IPPROTO_TCP, AF_INET6, "127.0.0.1");
    159     ASSERT_EQ(0, ret) << "Failed to send mapped dump request: " << strerror(-ret);
    160     fprintf(stderr, "Sent mapped dump\n");
    161     sd.readDiagMsg(IPPROTO_TCP, checkIPv6Dump);
    162     EXPECT_TRUE(seenServer46);
    163 
    164     seenNull = false;
    165     ret = sd.sendDumpRequest(IPPROTO_TCP, AF_INET6, "::1");
    166     ASSERT_EQ(0, ret) << "Failed to send IPv6 dump request: " << strerror(-ret);
    167     fprintf(stderr, "Sent IPv6 dump\n");
    168 
    169     sd.readDiagMsg(IPPROTO_TCP, checkIPv6Dump);
    170     EXPECT_GE(v6SocketsSeen, 1);
    171     EXPECT_TRUE(seenClient6);
    172     EXPECT_TRUE(seenServer6);
    173 
    174     close(v4socket);
    175     close(v6socket);
    176     close(listensocket);
    177     close(accepted4);
    178     close(accepted6);
    179 }
    180 
    181 TEST_F(SockDiagTest, TestMicroBenchmark) {
    182     fprintf(stderr, "Benchmarking closing %d sockets\n", NUM_SOCKETS);
    183 
    184     int listensocket = socket(AF_INET6, SOCK_STREAM, 0);
    185     ASSERT_NE(-1, listensocket) << "Failed to open listen socket";
    186 
    187     uint16_t port = bindAndListen(listensocket);
    188     ASSERT_NE(0, port) << "Can't bind to server port";
    189     sockaddr_in6 server = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
    190 
    191     using ms = std::chrono::duration<float, std::ratio<1, 1000>>;
    192 
    193     int clientsockets[NUM_SOCKETS], serversockets[NUM_SOCKETS];
    194     uint16_t clientports[NUM_SOCKETS];
    195     sockaddr_in6 client;
    196     socklen_t clientlen;
    197 
    198     auto start = std::chrono::steady_clock::now();
    199     for (int i = 0; i < NUM_SOCKETS; i++) {
    200         int s = socket(AF_INET6, SOCK_STREAM, 0);
    201         clientlen = sizeof(client);
    202         ASSERT_EQ(0, connect(s, (sockaddr *) &server, sizeof(server)))
    203             << "Connecting socket " << i << " failed " << strerror(errno);
    204         serversockets[i] = accept(listensocket, (sockaddr *) &client, &clientlen);
    205         ASSERT_NE(-1, serversockets[i])
    206             << "Accepting socket " << i << " failed " << strerror(errno);
    207         clientports[i] = client.sin6_port;
    208         clientsockets[i] = s;
    209     }
    210     fprintf(stderr, "  Connecting: %6.1f ms\n",
    211             std::chrono::duration_cast<ms>(std::chrono::steady_clock::now() - start).count());
    212 
    213     SockDiag sd;
    214     ASSERT_TRUE(sd.open()) << "Failed to open SOCK_DIAG socket";
    215 
    216     start = std::chrono::steady_clock::now();
    217     int ret = sd.destroySockets("::1");
    218     EXPECT_LE(0, ret) << ": Failed to destroy sockets on ::1: " << strerror(-ret);
    219     fprintf(stderr, "  Destroying: %6.1f ms\n",
    220             std::chrono::duration_cast<ms>(std::chrono::steady_clock::now() - start).count());
    221 
    222     int err;
    223     start = std::chrono::steady_clock::now();
    224     for (int i = 0; i < NUM_SOCKETS; i++) {
    225         ret = send(clientsockets[i], "foo", sizeof("foo"), 0);
    226         err = errno;
    227         EXPECT_EQ(-1, ret) << "Client socket " << i << " not closed";
    228         if (ret == -1) {
    229             // Since we're connected to ourselves, the error might be ECONNABORTED (if we destroyed
    230             // the socket) or ECONNRESET (if the other end was destroyed and sent a RST).
    231             EXPECT_TRUE(errno == ECONNABORTED || errno == ECONNRESET)
    232                 << "Client socket: unexpected error: " << strerror(errno);
    233         }
    234 
    235         ret = send(serversockets[i], "foo", sizeof("foo"), 0);
    236         err = errno;
    237         EXPECT_EQ(-1, ret) << "Server socket " << i << " not closed";
    238         if (ret == -1) {
    239             EXPECT_TRUE(errno == ECONNABORTED || errno == ECONNRESET)
    240                 << "Server socket: unexpected error: " << strerror(errno);
    241         }
    242     }
    243     fprintf(stderr, "   Verifying: %6.1f ms\n",
    244             std::chrono::duration_cast<ms>(std::chrono::steady_clock::now() - start).count());
    245 
    246 
    247 
    248     start = std::chrono::steady_clock::now();
    249     for (int i = 0; i < NUM_SOCKETS; i++) {
    250         close(clientsockets[i]);
    251         close(serversockets[i]);
    252     }
    253     fprintf(stderr, "     Closing: %6.1f ms\n",
    254             std::chrono::duration_cast<ms>(std::chrono::steady_clock::now() - start).count());
    255 
    256     close(listensocket);
    257 }
    258