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