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 * StrictControllerTest.cpp - unit tests for StrictController.cpp
17 */
18
19#include <string>
20#include <vector>
21
22#include <gtest/gtest.h>
23
24#include <android-base/strings.h>
25
26#include "StrictController.h"
27#include "IptablesBaseTest.h"
28
29class StrictControllerTest : public IptablesBaseTest {
30public:
31    StrictControllerTest() {
32        StrictController::execIptablesRestore = fakeExecIptablesRestore;
33    }
34    StrictController mStrictCtrl;
35};
36
37TEST_F(StrictControllerTest, TestEnableStrict) {
38    mStrictCtrl.enableStrict();
39
40    std::vector<std::string> common = {
41        "*filter",
42        ":st_OUTPUT -",
43        ":st_penalty_log -",
44        ":st_penalty_reject -",
45        ":st_clear_caught -",
46        ":st_clear_detect -",
47        "COMMIT\n"
48    };
49
50    std::vector<std::string> v4 = {
51        "*filter",
52        "-A st_penalty_log -j CONNMARK --or-mark 0x1000000",
53        "-A st_penalty_log -j NFLOG --nflog-group 0",
54        "-A st_penalty_reject -j CONNMARK --or-mark 0x2000000",
55        "-A st_penalty_reject -j NFLOG --nflog-group 0",
56        "-A st_penalty_reject -j REJECT",
57        "-A st_clear_detect -m connmark --mark 0x2000000/0x2000000 -j REJECT",
58        "-A st_clear_detect -m connmark --mark 0x1000000/0x1000000 -j RETURN",
59        "-A st_clear_detect -p tcp -m u32 --u32 \""
60            "0>>22&0x3C@ 12>>26&0x3C@ 0&0xFFFF0000=0x16030000 &&"
61            "0>>22&0x3C@ 12>>26&0x3C@ 4&0x00FF0000=0x00010000"
62            "\" -j CONNMARK --or-mark 0x1000000",
63        "-A st_clear_detect -p udp -m u32 --u32 \""
64            "0>>22&0x3C@ 8&0xFFFF0000=0x16FE0000 &&"
65            "0>>22&0x3C@ 20&0x00FF0000=0x00010000"
66            "\" -j CONNMARK --or-mark 0x1000000",
67        "-A st_clear_detect -m connmark --mark 0x1000000/0x1000000 -j RETURN",
68        "-A st_clear_detect -p tcp -m state --state ESTABLISHED -m u32 --u32 "
69            "\"0>>22&0x3C@ 12>>26&0x3C@ 0&0x0=0x0\" -j st_clear_caught",
70        "-A st_clear_detect -p udp -j st_clear_caught",
71        "COMMIT\n"
72    };
73
74    std::vector<std::string> v6 = {
75        "*filter",
76        "-A st_penalty_log -j CONNMARK --or-mark 0x1000000",
77        "-A st_penalty_log -j NFLOG --nflog-group 0",
78        "-A st_penalty_reject -j CONNMARK --or-mark 0x2000000",
79        "-A st_penalty_reject -j NFLOG --nflog-group 0",
80        "-A st_penalty_reject -j REJECT",
81        "-A st_clear_detect -m connmark --mark 0x2000000/0x2000000 -j REJECT",
82        "-A st_clear_detect -m connmark --mark 0x1000000/0x1000000 -j RETURN",
83
84        "-A st_clear_detect -p tcp -m u32 --u32 \""
85            "52>>26&0x3C@ 40&0xFFFF0000=0x16030000 &&"
86            "52>>26&0x3C@ 44&0x00FF0000=0x00010000"
87            "\" -j CONNMARK --or-mark 0x1000000",
88        "-A st_clear_detect -p udp -m u32 --u32 \""
89            "48&0xFFFF0000=0x16FE0000 &&"
90            "60&0x00FF0000=0x00010000"
91            "\" -j CONNMARK --or-mark 0x1000000",
92        "-A st_clear_detect -m connmark --mark 0x1000000/0x1000000 -j RETURN",
93        "-A st_clear_detect -p tcp -m state --state ESTABLISHED -m u32 --u32 "
94            "\"52>>26&0x3C@ 40&0x0=0x0\" -j st_clear_caught",
95        "-A st_clear_detect -p udp -j st_clear_caught",
96        "COMMIT\n"
97    };
98
99    std::string commandsCommon = android::base::Join(common, '\n');
100    std::string commands4 = android::base::Join(v4, '\n');
101    std::string commands6 = android::base::Join(v6, '\n');
102
103    std::vector<std::pair<IptablesTarget, std::string>> expected = {
104        { V4V6, commandsCommon },
105        { V4, commands4 },
106        { V6, commands6 },
107    };
108    expectIptablesRestoreCommands(expected);
109}
110
111TEST_F(StrictControllerTest, TestDisableStrict) {
112    mStrictCtrl.disableStrict();
113
114    const std::string expected =
115        "*filter\n"
116        ":st_OUTPUT -\n"
117        ":st_penalty_log -\n"
118        ":st_penalty_reject -\n"
119        ":st_clear_caught -\n"
120        ":st_clear_detect -\n"
121        "COMMIT\n";
122    expectIptablesRestoreCommands({ expected });
123}
124
125TEST_F(StrictControllerTest, TestSetUidCleartextPenalty) {
126    std::vector<std::string> acceptCommands = {
127        "*filter\n"
128        "-D st_OUTPUT -m owner --uid-owner 12345 -j st_clear_detect\n"
129        "-D st_clear_caught -m owner --uid-owner 12345 -j st_clear_caught_12345\n"
130        "-F st_clear_caught_12345\n"
131        "-X st_clear_caught_12345\n"
132        "COMMIT\n"
133    };
134    std::vector<std::string> logCommands = {
135        "*filter\n"
136        ":st_clear_caught_12345 -\n"
137        "-I st_OUTPUT -m owner --uid-owner 12345 -j st_clear_detect\n"
138        "-I st_clear_caught -m owner --uid-owner 12345 -j st_clear_caught_12345\n"
139        "-A st_clear_caught_12345 -j st_penalty_log\n"
140        "COMMIT\n"
141    };
142    std::vector<std::string> rejectCommands = {
143        "*filter\n"
144        ":st_clear_caught_12345 -\n"
145        "-I st_OUTPUT -m owner --uid-owner 12345 -j st_clear_detect\n"
146        "-I st_clear_caught -m owner --uid-owner 12345 -j st_clear_caught_12345\n"
147        "-A st_clear_caught_12345 -j st_penalty_reject\n"
148        "COMMIT\n"
149    };
150
151    mStrictCtrl.setUidCleartextPenalty(12345, LOG);
152    expectIptablesRestoreCommands(logCommands);
153
154    mStrictCtrl.setUidCleartextPenalty(12345, ACCEPT);
155    expectIptablesRestoreCommands(acceptCommands);
156
157    // StrictController doesn't keep any state and it is not correct to call its methods in the
158    // wrong order (e.g., to go from LOG to REJECT without passing through ACCEPT).
159    // NetworkManagementService does keep state (not just to ensure correctness, but also so it can
160    // reprogram the rules when netd crashes).
161    mStrictCtrl.setUidCleartextPenalty(12345, REJECT);
162    expectIptablesRestoreCommands(rejectCommands);
163
164    mStrictCtrl.setUidCleartextPenalty(12345, ACCEPT);
165    expectIptablesRestoreCommands(acceptCommands);
166}
167