1 /*
2 * Copyright 2017 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 * ControllersTest.cpp - unit tests for Controllers.cpp
17 */
18
19 #include <set>
20 #include <string>
21 #include <vector>
22
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25
26 #include <android-base/strings.h>
27
28 #include "Controllers.h"
29 #include "IptablesBaseTest.h"
30
31 using testing::ContainerEq;
32
33 namespace android {
34 namespace net {
35
36 class ControllersTest : public IptablesBaseTest {
37 public:
ControllersTest()38 ControllersTest() {
39 Controllers::execIptablesRestore = fakeExecIptablesRestore;
40 Controllers::execIptablesRestoreWithOutput = fakeExecIptablesRestoreWithOutput;
41 }
42
43 protected:
initChildChains()44 void initChildChains() { Controllers::initChildChains(); };
findExistingChildChains(IptablesTarget a,const char * b,const char * c)45 std::set<std::string> findExistingChildChains(IptablesTarget a, const char* b, const char*c) {
46 return Controllers::findExistingChildChains(a, b, c);
47 }
48 };
49
TEST_F(ControllersTest,TestFindExistingChildChains)50 TEST_F(ControllersTest, TestFindExistingChildChains) {
51 ExpectedIptablesCommands expectedCmds = {
52 { V6, "*raw\n-S PREROUTING\nCOMMIT\n" },
53 };
54 sIptablesRestoreOutput.push_back(
55 "-P PREROUTING ACCEPT\n"
56 "-A PREROUTING -j bw_raw_PREROUTING\n"
57 "-A PREROUTING -j idletimer_raw_PREROUTING\n"
58 "-A PREROUTING -j tetherctrl_raw_PREROUTING\n"
59 );
60 std::set<std::string> expectedChains = {
61 "bw_raw_PREROUTING",
62 "idletimer_raw_PREROUTING",
63 "tetherctrl_raw_PREROUTING",
64 };
65 std::set<std::string> actual = findExistingChildChains(V6, "raw", "PREROUTING");
66 EXPECT_THAT(expectedChains, ContainerEq(actual));
67 expectIptablesRestoreCommands(expectedCmds);
68 }
69
TEST_F(ControllersTest,TestInitIptablesRules)70 TEST_F(ControllersTest, TestInitIptablesRules) {
71 // Test what happens when we boot and there are no rules.
72 ExpectedIptablesCommands expected = {
73 {V4V6,
74 "*filter\n"
75 ":INPUT -\n"
76 "-F INPUT\n"
77 ":bw_INPUT -\n"
78 "-A INPUT -j bw_INPUT\n"
79 ":fw_INPUT -\n"
80 "-A INPUT -j fw_INPUT\n"
81 "COMMIT\n"},
82 {V4V6,
83 "*filter\n"
84 ":FORWARD -\n"
85 "-F FORWARD\n"
86 ":oem_fwd -\n"
87 "-A FORWARD -j oem_fwd\n"
88 ":fw_FORWARD -\n"
89 "-A FORWARD -j fw_FORWARD\n"
90 ":bw_FORWARD -\n"
91 "-A FORWARD -j bw_FORWARD\n"
92 ":tetherctrl_FORWARD -\n"
93 "-A FORWARD -j tetherctrl_FORWARD\n"
94 "COMMIT\n"},
95 {V4V6,
96 "*raw\n"
97 ":PREROUTING -\n"
98 "-F PREROUTING\n"
99 ":idletimer_raw_PREROUTING -\n"
100 "-A PREROUTING -j idletimer_raw_PREROUTING\n"
101 ":bw_raw_PREROUTING -\n"
102 "-A PREROUTING -j bw_raw_PREROUTING\n"
103 ":tetherctrl_raw_PREROUTING -\n"
104 "-A PREROUTING -j tetherctrl_raw_PREROUTING\n"
105 "COMMIT\n"},
106 {V4V6,
107 "*mangle\n"
108 ":FORWARD -\n"
109 "-F FORWARD\n"
110 ":tetherctrl_mangle_FORWARD -\n"
111 "-A FORWARD -j tetherctrl_mangle_FORWARD\n"
112 "COMMIT\n"},
113 {V4V6,
114 "*mangle\n"
115 ":INPUT -\n"
116 "-F INPUT\n"
117 ":connmark_mangle_INPUT -\n"
118 "-A INPUT -j connmark_mangle_INPUT\n"
119 ":wakeupctrl_mangle_INPUT -\n"
120 "-A INPUT -j wakeupctrl_mangle_INPUT\n"
121 ":routectrl_mangle_INPUT -\n"
122 "-A INPUT -j routectrl_mangle_INPUT\n"
123 "COMMIT\n"},
124 {V4V6,
125 "*mangle\n"
126 ":OUTPUT -\n"
127 "-F OUTPUT\n"
128 ":connmark_mangle_OUTPUT -\n"
129 "-A OUTPUT -j connmark_mangle_OUTPUT\n"
130 "COMMIT\n"},
131 {V4,
132 "*nat\n"
133 ":PREROUTING -\n"
134 "-F PREROUTING\n"
135 ":oem_nat_pre -\n"
136 "-A PREROUTING -j oem_nat_pre\n"
137 "COMMIT\n"},
138 {V4,
139 "*nat\n"
140 ":POSTROUTING -\n"
141 "-F POSTROUTING\n"
142 ":tetherctrl_nat_POSTROUTING -\n"
143 "-A POSTROUTING -j tetherctrl_nat_POSTROUTING\n"
144 "COMMIT\n"},
145 {V4,
146 "*filter\n"
147 "-S OUTPUT\n"
148 "COMMIT\n"},
149 {V4,
150 "*filter\n"
151 ":oem_out -\n"
152 "-A OUTPUT -j oem_out\n"
153 ":fw_OUTPUT -\n"
154 "-A OUTPUT -j fw_OUTPUT\n"
155 ":st_OUTPUT -\n"
156 "-A OUTPUT -j st_OUTPUT\n"
157 ":bw_OUTPUT -\n"
158 "-A OUTPUT -j bw_OUTPUT\n"
159 "COMMIT\n"},
160 {V6,
161 "*filter\n"
162 "-S OUTPUT\n"
163 "COMMIT\n"},
164 {V6,
165 "*filter\n"
166 ":oem_out -\n"
167 "-A OUTPUT -j oem_out\n"
168 ":fw_OUTPUT -\n"
169 "-A OUTPUT -j fw_OUTPUT\n"
170 ":st_OUTPUT -\n"
171 "-A OUTPUT -j st_OUTPUT\n"
172 ":bw_OUTPUT -\n"
173 "-A OUTPUT -j bw_OUTPUT\n"
174 "COMMIT\n"},
175 {V4,
176 "*mangle\n"
177 "-S POSTROUTING\n"
178 "COMMIT\n"},
179 {V4,
180 "*mangle\n"
181 ":oem_mangle_post -\n"
182 "-A POSTROUTING -j oem_mangle_post\n"
183 ":bw_mangle_POSTROUTING -\n"
184 "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
185 ":idletimer_mangle_POSTROUTING -\n"
186 "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
187 "COMMIT\n"},
188 {V6,
189 "*mangle\n"
190 "-S POSTROUTING\n"
191 "COMMIT\n"},
192 {V6,
193 "*mangle\n"
194 ":oem_mangle_post -\n"
195 "-A POSTROUTING -j oem_mangle_post\n"
196 ":bw_mangle_POSTROUTING -\n"
197 "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
198 ":idletimer_mangle_POSTROUTING -\n"
199 "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
200 "COMMIT\n"},
201 };
202
203 // Check that we run these commands and these only.
204 initChildChains();
205 expectIptablesRestoreCommands(expected);
206 expectIptablesRestoreCommands(ExpectedIptablesCommands{});
207
208 // Now test what happens when some rules exist (e.g., if we crash and restart).
209
210 // First, explicitly tell the iptables test code to return empty output to all the commands we
211 // send. This allows us to tell it to return non-empty output to particular commands in the
212 // following code.
213 for (size_t i = 0; i < expected.size(); i++) {
214 sIptablesRestoreOutput.push_back("");
215 }
216
217 // Define a macro to remove a substring from a string. We use a macro instead of a function so
218 // we can assert in it. In the following code, we use ASSERT_* to check for programming errors
219 // in the test code, and EXPECT_* to check for errors in the actual code.
220 #define DELETE_SUBSTRING(substr, str) { \
221 const size_t start = (str).find((substr)); \
222 ASSERT_NE(std::string::npos, start); \
223 (str).erase(start, strlen((substr))); \
224 ASSERT_EQ(std::string::npos, (str).find((substr))); \
225 }
226
227 // Now set test expectations.
228
229 // 1. Test that if we find rules that we don't create ourselves, we ignore them.
230 // First check that command #8 is where we list the OUTPUT chain in the (IPv4) filter table:
231 ASSERT_NE(std::string::npos, expected[8].second.find("*filter\n-S OUTPUT\n"));
232 // ... and pretend that when we run that command, we find the following rules. Because we don't
233 // create any of these rules ourselves, our behaviour is unchanged.
234 sIptablesRestoreOutput[8] =
235 "-P OUTPUT ACCEPT\n"
236 "-A OUTPUT -o r_rmnet_data8 -p udp -m udp --dport 1900 -j DROP\n";
237
238 // 2. Test that rules that we create ourselves are not added if they already exist.
239 // Pretend that when we list the OUTPUT chain in the (IPv6) filter table, we find the oem_out
240 // and st_OUTPUT chains:
241 ASSERT_NE(std::string::npos, expected[10].second.find("*filter\n-S OUTPUT\n"));
242 sIptablesRestoreOutput[10] =
243 "-A OUTPUT -j oem_out\n"
244 "-A OUTPUT -j st_OUTPUT\n";
245 // ... and expect that when we populate the OUTPUT chain, we do not re-add them.
246 DELETE_SUBSTRING("-A OUTPUT -j oem_out\n", expected[11].second);
247 DELETE_SUBSTRING("-A OUTPUT -j st_OUTPUT\n", expected[11].second);
248
249 // 3. Now test that when we list the POSTROUTING chain in the mangle table, we find a mixture of
250 // netd-created rules and vendor rules:
251 ASSERT_NE(std::string::npos, expected[14].second.find("*mangle\n-S POSTROUTING\n"));
252 sIptablesRestoreOutput[14] =
253 "-P POSTROUTING ACCEPT\n"
254 "-A POSTROUTING -j oem_mangle_post\n"
255 "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
256 "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
257 "-A POSTROUTING -j qcom_qos_reset_POSTROUTING\n"
258 "-A POSTROUTING -j qcom_qos_filter_POSTROUTING\n";
259 // and expect that we don't re-add the netd-created rules that already exist.
260 DELETE_SUBSTRING("-A POSTROUTING -j oem_mangle_post\n", expected[15].second);
261 DELETE_SUBSTRING("-A POSTROUTING -j bw_mangle_POSTROUTING\n", expected[15].second);
262 DELETE_SUBSTRING("-A POSTROUTING -j idletimer_mangle_POSTROUTING\n", expected[15].second);
263
264 // In this last case, also check that our expectations are reasonable.
265 std::string expectedCmd14 =
266 "*mangle\n"
267 ":oem_mangle_post -\n"
268 ":bw_mangle_POSTROUTING -\n"
269 ":idletimer_mangle_POSTROUTING -\n"
270 "COMMIT\n";
271 ASSERT_EQ(expectedCmd14, expected[15].second);
272
273 // Finally, actually test that initChildChains runs the expected commands, and nothing more.
274 initChildChains();
275 expectIptablesRestoreCommands(expected);
276 expectIptablesRestoreCommands(ExpectedIptablesCommands{});
277 }
278
279 } // namespace net
280 } // namespace android
281