* limitations under the License.
*/
+#include <string>
+#include <vector>
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define LOG_TAG "StrictController"
#define LOG_NDEBUG 0
-
#include <cutils/log.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
#include "ConnmarkFlags.h"
#include "NetdConstants.h"
#include "StrictController.h"
+auto StrictController::execIptables = ::execIptables;
+auto StrictController::execIptablesRestore = ::execIptablesRestore;
+
const char* StrictController::LOCAL_OUTPUT = "st_OUTPUT";
const char* StrictController::LOCAL_CLEAR_DETECT = "st_clear_detect";
const char* StrictController::LOCAL_CLEAR_CAUGHT = "st_clear_caught";
const char* StrictController::LOCAL_PENALTY_LOG = "st_penalty_log";
const char* StrictController::LOCAL_PENALTY_REJECT = "st_penalty_reject";
+using android::base::StringPrintf;
+
StrictController::StrictController(void) {
}
ConnmarkFlags::STRICT_RESOLVED_REJECT,
ConnmarkFlags::STRICT_RESOLVED_REJECT);
+ disableStrict();
+
int res = 0;
+ std::vector<std::string> v4, v6;
- disableStrict();
+#define CMD_V4(...) { auto cmd = StringPrintf(__VA_ARGS__); v4.push_back(cmd); }
+#define CMD_V6(...) { auto cmd = StringPrintf(__VA_ARGS__); v6.push_back(cmd); }
+#define CMD_V4V6(...) { CMD_V4(__VA_ARGS__); CMD_V6(__VA_ARGS__); };
+
+ CMD_V4V6("*filter");
// Chain triggered when cleartext socket detected and penalty is log
- res |= execIptables(V4V6, "-N", LOCAL_PENALTY_LOG, NULL);
- res |= execIptables(V4V6, "-A", LOCAL_PENALTY_LOG,
- "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
- res |= execIptables(V4V6, "-A", LOCAL_PENALTY_LOG,
- "-j", "NFLOG", "--nflog-group", "0", NULL);
+ CMD_V4V6("-A %s -j CONNMARK --or-mark %s", LOCAL_PENALTY_LOG, connmarkFlagAccept);
+ CMD_V4V6("-A %s -j NFLOG --nflog-group 0", LOCAL_PENALTY_LOG);
// Chain triggered when cleartext socket detected and penalty is reject
- res |= execIptables(V4V6, "-N", LOCAL_PENALTY_REJECT, NULL);
- res |= execIptables(V4V6, "-A", LOCAL_PENALTY_REJECT,
- "-j", "CONNMARK", "--or-mark", connmarkFlagReject, NULL);
- res |= execIptables(V4V6, "-A", LOCAL_PENALTY_REJECT,
- "-j", "NFLOG", "--nflog-group", "0", NULL);
- res |= execIptables(V4V6, "-A", LOCAL_PENALTY_REJECT,
- "-j", "REJECT", NULL);
-
- // Create chain to detect non-TLS traffic. We use a high-order
- // mark bit to keep track of connections that we've already resolved.
- res |= execIptables(V4V6, "-N", LOCAL_CLEAR_DETECT, NULL);
- res |= execIptables(V4V6, "-N", LOCAL_CLEAR_CAUGHT, NULL);
+ CMD_V4V6("-A %s -j CONNMARK --or-mark %s", LOCAL_PENALTY_REJECT, connmarkFlagReject);
+ CMD_V4V6("-A %s -j NFLOG --nflog-group 0", LOCAL_PENALTY_REJECT);
+ CMD_V4V6("-A %s -j REJECT", LOCAL_PENALTY_REJECT);
+ // We use a high-order mark bit to keep track of connections that we've already resolved.
// Quickly skip connections that we've already resolved
- res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT,
- "-m", "connmark", "--mark", connmarkFlagTestReject,
- "-j", "REJECT", NULL);
- res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT,
- "-m", "connmark", "--mark", connmarkFlagTestAccept,
- "-j", "RETURN", NULL);
+ CMD_V4V6("-A %s -m connmark --mark %s -j REJECT", LOCAL_CLEAR_DETECT, connmarkFlagTestReject);
+ CMD_V4V6("-A %s -m connmark --mark %s -j RETURN", LOCAL_CLEAR_DETECT, connmarkFlagTestAccept);
// Look for IPv4 TCP/UDP connections with TLS/DTLS header
- res |= execIptables(V4, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
- "-m", "u32", "--u32", "0>>22&0x3C@ 12>>26&0x3C@ 0&0xFFFF0000=0x16030000 &&"
- "0>>22&0x3C@ 12>>26&0x3C@ 4&0x00FF0000=0x00010000",
- "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
- res |= execIptables(V4, "-A", LOCAL_CLEAR_DETECT, "-p", "udp",
- "-m", "u32", "--u32", "0>>22&0x3C@ 8&0xFFFF0000=0x16FE0000 &&"
- "0>>22&0x3C@ 20&0x00FF0000=0x00010000",
- "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
+ const char *u32;
+ u32 = "0>>22&0x3C@ 12>>26&0x3C@ 0&0xFFFF0000=0x16030000 &&"
+ "0>>22&0x3C@ 12>>26&0x3C@ 4&0x00FF0000=0x00010000";
+ CMD_V4("-A %s -p tcp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
+ LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
+
+ u32 = "0>>22&0x3C@ 8&0xFFFF0000=0x16FE0000 &&"
+ "0>>22&0x3C@ 20&0x00FF0000=0x00010000";
+ CMD_V4("-A %s -p udp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
+ LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
// Look for IPv6 TCP/UDP connections with TLS/DTLS header. The IPv6 header
// doesn't have an IHL field to shift with, so we have to manually add in
// the 40-byte offset at every step.
- res |= execIptables(V6, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
- "-m", "u32", "--u32", "52>>26&0x3C@ 40&0xFFFF0000=0x16030000 &&"
- "52>>26&0x3C@ 44&0x00FF0000=0x00010000",
- "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
- res |= execIptables(V6, "-A", LOCAL_CLEAR_DETECT, "-p", "udp",
- "-m", "u32", "--u32", "48&0xFFFF0000=0x16FE0000 &&"
- "60&0x00FF0000=0x00010000",
- "-j", "CONNMARK", "--or-mark", connmarkFlagAccept, NULL);
+ u32 = "52>>26&0x3C@ 40&0xFFFF0000=0x16030000 &&"
+ "52>>26&0x3C@ 44&0x00FF0000=0x00010000";
+ CMD_V6("-A %s -p tcp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
+ LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
+
+ u32 = "48&0xFFFF0000=0x16FE0000 &&"
+ "60&0x00FF0000=0x00010000";
+ CMD_V6("-A %s -p udp -m u32 --u32 \"%s\" -j CONNMARK --or-mark %s",
+ LOCAL_CLEAR_DETECT, u32, connmarkFlagAccept);
// Skip newly classified connections from above
- res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT,
- "-m", "connmark", "--mark", connmarkFlagTestAccept,
- "-j", "RETURN", NULL);
+ CMD_V4V6("-A %s -m connmark --mark %s -j RETURN", LOCAL_CLEAR_DETECT, connmarkFlagTestAccept);
// Handle TCP/UDP payloads that didn't match TLS/DTLS filters above,
// which means we've probably found cleartext data. The TCP variant
// depends on u32 returning false when we try reading into the message
// body to ignore empty ACK packets.
- res |= execIptables(V4, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
- "-m", "state", "--state", "ESTABLISHED",
- "-m", "u32", "--u32", "0>>22&0x3C@ 12>>26&0x3C@ 0&0x0=0x0",
- "-j", LOCAL_CLEAR_CAUGHT, NULL);
- res |= execIptables(V6, "-A", LOCAL_CLEAR_DETECT, "-p", "tcp",
- "-m", "state", "--state", "ESTABLISHED",
- "-m", "u32", "--u32", "52>>26&0x3C@ 40&0x0=0x0",
- "-j", LOCAL_CLEAR_CAUGHT, NULL);
-
- res |= execIptables(V4V6, "-A", LOCAL_CLEAR_DETECT, "-p", "udp",
- "-j", LOCAL_CLEAR_CAUGHT, NULL);
+ u32 = "0>>22&0x3C@ 12>>26&0x3C@ 0&0x0=0x0";
+ CMD_V4("-A %s -p tcp -m state --state ESTABLISHED -m u32 --u32 \"%s\" -j %s",
+ LOCAL_CLEAR_DETECT, u32, LOCAL_CLEAR_CAUGHT);
- return res;
-}
-
-int StrictController::disableStrict(void) {
- int res = 0;
+ u32 = "52>>26&0x3C@ 40&0x0=0x0";
+ CMD_V6("-A %s -p tcp -m state --state ESTABLISHED -m u32 --u32 \"%s\" -j %s",
+ LOCAL_CLEAR_DETECT, u32, LOCAL_CLEAR_CAUGHT);
- // Flush any existing rules
- res |= execIptables(V4V6, "-F", LOCAL_OUTPUT, NULL);
+ CMD_V4V6("-A %s -p udp -j %s", LOCAL_CLEAR_DETECT, LOCAL_CLEAR_CAUGHT);
+ CMD_V4V6("COMMIT\n\x04");
- res |= execIptables(V4V6, "-F", LOCAL_PENALTY_LOG, NULL);
- res |= execIptables(V4V6, "-F", LOCAL_PENALTY_REJECT, NULL);
- res |= execIptables(V4V6, "-F", LOCAL_CLEAR_CAUGHT, NULL);
- res |= execIptables(V4V6, "-F", LOCAL_CLEAR_DETECT, NULL);
+ res |= execIptablesRestore(V4, android::base::Join(v4, '\n'));
+ res |= execIptablesRestore(V6, android::base::Join(v6, '\n'));
- res |= execIptables(V4V6, "-X", LOCAL_PENALTY_LOG, NULL);
- res |= execIptables(V4V6, "-X", LOCAL_PENALTY_REJECT, NULL);
- res |= execIptables(V4V6, "-X", LOCAL_CLEAR_CAUGHT, NULL);
- res |= execIptables(V4V6, "-X", LOCAL_CLEAR_DETECT, NULL);
+#undef CMD_V4
+#undef CMD_V6
+#undef CMD_V4V6
return res;
}
+int StrictController::disableStrict(void) {
+ // Flush any existing rules
+#define CLEAR_CHAIN(x) StringPrintf(":%s -", (x))
+ std::vector<std::string> commandList = {
+ "*filter",
+ CLEAR_CHAIN(LOCAL_OUTPUT),
+ CLEAR_CHAIN(LOCAL_PENALTY_LOG),
+ CLEAR_CHAIN(LOCAL_PENALTY_REJECT),
+ CLEAR_CHAIN(LOCAL_CLEAR_CAUGHT),
+ CLEAR_CHAIN(LOCAL_CLEAR_DETECT),
+ "COMMIT\n\x04"
+ };
+ const std::string commands = android::base::Join(commandList, '\n');
+ return execIptablesRestore(V4V6, commands);
+#undef CLEAR_CHAIN
+}
+
int StrictController::setUidCleartextPenalty(uid_t uid, StrictPenalty penalty) {
char uidStr[16];
sprintf(uidStr, "%d", uid);