summaryrefslogtreecommitdiff
path: root/netutils_wrappers/NetUtilsWrapper-1.0.cpp
blob: 94c08ff309db04c39d4a4c701a32b991bbe4243e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <regex>
#include <string>

#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <android-base/strings.h>

#define LOG_TAG "NetUtilsWrapper"
#include <log/log.h>

#include "NetUtilsWrapper.h"

#define SYSTEM_DIRNAME  "/system/bin/"

#define OEM_IFACE "[^ ]*oem[0-9]+"
#define RMNET_IFACE "(r_)?rmnet_(data)?[0-9]+"
#define VENDOR_IFACE "(" OEM_IFACE "|" RMNET_IFACE ")"
#define VENDOR_CHAIN "(oem_.*|nm_.*|qcom_.*)"

// List of net utils wrapped by this program
// The list MUST be in descending order of string length
const char *netcmds[] = {
    "ip6tables",
    "iptables",
    "ndc",
    "tc",
    "ip",
    nullptr,
};

// List of regular expressions of expected commands.
const char *EXPECTED_REGEXPS[] = {
#define CMD "^" SYSTEM_DIRNAME
    // Create, delete, and manage OEM networks.
    CMD "ndc network (create|destroy) (oem|handle)[0-9]+( |$)",
    CMD "ndc network interface (add|remove) (oem|handle)[0-9]+ " VENDOR_IFACE,
    CMD "ndc network route (add|remove) (oem|handle)[0-9]+ ",
    CMD "ndc ipfwd (enable|disable) ",
    CMD "ndc ipfwd (add|remove) .*" VENDOR_IFACE,

    // Manage vendor iptables rules.
    CMD "ip(6)?tables -w.* (-A|-D|-F|-I|-N|-X) " VENDOR_CHAIN,
    CMD "ip(6)?tables -w.* (-i|-o) " VENDOR_IFACE,

    // Manage IPsec state.
    CMD "ip xfrm .*",

    // Manage vendor interfaces.
    CMD "tc .* dev " VENDOR_IFACE,
    CMD "ip( -4| -6)? (addr|address) (add|del|delete|flush).* dev " VENDOR_IFACE,

    // Other activities observed on current devices. In future releases, these should be supported
    // in a way that is less likely to interfere with general Android networking behaviour.
    CMD "tc qdisc del dev root",
    CMD "ip( -4| -6)? rule .* goto 13000 prio 11999",
    CMD "ip( -4| -6)? rule .* prio 25000",
    CMD "ip(6)?tables -w .* -j " VENDOR_CHAIN,
    CMD "iptables -w -t mangle -[AD] PREROUTING -m socket --nowildcard --restore-skmark -j ACCEPT",
    CMD "ndc network interface (add|remove) oem[0-9]+$",  // Invalid command: no interface removed.
#undef CMD
};

bool checkExpectedCommand(int argc, char **argv) {
    static bool loggedError = false;
    std::vector<const char*> allArgs(argc);
    for (int i = 0; i < argc; i++) {
        allArgs[i] = argv[i];
    }
    std::string fullCmd = android::base::Join(allArgs, ' ');
    for (size_t i = 0; i < ARRAY_SIZE(EXPECTED_REGEXPS); i++) {
        const std::regex expectedRegexp(EXPECTED_REGEXPS[i], std::regex_constants::extended);
        if (std::regex_search(fullCmd, expectedRegexp)) {
            return true;
        }
    }
    if (!loggedError) {
        ALOGI("Unexpected command: %s", fullCmd.c_str());
        fprintf(stderr, LOG_TAG ": Unexpected command: %s\n", fullCmd.c_str());
        loggedError = true;
    }
    return false;
}


// This is the only gateway for vendor programs to reach net utils.
int doMain(int argc, char **argv) {
    char *progname = argv[0];
    char *basename = nullptr;

    basename = strrchr(progname, '/');
    basename = basename ? basename + 1 : progname;

    for (int i = 0; netcmds[i]; ++i) {
        size_t len = strlen(netcmds[i]);
        if (!strncmp(basename, netcmds[i], len)) {
            // truncate to match netcmds[i]
            basename[len] = '\0';

            // hardcode the path to /system so it cannot be overwritten
            char *cmd;
            if (asprintf(&cmd, "%s%s", SYSTEM_DIRNAME, basename) == -1) {
                perror("asprintf");
                exit(EXIT_FAILURE);
            }
            argv[0] = cmd;
            if (checkExpectedCommand(argc, argv)) {
                execv(cmd, argv);
            }
        }
    }

    // Invalid command. Reject and fail.
    exit(EXIT_FAILURE);
}