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.
22 #define LOG_TAG "StrictController"
25 #include <cutils/log.h>
27 #include "ConnmarkFlags.h"
28 #include "NetdConstants.h"
29 #include "StrictController.h"
31 auto StrictController::execIptables = ::execIptables;
33 const char* StrictController::LOCAL_OUTPUT = "st_OUTPUT";
34 const char* StrictController::LOCAL_CLEAR_DETECT = "st_clear_detect";
35 const char* StrictController::LOCAL_CLEAR_CAUGHT = "st_clear_caught";
36 const char* StrictController::LOCAL_PENALTY_LOG = "st_penalty_log";
37 const char* StrictController::LOCAL_PENALTY_REJECT = "st_penalty_reject";
39 StrictController::StrictController(void) {
42 int StrictController::enableStrict(void) {
43 char connmarkFlagAccept[16];
44 char connmarkFlagReject[16];
45 char connmarkFlagTestAccept[32];
46 char connmarkFlagTestReject[32];
47 sprintf(connmarkFlagAccept, "0x%x", ConnmarkFlags::STRICT_RESOLVED_ACCEPT);
48 sprintf(connmarkFlagReject, "0x%x", ConnmarkFlags::STRICT_RESOLVED_REJECT);
49 sprintf(connmarkFlagTestAccept, "0x%x/0x%x",
50 ConnmarkFlags::STRICT_RESOLVED_ACCEPT,
51 ConnmarkFlags::STRICT_RESOLVED_ACCEPT);
52 sprintf(connmarkFlagTestReject, "0x%x/0x%x",
53 ConnmarkFlags::STRICT_RESOLVED_REJECT,
54 ConnmarkFlags::STRICT_RESOLVED_REJECT);
60 // Chain triggered when cleartext socket detected and penalty is log
61 res |= execIptables(V4V6, "-N", LOCAL_PENALTY_LOG, NULL);
62 res |= execIptables(V4V6, "-A", LOCAL_PENALTY_LOG,
63 "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
64 res |= execIptables(V4V6, "-A", LOCAL_PENALTY_LOG,
65 "-j", "NFLOG", "--nflog-group", "0", NULL);
67 // Chain triggered when cleartext socket detected and penalty is reject
68 res |= execIptables(V4V6, "-N", LOCAL_PENALTY_REJECT, NULL);
69 res |= execIptables(V4V6, "-A", LOCAL_PENALTY_REJECT,
70 "-j", "CONNMARK", "--or-mark", connmarkFlagReject, NULL);
71 res |= execIptables(V4V6, "-A", LOCAL_PENALTY_REJECT,
72 "-j", "NFLOG", "--nflog-group", "0", NULL);
73 res |= execIptables(V4V6, "-A", LOCAL_PENALTY_REJECT,
74 "-j", "REJECT", NULL);
76 // Create chain to detect non-TLS traffic. We use a high-order
77 // mark bit to keep track of connections that we've already resolved.
78 res |= execIptables(V4V6, "-N", LOCAL_CLEAR_DETECT, NULL);
79 res |= execIptables(V4V6, "-N", LOCAL_CLEAR_CAUGHT, NULL);
81 // Quickly skip connections that we've already resolved
82 res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT,
83 "-m", "connmark", "--mark", connmarkFlagTestReject,
84 "-j", "REJECT", NULL);
85 res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT,
86 "-m", "connmark", "--mark", connmarkFlagTestAccept,
87 "-j", "RETURN", NULL);
89 // Look for IPv4 TCP/UDP connections with TLS/DTLS header
90 res |= execIptables(V4, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
91 "-m", "u32", "--u32", "0>>22&0x3C@ 12>>26&0x3C@ 0&0xFFFF0000=0x16030000 &&"
92 "0>>22&0x3C@ 12>>26&0x3C@ 4&0x00FF0000=0x00010000",
93 "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
94 res |= execIptables(V4, "-A", LOCAL_CLEAR_DETECT, "-p", "udp",
95 "-m", "u32", "--u32", "0>>22&0x3C@ 8&0xFFFF0000=0x16FE0000 &&"
96 "0>>22&0x3C@ 20&0x00FF0000=0x00010000",
97 "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
99 // Look for IPv6 TCP/UDP connections with TLS/DTLS header. The IPv6 header
100 // doesn't have an IHL field to shift with, so we have to manually add in
101 // the 40-byte offset at every step.
102 res |= execIptables(V6, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
103 "-m", "u32", "--u32", "52>>26&0x3C@ 40&0xFFFF0000=0x16030000 &&"
104 "52>>26&0x3C@ 44&0x00FF0000=0x00010000",
105 "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
106 res |= execIptables(V6, "-A", LOCAL_CLEAR_DETECT, "-p", "udp",
107 "-m", "u32", "--u32", "48&0xFFFF0000=0x16FE0000 &&"
108 "60&0x00FF0000=0x00010000",
109 "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
111 // Skip newly classified connections from above
112 res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT,
113 "-m", "connmark", "--mark", connmarkFlagTestAccept,
114 "-j", "RETURN", NULL);
116 // Handle TCP/UDP payloads that didn't match TLS/DTLS filters above,
117 // which means we've probably found cleartext data. The TCP variant
118 // depends on u32 returning false when we try reading into the message
119 // body to ignore empty ACK packets.
120 res |= execIptables(V4, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
121 "-m", "state", "--state", "ESTABLISHED",
122 "-m", "u32", "--u32", "0>>22&0x3C@ 12>>26&0x3C@ 0&0x0=0x0",
123 "-j", LOCAL_CLEAR_CAUGHT, NULL);
124 res |= execIptables(V6, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
125 "-m", "state", "--state", "ESTABLISHED",
126 "-m", "u32", "--u32", "52>>26&0x3C@ 40&0x0=0x0",
127 "-j", LOCAL_CLEAR_CAUGHT, NULL);
129 res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT, "-p", "udp",
130 "-j", LOCAL_CLEAR_CAUGHT, NULL);
135 int StrictController::disableStrict(void) {
138 // Flush any existing rules
139 res |= execIptables(V4V6, "-F", LOCAL_OUTPUT, NULL);
141 res |= execIptables(V4V6, "-F", LOCAL_PENALTY_LOG, NULL);
142 res |= execIptables(V4V6, "-F", LOCAL_PENALTY_REJECT, NULL);
143 res |= execIptables(V4V6, "-F", LOCAL_CLEAR_CAUGHT, NULL);
144 res |= execIptables(V4V6, "-F", LOCAL_CLEAR_DETECT, NULL);
146 res |= execIptables(V4V6, "-X", LOCAL_PENALTY_LOG, NULL);
147 res |= execIptables(V4V6, "-X", LOCAL_PENALTY_REJECT, NULL);
148 res |= execIptables(V4V6, "-X", LOCAL_CLEAR_CAUGHT, NULL);
149 res |= execIptables(V4V6, "-X", LOCAL_CLEAR_DETECT, NULL);
154 int StrictController::setUidCleartextPenalty(uid_t uid, StrictPenalty penalty) {
156 sprintf(uidStr, "%d", uid);
159 if (penalty == ACCEPT) {
160 // Clean up any old rules
161 execIptables(V4V6, "-D", LOCAL_OUTPUT,
162 "-m", "owner", "--uid-owner", uidStr,
163 "-j", LOCAL_CLEAR_DETECT, NULL);
164 execIptables(V4V6, "-D", LOCAL_CLEAR_CAUGHT,
165 "-m", "owner", "--uid-owner", uidStr,
166 "-j", LOCAL_PENALTY_LOG, NULL);
167 execIptables(V4V6, "-D", LOCAL_CLEAR_CAUGHT,
168 "-m", "owner", "--uid-owner", uidStr,
169 "-j", LOCAL_PENALTY_REJECT, NULL);
172 // Always take a detour to investigate this UID
173 res |= execIptables(V4V6, "-I", LOCAL_OUTPUT,
174 "-m", "owner", "--uid-owner", uidStr,
175 "-j", LOCAL_CLEAR_DETECT, NULL);
177 if (penalty == LOG) {
178 res |= execIptables(V4V6, "-I", LOCAL_CLEAR_CAUGHT,
179 "-m", "owner", "--uid-owner", uidStr,
180 "-j", LOCAL_PENALTY_LOG, NULL);
181 } else if (penalty == REJECT) {
182 res |= execIptables(V4V6, "-I", LOCAL_CLEAR_CAUGHT,
183 "-m", "owner", "--uid-owner", uidStr,
184 "-j", LOCAL_PENALTY_REJECT, NULL);