2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #define LOG_TAG "StrictController"
27 #include <cutils/log.h>
29 #include <android-base/stringprintf.h>
30 #include <android-base/strings.h>
32 #include "ConnmarkFlags.h"
33 #include "NetdConstants.h"
34 #include "StrictController.h"
36 auto StrictController::execIptables = ::execIptables;
37 auto StrictController::execIptablesRestore = ::execIptablesRestore;
39 const char* StrictController::LOCAL_OUTPUT = "st_OUTPUT";
40 const char* StrictController::LOCAL_CLEAR_DETECT = "st_clear_detect";
41 const char* StrictController::LOCAL_CLEAR_CAUGHT = "st_clear_caught";
42 const char* StrictController::LOCAL_PENALTY_LOG = "st_penalty_log";
43 const char* StrictController::LOCAL_PENALTY_REJECT = "st_penalty_reject";
45 using android::base::StringPrintf;
47 StrictController::StrictController(void) {
50 int StrictController::enableStrict(void) {
51 char connmarkFlagAccept[16];
52 char connmarkFlagReject[16];
53 char connmarkFlagTestAccept[32];
54 char connmarkFlagTestReject[32];
55 sprintf(connmarkFlagAccept, "0x%x", ConnmarkFlags::STRICT_RESOLVED_ACCEPT);
56 sprintf(connmarkFlagReject, "0x%x", ConnmarkFlags::STRICT_RESOLVED_REJECT);
57 sprintf(connmarkFlagTestAccept, "0x%x/0x%x",
58 ConnmarkFlags::STRICT_RESOLVED_ACCEPT,
59 ConnmarkFlags::STRICT_RESOLVED_ACCEPT);
60 sprintf(connmarkFlagTestReject, "0x%x/0x%x",
61 ConnmarkFlags::STRICT_RESOLVED_REJECT,
62 ConnmarkFlags::STRICT_RESOLVED_REJECT);
67 std::vector<std::string> v4, v6;
69 #define CMD_V4(...) { auto cmd = StringPrintf(__VA_ARGS__); v4.push_back(cmd); }
70 #define CMD_V6(...) { auto cmd = StringPrintf(__VA_ARGS__); v6.push_back(cmd); }
71 #define CMD_V4V6(...) { CMD_V4(__VA_ARGS__); CMD_V6(__VA_ARGS__); };
75 // Chain triggered when cleartext socket detected and penalty is log
76 CMD_V4V6("-A %s -j CONNMARK --or-mark %s", LOCAL_PENALTY_LOG, connmarkFlagAccept);
77 CMD_V4V6("-A %s -j NFLOG --nflog-group 0", LOCAL_PENALTY_LOG);
79 // Chain triggered when cleartext socket detected and penalty is reject
80 CMD_V4V6("-A %s -j CONNMARK --or-mark %s", LOCAL_PENALTY_REJECT, connmarkFlagReject);
81 CMD_V4V6("-A %s -j NFLOG --nflog-group 0", LOCAL_PENALTY_REJECT);
82 CMD_V4V6("-A %s -j REJECT", LOCAL_PENALTY_REJECT);
84 // We use a high-order mark bit to keep track of connections that we've already resolved.
85 // Quickly skip connections that we've already resolved
86 CMD_V4V6("-A %s -m connmark --mark %s -j REJECT", LOCAL_CLEAR_DETECT, connmarkFlagTestReject);
87 CMD_V4V6("-A %s -m connmark --mark %s -j RETURN", LOCAL_CLEAR_DETECT, connmarkFlagTestAccept);
89 // Look for IPv4 TCP/UDP connections with TLS/DTLS header
91 u32 = "0>>22&0x3C@ 12>>26&0x3C@ 0&0xFFFF0000=0x16030000 &&"
92 "0>>22&0x3C@ 12>>26&0x3C@ 4&0x00FF0000=0x00010000";
93 CMD_V4("-A %s -p tcp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
94 LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
96 u32 = "0>>22&0x3C@ 8&0xFFFF0000=0x16FE0000 &&"
97 "0>>22&0x3C@ 20&0x00FF0000=0x00010000";
98 CMD_V4("-A %s -p udp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
99 LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
101 // Look for IPv6 TCP/UDP connections with TLS/DTLS header. The IPv6 header
102 // doesn't have an IHL field to shift with, so we have to manually add in
103 // the 40-byte offset at every step.
104 u32 = "52>>26&0x3C@ 40&0xFFFF0000=0x16030000 &&"
105 "52>>26&0x3C@ 44&0x00FF0000=0x00010000";
106 CMD_V6("-A %s -p tcp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
107 LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
109 u32 = "48&0xFFFF0000=0x16FE0000 &&"
110 "60&0x00FF0000=0x00010000";
111 CMD_V6("-A %s -p udp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
112 LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
114 // Skip newly classified connections from above
115 CMD_V4V6("-A %s -m connmark --mark %s -j RETURN", LOCAL_CLEAR_DETECT, connmarkFlagTestAccept);
117 // Handle TCP/UDP payloads that didn't match TLS/DTLS filters above,
118 // which means we've probably found cleartext data. The TCP variant
119 // depends on u32 returning false when we try reading into the message
120 // body to ignore empty ACK packets.
121 u32 = "0>>22&0x3C@ 12>>26&0x3C@ 0&0x0=0x0";
122 CMD_V4("-A %s -p tcp -m state --state ESTABLISHED -m u32 --u32 \"%s\" -j %s",
123 LOCAL_CLEAR_DETECT, u32, LOCAL_CLEAR_CAUGHT);
125 u32 = "52>>26&0x3C@ 40&0x0=0x0";
126 CMD_V6("-A %s -p tcp -m state --state ESTABLISHED -m u32 --u32 \"%s\" -j %s",
127 LOCAL_CLEAR_DETECT, u32, LOCAL_CLEAR_CAUGHT);
129 CMD_V4V6("-A %s -p udp -j %s", LOCAL_CLEAR_DETECT, LOCAL_CLEAR_CAUGHT);
130 CMD_V4V6("COMMIT\n\x04");
132 res |= execIptablesRestore(V4, android::base::Join(v4, '\n'));
133 res |= execIptablesRestore(V6, android::base::Join(v6, '\n'));
142 int StrictController::disableStrict(void) {
143 // Flush any existing rules
144 #define CLEAR_CHAIN(x) StringPrintf(":%s -", (x))
145 std::vector<std::string> commandList = {
147 CLEAR_CHAIN(LOCAL_OUTPUT),
148 CLEAR_CHAIN(LOCAL_PENALTY_LOG),
149 CLEAR_CHAIN(LOCAL_PENALTY_REJECT),
150 CLEAR_CHAIN(LOCAL_CLEAR_CAUGHT),
151 CLEAR_CHAIN(LOCAL_CLEAR_DETECT),
154 const std::string commands = android::base::Join(commandList, '\n');
155 return execIptablesRestore(V4V6, commands);
159 int StrictController::setUidCleartextPenalty(uid_t uid, StrictPenalty penalty) {
161 sprintf(uidStr, "%d", uid);
164 if (penalty == ACCEPT) {
165 // Clean up any old rules
166 execIptables(V4V6, "-D", LOCAL_OUTPUT,
167 "-m", "owner", "--uid-owner", uidStr,
168 "-j", LOCAL_CLEAR_DETECT, NULL);
169 execIptables(V4V6, "-D", LOCAL_CLEAR_CAUGHT,
170 "-m", "owner", "--uid-owner", uidStr,
171 "-j", LOCAL_PENALTY_LOG, NULL);
172 execIptables(V4V6, "-D", LOCAL_CLEAR_CAUGHT,
173 "-m", "owner", "--uid-owner", uidStr,
174 "-j", LOCAL_PENALTY_REJECT, NULL);
177 // Always take a detour to investigate this UID
178 res |= execIptables(V4V6, "-I", LOCAL_OUTPUT,
179 "-m", "owner", "--uid-owner", uidStr,
180 "-j", LOCAL_CLEAR_DETECT, NULL);
182 if (penalty == LOG) {
183 res |= execIptables(V4V6, "-I", LOCAL_CLEAR_CAUGHT,
184 "-m", "owner", "--uid-owner", uidStr,
185 "-j", LOCAL_PENALTY_LOG, NULL);
186 } else if (penalty == REJECT) {
187 res |= execIptables(V4V6, "-I", LOCAL_CLEAR_CAUGHT,
188 "-m", "owner", "--uid-owner", uidStr,
189 "-j", LOCAL_PENALTY_REJECT, NULL);