1 /*
2  * Copyright (C) 2020 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 
17 #include <netdb.h>
18 #include <netinet/in.h>
19 #include <poll.h> /* poll */
20 #include <sys/socket.h>
21 #include <sys/types.h>
22 
23 #include <android-base/unique_fd.h>
24 #include <gtest/gtest.h>
25 
26 #include "NetdClient.h"
27 
28 #define SKIP_IF_NO_NETWORK_CONNECTIVITY                                    \
29     do {                                                                   \
30         if (!checkNetworkConnectivity()) {                                 \
31             GTEST_LOG_(INFO) << "Skip. Required Network Connectivity. \n"; \
32             return;                                                        \
33         }                                                                  \
34     } while (0)
35 
36 namespace {
37 
38 constexpr char TEST_DOMAIN[] = "www.google.com";
39 
checkNetworkConnectivity()40 bool checkNetworkConnectivity() {
41     android::base::unique_fd sock(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP));
42     if (sock == -1) return false;
43     static const sockaddr_in6 server6 = {
44             .sin6_family = AF_INET6,
45             .sin6_addr.s6_addr = {// 2000::
46                                   0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
47     int ret = connect(sock, reinterpret_cast<const sockaddr*>(&server6), sizeof(server6));
48     if (ret == 0) return true;
49     sock.reset(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP));
50     if (sock == -1) return false;
51     static const sockaddr_in server4 = {
52             .sin_family = AF_INET,
53             .sin_addr.s_addr = __constant_htonl(0x08080808L)  // 8.8.8.8
54     };
55     ret = connect(sock, reinterpret_cast<const sockaddr*>(&server4), sizeof(server4));
56     return !ret;
57 }
58 
expectHasNetworking()59 void expectHasNetworking() {
60     // Socket
61     android::base::unique_fd ipv4(socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)),
62             ipv6(socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0));
63     EXPECT_LE(3, ipv4);
64     EXPECT_LE(3, ipv6);
65 
66     // DNS
67     addrinfo* result = nullptr;
68     errno = 0;
69     const addrinfo hints = {
70             .ai_family = AF_UNSPEC,
71             .ai_socktype = SOCK_DGRAM,
72     };
73     EXPECT_EQ(0, getaddrinfo(TEST_DOMAIN, nullptr, &hints, &result));
74     EXPECT_EQ(0, errno);
75     freeaddrinfo(result);
76 }
77 
expectNoNetworking()78 void expectNoNetworking() {
79     // Socket
80     android::base::unique_fd unixSocket(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
81     EXPECT_LE(3, unixSocket);
82     android::base::unique_fd ipv4(socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0));
83     EXPECT_EQ(-1, ipv4);
84     EXPECT_EQ(EPERM, errno);
85     android::base::unique_fd ipv6(socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0));
86     EXPECT_EQ(-1, ipv6);
87     EXPECT_EQ(EPERM, errno);
88 
89     // DNS
90     addrinfo* result = nullptr;
91     errno = 0;
92     const addrinfo hints = {
93             .ai_family = AF_UNSPEC,
94             .ai_socktype = SOCK_DGRAM,
95     };
96     EXPECT_EQ(EAI_NODATA, getaddrinfo(TEST_DOMAIN, nullptr, &hints, &result));
97     EXPECT_EQ(EPERM, errno);
98     freeaddrinfo(result);
99 }
100 
101 }  // namespace
102 
TEST(NetdClientIntegrationTest,setAllowNetworkingForProcess)103 TEST(NetdClientIntegrationTest, setAllowNetworkingForProcess) {
104     SKIP_IF_NO_NETWORK_CONNECTIVITY;
105     // At the beginning, we should be able to use socket since the default setting is allowing.
106     expectHasNetworking();
107     // Disable
108     setAllowNetworkingForProcess(false);
109     expectNoNetworking();
110     // Reset
111     setAllowNetworkingForProcess(true);
112     expectHasNetworking();
113 }
114