Snap for 8426163 from e4b5a883015cd7dd8da5d9603498cde4c6db018d to mainline-tzdata2-release
Change-Id: I80f044bf8d3d9009a9b7ad13f0f03f7aefa7fbdb
diff --git a/Android.bp b/Android.bp
index 0838a8d..01a8e77 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,27 +1,6 @@
-package {
- default_applicable_licenses: ["system_netd_license"],
-}
-
-// Added automatically by a large-scale-change
-// See: http://go/android-license-faq
-license {
- name: "system_netd_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- ],
- license_text: [
- "NOTICE",
- ],
-}
-
cc_library_headers {
name: "libnetd_client_headers",
export_include_dirs: ["include"],
- apex_available: [
- "//apex_available:platform",
- "com.android.tethering",
- ],
}
cc_library_headers {
@@ -59,22 +38,12 @@
"google-*",
"misc-*",
"performance-*",
- "-bugprone-macro-parentheses",
"-bugprone-narrowing-conversions", // lots of unsigned -> int conversions
- "-bugprone-unhandled-self-assignment", // found in DnsResolver/stats.pb.h
- "-cert-dcl50-cpp",
"-cert-err34-c", // TODO: re-enable after removing atoi() and sscanf() calls
- "-cert-oop54-cpp", // found in DnsResolver/stats.pb.h
- "-google-default-arguments",
- "-google-explicit-constructor",
- "-google-global-names-in-headers",
"-google-readability-*", // Too pedantic
"-google-runtime-int", // Too many unavoidable warnings due to strtol()
"-google-runtime-references", // Grandfathered usage of pass by non-const reference
"-misc-non-private-member-variables-in-classes", // Also complains about structs
- "-performance-noexcept-move-constructor",
- "-performance-unnecessary-value-param",
- "-performance-no-int-to-ptr",
],
tidy_flags: [
"-warnings-as-errors="
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
index 94e70d5..7d617ec 100644
--- a/OWNERS
+++ b/OWNERS
@@ -8,4 +8,3 @@
reminv@google.com
satk@google.com
xiaom@google.com
-yumike@google.com
\ No newline at end of file
diff --git a/bpf_progs/Android.bp b/bpf_progs/Android.bp
index 1311ca9..7b1f015 100644
--- a/bpf_progs/Android.bp
+++ b/bpf_progs/Android.bp
@@ -14,15 +14,6 @@
// limitations under the License.
//
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_library_headers {
name: "netd_bpf_progs_headers",
export_include_dirs: ["."],
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index 31e0522..e758692 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -37,7 +37,7 @@
// From kernel:include/net/ip.h
#define IP_DF 0x4000 // Flag: "Don't Fragment"
-DEFINE_BPF_MAP(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16)
+DEFINE_BPF_MAP(clat_ingress_map, HASH, ClatIngressKey, ClatIngressValue, 16)
static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet) {
const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
@@ -46,9 +46,6 @@
const struct ethhdr* const eth = is_ethernet ? data : NULL; // used iff is_ethernet
const struct ipv6hdr* const ip6 = is_ethernet ? (void*)(eth + 1) : data;
- // Require ethernet dst mac address to be our unicast address.
- if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_OK;
-
// Must be meta-ethernet IPv6 frame
if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
@@ -75,7 +72,7 @@
return TC_ACT_OK;
}
- ClatIngress6Key k = {
+ ClatIngressKey k = {
.iif = skb->ifindex,
.pfx96.in6_u.u6_addr32 =
{
@@ -86,7 +83,7 @@
.local6 = ip6->daddr,
};
- ClatIngress6Value* v = bpf_clat_ingress6_map_lookup_elem(&k);
+ ClatIngressValue* v = bpf_clat_ingress_map_lookup_elem(&k);
if (!v) return TC_ACT_OK;
@@ -179,25 +176,25 @@
return TC_ACT_OK;
}
-DEFINE_BPF_PROG("schedcls/ingress6/clat_ether", AID_ROOT, AID_ROOT, sched_cls_ingress6_clat_ether)
-(struct __sk_buff* skb) {
+SEC("schedcls/ingress/clat_ether")
+int sched_cls_ingress_clat_ether(struct __sk_buff* skb) {
return nat64(skb, true);
}
-DEFINE_BPF_PROG("schedcls/ingress6/clat_rawip", AID_ROOT, AID_ROOT, sched_cls_ingress6_clat_rawip)
-(struct __sk_buff* skb) {
+SEC("schedcls/ingress/clat_rawip")
+int sched_cls_ingress_clat_rawip(struct __sk_buff* skb) {
return nat64(skb, false);
}
-DEFINE_BPF_MAP(clat_egress4_map, HASH, ClatEgress4Key, ClatEgress4Value, 16)
+DEFINE_BPF_MAP(clat_egress_map, HASH, ClatEgressKey, ClatEgressValue, 16)
-DEFINE_BPF_PROG("schedcls/egress4/clat_ether", AID_ROOT, AID_ROOT, sched_cls_egress4_clat_ether)
-(struct __sk_buff* skb) {
+SEC("schedcls/egress/clat_ether")
+int sched_cls_egress_clat_ether(struct __sk_buff* skb) {
return TC_ACT_OK;
}
-DEFINE_BPF_PROG("schedcls/egress4/clat_rawip", AID_ROOT, AID_ROOT, sched_cls_egress4_clat_rawip)
-(struct __sk_buff* skb) {
+SEC("schedcls/egress/clat_rawip")
+int sched_cls_egress_clat_rawip(struct __sk_buff* skb) {
void* data = (void*)(long)skb->data;
const void* data_end = (void*)(long)skb->data_end;
const struct iphdr* const ip4 = data;
@@ -251,12 +248,12 @@
return TC_ACT_OK;
}
- ClatEgress4Key k = {
+ ClatEgressKey k = {
.iif = skb->ifindex,
.local4.s_addr = ip4->saddr,
};
- ClatEgress4Value* v = bpf_clat_egress4_map_lookup_elem(&k);
+ ClatEgressValue* v = bpf_clat_egress_map_lookup_elem(&k);
if (!v) return TC_ACT_OK;
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index e9e1477..f347028 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -203,12 +203,9 @@
if ((enabledRules & POWERSAVE_MATCH) && !(uidRules & POWERSAVE_MATCH)) {
return BPF_DROP;
}
- if ((enabledRules & RESTRICTED_MATCH) && !(uidRules & RESTRICTED_MATCH)) {
- return BPF_DROP;
- }
}
if (direction == BPF_INGRESS && (uidRules & IIF_MATCH)) {
- // Drops packets not coming from lo nor the allowlisted interface
+ // Drops packets not coming from lo nor the whitelisted interface
if (allowed_iif && skb->ifindex != 1 && skb->ifindex != allowed_iif) {
return BPF_DROP_UNLESS_DNS;
}
@@ -283,13 +280,13 @@
return match;
}
-DEFINE_BPF_PROG("cgroupskb/ingress/stats", AID_ROOT, AID_ROOT, bpf_cgroup_ingress)
-(struct __sk_buff* skb) {
+SEC("cgroupskb/ingress/stats")
+int bpf_cgroup_ingress(struct __sk_buff* skb) {
return bpf_traffic_account(skb, BPF_INGRESS);
}
-DEFINE_BPF_PROG("cgroupskb/egress/stats", AID_ROOT, AID_ROOT, bpf_cgroup_egress)
-(struct __sk_buff* skb) {
+SEC("cgroupskb/egress/stats")
+int bpf_cgroup_egress(struct __sk_buff* skb) {
return bpf_traffic_account(skb, BPF_EGRESS);
}
@@ -318,7 +315,7 @@
return BPF_MATCH;
}
-DEFINE_BPF_PROG("skfilter/allowlist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_allowlist_prog)
+DEFINE_BPF_PROG("skfilter/whitelist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_whitelist_prog)
(struct __sk_buff* skb) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
if (is_system_uid(sock_uid)) return BPF_MATCH;
@@ -330,16 +327,16 @@
if ((sock_uid == 65534) && !bpf_get_socket_cookie(skb) && is_received_skb(skb))
return BPF_MATCH;
- UidOwnerValue* allowlistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
- if (allowlistMatch) return allowlistMatch->rule & HAPPY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
+ UidOwnerValue* whitelistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
+ if (whitelistMatch) return whitelistMatch->rule & HAPPY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
return BPF_NOMATCH;
}
-DEFINE_BPF_PROG("skfilter/denylist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_denylist_prog)
+DEFINE_BPF_PROG("skfilter/blacklist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_blacklist_prog)
(struct __sk_buff* skb) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
- UidOwnerValue* denylistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
- if (denylistMatch) return denylistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
+ UidOwnerValue* blacklistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
+ if (blacklistMatch) return blacklistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
return BPF_NOMATCH;
}
diff --git a/client/Android.bp b/client/Android.bp
index b8eb56c..53afc97 100644
--- a/client/Android.bp
+++ b/client/Android.bp
@@ -12,15 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_library {
name: "libnetd_client",
srcs: [
@@ -31,6 +22,7 @@
"dnsproxyd_protocol_headers", // NETID_USE_LOCAL_NAMESERVERS
"libnetd_client_headers",
"libbase_headers", // for unique_fd.h
+ "libnetd_resolv_headers",
],
export_header_lib_headers: ["libnetd_client_headers"],
include_dirs: [
@@ -40,10 +32,6 @@
sanitize: {
cfi: true,
},
- apex_available: [
- "//apex_available:platform",
- "com.android.tethering",
- ],
}
cc_test {
@@ -56,13 +44,16 @@
include_dirs: [
"system/netd/include",
],
+ header_libs: [
+ "libnetd_resolv_headers",
+ ],
static_libs: [
"libgmock",
"libbase",
"libnetd_client",
],
sanitize: {
- address: false,
+ address: true,
recover: [ "all" ],
},
}
diff --git a/include/binder_utils/BinderUtil.h b/include/binder_utils/BinderUtil.h
index 469fa68..6b41465 100644
--- a/include/binder_utils/BinderUtil.h
+++ b/include/binder_utils/BinderUtil.h
@@ -16,8 +16,9 @@
#pragma once
-#include <android-base/strings.h>
-#include <fmt/format.h>
+#include <android-base/stringprintf.h>
+#include <json/value.h>
+#include <json/writer.h>
#ifdef ANDROID_BINDER_STATUS_H
#define IS_BINDER_OK(__ex__) (__ex__ == ::android::binder::Status::EX_NONE)
@@ -58,26 +59,31 @@
using LogFn = std::function<void(const std::string& msg)>;
-template <typename LogType>
-void binderCallLogFn(const LogType& log, const LogFn& logFn) {
+void binderCallLogFn(const Json::Value& logTransaction, const LogFn& logFn) {
using namespace std::string_literals;
bool hasReturnArgs;
std::string output;
+ const Json::Value& returnArgs = logTransaction["_aidl_return"];
+ const Json::Value& inputArgsArray = logTransaction["input_args"];
- hasReturnArgs = !log.result.empty();
- output.append(log.method_name + "("s);
+ hasReturnArgs = !returnArgs.empty();
+ output.append(logTransaction["method_name"].asString() + "("s);
// input args
- for (size_t i = 0; i < log.input_args.size(); ++i) {
- output.append(log.input_args[i].second);
- if (i != log.input_args.size() - 1) {
+ Json::FastWriter fastWriter;
+ fastWriter.omitEndingLineFeed();
+ for (Json::Value::ArrayIndex i = 0; i < inputArgsArray.size(); ++i) {
+ std::string value = fastWriter.write(inputArgsArray[i]["value"]);
+ output.append(value);
+ if (i != inputArgsArray.size() - 1) {
output.append(", "s);
}
}
output.append(")"s);
- const int exceptionCode = TO_EXCEPTION(log.exception_code);
+ const int exceptionCode =
+ TO_EXCEPTION(logTransaction["binder_status"]["exception_code"].asInt());
if (hasReturnArgs || !IS_BINDER_OK(exceptionCode)) {
output.append(" -> "s);
@@ -86,17 +92,18 @@
// return status
if (!IS_BINDER_OK(exceptionCode)) {
// an exception occurred
- const int errCode = log.service_specific_error_code;
- output.append(fmt::format("{}({}, \"{}\")", exceptionToString(exceptionCode),
- (errCode != 0) ? errCode : exceptionCode, log.exception_message));
+ const int errCode = logTransaction["binder_status"]["service_specific_error_code"].asInt();
+ output.append(::android::base::StringPrintf(
+ "%s(%d, \"%s\")", exceptionToString(exceptionCode).c_str(),
+ (errCode != 0) ? errCode : exceptionCode,
+ logTransaction["binder_status"]["exception_message"].asString().c_str()));
}
// return args
if (hasReturnArgs) {
- output.append("{" + log.result + "}");
+ output.append(::android::base::StringPrintf("{%s}", fastWriter.write(returnArgs).c_str()));
}
// duration time
- output.append(fmt::format(" <{:.2f}ms>", log.duration_ms));
-
- // escape newline characters to avoid multiline log entries
- logFn(::android::base::StringReplace(output, "\n", "\\n", true));
+ output.append(
+ ::android::base::StringPrintf(" <%.2fms>", logTransaction["duration_ms"].asFloat()));
+ logFn(output);
}
diff --git a/libnetdbpf/Android.bp b/libnetdbpf/Android.bp
index 7c0207c..72e0fec 100644
--- a/libnetdbpf/Android.bp
+++ b/libnetdbpf/Android.bp
@@ -14,15 +14,6 @@
// limitations under the License.
//
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_library {
name: "libnetdbpf",
vendor_available: false,
diff --git a/libnetdbpf/BpfNetworkStatsTest.cpp b/libnetdbpf/BpfNetworkStatsTest.cpp
index fb8f0ec..a9581ce 100644
--- a/libnetdbpf/BpfNetworkStatsTest.cpp
+++ b/libnetdbpf/BpfNetworkStatsTest.cpp
@@ -78,6 +78,7 @@
BpfMap<uint32_t, StatsValue> mFakeIfaceStatsMap;
void SetUp() {
+ SKIP_IF_BPF_NOT_SUPPORTED;
ASSERT_EQ(0, setrlimitForTest());
mFakeCookieTagMap = BpfMap<uint64_t, UidTagValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
@@ -139,6 +140,8 @@
// TEST to verify the behavior of bpf map when cocurrent deletion happens when
// iterating the same map.
TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
for (int i = 0; i < 5; i++) {
uint64_t cookie = i + 1;
UidTagValue tag = {.uid = TEST_UID1, .tag = TEST_TAG};
@@ -168,6 +171,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestBpfIterateMap) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
for (int i = 0; i < 5; i++) {
uint64_t cookie = i + 1;
UidTagValue tag = {.uid = TEST_UID1, .tag = TEST_TAG};
@@ -188,6 +193,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestUidStatsNoTraffic) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
StatsValue value1 = {
.rxPackets = 0,
.rxBytes = 0,
@@ -200,6 +207,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -240,6 +249,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -283,6 +294,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
StatsValue value1 = {
@@ -318,6 +331,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
StatsValue value1 = {
@@ -353,6 +368,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
StatsValue value1 = {
.rxPackets = TEST_PACKET0,
@@ -395,6 +412,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -432,6 +451,8 @@
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortedAndGrouped) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
// Create iface indexes with duplicate iface name.
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
@@ -522,6 +543,8 @@
// Test to verify that subtract overflow will not be triggered by the compare function invoked from
// sorting. See http:/b/119193941.
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortAndOverflow) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
StatsValue value1 = {
diff --git a/libnetdbpf/include/netdbpf/bpf_shared.h b/libnetdbpf/include/netdbpf/bpf_shared.h
index 2fcb612..6f31879 100644
--- a/libnetdbpf/include/netdbpf/bpf_shared.h
+++ b/libnetdbpf/include/netdbpf/bpf_shared.h
@@ -14,26 +14,20 @@
* limitations under the License.
*/
-#pragma once
+#ifndef NETDBPF_BPF_SHARED_H
+#define NETDBPF_BPF_SHARED_H
-#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <netdutils/UidConstants.h>
-// This header file is shared by eBPF kernel programs (C) and netd (C++) and
-// some of the maps are also accessed directly from Java mainline module code.
-//
-// Hence: explicitly pad all relevant structures and assert that their size
-// is the sum of the sizes of their fields.
-#define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")
+// This header file is shared by eBPF kernel programs and netd
typedef struct {
uint32_t uid;
uint32_t tag;
} UidTagValue;
-STRUCT_SIZE(UidTagValue, 2 * 4); // 8
typedef struct {
uint32_t uid;
@@ -41,7 +35,6 @@
uint32_t counterSet;
uint32_t ifaceIndex;
} StatsKey;
-STRUCT_SIZE(StatsKey, 4 * 4); // 16
typedef struct {
uint64_t rxPackets;
@@ -49,12 +42,10 @@
uint64_t txPackets;
uint64_t txBytes;
} StatsValue;
-STRUCT_SIZE(StatsValue, 4 * 8); // 32
typedef struct {
char name[IFNAMSIZ];
} IfaceValue;
-STRUCT_SIZE(IfaceValue, 16);
typedef struct {
uint64_t rxBytes;
@@ -98,26 +89,26 @@
const int CONFIGURATION_MAP_SIZE = 2;
const int UID_OWNER_MAP_SIZE = 2000;
-#define BPF_PATH "/sys/fs/bpf/"
+#define BPF_PATH "/sys/fs/bpf"
-#define BPF_EGRESS_PROG_PATH BPF_PATH "prog_netd_cgroupskb_egress_stats"
-#define BPF_INGRESS_PROG_PATH BPF_PATH "prog_netd_cgroupskb_ingress_stats"
-#define XT_BPF_INGRESS_PROG_PATH BPF_PATH "prog_netd_skfilter_ingress_xtbpf"
-#define XT_BPF_EGRESS_PROG_PATH BPF_PATH "prog_netd_skfilter_egress_xtbpf"
-#define XT_BPF_ALLOWLIST_PROG_PATH BPF_PATH "prog_netd_skfilter_allowlist_xtbpf"
-#define XT_BPF_DENYLIST_PROG_PATH BPF_PATH "prog_netd_skfilter_denylist_xtbpf"
-#define CGROUP_SOCKET_PROG_PATH BPF_PATH "prog_netd_cgroupsock_inet_create"
+#define BPF_EGRESS_PROG_PATH BPF_PATH "/prog_netd_cgroupskb_egress_stats"
+#define BPF_INGRESS_PROG_PATH BPF_PATH "/prog_netd_cgroupskb_ingress_stats"
+#define XT_BPF_INGRESS_PROG_PATH BPF_PATH "/prog_netd_skfilter_ingress_xtbpf"
+#define XT_BPF_EGRESS_PROG_PATH BPF_PATH "/prog_netd_skfilter_egress_xtbpf"
+#define XT_BPF_WHITELIST_PROG_PATH BPF_PATH "/prog_netd_skfilter_whitelist_xtbpf"
+#define XT_BPF_BLACKLIST_PROG_PATH BPF_PATH "/prog_netd_skfilter_blacklist_xtbpf"
+#define CGROUP_SOCKET_PROG_PATH BPF_PATH "/prog_netd_cgroupsock_inet_create"
-#define COOKIE_TAG_MAP_PATH BPF_PATH "map_netd_cookie_tag_map"
-#define UID_COUNTERSET_MAP_PATH BPF_PATH "map_netd_uid_counterset_map"
-#define APP_UID_STATS_MAP_PATH BPF_PATH "map_netd_app_uid_stats_map"
-#define STATS_MAP_A_PATH BPF_PATH "map_netd_stats_map_A"
-#define STATS_MAP_B_PATH BPF_PATH "map_netd_stats_map_B"
-#define IFACE_INDEX_NAME_MAP_PATH BPF_PATH "map_netd_iface_index_name_map"
-#define IFACE_STATS_MAP_PATH BPF_PATH "map_netd_iface_stats_map"
-#define CONFIGURATION_MAP_PATH BPF_PATH "map_netd_configuration_map"
-#define UID_OWNER_MAP_PATH BPF_PATH "map_netd_uid_owner_map"
-#define UID_PERMISSION_MAP_PATH BPF_PATH "map_netd_uid_permission_map"
+#define COOKIE_TAG_MAP_PATH BPF_PATH "/map_netd_cookie_tag_map"
+#define UID_COUNTERSET_MAP_PATH BPF_PATH "/map_netd_uid_counterset_map"
+#define APP_UID_STATS_MAP_PATH BPF_PATH "/map_netd_app_uid_stats_map"
+#define STATS_MAP_A_PATH BPF_PATH "/map_netd_stats_map_A"
+#define STATS_MAP_B_PATH BPF_PATH "/map_netd_stats_map_B"
+#define IFACE_INDEX_NAME_MAP_PATH BPF_PATH "/map_netd_iface_index_name_map"
+#define IFACE_STATS_MAP_PATH BPF_PATH "/map_netd_iface_stats_map"
+#define CONFIGURATION_MAP_PATH BPF_PATH "/map_netd_configuration_map"
+#define UID_OWNER_MAP_PATH BPF_PATH "/map_netd_uid_owner_map"
+#define UID_PERMISSION_MAP_PATH BPF_PATH "/map_netd_uid_permission_map"
enum UidOwnerMatchType {
NO_MATCH = 0,
@@ -126,8 +117,7 @@
DOZABLE_MATCH = (1 << 2),
STANDBY_MATCH = (1 << 3),
POWERSAVE_MATCH = (1 << 4),
- RESTRICTED_MATCH = (1 << 5),
- IIF_MATCH = (1 << 6),
+ IIF_MATCH = (1 << 5),
};
enum BpfPermissionMatch {
@@ -151,55 +141,84 @@
// Allowed interface index. Only applicable if IIF_MATCH is set in the rule bitmask above.
uint32_t iif;
// A bitmask of enum values in UidOwnerMatchType.
- uint32_t rule;
+ uint8_t rule;
} UidOwnerValue;
-STRUCT_SIZE(UidOwnerValue, 2 * 4); // 8
#define UID_RULES_CONFIGURATION_KEY 1
#define CURRENT_STATS_MAP_CONFIGURATION_KEY 2
-#define CLAT_INGRESS6_PROG_RAWIP_NAME "prog_clatd_schedcls_ingress6_clat_rawip"
-#define CLAT_INGRESS6_PROG_ETHER_NAME "prog_clatd_schedcls_ingress6_clat_ether"
+#define CLAT_INGRESS_PROG_RAWIP_NAME "prog_clatd_schedcls_ingress_clat_rawip"
+#define CLAT_INGRESS_PROG_ETHER_NAME "prog_clatd_schedcls_ingress_clat_ether"
-#define CLAT_INGRESS6_PROG_RAWIP_PATH BPF_PATH CLAT_INGRESS6_PROG_RAWIP_NAME
-#define CLAT_INGRESS6_PROG_ETHER_PATH BPF_PATH CLAT_INGRESS6_PROG_ETHER_NAME
+#define CLAT_INGRESS_PROG_RAWIP_PATH BPF_PATH "/" CLAT_INGRESS_PROG_RAWIP_NAME
+#define CLAT_INGRESS_PROG_ETHER_PATH BPF_PATH "/" CLAT_INGRESS_PROG_ETHER_NAME
-#define CLAT_INGRESS6_MAP_PATH BPF_PATH "map_clatd_clat_ingress6_map"
+#define CLAT_INGRESS_MAP_PATH BPF_PATH "/map_clatd_clat_ingress_map"
typedef struct {
uint32_t iif; // The input interface index
struct in6_addr pfx96; // The source /96 nat64 prefix, bottom 32 bits must be 0
struct in6_addr local6; // The full 128-bits of the destination IPv6 address
-} ClatIngress6Key;
-STRUCT_SIZE(ClatIngress6Key, 4 + 2 * 16); // 36
+} ClatIngressKey;
typedef struct {
uint32_t oif; // The output interface to redirect to (0 means don't redirect)
struct in_addr local4; // The destination IPv4 address
-} ClatIngress6Value;
-STRUCT_SIZE(ClatIngress6Value, 4 + 4); // 8
+} ClatIngressValue;
-#define CLAT_EGRESS4_PROG_RAWIP_NAME "prog_clatd_schedcls_egress4_clat_rawip"
-#define CLAT_EGRESS4_PROG_ETHER_NAME "prog_clatd_schedcls_egress4_clat_ether"
+#define CLAT_EGRESS_PROG_RAWIP_NAME "prog_clatd_schedcls_egress_clat_rawip"
+#define CLAT_EGRESS_PROG_ETHER_NAME "prog_clatd_schedcls_egress_clat_ether"
-#define CLAT_EGRESS4_PROG_RAWIP_PATH BPF_PATH CLAT_EGRESS4_PROG_RAWIP_NAME
-#define CLAT_EGRESS4_PROG_ETHER_PATH BPF_PATH CLAT_EGRESS4_PROG_ETHER_NAME
+#define CLAT_EGRESS_PROG_RAWIP_PATH BPF_PATH "/" CLAT_EGRESS_PROG_RAWIP_NAME
+#define CLAT_EGRESS_PROG_ETHER_PATH BPF_PATH "/" CLAT_EGRESS_PROG_ETHER_NAME
-#define CLAT_EGRESS4_MAP_PATH BPF_PATH "map_clatd_clat_egress4_map"
+#define CLAT_EGRESS_MAP_PATH BPF_PATH "/map_clatd_clat_egress_map"
typedef struct {
uint32_t iif; // The input interface index
struct in_addr local4; // The source IPv4 address
-} ClatEgress4Key;
-STRUCT_SIZE(ClatEgress4Key, 4 + 4); // 8
+} ClatEgressKey;
typedef struct {
uint32_t oif; // The output interface to redirect to
struct in6_addr local6; // The full 128-bits of the source IPv6 address
struct in6_addr pfx96; // The destination /96 nat64 prefix, bottom 32 bits must be 0
bool oifIsEthernet; // Whether the output interface requires ethernet header
- uint8_t pad[3];
-} ClatEgress4Value;
-STRUCT_SIZE(ClatEgress4Value, 4 + 2 * 16 + 1 + 3); // 40
+} ClatEgressValue;
-#undef STRUCT_SIZE
+#define TETHER_INGRESS_PROG_RAWIP_NAME "prog_offload_schedcls_ingress_tether_rawip"
+#define TETHER_INGRESS_PROG_ETHER_NAME "prog_offload_schedcls_ingress_tether_ether"
+
+#define TETHER_INGRESS_PROG_RAWIP_PATH BPF_PATH "/" TETHER_INGRESS_PROG_RAWIP_NAME
+#define TETHER_INGRESS_PROG_ETHER_PATH BPF_PATH "/" TETHER_INGRESS_PROG_ETHER_NAME
+
+#define TETHER_INGRESS_MAP_PATH BPF_PATH "/map_offload_tether_ingress_map"
+
+typedef struct {
+ uint32_t iif; // The input interface index
+ struct in6_addr neigh6; // The destination IPv6 address
+} TetherIngressKey;
+
+typedef struct {
+ uint32_t oif; // The output interface to redirect to
+ // For now tethering offload only needs to support downstreams that use 6-byte MAC addresses,
+ // because all downstream types that are currently supported (WiFi, USB, Bluetooth and
+ // Ethernet) have 6-byte MAC addresses.
+ struct ethhdr macHeader; // includes dst/src mac and ethertype
+ uint16_t pmtu; // The maximum L3 output path/route mtu
+} TetherIngressValue;
+
+#define TETHER_STATS_MAP_PATH BPF_PATH "/map_offload_tether_stats_map"
+
+typedef struct {
+ uint64_t rxPackets;
+ uint64_t rxBytes;
+ uint64_t rxErrors;
+ uint64_t txPackets;
+ uint64_t txBytes;
+ uint64_t txErrors;
+} TetherStatsValue;
+
+#define TETHER_LIMIT_MAP_PATH BPF_PATH "/map_offload_tether_limit_map"
+
+#endif // NETDBPF_BPF_SHARED_H
diff --git a/libnetdutils/Android.bp b/libnetdutils/Android.bp
index 31f2c53..00bdc74 100644
--- a/libnetdutils/Android.bp
+++ b/libnetdutils/Android.bp
@@ -1,12 +1,3 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_library {
name: "libnetdutils",
srcs: [
@@ -53,6 +44,7 @@
"InternetAddressesTest.cpp",
"LogTest.cpp",
"MemBlockTest.cpp",
+ "OperationLimiterTest.cpp",
"SliceTest.cpp",
"StatusTest.cpp",
"SyscallsTest.cpp",
diff --git a/libnetdutils/OperationLimiterTest.cpp b/libnetdutils/OperationLimiterTest.cpp
new file mode 100644
index 0000000..8d72d75
--- /dev/null
+++ b/libnetdutils/OperationLimiterTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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 "netdutils/OperationLimiter.h"
+
+#include <gtest/gtest-spi.h>
+
+namespace android {
+namespace netdutils {
+
+TEST(OperationLimiter, limits) {
+ OperationLimiter<int> limiter(3);
+
+ EXPECT_TRUE(limiter.start(42));
+ EXPECT_TRUE(limiter.start(42));
+ EXPECT_TRUE(limiter.start(42));
+
+ // Limit reached... calling any number of times should have no effect.
+ EXPECT_FALSE(limiter.start(42));
+ EXPECT_FALSE(limiter.start(42));
+ EXPECT_FALSE(limiter.start(42));
+
+ // Finishing a single operations is enough for starting a new one...
+ limiter.finish(42);
+ EXPECT_TRUE(limiter.start(42));
+
+ // ...but not two!
+ EXPECT_FALSE(limiter.start(42));
+
+ // Different ids should still have quota...
+ EXPECT_TRUE(limiter.start(666));
+ limiter.finish(666);
+
+ // Finish all pending operations
+ limiter.finish(42);
+ limiter.finish(42);
+ limiter.finish(42);
+}
+
+TEST(OperationLimiter, finishWithoutStart) {
+ OperationLimiter<int> limiter(1);
+
+ // Will output a LOG(FATAL_WITHOUT_ABORT), but we have no way to probe this.
+ limiter.finish(42);
+
+ // This will ensure that the finish() above didn't set a negative value.
+ EXPECT_TRUE(limiter.start(42));
+ EXPECT_FALSE(limiter.start(42));
+}
+
+TEST(OperationLimiter, destroyWithActiveOperations) {
+ // The death message doesn't seem to be captured on Android.
+ EXPECT_DEBUG_DEATH({
+ OperationLimiter<int> limiter(3);
+ limiter.start(42);
+ }, "" /* "active operations */);
+}
+
+} // namespace netdutils
+} // namespace android
diff --git a/libnetdutils/include/netdutils/OperationLimiter.h b/libnetdutils/include/netdutils/OperationLimiter.h
new file mode 100644
index 0000000..992a849
--- /dev/null
+++ b/libnetdutils/include/netdutils/OperationLimiter.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef NETUTILS_OPERATIONLIMITER_H
+#define NETUTILS_OPERATIONLIMITER_H
+
+#include <mutex>
+#include <unordered_map>
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+
+namespace android {
+namespace netdutils {
+
+// Tracks the number of operations in progress on behalf of a particular key or
+// ID, rejecting further attempts to start new operations after a configurable
+// limit has been reached.
+//
+// The intended usage pattern is:
+// OperationLimiter<UserId> connections_per_user;
+// ...
+// // Before opening a new connection
+// if (!limiter.start(user)) {
+// return error;
+// } else {
+// // open the connection
+// // ...do some work...
+// // close the connection
+// limiter.finish(user);
+// }
+//
+// This class is thread-safe.
+template<typename KeyType>
+class OperationLimiter {
+public:
+ explicit OperationLimiter(int limit) : mLimitPerKey(limit) {}
+
+ ~OperationLimiter() {
+ DCHECK(mCounters.empty())
+ << "Destroying OperationLimiter with active operations";
+ }
+
+ // Returns false if |key| has reached the maximum number of concurrent
+ // operations, otherwise increments the counter and returns true.
+ //
+ // Note: each successful start(key) must be matched by exactly one call to
+ // finish(key).
+ bool start(KeyType key) EXCLUDES(mMutex) {
+ std::lock_guard lock(mMutex);
+ auto& cnt = mCounters[key]; // operator[] creates new entries as needed.
+ if (cnt >= mLimitPerKey) {
+ // Oh, no!
+ return false;
+ }
+ ++cnt;
+ return true;
+ }
+
+ // Decrements the number of operations in progress accounted to |key|.
+ // See usage notes on start().
+ void finish(KeyType key) EXCLUDES(mMutex) {
+ std::lock_guard lock(mMutex);
+ auto it = mCounters.find(key);
+ if (it == mCounters.end()) {
+ LOG(FATAL_WITHOUT_ABORT) << "Decremented non-existent counter for key=" << key;
+ return;
+ }
+ auto& cnt = it->second;
+ --cnt;
+ if (cnt <= 0) {
+ // Cleanup counters once they drop down to zero.
+ mCounters.erase(it);
+ }
+ }
+
+private:
+ // Protects access to the map below.
+ std::mutex mMutex;
+
+ // Tracks the number of outstanding queries by key.
+ std::unordered_map<KeyType, int> mCounters GUARDED_BY(mMutex);
+
+ // Maximum number of outstanding queries from a single key.
+ const int mLimitPerKey;
+};
+
+} // namespace netdutils
+} // namespace android
+
+#endif // NETUTILS_OPERATIONLIMITER_H
diff --git a/netutils_wrappers/Android.bp b/netutils_wrappers/Android.bp
index fdf802f..af7d8c3 100644
--- a/netutils_wrappers/Android.bp
+++ b/netutils_wrappers/Android.bp
@@ -1,12 +1,3 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_binary {
name: "netutils-wrapper-1.0",
defaults: ["netd_defaults"],
@@ -32,7 +23,6 @@
],
sanitize: {
cfi: true,
- memtag_heap: true,
},
}
diff --git a/netutils_wrappers/NetUtilsWrapper-1.0.cpp b/netutils_wrappers/NetUtilsWrapper-1.0.cpp
index d81b0ec..cdc454e 100644
--- a/netutils_wrappers/NetUtilsWrapper-1.0.cpp
+++ b/netutils_wrappers/NetUtilsWrapper-1.0.cpp
@@ -73,6 +73,8 @@
// 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.
diff --git a/server/Android.bp b/server/Android.bp
index 18042ae..8fc0d03 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -1,10 +1,125 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
+java_library {
+ name: "netd_aidl_interface-lateststable-java",
+ sdk_version: "system_current",
+ min_sdk_version: "29",
+ static_libs: [
+ "netd_aidl_interface-java",
+ ],
+ apex_available: [
+ "//apex_available:platform", // used from services.net
+ "com.android.bluetooth.updatable",
+ "com.android.tethering",
+ "com.android.wifi",
+ ],
+}
+
+cc_library_static {
+ name: "netd_event_listener_interface-lateststable-ndk_platform",
+ whole_static_libs: [
+ "netd_event_listener_interface-ndk_platform",
+ ],
+ apex_available: [
+ "com.android.resolv",
+ ],
+ min_sdk_version: "29",
+}
+
+cc_library_static {
+ name: "netd_aidl_interface-lateststable-ndk_platform",
+ whole_static_libs: [
+ "netd_aidl_interface-ndk_platform",
+ ],
+ apex_available: [
+ "com.android.resolv",
+ ],
+ min_sdk_version: "29",
+}
+
+cc_library_static {
+ name: "netd_aidl_interface-lateststable-cpp",
+ whole_static_libs: [
+ "netd_aidl_interface-cpp",
+ ],
+}
+
+aidl_interface {
+ name: "netd_aidl_interface",
+ local_include_dir: "binder",
+ srcs: [
+ "binder/android/net/INetd.aidl",
+ // AIDL interface that callers can implement to receive networking events from netd.
+ "binder/android/net/INetdUnsolicitedEventListener.aidl",
+ "binder/android/net/InterfaceConfigurationParcel.aidl",
+ "binder/android/net/MarkMaskParcel.aidl",
+ "binder/android/net/RouteInfoParcel.aidl",
+ "binder/android/net/TetherConfigParcel.aidl",
+ "binder/android/net/TetherOffloadRuleParcel.aidl",
+ "binder/android/net/TetherStatsParcel.aidl",
+ "binder/android/net/UidRangeParcel.aidl",
+ ],
+ backend: {
+ cpp: {
+ gen_log: true,
+ },
+ java: {
+ // TODO: Remove apex_available and restrict visibility to only mainline modules that are
+ // either outside the system server or use jarjar to rename the generated AIDL classes.
+ apex_available: [
+ "//apex_available:platform", // used from services.net
+ "com.android.bluetooth.updatable",
+ "com.android.tethering",
+ "com.android.wifi",
+ ],
+ // this is part of updatable modules(NetworkStack) which targets 29(Q)
+ min_sdk_version: "29",
+ },
+ },
+ versions: [
+ "1",
+ "2",
+ "3",
+ "4",
+ ],
+}
+
+java_library {
+ name: "netd_event_listener_interface-lateststable-java",
+ sdk_version: "system_current",
+ min_sdk_version: "29",
+ static_libs: [
+ "netd_event_listener_interface-java",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth.updatable",
+ "com.android.wifi",
+ "com.android.tethering",
+ ],
+}
+
+aidl_interface {
+ name: "netd_event_listener_interface",
+ local_include_dir: "binder",
+ srcs: [
+ "binder/android/net/metrics/INetdEventListener.aidl",
+ ],
+ versions: ["1"],
+ backend: {
+ ndk: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.resolv",
+ ],
+ min_sdk_version: "29",
+ },
+ java: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+ min_sdk_version: "29",
+ },
+ },
}
aidl_interface {
@@ -21,6 +136,27 @@
],
}
+// Convenience build target for the version of the netd stable AIDL interface used by the platform.
+// This exists to ensure that all non-updatable code in the system server uses the same version.
+// Mixing different versions of generated classes results in code non-deterministically(?) using one
+// of the compiled-in versions, and potentially crashing when code compiled against a newer version
+// ends up using a generated class from an older version and calls methods that don't exist.
+// This must be a frozen version on REL builds and can be -unstable on development builds.
+// See http://b/143560726 for an example.
+java_library {
+ name: "netd_aidl_interfaces-platform-java",
+ static_libs: [
+ "netd_aidl_interface-java",
+ "netd_event_listener_interface-java",
+ ],
+ // TODO: remove bluetooth, which doesn't actually use netd at all.
+ apex_available: [
+ "//apex_available:platform", // due to the dependency from services.net
+ "com.android.bluetooth.updatable",
+ ],
+ sdk_version: "system_current",
+}
+
// These are used in netd_integration_test
// TODO: fold these into a cc_library_static after converting netd/server to Android.bp
filegroup {
@@ -79,9 +215,8 @@
"libpcap",
"libqtaguid",
"libssl",
- "libsysutils",
- "netd_aidl_interface-V7-cpp",
- "netd_event_listener_interface-V1-cpp",
+ "netd_aidl_interface-cpp",
+ "netd_event_listener_interface-cpp",
],
aidl: {
export_aidl_headers: true,
@@ -111,6 +246,7 @@
"libcutils",
"libdl",
"libhidlbase",
+ "libjsoncpp",
"liblog",
"libmdnssd",
"libnetd_resolv",
@@ -123,8 +259,8 @@
"libselinux",
"libsysutils",
"libutils",
- "netd_aidl_interface-V7-cpp",
- "netd_event_listener_interface-V1-cpp",
+ "netd_aidl_interface-cpp",
+ "netd_event_listener_interface-cpp",
"oemnetd_aidl_interface-cpp",
],
static_libs: [
@@ -146,7 +282,6 @@
"PhysicalNetwork.cpp",
"PppController.cpp",
"Process.cpp",
- "UnreachableNetwork.cpp",
"VirtualNetwork.cpp",
"main.cpp",
"oem_iptables_hook.cpp",
@@ -173,8 +308,8 @@
"liblog",
"libutils",
"libbinder",
- "dnsresolver_aidl_interface-V7-cpp",
- "netd_aidl_interface-V6-cpp",
+ "dnsresolver_aidl_interface-cpp",
+ "netd_aidl_interface-cpp",
],
srcs: [
"ndc.cpp",
@@ -183,7 +318,6 @@
],
sanitize: {
cfi: true,
- memtag_heap: true,
},
}
@@ -221,8 +355,8 @@
"libnetd_server",
"libnetd_test_tun_interface",
"libqtaguid",
- "netd_aidl_interface-V7-cpp",
- "netd_event_listener_interface-V1-cpp",
+ "netd_aidl_interface-unstable-cpp",
+ "netd_event_listener_interface-cpp",
],
shared_libs: [
"libbase",
@@ -237,5 +371,4 @@
"libsysutils",
"libutils",
],
- // tidy: false, // cuts test build time by almost 1 minute
}
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index 1b46234..e1ce56f 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -70,7 +70,6 @@
auto BandwidthController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
using android::base::Join;
-using android::base::StartsWith;
using android::base::StringAppendF;
using android::base::StringPrintf;
using android::net::FirewallController;
@@ -84,6 +83,9 @@
const char ALERT_GLOBAL_NAME[] = "globalAlert";
const std::string NEW_CHAIN_COMMAND = "-N ";
+const char NAUGHTY_CHAIN[] = "bw_penalty_box";
+const char NICE_CHAIN[] = "bw_happy_box";
+
/**
* Some comments about the rules:
* * Ordering
@@ -118,12 +120,12 @@
* iptables -A bw_costly_iface0 -j bw_penalty_box
*
* * Penalty box, happy box and data saver.
- * - bw_penalty box is a denylist of apps that are rejected.
- * - bw_happy_box is an allowlist of apps. It always includes all system apps
+ * - bw_penalty box is a blacklist of apps that are rejected.
+ * - bw_happy_box is a whitelist of apps. It always includes all system apps
* - bw_data_saver implements data usage restrictions.
- * - Via the UI the user can add and remove apps from the allowlist and
- * denylist, and turn on/off data saver.
- * - The denylist takes precedence over the allowlist and the allowlist
+ * - Via the UI the user can add and remove apps from the whitelist and
+ * blacklist, and turn on/off data saver.
+ * - The blacklist takes precedence over the whitelist and the whitelist
* takes precedence over data saver.
*
* * bw_penalty_box handling:
@@ -147,8 +149,12 @@
*/
const std::string COMMIT_AND_CLOSE = "COMMIT\n";
-const std::string BPF_PENALTY_BOX_MATCH_DENYLIST_COMMAND = StringPrintf(
- "-I bw_penalty_box -m bpf --object-pinned %s -j REJECT", XT_BPF_DENYLIST_PROG_PATH);
+const std::string HAPPY_BOX_MATCH_WHITELIST_COMMAND =
+ StringPrintf("-I bw_happy_box -m owner --uid-owner %d-%d -j RETURN", 0, MAX_SYSTEM_UID);
+const std::string BPF_HAPPY_BOX_MATCH_WHITELIST_COMMAND = StringPrintf(
+ "-I bw_happy_box -m bpf --object-pinned %s -j RETURN", XT_BPF_WHITELIST_PROG_PATH);
+const std::string BPF_PENALTY_BOX_MATCH_BLACKLIST_COMMAND = StringPrintf(
+ "-I bw_penalty_box -m bpf --object-pinned %s -j REJECT", XT_BPF_BLACKLIST_PROG_PATH);
static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
/*
@@ -206,8 +212,7 @@
* See go/ipsec-data-accounting for more information.
*/
-std::vector<std::string> getBasicAccountingCommands() {
- // clang-format off
+std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
std::vector<std::string> ipt_basic_accounting_commands = {
"*filter",
@@ -216,14 +221,29 @@
"-A bw_INPUT -p esp -j RETURN",
StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN", uidBillingMask,
uidBillingMask),
+ // This is ingress application UID xt_qtaguid (pre-ebpf) accounting,
+ // for bpf this is handled out of cgroup hooks instead.
+ useBpf ? "" : "-A bw_INPUT -m owner --socket-exists",
StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x", uidBillingMask),
+
"-A bw_OUTPUT -j bw_global_alert",
+ // Prevents IPSec double counting (Tunnel mode and Transport mode,
+ // respectively)
+ useBpf ? "" : "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
+ useBpf ? "" : "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN",
+ // Don't count clat traffic, as it has already been counted (and subject to
+ // costly / happy_box / data_saver / penalty_box etc. based on the real UID)
+ // on the stacked interface.
+ useBpf ? "" : "-A bw_OUTPUT -m owner --uid-owner clat -j RETURN",
+ // This is egress application UID xt_qtaguid (pre-ebpf) accounting,
+ // for bpf this is handled out of cgroup hooks instead.
+ useBpf ? "" : "-A bw_OUTPUT -m owner --socket-exists",
+
"-A bw_costly_shared -j bw_penalty_box",
- ("-I bw_penalty_box -m bpf --object-pinned " XT_BPF_DENYLIST_PROG_PATH " -j REJECT"),
- "-A bw_penalty_box -j bw_happy_box",
- "-A bw_happy_box -j bw_data_saver",
+ useBpf ? BPF_PENALTY_BOX_MATCH_BLACKLIST_COMMAND : "",
+ "-A bw_penalty_box -j bw_happy_box", "-A bw_happy_box -j bw_data_saver",
"-A bw_data_saver -j RETURN",
- ("-I bw_happy_box -m bpf --object-pinned " XT_BPF_ALLOWLIST_PROG_PATH " -j RETURN"),
+ useBpf ? BPF_HAPPY_BOX_MATCH_WHITELIST_COMMAND : HAPPY_BOX_MATCH_WHITELIST_COMMAND,
"COMMIT",
"*raw",
@@ -242,7 +262,8 @@
//
// Hence we will never double count and additional corrections are not needed.
// We can simply take the sum of base and stacked (+20B/pkt) interface counts.
- ("-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH),
+ useBpf ? "-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH
+ : "-A bw_raw_PREROUTING -m owner --socket-exists",
"COMMIT",
"*mangle",
@@ -258,14 +279,22 @@
// This is egress interface accounting: we account 464xlat traffic only on
// the clat interface (as offloaded packets never hit base interface's ip6tables)
// and later sum base and stacked with overhead (+20B/pkt) in higher layers
- ("-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH),
+ useBpf ? "-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH
+ : "-A bw_mangle_POSTROUTING -m owner --socket-exists",
COMMIT_AND_CLOSE};
- // clang-format on
return ipt_basic_accounting_commands;
}
+std::vector<std::string> toStrVec(int num, const char* const strs[]) {
+ return std::vector<std::string>(strs, strs + num);
+}
+
} // namespace
+void BandwidthController::setBpfEnabled(bool isEnabled) {
+ mBpfSupported = isEnabled;
+}
+
BandwidthController::BandwidthController() {
}
@@ -292,7 +321,7 @@
flushCleanTables(false);
- std::string commands = Join(getBasicAccountingCommands(), '\n');
+ std::string commands = Join(getBasicAccountingCommands(mBpfSupported), '\n');
return iptablesRestoreFunction(V4V6, commands, nullptr);
}
@@ -323,29 +352,63 @@
return ret;
}
-int BandwidthController::addNaughtyApps(const std::vector<uint32_t>& appUids) {
- return manipulateSpecialApps(appUids, PENALTY_BOX_MATCH, IptOpInsert);
+// TODO: Remove after removing these commands in CommandListener
+int BandwidthController::addNaughtyApps(int numUids, const char* const appUids[]) {
+ return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
+ IptJumpReject, IptOpInsert);
}
-int BandwidthController::removeNaughtyApps(const std::vector<uint32_t>& appUids) {
- return manipulateSpecialApps(appUids, PENALTY_BOX_MATCH, IptOpDelete);
+// TODO: Remove after removing these commands in CommandListener
+int BandwidthController::removeNaughtyApps(int numUids, const char* const appUids[]) {
+ return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
+ IptJumpReject, IptOpDelete);
}
-int BandwidthController::addNiceApps(const std::vector<uint32_t>& appUids) {
- return manipulateSpecialApps(appUids, HAPPY_BOX_MATCH, IptOpInsert);
+// TODO: Remove after removing these commands in CommandListener
+int BandwidthController::addNiceApps(int numUids, const char* const appUids[]) {
+ return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
+ IptJumpReturn, IptOpInsert);
}
-int BandwidthController::removeNiceApps(const std::vector<uint32_t>& appUids) {
- return manipulateSpecialApps(appUids, HAPPY_BOX_MATCH, IptOpDelete);
+// TODO: Remove after removing these commands in CommandListener
+int BandwidthController::removeNiceApps(int numUids, const char* const appUids[]) {
+ return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
+ IptJumpReturn, IptOpDelete);
}
-int BandwidthController::manipulateSpecialApps(const std::vector<uint32_t>& appUids,
- UidOwnerMatchType matchType, IptOp op) {
- Status status = gCtls->trafficCtrl.updateUidOwnerMap(appUids, matchType, op);
- if (!isOk(status)) {
- ALOGE("unable to update the Bandwidth Uid Map: %s", toString(status).c_str());
+int BandwidthController::addNaughtyApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NAUGHTY_CHAIN, IptJumpReject, IptOpInsert);
+}
+
+int BandwidthController::removeNaughtyApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NAUGHTY_CHAIN, IptJumpReject, IptOpDelete);
+}
+
+int BandwidthController::addNiceApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NICE_CHAIN, IptJumpReturn, IptOpInsert);
+}
+
+int BandwidthController::removeNiceApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NICE_CHAIN, IptJumpReturn, IptOpDelete);
+}
+
+int BandwidthController::manipulateSpecialApps(const std::vector<std::string>& appStrUids,
+ const std::string& chain, IptJumpOp jumpHandling,
+ IptOp op) {
+ if (mBpfSupported) {
+ Status status = gCtls->trafficCtrl.updateUidOwnerMap(appStrUids, jumpHandling, op);
+ if (!isOk(status)) {
+ ALOGE("unable to update the Bandwidth Uid Map: %s", toString(status).c_str());
+ }
+ return status.code();
}
- return status.code();
+ std::string cmd = "*filter\n";
+ for (const auto& appStrUid : appStrUids) {
+ StringAppendF(&cmd, "%s %s -m owner --uid-owner %s%s\n", opToString(op), chain.c_str(),
+ appStrUid.c_str(), jumpToString(jumpHandling));
+ }
+ StringAppendF(&cmd, "COMMIT\n");
+ return iptablesRestoreFunction(V4V6, cmd, nullptr);
}
int BandwidthController::setInterfaceSharedQuota(const std::string& iface, int64_t maxBytes) {
@@ -772,11 +835,11 @@
// Find and flush all rules starting with "-N bw_costly_<iface>" except "-N bw_costly_shared".
while (std::getline(stream, rule, '\n')) {
- if (!StartsWith(rule, NEW_CHAIN_COMMAND)) continue;
+ if (rule.find(NEW_CHAIN_COMMAND) != 0) continue;
chainName = rule.substr(NEW_CHAIN_COMMAND.size());
ALOGV("parse chainName=<%s> orig line=<%s>", chainName.c_str(), rule.c_str());
- if (!StartsWith(chainName, "bw_costly_") || chainName == std::string("bw_costly_shared")) {
+ if (chainName.find("bw_costly_") != 0 || chainName == std::string("bw_costly_shared")) {
continue;
}
@@ -811,6 +874,8 @@
* For port-unreachable (default), TCP should consider as an abort (RFC1122).
*/
switch (jumpHandling) {
+ case IptJumpNoAdd:
+ return "";
case IptJumpReject:
return " -j REJECT";
case IptJumpReturn:
diff --git a/server/BandwidthController.h b/server/BandwidthController.h
index 414e91b..b8691dc 100644
--- a/server/BandwidthController.h
+++ b/server/BandwidthController.h
@@ -24,7 +24,6 @@
#include <mutex>
#include "NetdConstants.h"
-#include "netdbpf/bpf_shared.h"
class BandwidthController {
public:
@@ -33,6 +32,7 @@
BandwidthController();
int setupIptablesHooks();
+ void setBpfEnabled(bool isEnabled);
int enableBandwidthControl();
int disableBandwidthControl();
@@ -46,10 +46,16 @@
int getInterfaceQuota(const std::string& iface, int64_t* bytes);
int removeInterfaceQuota(const std::string& iface);
- int addNaughtyApps(const std::vector<uint32_t>& appUids);
- int removeNaughtyApps(const std::vector<uint32_t>& appUids);
- int addNiceApps(const std::vector<uint32_t>& appUids);
- int removeNiceApps(const std::vector<uint32_t>& appUids);
+ // TODO: Remove after removing these commands in CommandListener
+ int addNaughtyApps(int numUids, const char* const appUids[]);
+ int removeNaughtyApps(int numUids, const char* const appUids[]);
+ int addNiceApps(int numUids, const char* const appUids[]);
+ int removeNiceApps(int numUids, const char* const appUids[]);
+
+ int addNaughtyApps(const std::vector<std::string>& appStrUid);
+ int removeNaughtyApps(const std::vector<std::string>& appStrUid);
+ int addNiceApps(const std::vector<std::string>& appStrUid);
+ int removeNiceApps(const std::vector<std::string>& appStrUid);
int setGlobalAlert(int64_t bytes);
int removeGlobalAlert();
@@ -69,7 +75,7 @@
static const char LOCAL_MANGLE_POSTROUTING[];
static const char LOCAL_GLOBAL_ALERT[];
- enum IptJumpOp { IptJumpReject, IptJumpReturn };
+ enum IptJumpOp { IptJumpReject, IptJumpReturn, IptJumpNoAdd };
enum IptOp { IptOpInsert, IptOpDelete };
private:
@@ -90,8 +96,8 @@
std::string makeDataSaverCommand(IptablesTarget target, bool enable);
- int manipulateSpecialApps(const std::vector<uint32_t>& appStrUids, UidOwnerMatchType matchType,
- IptOp appOp);
+ int manipulateSpecialApps(const std::vector<std::string>& appStrUids, const std::string& chain,
+ IptJumpOp jumpHandling, IptOp appOp);
int runIptablesAlertCmd(IptOp op, const std::string& alertName, int64_t bytes);
int runIptablesAlertFwdCmd(IptOp op, const std::string& alertName, int64_t bytes);
@@ -126,6 +132,8 @@
static const char *opToString(IptOp op);
static const char *jumpToString(IptJumpOp jumpHandling);
+ bool mBpfSupported = false;
+
int64_t mSharedQuotaBytes = 0;
int64_t mSharedAlertBytes = 0;
int64_t mGlobalAlertBytes = 0;
diff --git a/server/BandwidthControllerTest.cpp b/server/BandwidthControllerTest.cpp
index d635daf..115a0da 100644
--- a/server/BandwidthControllerTest.cpp
+++ b/server/BandwidthControllerTest.cpp
@@ -50,6 +50,73 @@
using android::netdutils::UniqueFile;
using android::netdutils::status::ok;
+const std::string ACCOUNT_RULES_WITHOUT_BPF =
+ "*filter\n"
+ "-A bw_INPUT -j bw_global_alert\n"
+ "-A bw_INPUT -p esp -j RETURN\n"
+ "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
+ "-A bw_INPUT -m owner --socket-exists\n"
+ "-A bw_INPUT -j MARK --or-mark 0x100000\n"
+ "-A bw_OUTPUT -j bw_global_alert\n"
+ "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
+ "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
+ "-A bw_OUTPUT -m owner --uid-owner clat -j RETURN\n"
+ "-A bw_OUTPUT -m owner --socket-exists\n"
+ "-A bw_costly_shared -j bw_penalty_box\n"
+ "\n"
+ "-A bw_penalty_box -j bw_happy_box\n"
+ "-A bw_happy_box -j bw_data_saver\n"
+ "-A bw_data_saver -j RETURN\n"
+ "-I bw_happy_box -m owner --uid-owner 0-9999 -j RETURN\n"
+ "COMMIT\n"
+ "*raw\n"
+ "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
+ "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
+ "-A bw_raw_PREROUTING -m owner --socket-exists\n"
+ "COMMIT\n"
+ "*mangle\n"
+ "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
+ "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
+ "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
+ "-A bw_mangle_POSTROUTING -m owner --uid-owner clat -j RETURN\n"
+ "-A bw_mangle_POSTROUTING -m owner --socket-exists\n"
+ "COMMIT\n";
+
+const std::string ACCOUNT_RULES_WITH_BPF =
+ "*filter\n"
+ "-A bw_INPUT -j bw_global_alert\n"
+ "-A bw_INPUT -p esp -j RETURN\n"
+ "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
+ "\n"
+ "-A bw_INPUT -j MARK --or-mark 0x100000\n"
+ "-A bw_OUTPUT -j bw_global_alert\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "-A bw_costly_shared -j bw_penalty_box\n" +
+ StringPrintf("-I bw_penalty_box -m bpf --object-pinned %s -j REJECT\n",
+ XT_BPF_BLACKLIST_PROG_PATH) +
+ "-A bw_penalty_box -j bw_happy_box\n"
+ "-A bw_happy_box -j bw_data_saver\n"
+ "-A bw_data_saver -j RETURN\n" +
+ StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN\n",
+ XT_BPF_WHITELIST_PROG_PATH) +
+ "COMMIT\n"
+ "*raw\n"
+ "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
+ "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n" +
+ StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s\n", XT_BPF_INGRESS_PROG_PATH) +
+ "COMMIT\n"
+ "*mangle\n"
+ "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
+ "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
+ "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
+ "-A bw_mangle_POSTROUTING -m owner --uid-owner clat -j RETURN\n" +
+ StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s\n",
+ XT_BPF_EGRESS_PROG_PATH) +
+ "COMMIT\n";
+
class BandwidthControllerTest : public IptablesBaseTest {
protected:
BandwidthControllerTest() {
@@ -128,6 +195,23 @@
EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
}
+ void checkBandwithControl(bool useBpf) {
+ // Pretend no bw_costly_shared_<iface> rules already exist...
+ addIptablesRestoreOutput(
+ "-P OUTPUT ACCEPT\n"
+ "-N bw_costly_shared\n"
+ "-N unrelated\n");
+
+ // ... so none are flushed or deleted.
+ std::string expectedClean = "";
+
+ std::string expectedAccounting =
+ useBpf ? ACCOUNT_RULES_WITH_BPF : ACCOUNT_RULES_WITHOUT_BPF;
+ mBw.setBpfEnabled(useBpf);
+ mBw.enableBandwidthControl();
+ expectSetupCommands(expectedClean, expectedAccounting);
+ }
+
StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
};
@@ -163,46 +247,12 @@
EXPECT_TRUE(isPowerOfTwo);
}
-TEST_F(BandwidthControllerTest, TestEnableBandwidthControl) {
- // Pretend no bw_costly_shared_<iface> rules already exist...
- addIptablesRestoreOutput(
- "-P OUTPUT ACCEPT\n"
- "-N bw_costly_shared\n"
- "-N unrelated\n");
+TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithBpf) {
+ checkBandwithControl(true);
+}
- // ... so none are flushed or deleted.
- // clang-format off
- static const std::string expectedClean = "";
- static const std::string expectedAccounting =
- "*filter\n"
- "-A bw_INPUT -j bw_global_alert\n"
- "-A bw_INPUT -p esp -j RETURN\n"
- "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
- "-A bw_INPUT -j MARK --or-mark 0x100000\n"
- "-A bw_OUTPUT -j bw_global_alert\n"
- "-A bw_costly_shared -j bw_penalty_box\n"
- "-I bw_penalty_box -m bpf --object-pinned " XT_BPF_DENYLIST_PROG_PATH " -j REJECT\n"
- "-A bw_penalty_box -j bw_happy_box\n"
- "-A bw_happy_box -j bw_data_saver\n"
- "-A bw_data_saver -j RETURN\n"
- "-I bw_happy_box -m bpf --object-pinned " XT_BPF_ALLOWLIST_PROG_PATH " -j RETURN\n"
- "COMMIT\n"
- "*raw\n"
- "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
- "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
- "-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH "\n"
- "COMMIT\n"
- "*mangle\n"
- "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
- "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
- "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
- "-A bw_mangle_POSTROUTING -m owner --uid-owner clat -j RETURN\n"
- "-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH "\n"
- "COMMIT\n";
- // clang-format on
-
- mBw.enableBandwidthControl();
- expectSetupCommands(expectedClean, expectedAccounting);
+TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithoutBpf) {
+ checkBandwithControl(false);
}
TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
@@ -462,3 +512,24 @@
expectIptablesRestoreCommands(expected);
}
+TEST_F(BandwidthControllerTest, ManipulateSpecialApps) {
+ std::vector<const char *> appUids = { "1000", "1001", "10012" };
+
+ std::vector<std::string> expected = {
+ "*filter\n"
+ "-I bw_happy_box -m owner --uid-owner 1000 -j RETURN\n"
+ "-I bw_happy_box -m owner --uid-owner 1001 -j RETURN\n"
+ "-I bw_happy_box -m owner --uid-owner 10012 -j RETURN\n"
+ "COMMIT\n"};
+ EXPECT_EQ(0, mBw.addNiceApps(appUids.size(), const_cast<char**>(&appUids[0])));
+ expectIptablesRestoreCommands(expected);
+
+ expected = {
+ "*filter\n"
+ "-D bw_penalty_box -m owner --uid-owner 1000 -j REJECT\n"
+ "-D bw_penalty_box -m owner --uid-owner 1001 -j REJECT\n"
+ "-D bw_penalty_box -m owner --uid-owner 10012 -j REJECT\n"
+ "COMMIT\n"};
+ EXPECT_EQ(0, mBw.removeNaughtyApps(appUids.size(), const_cast<char**>(&appUids[0])));
+ expectIptablesRestoreCommands(expected);
+}
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
index 847a6db..90afa3a 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -73,23 +73,51 @@
void ClatdController::init(void) {
std::lock_guard guard(mutex);
- int rv = getClatEgress4MapFd();
- if (rv < 0) {
- ALOGE("getClatEgress4MapFd() failure: %s", strerror(-rv));
+ // TODO: should refactor into separate function for testability
+ if (!bpf::isBpfSupported()) {
+ ALOGI("Pre-4.9 kernel or pre-P api shipping level - disabling clat ebpf.");
+ mClatEbpfMode = ClatEbpfDisabled;
return;
}
- mClatEgress4Map.reset(rv);
- rv = getClatIngress6MapFd();
+ // We know the device initially shipped with at least P...,
+ // but did it ship with at least Q?
+
+ uint64_t api_level = base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ if (api_level == 0) {
+ ALOGE("Cannot determine initial API level of the device.");
+ api_level = base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ }
+
+ // Note: MINIMUM_API_REQUIRED is for eBPF as a whole and is thus P
+ if (api_level > bpf::MINIMUM_API_REQUIRED) {
+ ALOGI("4.9+ kernel and device shipped with Q+ - clat ebpf should work.");
+ mClatEbpfMode = ClatEbpfEnabled;
+ } else {
+ // We cannot guarantee that 4.9-P kernels will include NET_CLS_BPF support.
+ ALOGI("4.9+ kernel and device shipped with P - clat ebpf might work.");
+ mClatEbpfMode = ClatEbpfMaybe;
+ }
+
+ int rv = getClatEgressMapFd();
if (rv < 0) {
- ALOGE("getClatIngress6MapFd() failure: %s", strerror(-rv));
- mClatEgress4Map.reset(-1);
+ ALOGE("getClatEgressMapFd() failure: %s", strerror(-rv));
+ mClatEbpfMode = ClatEbpfDisabled;
return;
}
- mClatIngress6Map.reset(rv);
+ mClatEgressMap.reset(rv);
- mClatEgress4Map.clear();
- mClatIngress6Map.clear();
+ rv = getClatIngressMapFd();
+ if (rv < 0) {
+ ALOGE("getClatIngressMapFd() failure: %s", strerror(-rv));
+ mClatEbpfMode = ClatEbpfDisabled;
+ mClatEgressMap.reset(-1);
+ return;
+ }
+ mClatIngressMap.reset(rv);
+
+ mClatEgressMap.clear();
+ mClatIngressMap.clear();
}
bool ClatdController::isIpv4AddressFree(in_addr_t addr) {
@@ -198,6 +226,8 @@
}
void ClatdController::maybeStartBpf(const ClatdTracker& tracker) {
+ if (mClatEbpfMode == ClatEbpfDisabled) return;
+
auto isEthernet = android::net::isEthernet(tracker.iface);
if (!isEthernet.ok()) {
ALOGE("isEthernet(%s[%d]) failure: %s", tracker.iface, tracker.ifIndex,
@@ -206,54 +236,54 @@
}
// This program will be attached to the v4-* interface which is a TUN and thus always rawip.
- int rv = getClatEgress4ProgFd(RAWIP);
+ int rv = getClatEgressProgFd(RAWIP);
if (rv < 0) {
- ALOGE("getClatEgress4ProgFd(RAWIP) failure: %s", strerror(-rv));
+ ALOGE("getClatEgressProgFd(RAWIP) failure: %s", strerror(-rv));
return;
}
unique_fd txRawIpProgFd(rv);
- rv = getClatIngress6ProgFd(isEthernet.value());
+ rv = getClatIngressProgFd(isEthernet.value());
if (rv < 0) {
- ALOGE("getClatIngress6ProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
+ ALOGE("getClatIngressProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
return;
}
unique_fd rxProgFd(rv);
- ClatEgress4Key txKey = {
+ ClatEgressKey txKey = {
.iif = tracker.v4ifIndex,
.local4 = tracker.v4,
};
- ClatEgress4Value txValue = {
+ ClatEgressValue txValue = {
.oif = tracker.ifIndex,
.local6 = tracker.v6,
.pfx96 = tracker.pfx96,
.oifIsEthernet = isEthernet.value(),
};
- auto ret = mClatEgress4Map.writeValue(txKey, txValue, BPF_ANY);
+ auto ret = mClatEgressMap.writeValue(txKey, txValue, BPF_ANY);
if (!ret.ok()) {
- ALOGE("mClatEgress4Map.writeValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatEgressMap.writeValue failure: %s", strerror(ret.error().code()));
return;
}
- ClatIngress6Key rxKey = {
+ ClatIngressKey rxKey = {
.iif = tracker.ifIndex,
.pfx96 = tracker.pfx96,
.local6 = tracker.v6,
};
- ClatIngress6Value rxValue = {
+ ClatIngressValue rxValue = {
// TODO: move all the clat code to eBPF and remove the tun interface entirely.
.oif = tracker.v4ifIndex,
.local4 = tracker.v4,
};
- ret = mClatIngress6Map.writeValue(rxKey, rxValue, BPF_ANY);
+ ret = mClatIngressMap.writeValue(rxKey, rxValue, BPF_ANY);
if (!ret.ok()) {
- ALOGE("mClatIngress6Map.writeValue failure: %s", strerror(ret.error().code()));
- ret = mClatEgress4Map.deleteValue(txKey);
+ ALOGE("mClatIngressMap.writeValue failure: %s", strerror(ret.error().code()));
+ ret = mClatEgressMap.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
@@ -268,37 +298,47 @@
if (rv) {
ALOGE("tcQdiscAddDevClsact(%d[%s]) failure: %s", tracker.v4ifIndex, tracker.v4iface,
strerror(-rv));
- ret = mClatEgress4Map.deleteValue(txKey);
+ ret = mClatEgressMap.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
- ret = mClatIngress6Map.deleteValue(rxKey);
+ ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngressMap.deleteValue(rxKey);
if (!ret.ok())
- ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
rv = tcFilterAddDevEgressClatIpv4(tracker.v4ifIndex, txRawIpProgFd, RAWIP);
if (rv) {
- ALOGE("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP) failure: %s", tracker.v4ifIndex,
- tracker.v4iface, strerror(-rv));
+ if ((rv == -ENOENT) && (mClatEbpfMode == ClatEbpfMaybe)) {
+ ALOGI("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP): %s", tracker.v4ifIndex,
+ tracker.v4iface, strerror(-rv));
+ } else {
+ ALOGE("tcFilterAddDevEgressClatIpv4(%d[%s], RAWIP) failure: %s", tracker.v4ifIndex,
+ tracker.v4iface, strerror(-rv));
+ }
// The v4- interface clsact is not deleted for unwinding error because once it is created
// with interface addition, the lifetime is till interface deletion. Moreover, the clsact
// has no clat filter now. It should not break anything.
- ret = mClatEgress4Map.deleteValue(txKey);
+ ret = mClatEgressMap.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
- ret = mClatIngress6Map.deleteValue(rxKey);
+ ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngressMap.deleteValue(rxKey);
if (!ret.ok())
- ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value());
if (rv) {
- ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex,
- tracker.iface, isEthernet.value(), strerror(-rv));
+ if ((rv == -ENOENT) && (mClatEbpfMode == ClatEbpfMaybe)) {
+ ALOGI("tcFilterAddDevIngressClatIpv6(%d[%s], %d): %s", tracker.ifIndex, tracker.iface,
+ isEthernet.value(), strerror(-rv));
+ } else {
+ ALOGE("tcFilterAddDevIngressClatIpv6(%d[%s], %d) failure: %s", tracker.ifIndex,
+ tracker.iface, isEthernet.value(), strerror(-rv));
+ }
rv = tcFilterDelDevEgressClatIpv4(tracker.v4ifIndex);
if (rv) {
ALOGE("tcFilterDelDevEgressClatIpv4(%d[%s]) failure: %s", tracker.v4ifIndex,
@@ -308,12 +348,12 @@
// The v4- interface clsact is not deleted. See the reason in the error unwinding code of
// the egress filter attaching of v4- tun interface.
- ret = mClatEgress4Map.deleteValue(txKey);
+ ret = mClatEgressMap.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
- ret = mClatIngress6Map.deleteValue(rxKey);
+ ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngressMap.deleteValue(rxKey);
if (!ret.ok())
- ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
@@ -332,6 +372,8 @@
}
void ClatdController::maybeStopBpf(const ClatdTracker& tracker) {
+ if (mClatEbpfMode == ClatEbpfDisabled) return;
+
int rv = tcFilterDelDevIngressClatIpv6(tracker.ifIndex);
if (rv < 0) {
ALOGE("tcFilterDelDevIngressClatIpv6(%d[%s]) failure: %s", tracker.ifIndex, tracker.iface,
@@ -347,22 +389,22 @@
// We cleanup the maps last, so scanning through them can be used to
// determine what still needs cleanup.
- ClatEgress4Key txKey = {
+ ClatEgressKey txKey = {
.iif = tracker.v4ifIndex,
.local4 = tracker.v4,
};
- auto ret = mClatEgress4Map.deleteValue(txKey);
- if (!ret.ok()) ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
+ auto ret = mClatEgressMap.deleteValue(txKey);
+ if (!ret.ok()) ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
- ClatIngress6Key rxKey = {
+ ClatIngressKey rxKey = {
.iif = tracker.ifIndex,
.pfx96 = tracker.pfx96,
.local6 = tracker.v6,
};
- ret = mClatIngress6Map.deleteValue(rxKey);
- if (!ret.ok()) ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngressMap.deleteValue(rxKey);
+ if (!ret.ok()) ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
}
// Finds the tracker of the clatd running on interface |interface|, or nullptr if clatd has not been
@@ -577,14 +619,14 @@
}
void ClatdController::dumpEgress(DumpWriter& dw) {
- if (!mClatEgress4Map.isValid()) return; // if unsupported just don't dump anything
+ if (!mClatEgressMap.isValid()) return; // if unsupported just don't dump anything
ScopedIndent bpfIndent(dw);
dw.println("BPF egress map: iif(iface) v4Addr -> v6Addr nat64Prefix oif(iface)");
ScopedIndent bpfDetailIndent(dw);
- const auto printClatMap = [&dw](const ClatEgress4Key& key, const ClatEgress4Value& value,
- const BpfMap<ClatEgress4Key, ClatEgress4Value>&) {
+ const auto printClatMap = [&dw](const ClatEgressKey& key, const ClatEgressValue& value,
+ const BpfMap<ClatEgressKey, ClatEgressValue>&) {
char iifStr[IFNAMSIZ] = "?";
char local4Str[INET_ADDRSTRLEN] = "?";
char local6Str[INET6_ADDRSTRLEN] = "?";
@@ -601,21 +643,21 @@
pfx96Str, value.oif, oifStr, value.oifIsEthernet ? "ether" : "rawip");
return Result<void>();
};
- auto res = mClatEgress4Map.iterateWithValue(printClatMap);
+ auto res = mClatEgressMap.iterateWithValue(printClatMap);
if (!res.ok()) {
dw.println("Error printing BPF map: %s", res.error().message().c_str());
}
}
void ClatdController::dumpIngress(DumpWriter& dw) {
- if (!mClatIngress6Map.isValid()) return; // if unsupported just don't dump anything
+ if (!mClatIngressMap.isValid()) return; // if unsupported just don't dump anything
ScopedIndent bpfIndent(dw);
dw.println("BPF ingress map: iif(iface) nat64Prefix v6Addr -> v4Addr oif(iface)");
ScopedIndent bpfDetailIndent(dw);
- const auto printClatMap = [&dw](const ClatIngress6Key& key, const ClatIngress6Value& value,
- const BpfMap<ClatIngress6Key, ClatIngress6Value>&) {
+ const auto printClatMap = [&dw](const ClatIngressKey& key, const ClatIngressValue& value,
+ const BpfMap<ClatIngressKey, ClatIngressValue>&) {
char iifStr[IFNAMSIZ] = "?";
char pfx96Str[INET6_ADDRSTRLEN] = "?";
char local6Str[INET6_ADDRSTRLEN] = "?";
@@ -632,7 +674,7 @@
value.oif, oifStr);
return Result<void>();
};
- auto res = mClatIngress6Map.iterateWithValue(printClatMap);
+ auto res = mClatIngressMap.iterateWithValue(printClatMap);
if (!res.ok()) {
dw.println("Error printing BPF map: %s", res.error().message().c_str());
}
diff --git a/server/ClatdController.h b/server/ClatdController.h
index 4b7c60b..2c13958 100644
--- a/server/ClatdController.h
+++ b/server/ClatdController.h
@@ -89,8 +89,19 @@
in6_addr* v6);
static void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix);
- bpf::BpfMap<ClatEgress4Key, ClatEgress4Value> mClatEgress4Map GUARDED_BY(mutex);
- bpf::BpfMap<ClatIngress6Key, ClatIngress6Value> mClatIngress6Map GUARDED_BY(mutex);
+ enum eClatEbpfMode {
+ ClatEbpfDisabled, // <4.9 kernel || <P api shipping level -- will not work
+ ClatEbpfMaybe, // >=4.9 kernel && P api shipping level -- might work
+ ClatEbpfEnabled, // >=4.9 kernel && >=Q api shipping level -- must work
+ };
+ eClatEbpfMode mClatEbpfMode GUARDED_BY(mutex);
+ eClatEbpfMode getEbpfMode() EXCLUDES(mutex) {
+ std::lock_guard guard(mutex);
+ return mClatEbpfMode;
+ }
+
+ bpf::BpfMap<ClatEgressKey, ClatEgressValue> mClatEgressMap GUARDED_BY(mutex);
+ bpf::BpfMap<ClatIngressKey, ClatIngressValue> mClatIngressMap GUARDED_BY(mutex);
void maybeStartBpf(const ClatdTracker& tracker) REQUIRES(mutex);
void maybeStopBpf(const ClatdTracker& tracker) REQUIRES(mutex);
diff --git a/server/ClatdControllerTest.cpp b/server/ClatdControllerTest.cpp
index d3a2aa7..dc71a03 100644
--- a/server/ClatdControllerTest.cpp
+++ b/server/ClatdControllerTest.cpp
@@ -69,6 +69,7 @@
protected:
ClatdController mClatdCtrl;
+ bool isEbpfDisabled() { return mClatdCtrl.getEbpfMode() == ClatdController::ClatEbpfDisabled; }
void setIptablesDropRule(bool a, const char* b, const char* c, const char* d) {
std::lock_guard guard(mClatdCtrl.mutex);
return mClatdCtrl.setIptablesDropRule(a, b, c, d);
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 1f2bac2..5af8a91 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -285,15 +285,10 @@
netdutils::Status tcStatus = trafficCtrl.start();
if (!isOk(tcStatus)) {
gLog.error("Failed to start trafficcontroller: (%s)", toString(tcStatus).c_str());
- gLog.error("CRITICAL: sleeping 60 seconds, netd exiting with failure, crash loop likely!");
- // The expected reason we get here is a major kernel or other code bug, as such
- // the probability that things will succeed on restart of netd is pretty small.
- // So, let's wait a minute to at least try to limit the log spam a little bit.
- sleep(60);
- exit(1);
}
gLog.info("Initializing traffic control: %" PRId64 "us", s.getTimeAndResetUs());
+ bandwidthCtrl.setBpfEnabled(trafficCtrl.getBpfEnabled());
bandwidthCtrl.enableBandwidthControl();
gLog.info("Enabling bandwidth control: %" PRId64 "us", s.getTimeAndResetUs());
diff --git a/server/DummyNetwork.cpp b/server/DummyNetwork.cpp
index 186072d..6cd6791 100644
--- a/server/DummyNetwork.cpp
+++ b/server/DummyNetwork.cpp
@@ -14,22 +14,17 @@
* limitations under the License.
*/
-#define LOG_TAG "Netd"
-
#include "DummyNetwork.h"
+#include "RouteController.h"
+
+#define LOG_TAG "Netd"
+#include "log/log.h"
#include "errno.h"
namespace android {
namespace net {
-// The dummy network is used to blackhole or reject traffic.
-// It has an IPv4 and an IPv6 default route that point to a dummy interface
-// which drops packets. It is used for system purposes only. Applications
-// cannot use multinetwork APIs such as Network#bindSocket or
-// android_setsocknetwork to send packets on the dummy network.
-// Any attempt to do so will fail with ENETUNREACH.
-
const char* DummyNetwork::INTERFACE_NAME = "dummy0";
DummyNetwork::DummyNetwork(unsigned netId) : Network(netId) {
@@ -39,5 +34,17 @@
DummyNetwork::~DummyNetwork() {
}
+Network::Type DummyNetwork::getType() const {
+ return DUMMY;
+}
+
+int DummyNetwork::addInterface(const std::string& /* interface */) {
+ return -EINVAL;
+}
+
+int DummyNetwork::removeInterface(const std::string& /* interface */) {
+ return -EINVAL;
+}
+
} // namespace net
} // namespace android
diff --git a/server/DummyNetwork.h b/server/DummyNetwork.h
index 8f9960b..5823ce5 100644
--- a/server/DummyNetwork.h
+++ b/server/DummyNetwork.h
@@ -27,7 +27,9 @@
virtual ~DummyNetwork();
private:
- std::string getTypeString() const override { return "DUMMY"; };
+ Type getType() const override;
+ [[nodiscard]] int addInterface(const std::string& interface) override;
+ [[nodiscard]] int removeInterface(const std::string& interface) override;
};
} // namespace android::net
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 0a0f8d8..3c070ce 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -53,6 +53,10 @@
// Proc file containing the uid mapping for the user namespace of the current process.
const char kUidMapProcFile[] = "/proc/self/uid_map";
+bool getBpfOwnerStatus() {
+ return gCtls->trafficCtrl.getBpfEnabled();
+}
+
} // namespace
namespace android {
@@ -69,7 +73,6 @@
const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
const char* FirewallController::LOCAL_STANDBY = "fw_standby";
const char* FirewallController::LOCAL_POWERSAVE = "fw_powersave";
-const char* FirewallController::LOCAL_RESTRICTED = "fw_restricted";
// ICMPv6 types that are required for any form of IPv6 connectivity to work. Note that because the
// fw_dozable chain is called from both INPUT and OUTPUT, this includes both packets that we need
@@ -84,22 +87,20 @@
};
FirewallController::FirewallController(void) : mMaxUid(discoverMaximumValidUid(kUidMapProcFile)) {
- // If no rules are set, it's in DENYLIST mode
- mFirewallType = DENYLIST;
+ // If no rules are set, it's in BLACKLIST mode
+ mFirewallType = BLACKLIST;
mIfaceRules = {};
}
int FirewallController::setupIptablesHooks(void) {
int res = 0;
- // mUseBpfOwnerMatch should be removed, but it is still depended upon by test code.
- mUseBpfOwnerMatch = true;
+ mUseBpfOwnerMatch = getBpfOwnerStatus();
if (mUseBpfOwnerMatch) {
return res;
}
res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
res |= createChain(LOCAL_STANDBY, getFirewallType(STANDBY));
res |= createChain(LOCAL_POWERSAVE, getFirewallType(POWERSAVE));
- res |= createChain(LOCAL_RESTRICTED, getFirewallType(RESTRICTED));
return res;
}
@@ -109,7 +110,7 @@
// flush any existing rules
resetFirewall();
- if (ftype == ALLOWLIST) {
+ if (ftype == WHITELIST) {
// create default rule to drop all traffic
std::string command =
"*filter\n"
@@ -120,14 +121,14 @@
res = execIptablesRestore(V4V6, command.c_str());
}
- // Set this after calling disableFirewall(), since it defaults to ALLOWLIST there
+ // Set this after calling disableFirewall(), since it defaults to WHITELIST there
mFirewallType = ftype;
}
return res ? -EREMOTEIO : 0;
}
int FirewallController::resetFirewall(void) {
- mFirewallType = ALLOWLIST;
+ mFirewallType = WHITELIST;
mIfaceRules.clear();
// flush any existing rules
@@ -154,9 +155,6 @@
case POWERSAVE:
name = LOCAL_POWERSAVE;
break;
- case RESTRICTED:
- name = LOCAL_RESTRICTED;
- break;
default:
return res;
}
@@ -180,8 +178,8 @@
}
int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
- if (mFirewallType == DENYLIST) {
- // Unsupported in DENYLIST mode
+ if (mFirewallType == BLACKLIST) {
+ // Unsupported in BLACKLIST mode
return -EINVAL;
}
@@ -216,17 +214,15 @@
FirewallType FirewallController::getFirewallType(ChildChain chain) {
switch(chain) {
case DOZABLE:
- return ALLOWLIST;
+ return WHITELIST;
case STANDBY:
- return DENYLIST;
+ return BLACKLIST;
case POWERSAVE:
- return ALLOWLIST;
- case RESTRICTED:
- return ALLOWLIST;
+ return WHITELIST;
case NONE:
return mFirewallType;
default:
- return DENYLIST;
+ return BLACKLIST;
}
}
@@ -234,11 +230,11 @@
const char* op;
const char* target;
FirewallType firewallType = getFirewallType(chain);
- if (firewallType == ALLOWLIST) {
+ if (firewallType == WHITELIST) {
target = "RETURN";
// When adding, insert RETURN rules at the front, before the catch-all DROP at the end.
op = (rule == ALLOW)? "-I" : "-D";
- } else { // DENYLIST mode
+ } else { // BLACKLIST mode
target = "DROP";
// When adding, append DROP rules at the end, after the RETURN rule that matches TCP RSTs.
op = (rule == DENY)? "-A" : "-D";
@@ -247,19 +243,16 @@
std::vector<std::string> chainNames;
switch(chain) {
case DOZABLE:
- chainNames = {LOCAL_DOZABLE};
+ chainNames = { LOCAL_DOZABLE };
break;
case STANDBY:
- chainNames = {LOCAL_STANDBY};
+ chainNames = { LOCAL_STANDBY };
break;
case POWERSAVE:
- chainNames = {LOCAL_POWERSAVE};
- break;
- case RESTRICTED:
- chainNames = {LOCAL_RESTRICTED};
+ chainNames = { LOCAL_POWERSAVE };
break;
case NONE:
- chainNames = {LOCAL_INPUT, LOCAL_OUTPUT};
+ chainNames = { LOCAL_INPUT, LOCAL_OUTPUT };
break;
default:
ALOGW("Unknown child chain: %d", chain);
@@ -281,7 +274,7 @@
int FirewallController::createChain(const char* chain, FirewallType type) {
static const std::vector<int32_t> NO_UIDS;
- return replaceUidChain(chain, type == ALLOWLIST, NO_UIDS);
+ return replaceUidChain(chain, type == WHITELIST, NO_UIDS);
}
/* static */
@@ -297,18 +290,18 @@
return commands;
}
-std::string FirewallController::makeUidRules(IptablesTarget target, const char* name,
- bool isAllowlist, const std::vector<int32_t>& uids) {
+std::string FirewallController::makeUidRules(IptablesTarget target, const char *name,
+ bool isWhitelist, const std::vector<int32_t>& uids) {
std::string commands;
StringAppendF(&commands, "*filter\n:%s -\n", name);
- // Allowlist chains have UIDs at the beginning, and new UIDs are added with '-I'.
- if (isAllowlist) {
+ // Whitelist chains have UIDs at the beginning, and new UIDs are added with '-I'.
+ if (isWhitelist) {
for (auto uid : uids) {
StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j RETURN\n", name, uid);
}
- // Always allowlist system UIDs.
+ // Always whitelist system UIDs.
StringAppendF(&commands,
"-A %s -m owner --uid-owner %d-%d -j RETURN\n", name, 0, MAX_SYSTEM_UID);
@@ -317,7 +310,7 @@
StringAppendF(&commands,
"-A %s -m owner ! --uid-owner %d-%u -j RETURN\n", name, 0, mMaxUid);
- // Always allowlist traffic with protocol ESP, or no known socket - required for IPSec
+ // Always whitelist traffic with protocol ESP, or no known socket - required for IPSec
StringAppendF(&commands, "-A %s -p esp -j RETURN\n", name);
}
@@ -329,20 +322,20 @@
// access. Both incoming and outgoing RSTs are allowed.
StringAppendF(&commands, "-A %s -p tcp --tcp-flags RST RST -j RETURN\n", name);
- if (isAllowlist) {
+ if (isWhitelist) {
commands.append(makeCriticalCommands(target, name));
}
- // Denylist chains have UIDs at the end, and new UIDs are added with '-A'.
- if (!isAllowlist) {
+ // Blacklist chains have UIDs at the end, and new UIDs are added with '-A'.
+ if (!isWhitelist) {
for (auto uid : uids) {
StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j DROP\n", name, uid);
}
}
- // If it's an allowlist chain, add a default DROP at the end. This is not necessary for a
- // denylist chain, because all user-defined chains implicitly RETURN at the end.
- if (isAllowlist) {
+ // If it's a whitelist chain, add a default DROP at the end. This is not necessary for a
+ // blacklist chain, because all user-defined chains implicitly RETURN at the end.
+ if (isWhitelist) {
StringAppendF(&commands, "-A %s -j DROP\n", name);
}
@@ -351,13 +344,13 @@
return commands;
}
-int FirewallController::replaceUidChain(const std::string& name, bool isAllowlist,
- const std::vector<int32_t>& uids) {
+int FirewallController::replaceUidChain(
+ const std::string &name, bool isWhitelist, const std::vector<int32_t>& uids) {
if (mUseBpfOwnerMatch) {
- return gCtls->trafficCtrl.replaceUidOwnerMap(name, isAllowlist, uids);
+ return gCtls->trafficCtrl.replaceUidOwnerMap(name, isWhitelist, uids);
}
- std::string commands4 = makeUidRules(V4, name.c_str(), isAllowlist, uids);
- std::string commands6 = makeUidRules(V6, name.c_str(), isAllowlist, uids);
+ std::string commands4 = makeUidRules(V4, name.c_str(), isWhitelist, uids);
+ std::string commands6 = makeUidRules(V6, name.c_str(), isWhitelist, uids);
return execIptablesRestore(V4, commands4.c_str()) | execIptablesRestore(V6, commands6.c_str());
}
@@ -405,4 +398,4 @@
}
} // namespace net
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 6cabfb5..620f196 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -33,17 +33,16 @@
enum FirewallRule { ALLOW = INetd::FIREWALL_RULE_ALLOW, DENY = INetd::FIREWALL_RULE_DENY };
-// ALLOWLIST means the firewall denies all by default, uids must be explicitly ALLOWed
-// DENYLIST means the firewall allows all by default, uids must be explicitly DENYed
+// WHITELIST means the firewall denies all by default, uids must be explicitly ALLOWed
+// BLACKLIST means the firewall allows all by default, uids must be explicitly DENYed
-enum FirewallType { ALLOWLIST = INetd::FIREWALL_ALLOWLIST, DENYLIST = INetd::FIREWALL_DENYLIST };
+enum FirewallType { WHITELIST = INetd::FIREWALL_WHITELIST, BLACKLIST = INetd::FIREWALL_BLACKLIST };
enum ChildChain {
NONE = INetd::FIREWALL_CHAIN_NONE,
DOZABLE = INetd::FIREWALL_CHAIN_DOZABLE,
STANDBY = INetd::FIREWALL_CHAIN_STANDBY,
POWERSAVE = INetd::FIREWALL_CHAIN_POWERSAVE,
- RESTRICTED = INetd::FIREWALL_CHAIN_RESTRICTED,
INVALID_CHAIN
};
@@ -86,7 +85,6 @@
static const char* LOCAL_DOZABLE;
static const char* LOCAL_STANDBY;
static const char* LOCAL_POWERSAVE;
- static const char* LOCAL_RESTRICTED;
static const char* ICMPV6_TYPES[];
@@ -94,7 +92,7 @@
protected:
friend class FirewallControllerTest;
- std::string makeUidRules(IptablesTarget target, const char* name, bool isAllowlist,
+ std::string makeUidRules(IptablesTarget target, const char *name, bool isWhitelist,
const std::vector<int32_t>& uids);
static int (*execIptablesRestore)(IptablesTarget target, const std::string& commands);
diff --git a/server/FirewallControllerTest.cpp b/server/FirewallControllerTest.cpp
index df6ca82..1b53fb8 100644
--- a/server/FirewallControllerTest.cpp
+++ b/server/FirewallControllerTest.cpp
@@ -56,58 +56,61 @@
}
};
-TEST_F(FirewallControllerTest, TestCreateAllowlistChain) {
+TEST_F(FirewallControllerTest, TestCreateWhitelistChain) {
std::vector<std::string> expectedRestore4 = {
- "*filter",
- ":fw_allowlist -",
- "-A fw_allowlist -m owner --uid-owner 0-9999 -j RETURN",
- "-A fw_allowlist -m owner ! --uid-owner 0-4294967294 -j RETURN",
- "-A fw_allowlist -p esp -j RETURN",
- "-A fw_allowlist -i lo -j RETURN",
- "-A fw_allowlist -o lo -j RETURN",
- "-A fw_allowlist -p tcp --tcp-flags RST RST -j RETURN",
- "-A fw_allowlist -j DROP",
- "COMMIT\n"};
+ "*filter",
+ ":fw_whitelist -",
+ "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN",
+ "-A fw_whitelist -m owner ! --uid-owner 0-4294967294 -j RETURN",
+ "-A fw_whitelist -p esp -j RETURN",
+ "-A fw_whitelist -i lo -j RETURN",
+ "-A fw_whitelist -o lo -j RETURN",
+ "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN",
+ "-A fw_whitelist -j DROP",
+ "COMMIT\n"
+ };
std::vector<std::string> expectedRestore6 = {
- "*filter",
- ":fw_allowlist -",
- "-A fw_allowlist -m owner --uid-owner 0-9999 -j RETURN",
- "-A fw_allowlist -m owner ! --uid-owner 0-4294967294 -j RETURN",
- "-A fw_allowlist -p esp -j RETURN",
- "-A fw_allowlist -i lo -j RETURN",
- "-A fw_allowlist -o lo -j RETURN",
- "-A fw_allowlist -p tcp --tcp-flags RST RST -j RETURN",
- "-A fw_allowlist -p icmpv6 --icmpv6-type packet-too-big -j RETURN",
- "-A fw_allowlist -p icmpv6 --icmpv6-type router-solicitation -j RETURN",
- "-A fw_allowlist -p icmpv6 --icmpv6-type router-advertisement -j RETURN",
- "-A fw_allowlist -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN",
- "-A fw_allowlist -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN",
- "-A fw_allowlist -p icmpv6 --icmpv6-type redirect -j RETURN",
- "-A fw_allowlist -j DROP",
- "COMMIT\n"};
+ "*filter",
+ ":fw_whitelist -",
+ "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN",
+ "-A fw_whitelist -m owner ! --uid-owner 0-4294967294 -j RETURN",
+ "-A fw_whitelist -p esp -j RETURN",
+ "-A fw_whitelist -i lo -j RETURN",
+ "-A fw_whitelist -o lo -j RETURN",
+ "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN",
+ "-A fw_whitelist -p icmpv6 --icmpv6-type packet-too-big -j RETURN",
+ "-A fw_whitelist -p icmpv6 --icmpv6-type router-solicitation -j RETURN",
+ "-A fw_whitelist -p icmpv6 --icmpv6-type router-advertisement -j RETURN",
+ "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN",
+ "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN",
+ "-A fw_whitelist -p icmpv6 --icmpv6-type redirect -j RETURN",
+ "-A fw_whitelist -j DROP",
+ "COMMIT\n"
+ };
std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
{V4, Join(expectedRestore4, '\n')},
{V6, Join(expectedRestore6, '\n')},
};
- createChain("fw_allowlist", ALLOWLIST);
+ createChain("fw_whitelist", WHITELIST);
expectIptablesRestoreCommands(expectedRestoreCommands);
}
-TEST_F(FirewallControllerTest, TestCreateDenylistChain) {
+TEST_F(FirewallControllerTest, TestCreateBlacklistChain) {
std::vector<std::string> expectedRestore = {
- "*filter",
- ":fw_denylist -",
- "-A fw_denylist -i lo -j RETURN",
- "-A fw_denylist -o lo -j RETURN",
- "-A fw_denylist -p tcp --tcp-flags RST RST -j RETURN",
- "COMMIT\n"};
+ "*filter",
+ ":fw_blacklist -",
+ "-A fw_blacklist -i lo -j RETURN",
+ "-A fw_blacklist -o lo -j RETURN",
+ "-A fw_blacklist -p tcp --tcp-flags RST RST -j RETURN",
+ "COMMIT\n"
+ };
std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
{V4, Join(expectedRestore, '\n')},
{V6, Join(expectedRestore, '\n')},
};
- createChain("fw_denylist", DENYLIST);
+ createChain("fw_blacklist", BLACKLIST);
expectIptablesRestoreCommands(expectedRestoreCommands);
}
@@ -159,50 +162,50 @@
expectIptablesRestoreCommands(expected);
}
-TEST_F(FirewallControllerTest, TestReplaceAllowlistUidRule) {
+TEST_F(FirewallControllerTest, TestReplaceWhitelistUidRule) {
std::string expected =
"*filter\n"
- ":FW_allowchain -\n"
- "-A FW_allowchain -m owner --uid-owner 10023 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 10059 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 10124 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 10111 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 110122 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 210153 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 210024 -j RETURN\n"
- "-A FW_allowchain -m owner --uid-owner 0-9999 -j RETURN\n"
- "-A FW_allowchain -m owner ! --uid-owner 0-4294967294 -j RETURN\n"
- "-A FW_allowchain -p esp -j RETURN\n"
- "-A FW_allowchain -i lo -j RETURN\n"
- "-A FW_allowchain -o lo -j RETURN\n"
- "-A FW_allowchain -p tcp --tcp-flags RST RST -j RETURN\n"
- "-A FW_allowchain -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
- "-A FW_allowchain -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
- "-A FW_allowchain -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
- "-A FW_allowchain -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
- "-A FW_allowchain -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
- "-A FW_allowchain -p icmpv6 --icmpv6-type redirect -j RETURN\n"
- "-A FW_allowchain -j DROP\n"
+ ":FW_whitechain -\n"
+ "-A FW_whitechain -m owner --uid-owner 10023 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 10059 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 10124 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 10111 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 110122 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 210153 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 210024 -j RETURN\n"
+ "-A FW_whitechain -m owner --uid-owner 0-9999 -j RETURN\n"
+ "-A FW_whitechain -m owner ! --uid-owner 0-4294967294 -j RETURN\n"
+ "-A FW_whitechain -p esp -j RETURN\n"
+ "-A FW_whitechain -i lo -j RETURN\n"
+ "-A FW_whitechain -o lo -j RETURN\n"
+ "-A FW_whitechain -p tcp --tcp-flags RST RST -j RETURN\n"
+ "-A FW_whitechain -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
+ "-A FW_whitechain -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
+ "-A FW_whitechain -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
+ "-A FW_whitechain -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
+ "-A FW_whitechain -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
+ "-A FW_whitechain -p icmpv6 --icmpv6-type redirect -j RETURN\n"
+ "-A FW_whitechain -j DROP\n"
"COMMIT\n";
std::vector<int32_t> uids = { 10023, 10059, 10124, 10111, 110122, 210153, 210024 };
- EXPECT_EQ(expected, makeUidRules(V6, "FW_allowchain", true, uids));
+ EXPECT_EQ(expected, makeUidRules(V6, "FW_whitechain", true, uids));
}
-TEST_F(FirewallControllerTest, TestReplaceDenylistUidRule) {
+TEST_F(FirewallControllerTest, TestReplaceBlacklistUidRule) {
std::string expected =
"*filter\n"
- ":FW_denychain -\n"
- "-A FW_denychain -i lo -j RETURN\n"
- "-A FW_denychain -o lo -j RETURN\n"
- "-A FW_denychain -p tcp --tcp-flags RST RST -j RETURN\n"
- "-A FW_denychain -m owner --uid-owner 10023 -j DROP\n"
- "-A FW_denychain -m owner --uid-owner 10059 -j DROP\n"
- "-A FW_denychain -m owner --uid-owner 10124 -j DROP\n"
+ ":FW_blackchain -\n"
+ "-A FW_blackchain -i lo -j RETURN\n"
+ "-A FW_blackchain -o lo -j RETURN\n"
+ "-A FW_blackchain -p tcp --tcp-flags RST RST -j RETURN\n"
+ "-A FW_blackchain -m owner --uid-owner 10023 -j DROP\n"
+ "-A FW_blackchain -m owner --uid-owner 10059 -j DROP\n"
+ "-A FW_blackchain -m owner --uid-owner 10124 -j DROP\n"
"COMMIT\n";
std::vector<int32_t> uids = { 10023, 10059, 10124 };
- EXPECT_EQ(expected, makeUidRules(V4, "FW_denychain", false, uids));
+ EXPECT_EQ(expected, makeUidRules(V4 ,"FW_blackchain", false, uids));
}
TEST_F(FirewallControllerTest, TestEnableChildChains) {
@@ -248,10 +251,10 @@
EXPECT_EQ(0, mFw.resetFirewall());
expectIptablesRestoreCommands(disableCommands);
- EXPECT_EQ(0, mFw.setFirewallType(DENYLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
expectIptablesRestoreCommands(disableCommands);
- EXPECT_EQ(0, mFw.setFirewallType(DENYLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
expectIptablesRestoreCommands(noCommands);
std::vector<std::string> disableEnableCommands;
@@ -260,7 +263,7 @@
disableEnableCommands.insert(
disableEnableCommands.end(), enableCommands.begin(), enableCommands.end());
- EXPECT_EQ(0, mFw.setFirewallType(ALLOWLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
expectIptablesRestoreCommands(disableEnableCommands);
std::vector<std::string> ifaceCommands = {
@@ -287,15 +290,15 @@
EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", DENY));
expectIptablesRestoreCommands(noCommands);
- EXPECT_EQ(0, mFw.setFirewallType(ALLOWLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
expectIptablesRestoreCommands(noCommands);
EXPECT_EQ(0, mFw.resetFirewall());
expectIptablesRestoreCommands(disableCommands);
- // TODO: calling resetFirewall and then setFirewallType(ALLOWLIST) does
+ // TODO: calling resetFirewall and then setFirewallType(WHITELIST) does
// nothing. This seems like a clear bug.
- EXPECT_EQ(0, mFw.setFirewallType(ALLOWLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
expectIptablesRestoreCommands(noCommands);
}
diff --git a/server/IdletimerController.cpp b/server/IdletimerController.cpp
index cc86d1b..103e7cd 100644
--- a/server/IdletimerController.cpp
+++ b/server/IdletimerController.cpp
@@ -39,8 +39,8 @@
* # For notifications to work the lable name must match the name of a valid interface.
* # If the label name does match an interface, the rules will be a no-op.
*
- * iptables -t raw -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg
- * iptables -t mangle -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg
+ * iptables -t raw -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
+ * iptables -t mangle -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
*
* iptables -nxvL -t raw
* iptables -nxvL -t mangle
@@ -147,14 +147,14 @@
const char *addRemove = (op == IptOpAdd) ? "-A" : "-D";
std::vector<std::string> cmds = {
- "*raw",
- StringPrintf("%s %s -i %s -j IDLETIMER --timeout %u --label %s --send_nl_msg",
- addRemove, LOCAL_RAW_PREROUTING, iface, timeout, classLabel),
- "COMMIT",
- "*mangle",
- StringPrintf("%s %s -o %s -j IDLETIMER --timeout %u --label %s --send_nl_msg",
- addRemove, LOCAL_MANGLE_POSTROUTING, iface, timeout, classLabel),
- "COMMIT\n",
+ "*raw",
+ StringPrintf("%s %s -i %s -j IDLETIMER --timeout %u --label %s --send_nl_msg 1",
+ addRemove, LOCAL_RAW_PREROUTING, iface, timeout, classLabel),
+ "COMMIT",
+ "*mangle",
+ StringPrintf("%s %s -o %s -j IDLETIMER --timeout %u --label %s --send_nl_msg 1",
+ addRemove, LOCAL_MANGLE_POSTROUTING, iface, timeout, classLabel),
+ "COMMIT\n",
};
return (execIptablesRestore(V4V6, Join(cmds, '\n')) == 0) ? 0 : -EREMOTEIO;
diff --git a/server/IdletimerControllerTest.cpp b/server/IdletimerControllerTest.cpp
index 68d6108..30c2298 100644
--- a/server/IdletimerControllerTest.cpp
+++ b/server/IdletimerControllerTest.cpp
@@ -43,16 +43,14 @@
const std::vector<std::string> makeAddRemoveCommands(bool add) {
const char *op = add ? "-A" : "-D";
std::vector<std::string> cmds = {
- "*raw",
- StringPrintf("%s idletimer_raw_PREROUTING -i wlan0 -j IDLETIMER"
- " --timeout 12345 --label hello --send_nl_msg",
- op),
- "COMMIT",
- "*mangle",
- StringPrintf("%s idletimer_mangle_POSTROUTING -o wlan0 -j IDLETIMER"
- " --timeout 12345 --label hello --send_nl_msg",
- op),
- "COMMIT\n",
+ "*raw",
+ StringPrintf("%s idletimer_raw_PREROUTING -i wlan0 -j IDLETIMER"
+ " --timeout 12345 --label hello --send_nl_msg 1", op),
+ "COMMIT",
+ "*mangle",
+ StringPrintf("%s idletimer_mangle_POSTROUTING -o wlan0 -j IDLETIMER"
+ " --timeout 12345 --label hello --send_nl_msg 1", op),
+ "COMMIT\n",
};
return { Join(cmds, '\n') };
}
diff --git a/server/IptablesRestoreControllerTest.cpp b/server/IptablesRestoreControllerTest.cpp
index 3881124..20f6183 100644
--- a/server/IptablesRestoreControllerTest.cpp
+++ b/server/IptablesRestoreControllerTest.cpp
@@ -40,14 +40,7 @@
#define XT_LOCK_ATTEMPTS 10
#define XT_LOCK_POLL_INTERVAL_MS 100
-#define PROC_STAT_MIN_ELEMENTS 52U
-#define PROC_STAT_RSS_INDEX 23U
-
-#define IPTABLES_COMM "(iptables-restor)"
-#define IP6TABLES_COMM "(ip6tables-resto)"
-
using android::base::Join;
-using android::base::StringAppendF;
using android::base::StringPrintf;
using android::netdutils::ScopedMockSyscalls;
using android::netdutils::Stopwatch;
@@ -82,29 +75,10 @@
return con.getIpRestorePid(type);
};
- const std::string getProcStatPath(pid_t pid) { return StringPrintf("/proc/%d/stat", pid); }
-
- std::vector<std::string> parseProcStat(int fd, const std::string& path) {
- std::vector<std::string> procStat;
-
- char statBuf[1024];
- EXPECT_NE(-1, read(fd, statBuf, sizeof(statBuf)))
- << "Could not read from " << path << ": " << strerror(errno);
-
- std::stringstream stream(statBuf);
- std::string item;
- while (std::getline(stream, item, ' ')) {
- procStat.push_back(item);
- }
-
- EXPECT_LE(PROC_STAT_MIN_ELEMENTS, procStat.size()) << "Too few elements in " << path;
- return procStat;
- }
-
void expectNoIptablesRestoreProcess(pid_t pid) {
// We can't readlink /proc/PID/exe, because zombie processes don't have it.
// Parse /proc/PID/stat instead.
- std::string statPath = getProcStatPath(pid);
+ std::string statPath = StringPrintf("/proc/%d/stat", pid);
int fd = open(statPath.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
// ENOENT means the process is gone (expected).
@@ -115,28 +89,14 @@
// If the PID exists, it's possible (though very unlikely) that the PID was reused. Check the
// binary name as well, to ensure the test isn't flaky.
- std::vector<std::string> procStat = parseProcStat(fd, statPath);
- EXPECT_FALSE(procStat[1] == IPTABLES_COMM || procStat[1] == IP6TABLES_COMM)
- << "Previous iptables-restore or ip6tables-restore pid " << pid
- << " still alive: " << Join(procStat, " ");
-
+ char statBuf[1024];
+ ASSERT_NE(-1, read(fd, statBuf, sizeof(statBuf)))
+ << "Could not read from " << statPath << ": " << strerror(errno);
close(fd);
- }
- int getRssPages(pid_t pid) {
- std::string statPath = getProcStatPath(pid);
- int fd = open(statPath.c_str(), O_RDONLY | O_CLOEXEC);
- EXPECT_NE(-1, fd) << "Unexpected error opening " << statPath << ": " << strerror(errno);
- if (fd == -1) return 0;
-
- const auto& procStat = parseProcStat(fd, statPath);
- close(fd);
-
- if (procStat.size() < PROC_STAT_MIN_ELEMENTS) return 0;
- EXPECT_TRUE(procStat[1] == IPTABLES_COMM || procStat[1] == IP6TABLES_COMM)
- << statPath << " is for unexpected process: " << procStat[1];
-
- return std::atoi(procStat[PROC_STAT_RSS_INDEX].c_str());
+ std::string statString(statBuf);
+ EXPECT_FALSE(statString.find("iptables-restor") || statString.find("ip6tables-resto"))
+ << "Previous iptables-restore pid " << pid << " still alive: " << statString;
}
int createTestChain() {
@@ -257,7 +217,7 @@
TEST_F(IptablesRestoreControllerTest, TestCommandTimeout) {
// Don't wait 10 seconds for this test to fail.
- setRetryParameters(3, 100);
+ setRetryParameters(3, 50);
// Expected contents of the chain.
std::vector<std::string> expectedLines = {
@@ -339,44 +299,3 @@
EXPECT_EQ(-1, con.execute(V4V6, "malformed command\n", nullptr));
EXPECT_EQ(0, con.execute(V4V6, "#Test\n", nullptr));
}
-
-TEST_F(IptablesRestoreControllerTest, TestMemoryLeak) {
- std::string cmd = "*filter\n";
-
- // Keep command within PIPE_BUF (4096) just to make sure. Each line is 60 bytes including \n:
- // -I netd_unit_test_9999 -p udp -m udp --sport 12345 -j DROP
- for (int i = 0; i < 33; i++) {
- StringAppendF(&cmd, "-I %s -p udp -m udp --sport 12345 -j DROP\n", mChainName.c_str());
- StringAppendF(&cmd, "-D %s -p udp -m udp --sport 12345 -j DROP\n", mChainName.c_str());
- }
- StringAppendF(&cmd, "COMMIT\n");
- ASSERT_GE(4096U, cmd.size());
-
- // Run the command once in case it causes the first allocations for these iptables-restore
- // processes, and check they don't crash.
- pid_t pid4 = getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS);
- pid_t pid6 = getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS);
- std::string output;
- EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, cmd, nullptr));
- EXPECT_EQ(pid4, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
- EXPECT_EQ(pid6, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
-
- // Check how much RAM the processes are using.
- int pages4 = getRssPages(pid4);
- ASSERT_NE(0, pages4);
- int pages6 = getRssPages(pid6);
- ASSERT_NE(0, pages6);
-
- // Run the command a few times and check that it doesn't crash.
- for (int i = 0; i < 10; i++) {
- EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, cmd, nullptr));
- }
- EXPECT_EQ(pid4, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
- EXPECT_EQ(pid6, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
-
- // Don't allow a leak of more than 25 pages (100kB).
- // This is more than enough for accuracy: the leak in b/162925719 fails with:
- // Expected: (25U) >= (getRssPages(pid4) - pages4), actual: 5 vs 66
- EXPECT_GE(25, getRssPages(pid4) - pages4) << "iptables-restore leaked too many pages";
- EXPECT_GE(25, getRssPages(pid6) - pages6) << "ip6tables-restore leaked too many pages";
-}
diff --git a/server/LocalNetwork.cpp b/server/LocalNetwork.cpp
index 7127b3f..91fda3c 100644
--- a/server/LocalNetwork.cpp
+++ b/server/LocalNetwork.cpp
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#define LOG_TAG "Netd"
-
#include "LocalNetwork.h"
#include "RouteController.h"
+#define LOG_TAG "Netd"
#include "log/log.h"
namespace android {
@@ -31,6 +30,10 @@
LocalNetwork::~LocalNetwork() {
}
+Network::Type LocalNetwork::getType() const {
+ return LOCAL;
+}
+
int LocalNetwork::addInterface(const std::string& interface) {
if (hasInterface(interface)) {
return 0;
diff --git a/server/LocalNetwork.h b/server/LocalNetwork.h
index c774067..7a39a9d 100644
--- a/server/LocalNetwork.h
+++ b/server/LocalNetwork.h
@@ -26,7 +26,7 @@
virtual ~LocalNetwork();
private:
- std::string getTypeString() const override { return "LOCAL"; };
+ Type getType() const override;
[[nodiscard]] int addInterface(const std::string& interface) override;
[[nodiscard]] int removeInterface(const std::string& interface) override;
};
diff --git a/server/NdcDispatcher.cpp b/server/NdcDispatcher.cpp
index 80ad7fb..48f7d9f 100644
--- a/server/NdcDispatcher.cpp
+++ b/server/NdcDispatcher.cpp
@@ -747,13 +747,13 @@
}
int NdcDispatcher::FirewallCmd::parseFirewallType(const char* arg) {
- if (!strcmp(arg, "allowlist")) {
- return INetd::FIREWALL_ALLOWLIST;
- } else if (!strcmp(arg, "denylist")) {
- return INetd::FIREWALL_DENYLIST;
+ if (!strcmp(arg, "whitelist")) {
+ return INetd::FIREWALL_WHITELIST;
+ } else if (!strcmp(arg, "blacklist")) {
+ return INetd::FIREWALL_BLACKLIST;
} else {
LOG(LOGLEVEL) << "failed to parse firewall type " << arg;
- return INetd::FIREWALL_DENYLIST;
+ return INetd::FIREWALL_BLACKLIST;
}
}
@@ -764,8 +764,6 @@
return INetd::FIREWALL_CHAIN_STANDBY;
} else if (!strcmp(arg, "powersave")) {
return INetd::FIREWALL_CHAIN_POWERSAVE;
- } else if (!strcmp(arg, "restricted")) {
- return INetd::FIREWALL_CHAIN_RESTRICTED;
} else if (!strcmp(arg, "none")) {
return INetd::FIREWALL_CHAIN_NONE;
} else {
@@ -783,7 +781,7 @@
if (!strcmp(argv[1], "enable")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: firewall enable <allowlist|denylist>", false);
+ "Usage: firewall enable <whitelist|blacklist>", false);
return 0;
}
int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk();
@@ -1049,12 +1047,9 @@
return syntaxError(cli, "Missing argument");
}
unsigned netId = stringToNetId(argv[2]);
- if (argc == 5 && !strcmp(argv[3], "vpn")) {
+ if (argc == 6 && !strcmp(argv[3], "vpn")) {
bool secure = strtol(argv[4], nullptr, 2);
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (Status status = mNetd->networkCreateVpn(netId, secure); !status.isOk()) {
-#pragma clang diagnostic pop
return operationError(cli, "createVirtualNetwork() failed",
status.serviceSpecificErrorCode());
}
@@ -1068,10 +1063,7 @@
return syntaxError(cli, "Unknown permission");
}
}
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (Status status = mNetd->networkCreatePhysical(netId, permission); !status.isOk()) {
-#pragma clang diagnostic pop
return operationError(cli, "createPhysicalNetwork() failed",
status.serviceSpecificErrorCode());
}
diff --git a/server/NetdConstants.cpp b/server/NetdConstants.cpp
index f3898f5..80282b3 100644
--- a/server/NetdConstants.cpp
+++ b/server/NetdConstants.cpp
@@ -66,8 +66,7 @@
}
for (i = 1; i < name.size(); i++) {
- if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-')
- && (name[i] != ':') && (name[i] != '.')) {
+ if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':')) {
return false;
}
}
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 1f5dc97..3bf879b 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -52,11 +52,9 @@
using android::base::StringPrintf;
using android::base::WriteStringToFile;
-using android::net::NativeNetworkType;
using android::net::TetherOffloadRuleParcel;
using android::net::TetherStatsParcel;
using android::net::UidRangeParcel;
-using android::net::netd::aidl::NativeUidRangeConfig;
using android::netdutils::DumpWriter;
using android::netdutils::ScopedIndent;
using android::os::ParcelFileDescriptor;
@@ -172,9 +170,8 @@
NetdNativeService::NetdNativeService() {
// register log callback to BnNetd::logFunc
- BnNetd::logFunc = [](const auto& log) {
- binderCallLogFn(log, [](const std::string& msg) { gLog.info("%s", msg.c_str()); });
- };
+ BnNetd::logFunc = std::bind(binderCallLogFn, std::placeholders::_1,
+ [](const std::string& msg) { gLog.info("%s", msg.c_str()); });
}
status_t NetdNativeService::start() {
@@ -271,11 +268,9 @@
}
binder::Status NetdNativeService::firewallReplaceUidChain(const std::string& chainName,
- bool isAllowlist,
- const std::vector<int32_t>& uids,
- bool* ret) {
+ bool isWhitelist, const std::vector<int32_t>& uids, bool *ret) {
NETD_LOCKING_RPC(gCtls->firewallCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- int err = gCtls->firewallCtrl.replaceUidChain(chainName, isAllowlist, uids);
+ int err = gCtls->firewallCtrl.replaceUidChain(chainName, isWhitelist, uids);
*ret = (err == 0);
return binder::Status::ok();
}
@@ -321,60 +316,41 @@
binder::Status NetdNativeService::bandwidthAddNaughtyApp(int32_t uid) {
NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
- int res = gCtls->bandwidthCtrl.addNaughtyApps(appUids);
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.addNaughtyApps(appStrUids);
return statusFromErrcode(res);
}
binder::Status NetdNativeService::bandwidthRemoveNaughtyApp(int32_t uid) {
NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
- int res = gCtls->bandwidthCtrl.removeNaughtyApps(appUids);
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.removeNaughtyApps(appStrUids);
return statusFromErrcode(res);
}
binder::Status NetdNativeService::bandwidthAddNiceApp(int32_t uid) {
NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
- int res = gCtls->bandwidthCtrl.addNiceApps(appUids);
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.addNiceApps(appStrUids);
return statusFromErrcode(res);
}
binder::Status NetdNativeService::bandwidthRemoveNiceApp(int32_t uid) {
NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
- int res = gCtls->bandwidthCtrl.removeNiceApps(appUids);
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.removeNiceApps(appStrUids);
return statusFromErrcode(res);
}
-// TODO: Remove this function when there are no users. Currently, it is still used by DNS resolver
-// tests.
binder::Status NetdNativeService::networkCreatePhysical(int32_t netId, int32_t permission) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
int ret = gCtls->netCtrl.createPhysicalNetwork(netId, convertPermission(permission));
return statusFromErrcode(ret);
}
-// TODO: Remove this function when there are no users. Currently, it is still used by DNS resolver
-// tests.
binder::Status NetdNativeService::networkCreateVpn(int32_t netId, bool secure) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
- // The value of vpnType does not matter here, because it is not used in AOSP and is only
- // implemented by OEMs. Also, the RPC is going to deprecate. Just pick a value defined in INetd
- // as default.
- int ret = gCtls->netCtrl.createVirtualNetwork(netId, secure, NativeVpnType::LEGACY);
- return statusFromErrcode(ret);
-}
-
-binder::Status NetdNativeService::networkCreate(const NativeNetworkConfig& config) {
- ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = -EINVAL;
- if (config.networkType == NativeNetworkType::PHYSICAL) {
- ret = gCtls->netCtrl.createPhysicalNetwork(config.netId,
- convertPermission(config.permission));
- } else if (config.networkType == NativeNetworkType::VIRTUAL) {
- ret = gCtls->netCtrl.createVirtualNetwork(config.netId, config.secure, config.vpnType);
- }
+ int ret = gCtls->netCtrl.createVirtualNetwork(netId, secure);
return statusFromErrcode(ret);
}
@@ -401,8 +377,7 @@
int32_t netId, const std::vector<UidRangeParcel>& uidRangeArray) {
// NetworkController::addUsersToNetwork is thread-safe.
ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray),
- UidRanges::DEFAULT_SUB_PRIORITY);
+ int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray));
return statusFromErrcode(ret);
}
@@ -410,22 +385,7 @@
int32_t netId, const std::vector<UidRangeParcel>& uidRangeArray) {
// NetworkController::removeUsersFromNetwork is thread-safe.
ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, UidRanges(uidRangeArray),
- UidRanges::DEFAULT_SUB_PRIORITY);
- return statusFromErrcode(ret);
-}
-
-binder::Status NetdNativeService::networkAddUidRangesParcel(const NativeUidRangeConfig& config) {
- ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.addUsersToNetwork(config.netId, UidRanges(config.uidRanges),
- config.subPriority);
- return statusFromErrcode(ret);
-}
-
-binder::Status NetdNativeService::networkRemoveUidRangesParcel(const NativeUidRangeConfig& config) {
- ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.removeUsersFromNetwork(config.netId, UidRanges(config.uidRanges),
- config.subPriority);
+ int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, UidRanges(uidRangeArray));
return statusFromErrcode(ret);
}
@@ -1160,7 +1120,7 @@
return binder::Status::ok();
}
-binder::Status NetdNativeService::networkSetProtectAllow(int32_t uid) {
+binder::Status NetdNativeService::NetdNativeService::networkSetProtectAllow(int32_t uid) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
std::vector<uid_t> uids = {(uid_t) uid};
gCtls->netCtrl.allowProtect(uids);
@@ -1291,43 +1251,65 @@
return binder::Status::ok();
}
-// TODO: remark @deprecated in INetd.aidl.
-binder::Status NetdNativeService::tetherOffloadRuleAdd(const TetherOffloadRuleParcel& /* rule */) {
- // deprecated
+binder::Status NetdNativeService::tetherOffloadRuleAdd(const TetherOffloadRuleParcel& rule) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
- return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
+
+ return asBinderStatus(gCtls->tetherCtrl.addOffloadRule(rule));
}
-// TODO: remark @deprecated in INetd.aidl.
-binder::Status NetdNativeService::tetherOffloadRuleRemove(
- const TetherOffloadRuleParcel& /* rule */) {
- // deprecated
+binder::Status NetdNativeService::tetherOffloadRuleRemove(const TetherOffloadRuleParcel& rule) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
- return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
+
+ return asBinderStatus(gCtls->tetherCtrl.removeOffloadRule(rule));
}
-// TODO: remark @deprecated in INetd.aidl.
+namespace {
+
+constexpr const char UNUSED_IFNAME[] = "";
+
+TetherStatsParcel toTetherStatsParcel(const TetherController::TetherOffloadStats& stats) {
+ TetherStatsParcel result;
+ result.iface = UNUSED_IFNAME;
+ result.rxBytes = stats.rxBytes;
+ result.rxPackets = stats.rxPackets;
+ result.txBytes = stats.txBytes;
+ result.txPackets = stats.txPackets;
+ result.ifIndex = stats.ifIndex;
+ return result;
+}
+
+} // namespace
+
binder::Status NetdNativeService::tetherOffloadGetStats(
- std::vector<TetherStatsParcel>* /* tetherStatsParcelVec */) {
- // deprecated
+ std::vector<TetherStatsParcel>* tetherStatsParcelVec) {
NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
+
+ tetherStatsParcelVec->clear();
+ const auto& statsList = gCtls->tetherCtrl.getTetherOffloadStats();
+ if (!isOk(statsList)) {
+ return asBinderStatus(statsList);
+ }
+ for (const auto& stats : statsList.value()) {
+ tetherStatsParcelVec->push_back(toTetherStatsParcel(stats));
+ }
+ return binder::Status::ok();
}
-// TODO: remark @deprecated in INetd.aidl.
-binder::Status NetdNativeService::tetherOffloadSetInterfaceQuota(int /* ifIndex */,
- int64_t /* quotaBytes */) {
- // deprecated
+binder::Status NetdNativeService::tetherOffloadSetInterfaceQuota(int ifIndex, int64_t quotaBytes) {
NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
+ int res = gCtls->tetherCtrl.setTetherOffloadInterfaceQuota(ifIndex, quotaBytes);
+ return statusFromErrcode(res);
}
-// TODO: remark @deprecated in INetd.aidl.
binder::Status NetdNativeService::tetherOffloadGetAndClearStats(
- int /* ifIndex */, android::net::TetherStatsParcel* /* tetherStats */) {
- // deprecated
+ int ifIndex, android::net::TetherStatsParcel* tetherStats) {
NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
+ const auto& stats = gCtls->tetherCtrl.getAndClearTetherOffloadStats(ifIndex);
+ if (!stats.ok()) {
+ return asBinderStatus(stats);
+ }
+ *tetherStats = toTetherStatsParcel(stats.value());
+ return binder::Status::ok();
}
} // namespace net
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 9779f36..7b7f9b3 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -37,8 +37,9 @@
binder::Status isAlive(bool *alive) override;
// Firewall commands.
- binder::Status firewallReplaceUidChain(const std::string& chainName, bool isAllowlist,
- const std::vector<int32_t>& uids, bool* ret) override;
+ binder::Status firewallReplaceUidChain(
+ const std::string& chainName, bool isWhitelist,
+ const std::vector<int32_t>& uids, bool *ret) override;
binder::Status firewallSetFirewallType(int32_t firewallType) override;
binder::Status firewallSetInterfaceRule(const std::string& ifName,
int32_t firewallRule) override;
@@ -64,7 +65,6 @@
// Network and routing commands.
binder::Status networkCreatePhysical(int32_t netId, int32_t permission) override;
binder::Status networkCreateVpn(int32_t netId, bool secure) override;
- binder::Status networkCreate(const NativeNetworkConfig& config) override;
binder::Status networkDestroy(int32_t netId) override;
binder::Status networkAddInterface(int32_t netId, const std::string& iface) override;
@@ -74,10 +74,6 @@
const std::vector<UidRangeParcel>& uids) override;
binder::Status networkRemoveUidRanges(int32_t netId,
const std::vector<UidRangeParcel>& uids) override;
- binder::Status networkAddUidRangesParcel(
- const netd::aidl::NativeUidRangeConfig& uidRangesConfig) override;
- binder::Status networkRemoveUidRangesParcel(
- const netd::aidl::NativeUidRangeConfig& uidRangesConfig) override;
binder::Status networkRejectNonSecureVpn(bool enable,
const std::vector<UidRangeParcel>& uids) override;
binder::Status networkAddRouteParcel(int32_t netId, const RouteInfoParcel& route) override;
diff --git a/server/NetlinkHandler.cpp b/server/NetlinkHandler.cpp
index 525bb2d..7fb3437 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -155,11 +155,7 @@
if (shouldDestroy) {
SockDiag sd;
if (sd.open()) {
- // Pass the interface index iff. destroying sockets on a link-local address.
- // This cannot use an interface name as the interface might no longer exist.
- int destroyIfaceIndex =
- std::string_view(addrstr).starts_with("fe80:") ? ifaceIndex : 0;
- int ret = sd.destroySockets(addrstr, destroyIfaceIndex);
+ int ret = sd.destroySockets(addrstr);
if (ret < 0) {
ALOGE("Error destroying sockets: %s", strerror(-ret));
}
diff --git a/server/Network.cpp b/server/Network.cpp
index 72a1545..eb2a233 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -13,12 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "Netd"
#include "Network.h"
-#include "RouteController.h"
-#include "SockDiag.h"
+#define LOG_TAG "Netd"
#include "log/log.h"
#include <android-base/strings.h>
@@ -61,7 +59,25 @@
const char kSeparator[] = " ";
std::stringstream repr;
- repr << mNetId << kSeparator << getTypeString();
+ repr << mNetId;
+
+ repr << kSeparator;
+ switch (getType()) {
+ case DUMMY:
+ repr << "DUMMY";
+ break;
+ case LOCAL:
+ repr << "LOCAL";
+ break;
+ case PHYSICAL:
+ repr << "PHYSICAL";
+ break;
+ case VIRTUAL:
+ repr << "VIRTUAL";
+ break;
+ default:
+ repr << "unknown";
+ }
if (mInterfaces.size() > 0) {
repr << kSeparator << android::base::Join(mInterfaces, ",");
@@ -70,73 +86,9 @@
return repr.str();
}
-std::string Network::uidRangesToString() const {
- if (mUidRangeMap.empty()) {
- return "";
- }
- std::ostringstream result;
- for (auto it = mUidRangeMap.begin(); it != mUidRangeMap.end(); ++it) {
- result << "prio " << it->first << " " << it->second.toString();
- if (std::next(it) != mUidRangeMap.end()) result << "; ";
- }
- return result.str();
+Network::Network(unsigned netId) : mNetId(netId) {
}
-// Check if the user has been added to this network. If yes, the highest priority of matching
-// setting is returned by subPriority. Thus caller can make choice among several matching
-// networks.
-bool Network::appliesToUser(uid_t uid, uint32_t* subPriority) const {
- for (const auto& [priority, uidRanges] : mUidRangeMap) {
- if (uidRanges.hasUid(uid)) {
- *subPriority = priority;
- return true;
- }
- }
- return false;
-}
-
-void Network::addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
- auto iter = mUidRangeMap.find(subPriority);
- if (iter != mUidRangeMap.end()) {
- iter->second.add(uidRanges);
- } else {
- mUidRangeMap[subPriority] = uidRanges;
- }
-}
-
-void Network::removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
- auto iter = mUidRangeMap.find(subPriority);
- if (iter != mUidRangeMap.end()) {
- iter->second.remove(uidRanges);
- if (iter->second.empty()) {
- mUidRangeMap.erase(subPriority);
- }
- } else {
- ALOGW("uidRanges with priority %u not found", subPriority);
- }
-}
-
-bool Network::canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const {
- if (uidRanges.overlapsSelf()) {
- ALOGE("uid range %s overlaps self", uidRanges.toString().c_str());
- return false;
- }
-
- auto iter = mUidRangeMap.find(subPriority);
- if (iter != mUidRangeMap.end() && uidRanges.overlaps(iter->second)) {
- ALOGE("uid range %s overlaps priority %u %s", uidRanges.toString().c_str(), subPriority,
- iter->second.toString().c_str());
- return false;
- }
- return true;
-}
-
-bool Network::isSecure() const {
- return mSecure;
-}
-
-Network::Network(unsigned netId, bool secure) : mNetId(netId), mSecure(secure) {}
-
} // namespace net
} // namespace android
diff --git a/server/Network.h b/server/Network.h
index aa1b21a..8417f34 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -17,67 +17,45 @@
#pragma once
#include "NetdConstants.h"
-#include "UidRanges.h"
#include <set>
#include <string>
namespace android::net {
-typedef std::map<uint32_t, UidRanges> UidRangeMap;
-
// A Network represents a collection of interfaces participating as a single administrative unit.
class Network {
public:
+ enum Type {
+ DUMMY,
+ LOCAL,
+ PHYSICAL,
+ VIRTUAL,
+ };
+
// You MUST ensure that no interfaces are still assigned to this network, say by calling
// clearInterfaces(), before deleting it. This is because interface removal may fail. If we
// automatically removed interfaces in the destructor, you wouldn't know if it failed.
virtual ~Network();
- virtual std::string getTypeString() const = 0;
+ virtual Type getType() const = 0;
unsigned getNetId() const;
bool hasInterface(const std::string& interface) const;
const std::set<std::string>& getInterfaces() const;
// These return 0 on success or negative errno on failure.
- [[nodiscard]] virtual int addInterface(const std::string&) { return -EINVAL; }
- [[nodiscard]] virtual int removeInterface(const std::string&) { return -EINVAL; }
+ [[nodiscard]] virtual int addInterface(const std::string& interface) = 0;
+ [[nodiscard]] virtual int removeInterface(const std::string& interface) = 0;
[[nodiscard]] int clearInterfaces();
std::string toString() const;
- std::string uidRangesToString() const;
- bool appliesToUser(uid_t uid, uint32_t* subPriority) const;
- [[nodiscard]] virtual int addUsers(const UidRanges&, uint32_t /*subPriority*/) {
- return -EINVAL;
- };
- [[nodiscard]] virtual int removeUsers(const UidRanges&, uint32_t /*subPriority*/) {
- return -EINVAL;
- };
- bool isSecure() const;
- virtual bool isPhysical() { return false; }
- virtual bool isUnreachable() { return false; }
- virtual bool isVirtual() { return false; }
- virtual bool canAddUsers() { return false; }
- virtual bool isValidSubPriority(uint32_t /*priority*/) { return false; }
- virtual void addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
- virtual void removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
protected:
- explicit Network(unsigned netId, bool mSecure = false);
- bool canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const;
+ explicit Network(unsigned netId);
const unsigned mNetId;
std::set<std::string> mInterfaces;
- // Each subsidiary priority maps to a set of UID ranges of a feature.
- std::map<uint32_t, UidRanges> mUidRangeMap;
- const bool mSecure;
-
-private:
- enum Action {
- REMOVE,
- ADD,
- };
};
} // namespace android::net
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 602639c..20ae44b 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -39,7 +39,6 @@
#include "OffloadUtils.h"
#include "PhysicalNetwork.h"
#include "RouteController.h"
-#include "UnreachableNetwork.h"
#include "VirtualNetwork.h"
#include "netdutils/DumpWriter.h"
#include "netid_client.h"
@@ -129,7 +128,7 @@
int NetworkController::DelegateImpl::modifyFallthrough(const std::string& physicalInterface,
Permission permission, bool add) {
for (const auto& entry : mNetworkController->mNetworks) {
- if (entry.second->isVirtual()) {
+ if (entry.second->getType() == Network::VIRTUAL) {
if (int ret = modifyFallthrough(entry.first, physicalInterface, permission, add)) {
return ret;
}
@@ -141,25 +140,24 @@
NetworkController::NetworkController() :
mDelegateImpl(new NetworkController::DelegateImpl(this)), mDefaultNetId(NETID_UNSET),
mProtectableUsers({AID_VPN}) {
- gLog.info("enter NetworkController ctor");
mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
mNetworks[DUMMY_NET_ID] = new DummyNetwork(DUMMY_NET_ID);
- mNetworks[UNREACHABLE_NET_ID] = new UnreachableNetwork(UNREACHABLE_NET_ID);
// Clear all clsact stubs on all interfaces.
// TODO: perhaps only remove the clsact on the interface which is added by
// RouteController::addInterfaceToPhysicalNetwork. Currently, the netd only
// attach the clsact to the interface for the physical network.
- const auto& ifaces = InterfaceController::getIfaceNames();
- if (isOk(ifaces)) {
- for (const std::string& iface : ifaces.value()) {
- if (int ifIndex = if_nametoindex(iface.c_str())) {
- // Ignore the error because the interface might not have a clsact.
- tcQdiscDelDevClsact(ifIndex);
+ if (bpf::isBpfSupported()) {
+ const auto& ifaces = InterfaceController::getIfaceNames();
+ if (isOk(ifaces)) {
+ for (const std::string& iface : ifaces.value()) {
+ if (int ifIndex = if_nametoindex(iface.c_str())) {
+ // Ignore the error because the interface might not have a clsact.
+ tcQdiscDelDevClsact(ifIndex);
+ }
}
}
}
- gLog.info("leave NetworkController ctor");
}
unsigned NetworkController::getDefaultNetwork() const {
@@ -180,7 +178,7 @@
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (!network->isPhysical()) {
+ if (network->getType() != Network::PHYSICAL) {
ALOGE("cannot set default to non-physical network with netId %u", netId);
return -EINVAL;
}
@@ -191,7 +189,7 @@
if (mDefaultNetId != NETID_UNSET) {
Network* network = getNetworkLocked(mDefaultNetId);
- if (!network || !network->isPhysical()) {
+ if (!network || network->getType() != Network::PHYSICAL) {
ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
return -ESRCH;
}
@@ -209,16 +207,13 @@
fwmark.protectedFromVpn = true;
fwmark.permission = PERMISSION_SYSTEM;
- Network* appDefaultNetwork = getPhysicalOrUnreachableNetworkForUserLocked(uid);
- unsigned defaultNetId = appDefaultNetwork ? appDefaultNetwork->getNetId() : mDefaultNetId;
-
// Common case: there is no VPN that applies to the user, and the query did not specify a netId.
// Therefore, it is safe to set the explicit bit on this query and skip all the complex logic
// below. While this looks like a special case, it is actually the one that handles the vast
// majority of DNS queries.
// TODO: untangle this code.
if (*netId == NETID_UNSET && getVirtualNetworkForUserLocked(uid) == nullptr) {
- *netId = defaultNetId;
+ *netId = mDefaultNetId;
fwmark.netId = *netId;
fwmark.explicitlySelected = true;
return fwmark.intValue;
@@ -234,8 +229,8 @@
// servers (through the default network). Otherwise, the query is guaranteed to fail.
// http://b/29498052
Network *network = getNetworkLocked(*netId);
- if (network && network->isVirtual() && !resolv_has_nameservers(*netId)) {
- *netId = defaultNetId;
+ if (network && network->getType() == Network::VIRTUAL && !resolv_has_nameservers(*netId)) {
+ *netId = mDefaultNetId;
}
} else {
// If the user is subject to a VPN and the VPN provides DNS servers, use those servers
@@ -248,7 +243,7 @@
} else {
// TODO: return an error instead of silently doing the DNS lookup on the wrong network.
// http://b/27560555
- *netId = defaultNetId;
+ *netId = mDefaultNetId;
}
}
fwmark.netId = *netId;
@@ -256,22 +251,17 @@
}
// Returns the NetId that a given UID would use if no network is explicitly selected. Specifically,
-// the VPN that applies to the UID if any; Otherwise, the default network for UID; Otherwise the
-// unreachable network that applies to the UID; lastly, the default network.
+// the VPN that applies to the UID if any; otherwise, the default network.
unsigned NetworkController::getNetworkForUser(uid_t uid) const {
ScopedRLock lock(mRWLock);
if (VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid)) {
return virtualNetwork->getNetId();
}
- if (Network* network = getPhysicalOrUnreachableNetworkForUserLocked(uid)) {
- return network->getNetId();
- }
return mDefaultNetId;
}
// Returns the NetId that will be set when a socket connect()s. This is the bypassable VPN that
-// applies to the user if any; otherwise, the default network that applies to user if any; lastly,
-// the default network.
+// applies to the user if any; otherwise, the default network.
//
// In general, we prefer to always set the default network's NetId in connect(), so that if the VPN
// is a split-tunnel and disappears later, the socket continues working (since the default network's
@@ -284,21 +274,11 @@
// traffic to the default network. But it does mean that if the bypassable VPN goes away (and thus
// the fallthrough rules also go away), the socket that used to fallthrough to the default network
// will stop working.
-//
-// Per-app physical default networks behave the same as bypassable VPNs: when a socket is connected
-// on one of these networks, we mark the socket with the netId of the network. This ensures that if
-// the per-app default network changes, sockets established on the previous network are still
-// routed to that network, assuming the network's UID ranges still apply to the UID. While this
-// means that fallthrough to the default network does not work, physical networks not expected
-// ever to be split tunnels.
unsigned NetworkController::getNetworkForConnectLocked(uid_t uid) const {
VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
if (virtualNetwork && !virtualNetwork->isSecure()) {
return virtualNetwork->getNetId();
}
- if (Network* network = getPhysicalOrUnreachableNetworkForUserLocked(uid)) {
- return network->getNetId();
- }
return mDefaultNetId;
}
@@ -377,7 +357,7 @@
bool NetworkController::isVirtualNetworkLocked(unsigned netId) const {
Network* network = getNetworkLocked(netId);
- return network && network->isVirtual();
+ return network && network->getType() == Network::VIRTUAL;
}
int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission permission) {
@@ -437,7 +417,7 @@
return ret;
}
-int NetworkController::createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType) {
+int NetworkController::createVirtualNetwork(unsigned netId, bool secure) {
ScopedWLock lock(mRWLock);
if (!(MIN_NET_ID <= netId && netId <= MAX_NET_ID)) {
@@ -450,11 +430,6 @@
return -EEXIST;
}
- if (vpnType < NativeVpnType::SERVICE || NativeVpnType::OEM < vpnType) {
- ALOGE("invalid vpnType %d", static_cast<int>(vpnType));
- return -EINVAL;
- }
-
if (int ret = modifyFallthroughLocked(netId, true)) {
return ret;
}
@@ -465,8 +440,8 @@
int NetworkController::destroyNetwork(unsigned netId) {
ScopedWLock lock(mRWLock);
- if (netId == LOCAL_NET_ID || netId == UNREACHABLE_NET_ID) {
- ALOGE("cannot destroy local or unreachable network");
+ if (netId == LOCAL_NET_ID) {
+ ALOGE("cannot destroy local network");
return -EINVAL;
}
if (!isValidNetworkLocked(netId)) {
@@ -491,7 +466,7 @@
}
}
mDefaultNetId = NETID_UNSET;
- } else if (network->isVirtual()) {
+ } else if (network->getType() == Network::VIRTUAL) {
if (int err = modifyFallthroughLocked(netId, false)) {
if (!ret) {
ret = err;
@@ -587,7 +562,7 @@
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (!network->isPhysical()) {
+ if (network->getType() != Network::PHYSICAL) {
ALOGE("cannot set permissions on non-physical network with netId %u", netId);
return -EINVAL;
}
@@ -599,41 +574,39 @@
return 0;
}
-namespace {
-
-int isWrongNetworkForUidRanges(unsigned netId, Network* network) {
+int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
+ ScopedWLock lock(mRWLock);
+ Network* network = getNetworkLocked(netId);
if (!network) {
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (!network->canAddUsers()) {
- ALOGE("cannot add/remove users to/from %s network %u", network->getTypeString().c_str(),
- netId);
+ if (network->getType() != Network::VIRTUAL) {
+ ALOGE("cannot add users to non-virtual network with netId %u", netId);
return -EINVAL;
}
+ if (int ret = static_cast<VirtualNetwork*>(network)->addUsers(uidRanges, mProtectableUsers)) {
+ return ret;
+ }
return 0;
}
-} // namespace
-
-int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
- uint32_t subPriority) {
+int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
ScopedWLock lock(mRWLock);
Network* network = getNetworkLocked(netId);
- if (int ret = isWrongNetworkForUidRanges(netId, network)) {
+ if (!network) {
+ ALOGE("no such netId %u", netId);
+ return -ENONET;
+ }
+ if (network->getType() != Network::VIRTUAL) {
+ ALOGE("cannot remove users from non-virtual network with netId %u", netId);
+ return -EINVAL;
+ }
+ if (int ret = static_cast<VirtualNetwork*>(network)->removeUsers(uidRanges,
+ mProtectableUsers)) {
return ret;
}
- return network->addUsers(uidRanges, subPriority);
-}
-
-int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
- uint32_t subPriority) {
- ScopedWLock lock(mRWLock);
- Network* network = getNetworkLocked(netId);
- if (int ret = isWrongNetworkForUidRanges(netId, network)) {
- return ret;
- }
- return network->removeUsers(uidRanges, subPriority);
+ return 0;
}
int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
@@ -736,17 +709,12 @@
for (const auto& i : mNetworks) {
Network* network = i.second;
dw.println(network->toString());
- if (network->isPhysical()) {
+ if (network->getType() == Network::PHYSICAL) {
dw.incIndent();
Permission permission = reinterpret_cast<PhysicalNetwork*>(network)->getPermission();
dw.println("Required permission: %s", permissionToName(permission));
dw.decIndent();
}
- if (const auto& str = network->uidRangesToString(); !str.empty()) {
- dw.incIndent();
- dw.println(str);
- dw.decIndent();
- }
dw.blankline();
}
dw.decIndent();
@@ -783,34 +751,17 @@
}
VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
- uint32_t subPriority;
- for (const auto& [_, network] : mNetworks) {
- if (network->isVirtual() && network->appliesToUser(uid, &subPriority)) {
- return static_cast<VirtualNetwork*>(network);
+ for (const auto& entry : mNetworks) {
+ if (entry.second->getType() == Network::VIRTUAL) {
+ VirtualNetwork* virtualNetwork = static_cast<VirtualNetwork*>(entry.second);
+ if (virtualNetwork->appliesToUser(uid)) {
+ return virtualNetwork;
+ }
}
}
return nullptr;
}
-// Returns a network with the highest subsidiary priority among physical and unreachable networks
-// that applies to uid. For a single subsidiary priority, an uid should belong to only one network.
-// If the uid apply to different network with the same priority at the same time, the behavior is
-// undefined. That is a configuration error.
-Network* NetworkController::getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const {
- Network* bestNetwork = nullptr;
- unsigned bestSubPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
- for (const auto& [netId, network] : mNetworks) {
- uint32_t subPriority;
- if (!network->isPhysical() && !network->isUnreachable()) continue;
- if (!network->appliesToUser(uid, &subPriority)) continue;
- if (subPriority < bestSubPriority) {
- bestNetwork = network;
- bestSubPriority = subPriority;
- }
- }
- return bestNetwork;
-}
-
Permission NetworkController::getPermissionForUserLocked(uid_t uid) const {
auto iter = mUsers.find(uid);
if (iter != mUsers.end()) {
@@ -830,35 +781,18 @@
if (uid == INVALID_UID) {
return -EREMOTEIO;
}
- // If the UID has PERMISSION_SYSTEM, it can use whatever network it wants.
Permission userPermission = getPermissionForUserLocked(uid);
if ((userPermission & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
return 0;
}
- // If the UID wants to use a VPN, it can do so if and only if the VPN applies to the UID.
- uint32_t subPriority;
- if (network->isVirtual()) {
- return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM;
+ if (network->getType() == Network::VIRTUAL) {
+ return static_cast<VirtualNetwork*>(network)->appliesToUser(uid) ? 0 : -EPERM;
}
- // If a VPN applies to the UID, and the VPN is secure (i.e., not bypassable), then the UID can
- // only select a different network if it has the ability to protect its sockets.
VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
if (virtualNetwork && virtualNetwork->isSecure() &&
mProtectableUsers.find(uid) == mProtectableUsers.end()) {
return -EPERM;
}
- // If the UID wants to use a physical network and it has a UID range that includes the UID, the
- // UID has permission to use it regardless of whether the permission bits match.
- if (network->isPhysical() && network->appliesToUser(uid, &subPriority)) {
- return 0;
- }
- // Only apps that are configured as "no default network" can use the unreachable network.
- if (network->isUnreachable()) {
- return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM;
- }
- // Check whether the UID's permission bits are sufficient to use the network.
- // Because the permission of the system default network is PERMISSION_NONE(0x0), apps can always
- // pass the check here when using the system default network.
Permission networkPermission = static_cast<PhysicalNetwork*>(network)->getPermission();
return ((userPermission & networkPermission) == networkPermission) ? 0 : -EACCES;
}
@@ -915,7 +849,7 @@
ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
return -ESRCH;
}
- if (!network->isPhysical()) {
+ if (network->getType() != Network::PHYSICAL) {
ALOGE("inconceivable! default network must be a physical network");
return -EINVAL;
}
@@ -933,7 +867,7 @@
bool physicalNetworkExists = false;
for (const auto& entry : mNetworks) {
const auto& network = entry.second;
- if (network->isPhysical() && network->getNetId() >= MIN_NET_ID) {
+ if (network->getType() == Network::PHYSICAL && network->getNetId() >= MIN_NET_ID) {
physicalNetworkExists = true;
break;
}
diff --git a/server/NetworkController.h b/server/NetworkController.h
index a61ac39..ff49c02 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -22,8 +22,6 @@
#include "NetdConstants.h"
#include "Permission.h"
-#include "PhysicalNetwork.h"
-#include "UnreachableNetwork.h"
#include "android/net/INetd.h"
#include "netdutils/DumpWriter.h"
@@ -84,12 +82,11 @@
*/
class NetworkController {
public:
- // NetIds 53..98 are reserved for future use.
+ // NetIds 52..98 are reserved for future use.
static constexpr int MIN_OEM_ID = 1;
static constexpr int MAX_OEM_ID = 50;
static constexpr int LOCAL_NET_ID = INetd::LOCAL_NET_ID;
- static constexpr int DUMMY_NET_ID = INetd::DUMMY_NET_ID;
- static constexpr int UNREACHABLE_NET_ID = INetd::UNREACHABLE_NET_ID;
+ static constexpr int DUMMY_NET_ID = 51;
// Route mode for modify route
enum RouteOperation { ROUTE_ADD, ROUTE_UPDATE, ROUTE_REMOVE };
@@ -107,7 +104,7 @@
[[nodiscard]] int createPhysicalNetwork(unsigned netId, Permission permission);
[[nodiscard]] int createPhysicalOemNetwork(Permission permission, unsigned* netId);
- [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType);
+ [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure);
[[nodiscard]] int destroyNetwork(unsigned netId);
[[nodiscard]] int addInterfaceToNetwork(unsigned netId, const char* interface);
@@ -119,10 +116,8 @@
[[nodiscard]] int setPermissionForNetworks(Permission permission,
const std::vector<unsigned>& netIds);
- [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
- uint32_t subPriority);
- [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
- uint32_t subPriority);
+ [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges);
+ [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges);
// |nexthop| can be NULL (to indicate a directly-connected route), "unreachable" (to indicate a
// route that's blocked), "throw" (to indicate the lack of a match), or a regular IP address.
@@ -156,12 +151,13 @@
// set to a non-NETID_UNSET value if the user already has indicated a preference. Returns the
// fwmark value to set on the socket when performing the DNS request.
uint32_t getNetworkForDnsLocked(unsigned* netId, uid_t uid) const;
+
+ unsigned getNetworkForUserLocked(uid_t uid) const;
unsigned getNetworkForConnectLocked(uid_t uid) const;
unsigned getNetworkForInterfaceLocked(const char* interface) const;
bool canProtectLocked(uid_t uid) const;
bool isVirtualNetworkLocked(unsigned netId) const;
VirtualNetwork* getVirtualNetworkForUserLocked(uid_t uid) const;
- Network* getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const;
Permission getPermissionForUserLocked(uid_t uid) const;
int checkUserNetworkAccessLocked(uid_t uid, unsigned netId) const;
[[nodiscard]] int createPhysicalNetworkLocked(unsigned netId, Permission permission);
diff --git a/server/OemNetdListener.cpp b/server/OemNetdListener.cpp
index 9c44cf2..fb07a80 100644
--- a/server/OemNetdListener.cpp
+++ b/server/OemNetdListener.cpp
@@ -24,10 +24,16 @@
namespace net {
::android::sp<::android::IBinder> OemNetdListener::getListener() {
- // Thread-safe initialization.
- static ::android::sp<OemNetdListener> listener = ::android::sp<OemNetdListener>::make();
- static ::android::sp<::android::IBinder> sIBinder = ::android::IInterface::asBinder(listener);
- return sIBinder;
+ static OemNetdListener listener;
+ return listener.getIBinder();
+}
+
+::android::sp<::android::IBinder> OemNetdListener::getIBinder() {
+ std::lock_guard lock(mMutex);
+ if (mIBinder == nullptr) {
+ mIBinder = ::android::IInterface::asBinder(this);
+ }
+ return mIBinder;
}
::android::binder::Status OemNetdListener::isAlive(bool* alive) {
diff --git a/server/OemNetdListener.h b/server/OemNetdListener.h
index b94827b..4fb4fb7 100644
--- a/server/OemNetdListener.h
+++ b/server/OemNetdListener.h
@@ -43,10 +43,14 @@
const ::android::sp<IOemNetdUnsolicitedEventListener>& listener) override;
private:
+ std::mutex mMutex;
std::mutex mOemUnsolicitedMutex;
+ ::android::sp<::android::IBinder> mIBinder GUARDED_BY(mMutex);
OemUnsolListenerMap mOemUnsolListenerMap GUARDED_BY(mOemUnsolicitedMutex);
+ ::android::sp<::android::IBinder> getIBinder() EXCLUDES(mMutex);
+
void registerOemUnsolicitedEventListenerInternal(
const ::android::sp<IOemNetdUnsolicitedEventListener>& listener)
EXCLUDES(mOemUnsolicitedMutex);
@@ -60,4 +64,4 @@
} // namespace android
} // namespace com
-#endif // NETD_SERVER_OEM_NETD_LISTENER_H
+#endif // NETD_SERVER_OEM_NETD_LISTENER_H
\ No newline at end of file
diff --git a/server/OffloadUtils.cpp b/server/OffloadUtils.cpp
index 0d9869f..a743458 100644
--- a/server/OffloadUtils.cpp
+++ b/server/OffloadUtils.cpp
@@ -38,7 +38,7 @@
using std::max;
-static int doSIOCGIF(const std::string& interface, int opt) {
+int hardwareAddressType(const std::string& interface) {
base::unique_fd ufd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (ufd < 0) {
@@ -56,19 +56,9 @@
// match a truncated interface if one were to exist.
strncpy(ifr.ifr_name, interface.c_str(), sizeof(ifr.ifr_name));
- if (ioctl(ufd, opt, &ifr, sizeof(ifr))) return -errno;
+ if (ioctl(ufd, SIOCGIFHWADDR, &ifr, sizeof(ifr))) return -errno;
- if (opt == SIOCGIFHWADDR) return ifr.ifr_hwaddr.sa_family;
- if (opt == SIOCGIFMTU) return ifr.ifr_mtu;
- return -EINVAL;
-}
-
-int hardwareAddressType(const std::string& interface) {
- return doSIOCGIF(interface, SIOCGIFHWADDR);
-}
-
-int deviceMTU(const std::string& interface) {
- return doSIOCGIF(interface, SIOCGIFMTU);
+ return ifr.ifr_hwaddr.sa_family;
}
base::Result<bool> isEthernet(const std::string& interface) {
@@ -204,12 +194,10 @@
return sendAndProcessNetlinkResponse(&req, sizeof(req));
}
-// The priority of clat hook - must be after tethering.
-constexpr uint16_t PRIO_CLAT = 4;
-
-// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
+// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
// direct-action
-int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet) {
+int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, int bpfFd,
+ bool ethernet) {
// This is the name of the filter we're attaching (ie. this is the 'bpf'
// packet classifier enabled by kernel config option CONFIG_NET_CLS_BPF.
//
@@ -225,28 +213,40 @@
#define FSOBJ_SUFFIX ":[*fsobj]"
// This macro expands (from header files) to:
- // prog_clatd_schedcls_ingress6_clat_rawip:[*fsobj]
+ // prog_clatd_schedcls_ingress_clat_rawip:[*fsobj]
// and is the name of the pinned ingress ebpf program for ARPHRD_RAWIP interfaces.
// (also compatible with anything that has 0 size L2 header)
- static constexpr char name_clat_rx_rawip[] = CLAT_INGRESS6_PROG_RAWIP_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_rx_rawip[] = CLAT_INGRESS_PROG_RAWIP_NAME FSOBJ_SUFFIX;
// This macro expands (from header files) to:
- // prog_clatd_schedcls_ingress6_clat_ether:[*fsobj]
+ // prog_clatd_schedcls_ingress_clat_ether:[*fsobj]
// and is the name of the pinned ingress ebpf program for ARPHRD_ETHER interfaces.
// (also compatible with anything that has standard ethernet header)
- static constexpr char name_clat_rx_ether[] = CLAT_INGRESS6_PROG_ETHER_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_rx_ether[] = CLAT_INGRESS_PROG_ETHER_NAME FSOBJ_SUFFIX;
// This macro expands (from header files) to:
- // prog_clatd_schedcls_egress4_clat_rawip:[*fsobj]
+ // prog_clatd_schedcls_egress_clat_rawip:[*fsobj]
// and is the name of the pinned egress ebpf program for ARPHRD_RAWIP interfaces.
// (also compatible with anything that has 0 size L2 header)
- static constexpr char name_clat_tx_rawip[] = CLAT_EGRESS4_PROG_RAWIP_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_tx_rawip[] = CLAT_EGRESS_PROG_RAWIP_NAME FSOBJ_SUFFIX;
// This macro expands (from header files) to:
- // prog_clatd_schedcls_egress4_clat_ether:[*fsobj]
+ // prog_clatd_schedcls_egress_clat_ether:[*fsobj]
// and is the name of the pinned egress ebpf program for ARPHRD_ETHER interfaces.
// (also compatible with anything that has standard ethernet header)
- static constexpr char name_clat_tx_ether[] = CLAT_EGRESS4_PROG_ETHER_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_tx_ether[] = CLAT_EGRESS_PROG_ETHER_NAME FSOBJ_SUFFIX;
+
+ // This macro expands (from header files) to:
+ // prog_offload_schedcls_ingress_tether_rawip:[*fsobj]
+ // and is the name of the pinned ingress ebpf program for ARPHRD_RAWIP interfaces.
+ // (also compatible with anything that has 0 size L2 header)
+ static constexpr char name_tether_rawip[] = TETHER_INGRESS_PROG_RAWIP_NAME FSOBJ_SUFFIX;
+
+ // This macro expands (from header files) to:
+ // prog_offload_schedcls_ingress_tether_ether:[*fsobj]
+ // and is the name of the pinned ingress ebpf program for ARPHRD_ETHER interfaces.
+ // (also compatible with anything that has standard ethernet header)
+ static constexpr char name_tether_ether[] = TETHER_INGRESS_PROG_ETHER_NAME FSOBJ_SUFFIX;
#undef FSOBJ_SUFFIX
@@ -259,12 +259,16 @@
sizeof(name_clat_rx_ether),
sizeof(name_clat_tx_rawip),
sizeof(name_clat_tx_ether),
+ sizeof(name_tether_rawip),
+ sizeof(name_tether_ether),
});
// These are not compile time constants: 'name' is used in strncpy below
const char* const name_clat_rx = ethernet ? name_clat_rx_ether : name_clat_rx_rawip;
const char* const name_clat_tx = ethernet ? name_clat_tx_ether : name_clat_tx_rawip;
- const char* const name = ingress ? name_clat_rx : name_clat_tx;
+ const char* const name_clat = ingress ? name_clat_rx : name_clat_tx;
+ const char* const name_tether = ethernet ? name_tether_ether : name_tether_rawip;
+ const char* const name = (prio == PRIO_TETHER) ? name_tether : name_clat;
struct {
nlmsghdr n;
@@ -302,7 +306,7 @@
.tcm_handle = TC_H_UNSPEC,
.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS),
- .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)),
+ .tcm_info = static_cast<__u32>((prio << 16) | htons(proto)),
},
.kind =
{
@@ -318,7 +322,7 @@
.attr =
{
.nla_len = sizeof(req.options),
- .nla_type = NLA_F_NESTED | TCA_OPTIONS,
+ .nla_type = TCA_OPTIONS,
},
.fd =
{
@@ -358,8 +362,8 @@
return sendAndProcessNetlinkResponse(&req, sizeof(req));
}
-// tc filter del dev .. in/egress prio 4 protocol ..
-int tcFilterDelDev(int ifIndex, bool ingress, uint16_t proto) {
+// tc filter del dev .. in/egress prio .. protocol ..
+int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) {
const struct {
nlmsghdr n;
tcmsg t;
@@ -377,7 +381,7 @@
.tcm_handle = TC_H_UNSPEC,
.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS),
- .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)),
+ .tcm_info = static_cast<__u32>((prio << 16) | htons(proto)),
},
};
diff --git a/server/OffloadUtils.h b/server/OffloadUtils.h
index 684ffb3..818fd39 100644
--- a/server/OffloadUtils.h
+++ b/server/OffloadUtils.h
@@ -19,7 +19,6 @@
#include <android-base/result.h>
#include <errno.h>
#include <linux/if_ether.h>
-#include <linux/if_link.h>
#include <linux/rtnetlink.h>
#include <string>
@@ -39,33 +38,55 @@
constexpr bool EGRESS = false;
constexpr bool INGRESS = true;
+// The priority of clat/tether hooks - smaller is higher priority.
+constexpr uint16_t PRIO_CLAT = 1;
+constexpr uint16_t PRIO_TETHER = 2;
+
// this returns an ARPHRD_* constant or a -errno
int hardwareAddressType(const std::string& interface);
-// return MTU or -errno
-int deviceMTU(const std::string& interface);
-
base::Result<bool> isEthernet(const std::string& interface);
-inline int getClatEgress4MapFd(void) {
- const int fd = bpf::mapRetrieveRW(CLAT_EGRESS4_MAP_PATH);
+inline int getClatEgressMapFd(void) {
+ const int fd = bpf::mapRetrieveRW(CLAT_EGRESS_MAP_PATH);
return (fd == -1) ? -errno : fd;
}
-inline int getClatEgress4ProgFd(bool with_ethernet_header) {
- const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_EGRESS4_PROG_ETHER_PATH
- : CLAT_EGRESS4_PROG_RAWIP_PATH);
+inline int getClatEgressProgFd(bool with_ethernet_header) {
+ const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_EGRESS_PROG_ETHER_PATH
+ : CLAT_EGRESS_PROG_RAWIP_PATH);
return (fd == -1) ? -errno : fd;
}
-inline int getClatIngress6MapFd(void) {
- const int fd = bpf::mapRetrieveRW(CLAT_INGRESS6_MAP_PATH);
+inline int getClatIngressMapFd(void) {
+ const int fd = bpf::mapRetrieveRW(CLAT_INGRESS_MAP_PATH);
return (fd == -1) ? -errno : fd;
}
-inline int getClatIngress6ProgFd(bool with_ethernet_header) {
- const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_INGRESS6_PROG_ETHER_PATH
- : CLAT_INGRESS6_PROG_RAWIP_PATH);
+inline int getClatIngressProgFd(bool with_ethernet_header) {
+ const int fd = bpf::retrieveProgram(with_ethernet_header ? CLAT_INGRESS_PROG_ETHER_PATH
+ : CLAT_INGRESS_PROG_RAWIP_PATH);
+ return (fd == -1) ? -errno : fd;
+}
+
+inline int getTetherIngressMapFd(void) {
+ const int fd = bpf::mapRetrieveRW(TETHER_INGRESS_MAP_PATH);
+ return (fd == -1) ? -errno : fd;
+}
+
+inline int getTetherIngressProgFd(bool with_ethernet_header) {
+ const int fd = bpf::retrieveProgram(with_ethernet_header ? TETHER_INGRESS_PROG_ETHER_PATH
+ : TETHER_INGRESS_PROG_RAWIP_PATH);
+ return (fd == -1) ? -errno : fd;
+}
+
+inline int getTetherStatsMapFd(void) {
+ const int fd = bpf::mapRetrieveRW(TETHER_STATS_MAP_PATH);
+ return (fd == -1) ? -errno : fd;
+}
+
+inline int getTetherLimitMapFd(void) {
+ const int fd = bpf::mapRetrieveRW(TETHER_LIMIT_MAP_PATH);
return (fd == -1) ? -errno : fd;
}
@@ -83,31 +104,42 @@
return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0);
}
-// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
+// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
// direct-action
-int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet);
+int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, int bpfFd,
+ bool ethernet);
-// tc filter add dev .. ingress prio 4 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
+// tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
inline int tcFilterAddDevIngressClatIpv6(int ifIndex, int bpfFd, bool ethernet) {
- return tcFilterAddDevBpf(ifIndex, INGRESS, ETH_P_IPV6, bpfFd, ethernet);
+ return tcFilterAddDevBpf(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6, bpfFd, ethernet);
}
-// tc filter add dev .. egress prio 4 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action
+// tc filter add dev .. egress prio 1 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action
inline int tcFilterAddDevEgressClatIpv4(int ifIndex, int bpfFd, bool ethernet) {
- return tcFilterAddDevBpf(ifIndex, EGRESS, ETH_P_IP, bpfFd, ethernet);
+ return tcFilterAddDevBpf(ifIndex, EGRESS, PRIO_CLAT, ETH_P_IP, bpfFd, ethernet);
+}
+
+// tc filter add dev .. ingress prio 2 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
+inline int tcFilterAddDevIngressTether(int ifIndex, int bpfFd, bool ethernet) {
+ return tcFilterAddDevBpf(ifIndex, INGRESS, PRIO_TETHER, ETH_P_IPV6, bpfFd, ethernet);
}
// tc filter del dev .. in/egress prio .. protocol ..
-int tcFilterDelDev(int ifIndex, bool ingress, uint16_t proto);
+int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto);
-// tc filter del dev .. ingress prio 4 protocol ipv6
+// tc filter del dev .. ingress prio 1 protocol ipv6
inline int tcFilterDelDevIngressClatIpv6(int ifIndex) {
- return tcFilterDelDev(ifIndex, INGRESS, ETH_P_IPV6);
+ return tcFilterDelDev(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6);
}
-// tc filter del dev .. egress prio 4 protocol ip
+// tc filter del dev .. egress prio 1 protocol ip
inline int tcFilterDelDevEgressClatIpv4(int ifIndex) {
- return tcFilterDelDev(ifIndex, EGRESS, ETH_P_IP);
+ return tcFilterDelDev(ifIndex, EGRESS, PRIO_CLAT, ETH_P_IP);
+}
+
+// tc filter del dev .. ingress prio 2 protocol ipv6
+inline int tcFilterDelDevIngressTether(int ifIndex) {
+ return tcFilterDelDev(ifIndex, INGRESS, PRIO_TETHER, ETH_P_IPV6);
}
} // namespace net
diff --git a/server/OffloadUtilsTest.cpp b/server/OffloadUtilsTest.cpp
index 16c108b..1760c1d 100644
--- a/server/OffloadUtilsTest.cpp
+++ b/server/OffloadUtilsTest.cpp
@@ -98,60 +98,160 @@
ASSERT_FALSE(res.value());
}
-TEST_F(OffloadUtilsTest, DeviceMTUOfNonExistingIf) {
- ASSERT_EQ(-ENODEV, deviceMTU("not_existing_if"));
-}
+TEST_F(OffloadUtilsTest, GetClatEgressMapFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
-TEST_F(OffloadUtilsTest, DeviceMTUofLoopback) {
- ASSERT_EQ(65536, deviceMTU("lo"));
-}
-
-TEST_F(OffloadUtilsTest, GetClatEgress4MapFd) {
- int fd = getClatEgress4MapFd();
+ int fd = getClatEgressMapFd();
ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
-TEST_F(OffloadUtilsTest, GetClatEgress4RawIpProgFd) {
- int fd = getClatEgress4ProgFd(RAWIP);
+TEST_F(OffloadUtilsTest, GetClatEgressRawIpProgFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getClatEgressProgFd(RAWIP);
ASSERT_GE(fd, 3);
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
-TEST_F(OffloadUtilsTest, GetClatEgress4EtherProgFd) {
- int fd = getClatEgress4ProgFd(ETHER);
+TEST_F(OffloadUtilsTest, GetClatEgressEtherProgFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getClatEgressProgFd(ETHER);
ASSERT_GE(fd, 3);
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
-TEST_F(OffloadUtilsTest, GetClatIngress6MapFd) {
- int fd = getClatIngress6MapFd();
+TEST_F(OffloadUtilsTest, GetClatIngressMapFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getClatIngressMapFd();
ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
-TEST_F(OffloadUtilsTest, GetClatIngress6RawIpProgFd) {
- int fd = getClatIngress6ProgFd(RAWIP);
+TEST_F(OffloadUtilsTest, GetClatIngressRawIpProgFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getClatIngressProgFd(RAWIP);
ASSERT_GE(fd, 3);
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
-TEST_F(OffloadUtilsTest, GetClatIngress6EtherProgFd) {
- int fd = getClatIngress6ProgFd(ETHER);
+TEST_F(OffloadUtilsTest, GetClatIngressEtherProgFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getClatIngressProgFd(ETHER);
ASSERT_GE(fd, 3);
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
+TEST_F(OffloadUtilsTest, GetTetherIngressMapFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getTetherIngressMapFd();
+ ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3
+ EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
+ close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetTetherIngressRawIpProgFd) {
+ // Currently only implementing downstream direction offload.
+ // RX Rawip -> TX Ether requires header adjustments and thus 4.14.
+ SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED;
+
+ int fd = getTetherIngressProgFd(RAWIP);
+ ASSERT_GE(fd, 3);
+ EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
+ close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetTetherIngressEtherProgFd) {
+ // Currently only implementing downstream direction offload.
+ // RX Ether -> TX Ether does not require header adjustments
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getTetherIngressProgFd(ETHER);
+ ASSERT_GE(fd, 3);
+ EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
+ close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetTetherStatsMapFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getTetherStatsMapFd();
+ ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3
+ EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
+ close(fd);
+}
+
+TEST_F(OffloadUtilsTest, GetTetherLimitMapFd) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int fd = getTetherLimitMapFd();
+ ASSERT_GE(fd, 3); // 0,1,2 - stdin/out/err, thus fd >= 3
+ EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
+ close(fd);
+}
+
+// The SKIP_IF_BPF_NOT_SUPPORTED macro is effectively a check for 4.9+ kernel
+// combined with a launched on P device. Ie. it's a test for 4.9-P or better.
+
+// NET_SCH_INGRESS is only enabled starting with 4.9-Q and as such we need
+// a separate way to test for this...
+int doKernelSupportsNetSchIngress(void) {
+ // NOLINTNEXTLINE(cert-env33-c)
+ return system("zcat /proc/config.gz | egrep -q '^CONFIG_NET_SCH_INGRESS=[my]$'");
+}
+
+// NET_CLS_BPF is only enabled starting with 4.9-Q...
+int doKernelSupportsNetClsBpf(void) {
+ // NOLINTNEXTLINE(cert-env33-c)
+ return system("zcat /proc/config.gz | egrep -q '^CONFIG_NET_CLS_BPF=[my]$'");
+}
+
+// Make sure the above functions actually execute correctly rather than failing
+// due to missing binary or execution failure...
+TEST_F(OffloadUtilsTest, KernelSupportsNetFuncs) {
+ // Make sure the file is present and readable and decompressable.
+ // NOLINTNEXTLINE(cert-env33-c)
+ ASSERT_EQ(W_EXITCODE(0, 0), system("zcat /proc/config.gz > /dev/null"));
+
+ int v = doKernelSupportsNetSchIngress();
+ int w = doKernelSupportsNetClsBpf();
+
+ // They should always either return 0 (match) or 1 (no match),
+ // anything else is some sort of exec/environment/etc failure.
+ if (v != W_EXITCODE(1, 0)) ASSERT_EQ(v, W_EXITCODE(0, 0));
+ if (w != W_EXITCODE(1, 0)) ASSERT_EQ(w, W_EXITCODE(0, 0));
+}
+
+// True iff CONFIG_NET_SCH_INGRESS is enabled in /proc/config.gz
+bool kernelSupportsNetSchIngress(void) {
+ return doKernelSupportsNetSchIngress() == W_EXITCODE(0, 0);
+}
+
+// True iff CONFIG_NET_CLS_BPF is enabled in /proc/config.gz
+bool kernelSupportsNetClsBpf(void) {
+ return doKernelSupportsNetClsBpf() == W_EXITCODE(0, 0);
+}
+
// See Linux kernel source in include/net/flow.h
#define LOOPBACK_IFINDEX 1
TEST_F(OffloadUtilsTest, AttachReplaceDetachClsactLo) {
+ // Technically does not depend on ebpf, but does depend on clsact,
+ // and we do not really care if it works on pre-4.9-Q anyway.
+ SKIP_IF_BPF_NOT_SUPPORTED;
+ if (!kernelSupportsNetSchIngress()) return;
+
// This attaches and detaches a configuration-less and thus no-op clsact
// qdisc to loopback interface (and it takes fractions of a second)
EXPECT_EQ(0, tcQdiscAddDevClsact(LOOPBACK_IFINDEX));
@@ -161,12 +261,27 @@
}
static void checkAttachDetachBpfFilterClsactLo(const bool ingress, const bool ethernet) {
- // Older kernels return EINVAL instead of ENOENT due to lacking proper error propagation...
- const int errNOENT = android::bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL;
+ // This test requires kernel 4.9-Q or better
+ SKIP_IF_BPF_NOT_SUPPORTED;
+ if (!kernelSupportsNetSchIngress()) return;
+ if (!kernelSupportsNetClsBpf()) return;
- int clatBpfFd = ingress ? getClatIngress6ProgFd(ethernet) : getClatEgress4ProgFd(ethernet);
+ const bool extended =
+ (android::bpf::getBpfSupportLevel() >= android::bpf::BpfLevel::EXTENDED_4_14);
+ // Older kernels return EINVAL instead of ENOENT due to lacking proper error propagation...
+ const int errNOENT =
+ (android::bpf::getBpfSupportLevel() >= android::bpf::BpfLevel::EXTENDED_4_19) ? ENOENT
+ : EINVAL;
+
+ int clatBpfFd = ingress ? getClatIngressProgFd(ethernet) : getClatEgressProgFd(ethernet);
ASSERT_GE(clatBpfFd, 3);
+ int tetherBpfFd = -1;
+ if (extended && ingress) {
+ tetherBpfFd = getTetherIngressProgFd(ethernet);
+ ASSERT_GE(tetherBpfFd, 3);
+ }
+
// This attaches and detaches a clsact plus ebpf program to loopback
// interface, but it should not affect traffic by virtue of us not
// actually populating the ebpf control map.
@@ -178,6 +293,10 @@
EXPECT_EQ(-errNOENT, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
if (ingress) {
EXPECT_EQ(0, tcFilterAddDevIngressClatIpv6(LOOPBACK_IFINDEX, clatBpfFd, ethernet));
+ if (extended) {
+ EXPECT_EQ(0, tcFilterAddDevIngressTether(LOOPBACK_IFINDEX, tetherBpfFd, ethernet));
+ EXPECT_EQ(0, tcFilterDelDevIngressTether(LOOPBACK_IFINDEX));
+ }
EXPECT_EQ(0, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
} else {
EXPECT_EQ(0, tcFilterAddDevEgressClatIpv4(LOOPBACK_IFINDEX, clatBpfFd, ethernet));
@@ -189,6 +308,7 @@
EXPECT_EQ(-EINVAL, tcFilterDelDevIngressClatIpv6(LOOPBACK_IFINDEX));
EXPECT_EQ(-EINVAL, tcFilterDelDevEgressClatIpv4(LOOPBACK_IFINDEX));
+ if (tetherBpfFd != -1) close(tetherBpfFd);
close(clatBpfFd);
}
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index 7b9a19a..2808fbe 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -158,36 +158,8 @@
return 0;
}
-int PhysicalNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
- if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
- return -EINVAL;
- }
-
- for (const std::string& interface : mInterfaces) {
- int ret = RouteController::addUsersToPhysicalNetwork(mNetId, interface.c_str(),
- {{subPriority, uidRanges}});
- if (ret) {
- ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
- return ret;
- }
- }
- addToUidRangeMap(uidRanges, subPriority);
- return 0;
-}
-
-int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
- if (!isValidSubPriority(subPriority)) return -EINVAL;
-
- for (const std::string& interface : mInterfaces) {
- int ret = RouteController::removeUsersFromPhysicalNetwork(mNetId, interface.c_str(),
- {{subPriority, uidRanges}});
- if (ret) {
- ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
- return ret;
- }
- }
- removeFromUidRangeMap(uidRanges, subPriority);
- return 0;
+Network::Type PhysicalNetwork::getType() const {
+ return PHYSICAL;
}
int PhysicalNetwork::addInterface(const std::string& interface) {
@@ -195,7 +167,7 @@
return 0;
}
if (int ret = RouteController::addInterfaceToPhysicalNetwork(mNetId, interface.c_str(),
- mPermission, mUidRangeMap)) {
+ mPermission)) {
ALOGE("failed to add interface %s to netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -222,7 +194,7 @@
// to find the interface index in the cache in cases where the interface is already gone
// (e.g. bt-pan).
if (int ret = RouteController::removeInterfaceFromPhysicalNetwork(mNetId, interface.c_str(),
- mPermission, mUidRangeMap)) {
+ mPermission)) {
ALOGE("failed to remove interface %s from netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -230,9 +202,4 @@
return 0;
}
-bool PhysicalNetwork::isValidSubPriority(uint32_t priority) {
- return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
- priority <= UidRanges::LOWEST_SUB_PRIORITY;
-}
-
} // namespace android::net
diff --git a/server/PhysicalNetwork.h b/server/PhysicalNetwork.h
index d9461b2..0720824 100644
--- a/server/PhysicalNetwork.h
+++ b/server/PhysicalNetwork.h
@@ -42,18 +42,13 @@
[[nodiscard]] int addAsDefault();
[[nodiscard]] int removeAsDefault();
- [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
- [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
- bool isPhysical() override { return true; }
- bool canAddUsers() override { return true; }
private:
- std::string getTypeString() const override { return "PHYSICAL"; };
+ Type getType() const override;
[[nodiscard]] int addInterface(const std::string& interface) override;
[[nodiscard]] int removeInterface(const std::string& interface) override;
int destroySocketsLackingPermission(Permission permission);
void invalidateRouteCache(const std::string& interface);
- bool isValidSubPriority(uint32_t priority) override;
Delegate* const mDelegate;
Permission mPermission;
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index ba305e6..134bbca 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -27,11 +27,14 @@
#include <map>
+#define LOG_TAG "Netd"
+
#include "DummyNetwork.h"
#include "Fwmark.h"
#include "NetdConstants.h"
#include "NetlinkCommands.h"
#include "OffloadUtils.h"
+#include "UidRanges.h"
#include <android-base/file.h>
#include <android-base/stringprintf.h>
@@ -51,6 +54,23 @@
// BEGIN CONSTANTS --------------------------------------------------------------------------------
+const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
+const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF = 10500;
+const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 11000;
+const uint32_t RULE_PRIORITY_SECURE_VPN = 12000;
+const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN = 12500;
+const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK = 13000;
+const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE = 14000;
+const uint32_t RULE_PRIORITY_LEGACY_SYSTEM = 15000;
+const uint32_t RULE_PRIORITY_LEGACY_NETWORK = 16000;
+const uint32_t RULE_PRIORITY_LOCAL_NETWORK = 17000;
+const uint32_t RULE_PRIORITY_TETHERING = 18000;
+const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK = 19000;
+const uint32_t RULE_PRIORITY_BYPASSABLE_VPN = 20000;
+const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 21000;
+const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 22000;
+const uint32_t RULE_PRIORITY_UNREACHABLE = 32000;
+
const uint32_t ROUTE_TABLE_LOCAL_NETWORK = 97;
const uint32_t ROUTE_TABLE_LEGACY_NETWORK = 98;
const uint32_t ROUTE_TABLE_LEGACY_SYSTEM = 99;
@@ -111,9 +131,6 @@
uint8_t PADDING_BUFFER[RTA_ALIGNTO] = {0, 0, 0, 0};
-constexpr bool EXPLICIT = true;
-constexpr bool IMPLICIT = false;
-
// END CONSTANTS ----------------------------------------------------------------------------------
static const char* actionName(uint16_t action) {
@@ -129,8 +146,6 @@
}
}
-static void maybeModifyQdiscClsact(const char* interface, bool add);
-
// Caller must hold sInterfaceToTableLock.
uint32_t RouteController::getRouteTableForInterfaceLocked(const char* interface) {
// If we already know the routing table for this interface name, use it.
@@ -492,7 +507,7 @@
// have, if they are subject to this VPN, their traffic has to go through it. Allows the traffic to
// bypass the VPN if the protectedFromVpn bit is set.
[[nodiscard]] static int modifyVpnUidRangeRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
- uint32_t subPriority, bool secure, bool add) {
+ bool secure, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -510,8 +525,8 @@
mask.explicitlySelected = true;
}
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority + subPriority, table,
- fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority, table, fwmark.intValue,
+ mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
// A rule to allow system apps to send traffic over this VPN even if they are not part of the target
@@ -545,7 +560,7 @@
// modifyNetworkPermission().
[[nodiscard]] static int modifyExplicitNetworkRule(unsigned netId, uint32_t table,
Permission permission, uid_t uidStart,
- uid_t uidEnd, uint32_t subPriority, bool add) {
+ uid_t uidEnd, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -558,9 +573,8 @@
fwmark.permission = permission;
mask.permission = permission;
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- RULE_PRIORITY_EXPLICIT_NETWORK + subPriority, table, fwmark.intValue,
- mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_EXPLICIT_NETWORK, table,
+ fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
// A rule to route traffic based on a chosen outgoing interface.
@@ -569,7 +583,7 @@
// the outgoing interface (typically for link-local communications).
[[nodiscard]] static int modifyOutputInterfaceRules(const char* interface, uint32_t table,
Permission permission, uid_t uidStart,
- uid_t uidEnd, uint32_t subPriority, bool add) {
+ uid_t uidEnd, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -587,9 +601,8 @@
}
}
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- RULE_PRIORITY_OUTPUT_INTERFACE + subPriority, table, fwmark.intValue,
- mask.intValue, IIF_LOOPBACK, interface, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_OUTPUT_INTERFACE, table,
+ fwmark.intValue, mask.intValue, IIF_LOOPBACK, interface, uidStart, uidEnd);
}
// A rule to route traffic based on the chosen network.
@@ -669,8 +682,7 @@
// Add rules to lookup the local network when specified explicitly or otherwise.
[[nodiscard]] static int addLocalNetworkRules(unsigned localNetId) {
if (int ret = modifyExplicitNetworkRule(localNetId, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
- INVALID_UID, INVALID_UID,
- UidRanges::DEFAULT_SUB_PRIORITY, ACTION_ADD)) {
+ INVALID_UID, INVALID_UID, ACTION_ADD)) {
return ret;
}
@@ -701,9 +713,8 @@
return -errno;
}
- if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, INVALID_UID,
- INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
- ACTION_ADD))) {
+ if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE,
+ INVALID_UID, INVALID_UID, ACTION_ADD))) {
ALOGE("Can't create oif rules for %s: %s", interface, strerror(-ret));
return ret;
}
@@ -734,102 +745,27 @@
if (int ret = modifyIncomingPacketMark(netId, interface, PERMISSION_NONE, add)) {
return ret;
}
- maybeModifyQdiscClsact(interface, add);
return modifyOutputInterfaceRules(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
- INVALID_UID, INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
- add);
-}
-
-[[nodiscard]] static int modifyUidNetworkRule(unsigned netId, uint32_t table, uid_t uidStart,
- uid_t uidEnd, uint32_t subPriority, bool add,
- bool explicitSelect) {
- if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
- ALOGE("modifyUidNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
- return -EUSERS;
- }
-
- Fwmark fwmark;
- Fwmark mask;
-
- fwmark.netId = netId;
- mask.netId = FWMARK_NET_ID_MASK;
-
- fwmark.explicitlySelected = explicitSelect;
- mask.explicitlySelected = true;
-
- // Access to this network is controlled by UID rules, not permission bits.
- fwmark.permission = PERMISSION_NONE;
- mask.permission = PERMISSION_NONE;
-
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- explicitSelect ? (RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority)
- : (RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority),
- table, fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart,
- uidEnd);
-}
-
-[[nodiscard]] static int modifyUidDefaultNetworkRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
- uint32_t subPriority, bool add) {
- if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
- ALOGE("modifyUidDefaultNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
- return -EUSERS;
- }
-
- Fwmark fwmark;
- Fwmark mask;
-
- fwmark.netId = NETID_UNSET;
- mask.netId = FWMARK_NET_ID_MASK;
-
- // Access to this network is controlled by UID rules, not permission bits.
- fwmark.permission = PERMISSION_NONE;
- mask.permission = PERMISSION_NONE;
-
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- RULE_PRIORITY_UID_DEFAULT_NETWORK + subPriority, table, fwmark.intValue,
- mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ INVALID_UID, INVALID_UID, add);
}
/* static */
int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap, Permission permission,
- bool add, bool modifyNonUidBasedRules) {
+ Permission permission, bool add) {
uint32_t table = getRouteTableForInterface(interface);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
- for (const auto& [subPriority, uidRanges] : uidRangeMap) {
- for (const UidRangeParcel& range : uidRanges.getRanges()) {
- if (int ret = modifyUidNetworkRule(netId, table, range.start, range.stop, subPriority,
- add, EXPLICIT)) {
- return ret;
- }
- if (int ret = modifyUidNetworkRule(netId, table, range.start, range.stop, subPriority,
- add, IMPLICIT)) {
- return ret;
- }
- if (int ret = modifyUidDefaultNetworkRule(table, range.start, range.stop, subPriority,
- add)) {
- return ret;
- }
- }
- }
-
- if (!modifyNonUidBasedRules) {
- // we are done.
- return 0;
- }
-
if (int ret = modifyIncomingPacketMark(netId, interface, permission, add)) {
return ret;
}
if (int ret = modifyExplicitNetworkRule(netId, table, permission, INVALID_UID, INVALID_UID,
- UidRanges::DEFAULT_SUB_PRIORITY, add)) {
+ add)) {
return ret;
}
if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
- UidRanges::DEFAULT_SUB_PRIORITY, add)) {
+ add)) {
return ret;
}
@@ -859,79 +795,6 @@
return 0;
}
-[[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd,
- uint32_t subPriority, bool add,
- bool explicitSelect) {
- if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
- ALOGE("modifyUidUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
- return -EUSERS;
- }
-
- Fwmark fwmark;
- Fwmark mask;
-
- fwmark.netId = netId;
- mask.netId = FWMARK_NET_ID_MASK;
-
- fwmark.explicitlySelected = explicitSelect;
- mask.explicitlySelected = true;
-
- // Access to this network is controlled by UID rules, not permission bits.
- fwmark.permission = PERMISSION_NONE;
- mask.permission = PERMISSION_NONE;
-
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- explicitSelect ? (RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority)
- : (RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority),
- FR_ACT_UNREACHABLE, RT_TABLE_UNSPEC, fwmark.intValue, mask.intValue,
- IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
-}
-
-[[nodiscard]] static int modifyUidDefaultUnreachableRule(uid_t uidStart, uid_t uidEnd,
- uint32_t subPriority, bool add) {
- if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
- ALOGE("modifyUidDefaultUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
- return -EUSERS;
- }
-
- Fwmark fwmark;
- Fwmark mask;
-
- fwmark.netId = NETID_UNSET;
- mask.netId = FWMARK_NET_ID_MASK;
-
- // Access to this network is controlled by UID rules, not permission bits.
- fwmark.permission = PERMISSION_NONE;
- mask.permission = PERMISSION_NONE;
-
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- RULE_PRIORITY_UID_DEFAULT_UNREACHABLE + subPriority, FR_ACT_UNREACHABLE,
- RT_TABLE_UNSPEC, fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE,
- uidStart, uidEnd);
-}
-
-int RouteController::modifyUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap,
- bool add) {
- for (const auto& [subPriority, uidRanges] : uidRangeMap) {
- for (const UidRangeParcel& range : uidRanges.getRanges()) {
- if (int ret = modifyUidUnreachableRule(netId, range.start, range.stop, subPriority, add,
- EXPLICIT)) {
- return ret;
- }
- if (int ret = modifyUidUnreachableRule(netId, range.start, range.stop, subPriority, add,
- IMPLICIT)) {
- return ret;
- }
- if (int ret = modifyUidDefaultUnreachableRule(range.start, range.stop, subPriority,
- add)) {
- return ret;
- }
- }
- }
-
- return 0;
-}
-
[[nodiscard]] static int modifyRejectNonSecureNetworkRule(const UidRanges& uidRanges, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -950,27 +813,24 @@
}
int RouteController::modifyVirtualNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap, bool secure, bool add,
+ const UidRanges& uidRanges, bool secure, bool add,
bool modifyNonUidBasedRules) {
uint32_t table = getRouteTableForInterface(interface);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
- for (const auto& [subPriority, uidRanges] : uidRangeMap) {
- for (const UidRangeParcel& range : uidRanges.getRanges()) {
- if (int ret = modifyVpnUidRangeRule(table, range.start, range.stop, subPriority, secure,
- add)) {
- return ret;
- }
- if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, range.start,
- range.stop, subPriority, add)) {
- return ret;
- }
- if (int ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, range.start,
- range.stop, subPriority, add)) {
- return ret;
- }
+ for (const UidRangeParcel& range : uidRanges.getRanges()) {
+ if (int ret = modifyVpnUidRangeRule(table, range.start, range.stop, secure, add)) {
+ return ret;
+ }
+ if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, range.start,
+ range.stop, add)) {
+ return ret;
+ }
+ if (int ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, range.start,
+ range.stop, add)) {
+ return ret;
}
}
@@ -984,8 +844,7 @@
if (int ret = modifyVpnSystemPermissionRule(netId, table, secure, add)) {
return ret;
}
- return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT,
- UidRanges::DEFAULT_SUB_PRIORITY, add);
+ return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT, add);
}
return 0;
@@ -1059,7 +918,9 @@
return 0;
}
-static void maybeModifyQdiscClsact(const char* interface, bool add) {
+void maybeModifyQdiscClsact(const char* interface, bool add) {
+ if (!bpf::isBpfSupported()) return;
+
// The clsact attaching of v4- tun interface is triggered by ClatdController::maybeStartBpf
// because the clat is started before the v4- interface is added to the network and the
// clat startup needs to add {in, e}gress filters.
@@ -1186,10 +1047,8 @@
}
int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission,
- const UidRangeMap& uidRangeMap) {
- if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_ADD,
- MODIFY_NON_UID_BASED_RULES)) {
+ Permission permission) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, permission, ACTION_ADD)) {
return ret;
}
maybeModifyQdiscClsact(interface, ACTION_ADD);
@@ -1198,10 +1057,8 @@
}
int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission,
- const UidRangeMap& uidRangeMap) {
- if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_DEL,
- MODIFY_NON_UID_BASED_RULES)) {
+ Permission permission) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, permission, ACTION_DEL)) {
return ret;
}
if (int ret = flushRoutes(interface)) {
@@ -1216,8 +1073,8 @@
}
int RouteController::addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRangeMap& uidRangeMap) {
- if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
+ bool secure, const UidRanges& uidRanges) {
+ if (int ret = modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1226,9 +1083,8 @@
}
int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure,
- const UidRangeMap& uidRangeMap) {
- if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
+ bool secure, const UidRanges& uidRanges) {
+ if (int ret = modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_DEL,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1242,16 +1098,11 @@
int RouteController::modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
Permission newPermission) {
- // Physical network rules either use permission bits or UIDs, but not both.
- // So permission changes don't affect any UID-based rules.
- UidRangeMap emptyUidRangeMap;
// Add the new rules before deleting the old ones, to avoid race conditions.
- if (int ret = modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, newPermission,
- ACTION_ADD, MODIFY_NON_UID_BASED_RULES)) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, newPermission, ACTION_ADD)) {
return ret;
}
- return modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, oldPermission, ACTION_DEL,
- MODIFY_NON_UID_BASED_RULES);
+ return modifyPhysicalNetwork(netId, interface, oldPermission, ACTION_DEL);
}
int RouteController::addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges) {
@@ -1263,14 +1114,14 @@
}
int RouteController::addUsersToVirtualNetwork(unsigned netId, const char* interface, bool secure,
- const UidRangeMap& uidRangeMap) {
- return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
+ const UidRanges& uidRanges) {
+ return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,
!MODIFY_NON_UID_BASED_RULES);
}
int RouteController::removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRangeMap& uidRangeMap) {
- return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
+ bool secure, const UidRanges& uidRanges) {
+ return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_DEL,
!MODIFY_NON_UID_BASED_RULES);
}
@@ -1320,27 +1171,6 @@
return modifyVpnFallthroughRule(RTM_DELRULE, vpnNetId, physicalInterface, permission);
}
-int RouteController::addUsersToPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap) {
- return modifyPhysicalNetwork(netId, interface, uidRangeMap, PERMISSION_NONE, ACTION_ADD,
- !MODIFY_NON_UID_BASED_RULES);
-}
-
-int RouteController::removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap) {
- return modifyPhysicalNetwork(netId, interface, uidRangeMap, PERMISSION_NONE, ACTION_DEL,
- !MODIFY_NON_UID_BASED_RULES);
-}
-
-int RouteController::addUsersToUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap) {
- return modifyUnreachableNetwork(netId, uidRangeMap, ACTION_ADD);
-}
-
-int RouteController::removeUsersFromUnreachableNetwork(unsigned netId,
- const UidRangeMap& uidRangeMap) {
- return modifyUnreachableNetwork(netId, uidRangeMap, ACTION_DEL);
-}
-
// Protects sInterfaceToTable.
std::mutex RouteController::sInterfaceToTableLock;
std::map<std::string, uint32_t> RouteController::sInterfaceToTable;
diff --git a/server/RouteController.h b/server/RouteController.h
index 38d2d62..656fc21 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -17,7 +17,6 @@
#pragma once
#include "NetdConstants.h" // IptablesTarget
-#include "Network.h" // UidRangeMap
#include "Permission.h"
#include <android-base/thread_annotations.h>
@@ -29,53 +28,6 @@
namespace android::net {
-// clang-format off
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF = 11000;
-const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 12000;
-const uint32_t RULE_PRIORITY_SECURE_VPN = 13000;
-const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN = 14000;
-// Rules used when applications explicitly select a network that they have permission to use only
-// because they are in the list of UID ranges for that network.
-//
-// Sockets from these UIDs will not match RULE_PRIORITY_EXPLICIT_NETWORK rules because they will
-// not have the necessary permission bits in the fwmark. We cannot just give any socket on any of
-// these networks the permission bits, because if the UID that created the socket loses access to
-// the network, then the socket must not match any rule that selects that network.
-const uint32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK = 15000;
-const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK = 16000;
-const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE = 17000;
-const uint32_t RULE_PRIORITY_LEGACY_SYSTEM = 18000;
-const uint32_t RULE_PRIORITY_LEGACY_NETWORK = 19000;
-const uint32_t RULE_PRIORITY_LOCAL_NETWORK = 20000;
-const uint32_t RULE_PRIORITY_TETHERING = 21000;
-// Implicit rules for sockets that connected on a given network because the network was the default
-// network for the UID.
-const uint32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK = 22000;
-const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK = 23000;
-const uint32_t RULE_PRIORITY_BYPASSABLE_VPN = 24000;
-// reserved for RULE_PRIORITY_UID_VPN_FALLTHROUGH = 25000;
-const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 26000;
-const uint32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 27000;
-// Rule used when framework wants to disable default network from specified applications. There will
-// be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and
-// UID_DEFAULT_NETWORK when framework is switching user preferences.
-//
-// framework --> netd
-// step 1: set uid to unreachable network
-// step 2: remove uid from OEM-paid network list
-// or
-// step 1: add uid to OEM-paid network list
-// step 2: remove uid from unreachable network
-//
-// The priority is lower than UID_DEFAULT_NETWORK. Otherwise, the app will be told by
-// ConnectivityService that it has a network in step 1 of the second case. But if it tries to use
-// the network, it will not work. That will potentially cause a user-visible error.
-const uint32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 28000;
-const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 29000;
-const uint32_t RULE_PRIORITY_UNREACHABLE = 32000;
-// clang-format on
-
class UidRanges;
class RouteController {
@@ -107,29 +59,25 @@
[[nodiscard]] static int removeInterfaceFromLocalNetwork(unsigned netId, const char* interface);
[[nodiscard]] static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission,
- const UidRangeMap& uidRangeMap);
+ Permission permission);
[[nodiscard]] static int removeInterfaceFromPhysicalNetwork(unsigned netId,
const char* interface,
- Permission permission,
- const UidRangeMap& uidRangeMap);
+ Permission permission);
[[nodiscard]] static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
- bool secure,
- const UidRangeMap& uidRangeMap);
+ bool secure, const UidRanges& uidRanges);
[[nodiscard]] static int removeInterfaceFromVirtualNetwork(unsigned netId,
const char* interface, bool secure,
- const UidRangeMap& uidRangeMap);
+ const UidRanges& uidRanges);
[[nodiscard]] static int modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
Permission newPermission);
[[nodiscard]] static int addUsersToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRangeMap& uidRangeMap);
+ bool secure, const UidRanges& uidRanges);
[[nodiscard]] static int removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure,
- const UidRangeMap& uidRangeMap);
+ bool secure, const UidRanges& uidRanges);
[[nodiscard]] static int addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges);
[[nodiscard]] static int removeUsersFromRejectNonSecureNetworkRule(const UidRanges& uidRanges);
@@ -160,18 +108,6 @@
const char* physicalInterface,
Permission permission);
- [[nodiscard]] static int addUsersToPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap);
-
- [[nodiscard]] static int removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap);
-
- [[nodiscard]] static int addUsersToUnreachableNetwork(unsigned netId,
- const UidRangeMap& uidRangeMap);
-
- [[nodiscard]] static int removeUsersFromUnreachableNetwork(unsigned netId,
- const UidRangeMap& uidRangeMap);
-
// For testing.
static int (*iptablesRestoreCommandFunction)(IptablesTarget, const std::string&,
const std::string&, std::string *);
@@ -189,10 +125,8 @@
REQUIRES(sInterfaceToTableLock);
static uint32_t getRouteTableForInterface(const char *interface) EXCLUDES(sInterfaceToTableLock);
static int modifyDefaultNetwork(uint16_t action, const char* interface, Permission permission);
- static int modifyPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap, Permission permission,
- bool add, bool modifyNonUidBasedRules);
- static int modifyUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap, bool add);
+ static int modifyPhysicalNetwork(unsigned netId, const char* interface, Permission permission,
+ bool add);
static int modifyRoute(uint16_t action, uint16_t flags, const char* interface,
const char* destination, const char* nexthop, TableType tableType,
int mtu);
@@ -201,7 +135,7 @@
static int modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId,
const char* physicalInterface, Permission permission);
static int modifyVirtualNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap, bool secure, bool add,
+ const UidRanges& uidRanges, bool secure, bool add,
bool modifyNonUidBasedRules);
static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock);
};
diff --git a/server/RouteControllerTest.cpp b/server/RouteControllerTest.cpp
index e85a83c..fed15a3 100644
--- a/server/RouteControllerTest.cpp
+++ b/server/RouteControllerTest.cpp
@@ -45,10 +45,10 @@
// Expect a rule dump for these two families to contain at least the following priorities.
for (int family : {AF_INET, AF_INET6 }) {
std::set<uint32_t> expectedPriorities = {
- 0,
- RULE_PRIORITY_LEGACY_SYSTEM,
- RULE_PRIORITY_LEGACY_NETWORK,
- RULE_PRIORITY_UNREACHABLE,
+ 0,
+ 15000, // RULE_PRIORITY_LEGACY_SYSTEM
+ 16000, // RULE_PRIORITY_LEGACY_NETWORK
+ 32000, // RULE_PRIORITY_UNREACHABLE
};
NetlinkDumpCallback callback = [&expectedPriorities] (const nlmsghdr *nlh) {
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index b3d9150..44bda3b 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -31,8 +31,6 @@
#include <cinttypes>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <log/log.h>
#include <netdutils/InternetAddresses.h>
@@ -48,22 +46,12 @@
namespace android {
-using android::base::StringPrintf;
using netdutils::ScopedAddrinfo;
using netdutils::Stopwatch;
namespace net {
namespace {
-int getAdbPort() {
- return android::base::GetIntProperty("service.adb.tcp.port", 0);
-}
-
-bool isAdbSocket(const inet_diag_msg *msg, int adbPort) {
- return adbPort > 0 && msg->id.idiag_sport == htons(adbPort) &&
- (msg->idiag_uid == AID_ROOT || msg->idiag_uid == AID_SHELL);
-}
-
int checkError(int fd) {
struct {
nlmsghdr h;
@@ -306,7 +294,7 @@
return ret;
}
-int SockDiag::destroySockets(uint8_t proto, int family, const char* addrstr, int ifindex) {
+int SockDiag::destroySockets(uint8_t proto, int family, const char *addrstr) {
if (!hasSocks()) {
return -EBADFD;
}
@@ -315,33 +303,28 @@
return ret;
}
- auto destroyAll = [ifindex](uint8_t, const inet_diag_msg* msg) {
- return ifindex == 0 || ifindex == (int)msg->id.idiag_if;
- };
+ auto destroyAll = [] (uint8_t, const inet_diag_msg*) { return true; };
return readDiagMsg(proto, destroyAll);
}
-int SockDiag::destroySockets(const char* addrstr, int ifindex) {
+int SockDiag::destroySockets(const char *addrstr) {
Stopwatch s;
mSocketsDestroyed = 0;
- std::string where = addrstr;
- if (ifindex) where += StringPrintf(" ifindex %d", ifindex);
-
- if (!strchr(addrstr, ':')) { // inet_ntop never returns something like ::ffff:192.0.2.1
- if (int ret = destroySockets(IPPROTO_TCP, AF_INET, addrstr, ifindex)) {
- ALOGE("Failed to destroy IPv4 sockets on %s: %s", where.c_str(), strerror(-ret));
+ if (!strchr(addrstr, ':')) {
+ if (int ret = destroySockets(IPPROTO_TCP, AF_INET, addrstr)) {
+ ALOGE("Failed to destroy IPv4 sockets on %s: %s", addrstr, strerror(-ret));
return ret;
}
}
- if (int ret = destroySockets(IPPROTO_TCP, AF_INET6, addrstr, ifindex)) {
- ALOGE("Failed to destroy IPv6 sockets on %s: %s", where.c_str(), strerror(-ret));
+ if (int ret = destroySockets(IPPROTO_TCP, AF_INET6, addrstr)) {
+ ALOGE("Failed to destroy IPv6 sockets on %s: %s", addrstr, strerror(-ret));
return ret;
}
if (mSocketsDestroyed > 0) {
- ALOGI("Destroyed %d sockets on %s in %" PRId64 "us", mSocketsDestroyed, where.c_str(),
+ ALOGI("Destroyed %d sockets on %s in %" PRId64 "us", mSocketsDestroyed, addrstr,
s.timeTakenUs());
}
@@ -431,8 +414,7 @@
return msg != nullptr &&
uidRanges.hasUid(msg->idiag_uid) &&
skipUids.find(msg->idiag_uid) == skipUids.end() &&
- !(excludeLoopback && isLoopbackSocket(msg)) &&
- !isAdbSocket(msg, getAdbPort());
+ !(excludeLoopback && isLoopbackSocket(msg));
};
iovec iov[] = {
diff --git a/server/SockDiag.h b/server/SockDiag.h
index 240e4e5..745c09e 100644
--- a/server/SockDiag.h
+++ b/server/SockDiag.h
@@ -70,7 +70,7 @@
int sockDestroy(uint8_t proto, const inet_diag_msg *);
// Destroys all sockets on the given IPv4 or IPv6 address.
- int destroySockets(const char* addrstr, int ifindex);
+ int destroySockets(const char *addrstr);
// Destroys all sockets for the given protocol and UID.
int destroySockets(uint8_t proto, uid_t uid, bool excludeLoopback);
// Destroys all "live" (CONNECTED, SYN_SENT, SYN_RECV) TCP sockets for the given UID ranges.
@@ -91,7 +91,7 @@
int mSocketsDestroyed;
int sendDumpRequest(uint8_t proto, uint8_t family, uint8_t extensions, uint32_t states,
iovec *iov, int iovcnt);
- int destroySockets(uint8_t proto, int family, const char* addrstr, int ifindex);
+ int destroySockets(uint8_t proto, int family, const char *addrstr);
int destroyLiveSockets(const DestroyFilter& destroy, const char *what, iovec *iov, int iovcnt);
bool hasSocks() { return mSock != -1 && mWriteSock != -1; }
void closeSocks() { close(mSock); close(mWriteSock); mSock = mWriteSock = -1; }
diff --git a/server/SockDiagTest.cpp b/server/SockDiagTest.cpp
index 49601aa..b79471a 100644
--- a/server/SockDiagTest.cpp
+++ b/server/SockDiagTest.cpp
@@ -370,7 +370,7 @@
int ret;
switch (mode) {
case ADDRESS:
- ret = mSd.destroySockets("::1", 0 /* ifindex */);
+ ret = mSd.destroySockets("::1");
EXPECT_LE(0, ret) << ": Failed to destroy sockets on ::1: " << strerror(-ret);
break;
case UID:
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 325fc41..2445fb7 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -60,11 +60,14 @@
namespace android {
namespace net {
+using android::base::Error;
using android::base::Join;
using android::base::Pipe;
using android::base::Result;
+using android::base::StringAppendF;
using android::base::StringPrintf;
using android::base::unique_fd;
+using android::net::TetherOffloadRuleParcel;
using android::netdutils::DumpWriter;
using android::netdutils::ScopedIndent;
using android::netdutils::statusFromErrno;
@@ -81,6 +84,10 @@
// Chosen to match AID_DNS_TETHER, as made "friendly" by fs_config_generator.py.
constexpr const char kDnsmasqUsername[] = "dns_tether";
+// A value used by interface quota indicates there is no limit.
+// Sync from frameworks/base/core/java/android/net/netstats/provider/NetworkStatsProvider.java
+constexpr int64_t QUOTA_UNLIMITED = -1;
+
bool writeToFile(const char* filename, const char* value) {
int fd = open(filename, O_WRONLY | O_CLOEXEC);
if (fd < 0) {
@@ -157,13 +164,12 @@
}
TetherController::TetherController() {
- gLog.info("enter TetherController ctor");
if (inBpToolsMode()) {
enableForwarding(BP_TOOLS_MODE);
} else {
setIpFwdEnabled();
}
- gLog.info("leave TetherController ctor");
+ maybeInitMaps();
}
bool TetherController::setIpFwdEnabled() {
@@ -196,6 +202,27 @@
return setIpFwdEnabled();
}
+void TetherController::maybeInitMaps() {
+ if (!bpf::isBpfSupported()) return;
+
+ // Open BPF maps, ignoring errors because the device might not support BPF offload.
+ int fd = getTetherIngressMapFd();
+ if (fd >= 0) {
+ mBpfIngressMap.reset(fd);
+ mBpfIngressMap.clear();
+ }
+ fd = getTetherStatsMapFd();
+ if (fd >= 0) {
+ mBpfStatsMap.reset(fd);
+ mBpfStatsMap.clear();
+ }
+ fd = getTetherLimitMapFd();
+ if (fd >= 0) {
+ mBpfLimitMap.reset(fd);
+ mBpfLimitMap.clear();
+ }
+}
+
const std::set<std::string>& TetherController::getIpfwdRequesterList() const {
return mForwardingRequests;
}
@@ -579,7 +606,8 @@
}
// add this if we are the first enabled nat for this upstream
- if (!isAnyForwardingEnabledOnUpstream(extIface)) {
+ bool firstDownstreamForThisUpstream = !isAnyForwardingEnabledOnUpstream(extIface);
+ if (firstDownstreamForThisUpstream) {
std::vector<std::string> v4Cmds = {
"*nat",
StringPrintf("-A %s -o %s -j MASQUERADE", LOCAL_NAT_POSTROUTING, extIface),
@@ -605,6 +633,7 @@
return -ENODEV;
}
+ if (firstDownstreamForThisUpstream) maybeStartBpf(extIface);
return 0;
}
@@ -788,10 +817,82 @@
}
setForwardRules(false, intIface, extIface);
+ if (!isAnyForwardingEnabledOnUpstream(extIface)) maybeStopBpf(extIface);
if (!isAnyForwardingPairEnabled()) setDefaults();
return 0;
}
+namespace {
+Result<void> validateOffloadRule(const TetherOffloadRuleParcel& rule) {
+ struct ethhdr hdr;
+
+ if (rule.inputInterfaceIndex <= 0) {
+ return Error(ENODEV) << "Invalid input interface " << rule.inputInterfaceIndex;
+ }
+ if (rule.outputInterfaceIndex <= 0) {
+ return Error(ENODEV) << "Invalid output interface " << rule.inputInterfaceIndex;
+ }
+ if (rule.prefixLength != 128) {
+ return Error(EINVAL) << "Prefix length must be 128, not " << rule.prefixLength;
+ }
+ if (rule.destination.size() != sizeof(in6_addr)) {
+ return Error(EAFNOSUPPORT) << "Invalid IP address length " << rule.destination.size();
+ }
+ if (rule.srcL2Address.size() != sizeof(hdr.h_source)) {
+ return Error(ENXIO) << "Invalid L2 src address length " << rule.srcL2Address.size();
+ }
+ if (rule.dstL2Address.size() != sizeof(hdr.h_dest)) {
+ return Error(ENXIO) << "Invalid L2 dst address length " << rule.dstL2Address.size();
+ }
+ if (rule.pmtu < IPV6_MIN_MTU || rule.pmtu > 0xFFFF) {
+ return Error(EINVAL) << "Invalid IPv6 path mtu " << rule.pmtu;
+ }
+ return Result<void>();
+}
+} // namespace
+
+Result<void> TetherController::addOffloadRule(const TetherOffloadRuleParcel& rule) {
+ Result<void> res = validateOffloadRule(rule);
+ if (!res.ok()) return res;
+
+ ethhdr hdr = {
+ .h_proto = htons(ETH_P_IPV6),
+ };
+ memcpy(&hdr.h_dest, rule.dstL2Address.data(), sizeof(hdr.h_dest));
+ memcpy(&hdr.h_source, rule.srcL2Address.data(), sizeof(hdr.h_source));
+
+ // Only downstream supported for now.
+ TetherIngressKey key = {
+ .iif = static_cast<uint32_t>(rule.inputInterfaceIndex),
+ .neigh6 = *(const in6_addr*)rule.destination.data(),
+ };
+
+ TetherIngressValue value = {
+ .oif = static_cast<uint32_t>(rule.outputInterfaceIndex),
+ .macHeader = hdr,
+ .pmtu = static_cast<uint16_t>(rule.pmtu),
+ };
+
+ return mBpfIngressMap.writeValue(key, value, BPF_ANY);
+}
+
+Result<void> TetherController::removeOffloadRule(const TetherOffloadRuleParcel& rule) {
+ Result<void> res = validateOffloadRule(rule);
+ if (!res.ok()) return res;
+
+ TetherIngressKey key = {
+ .iif = static_cast<uint32_t>(rule.inputInterfaceIndex),
+ .neigh6 = *(const in6_addr*)rule.destination.data(),
+ };
+
+ Result<void> ret = mBpfIngressMap.deleteValue(key);
+
+ // Silently return success if the rule did not exist.
+ if (!ret.ok() && ret.error().code() == ENOENT) return {};
+
+ return ret;
+}
+
void TetherController::addStats(TetherStatsList& statsList, const TetherStats& stats) {
for (TetherStats& existing : statsList) {
if (existing.addStatsIfMatch(stats)) {
@@ -927,6 +1028,180 @@
return statsList;
}
+StatusOr<TetherController::TetherOffloadStatsList> TetherController::getTetherOffloadStats() {
+ TetherOffloadStatsList statsList;
+
+ const auto processTetherStats = [&statsList](const uint32_t& key, const TetherStatsValue& value,
+ const BpfMap<uint32_t, TetherStatsValue>&) {
+ statsList.push_back({.ifIndex = static_cast<int>(key),
+ .rxBytes = static_cast<int64_t>(value.rxBytes),
+ .rxPackets = static_cast<int64_t>(value.rxPackets),
+ .txBytes = static_cast<int64_t>(value.txBytes),
+ .txPackets = static_cast<int64_t>(value.txPackets)});
+ return Result<void>();
+ };
+
+ auto ret = mBpfStatsMap.iterateWithValue(processTetherStats);
+ if (!ret.ok()) {
+ // Ignore error to return the remaining tether stats result.
+ ALOGE("Error processing tether stats from BPF maps: %s", ret.error().message().c_str());
+ }
+
+ return statsList;
+}
+
+// Use UINT64_MAX (~0uLL) for unlimited.
+Result<void> TetherController::setBpfLimit(uint32_t ifIndex, uint64_t limit) {
+ // The common case is an update, where the stats already exist,
+ // hence we read first, even though writing with BPF_NOEXIST
+ // first would make the code simpler.
+ uint64_t rxBytes, txBytes;
+ auto statsEntry = mBpfStatsMap.readValue(ifIndex);
+
+ if (statsEntry.ok()) {
+ // Ok, there was a stats entry.
+ rxBytes = statsEntry.value().rxBytes;
+ txBytes = statsEntry.value().txBytes;
+ } else if (statsEntry.error().code() == ENOENT) {
+ // No stats entry - create one with zeroes.
+ TetherStatsValue stats = {};
+ // This function is the *only* thing that can create entries.
+ auto ret = mBpfStatsMap.writeValue(ifIndex, stats, BPF_NOEXIST);
+ if (!ret.ok()) {
+ ALOGE("mBpfStatsMap.writeValue failure: %s", strerror(ret.error().code()));
+ return ret;
+ }
+ rxBytes = 0;
+ txBytes = 0;
+ } else {
+ // Other error while trying to get stats entry.
+ return statsEntry.error();
+ }
+
+ // rxBytes + txBytes won't overflow even at 5gbps for ~936 years.
+ uint64_t newLimit = rxBytes + txBytes + limit;
+
+ // if adding limit (e.g., if limit is UINT64_MAX) caused overflow: clamp to 'infinity'
+ if (newLimit < rxBytes + txBytes) newLimit = ~0uLL;
+
+ auto ret = mBpfLimitMap.writeValue(ifIndex, newLimit, BPF_ANY);
+ if (!ret.ok()) {
+ ALOGE("mBpfLimitMap.writeValue failure: %s", strerror(ret.error().code()));
+ return ret;
+ }
+
+ return {};
+}
+
+void TetherController::maybeStartBpf(const char* extIface) {
+ if (!bpf::isBpfSupported()) return;
+
+ // TODO: perhaps ignore IPv4-only interface because IPv4 traffic downstream is not supported.
+ int ifIndex = if_nametoindex(extIface);
+ if (!ifIndex) {
+ ALOGE("Fail to get index for interface %s", extIface);
+ return;
+ }
+
+ auto isEthernet = android::net::isEthernet(extIface);
+ if (!isEthernet.ok()) {
+ ALOGE("isEthernet(%s[%d]) failure: %s", extIface, ifIndex,
+ isEthernet.error().message().c_str());
+ return;
+ }
+
+ int rv = getTetherIngressProgFd(isEthernet.value());
+ if (rv < 0) {
+ ALOGE("getTetherIngressProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
+ return;
+ }
+ unique_fd tetherProgFd(rv);
+
+ rv = tcFilterAddDevIngressTether(ifIndex, tetherProgFd, isEthernet.value());
+ if (rv) {
+ ALOGE("tcFilterAddDevIngressTether(%d[%s], %d) failure: %s", ifIndex, extIface,
+ isEthernet.value(), strerror(-rv));
+ return;
+ }
+}
+
+void TetherController::maybeStopBpf(const char* extIface) {
+ if (!bpf::isBpfSupported()) return;
+
+ // TODO: perhaps ignore IPv4-only interface because IPv4 traffic downstream is not supported.
+ int ifIndex = if_nametoindex(extIface);
+ if (!ifIndex) {
+ ALOGE("Fail to get index for interface %s", extIface);
+ return;
+ }
+
+ int rv = tcFilterDelDevIngressTether(ifIndex);
+ if (rv < 0) {
+ ALOGE("tcFilterDelDevIngressTether(%d[%s]) failure: %s", ifIndex, extIface, strerror(-rv));
+ }
+}
+
+int TetherController::setTetherOffloadInterfaceQuota(int ifIndex, int64_t maxBytes) {
+ if (!mBpfStatsMap.isValid() || !mBpfLimitMap.isValid()) return -ENOTSUP;
+
+ if (ifIndex <= 0) return -ENODEV;
+
+ if (maxBytes < QUOTA_UNLIMITED) {
+ ALOGE("Invalid bytes value. Must be -1 (unlimited) or 0..max_int64.");
+ return -ERANGE;
+ }
+
+ // Note that a value of unlimited quota (-1) indicates simply max_uint64.
+ const auto res = setBpfLimit(static_cast<uint32_t>(ifIndex), static_cast<uint64_t>(maxBytes));
+ if (!res.ok()) {
+ ALOGE("Fail to set quota %" PRId64 " for interface index %d: %s", maxBytes, ifIndex,
+ strerror(res.error().code()));
+ return -res.error().code();
+ }
+
+ return 0;
+}
+
+Result<TetherController::TetherOffloadStats> TetherController::getAndClearTetherOffloadStats(
+ int ifIndex) {
+ if (!mBpfStatsMap.isValid() || !mBpfLimitMap.isValid()) return Error(ENOTSUP);
+
+ if (ifIndex <= 0) {
+ return Error(ENODEV) << "Invalid interface " << ifIndex;
+ }
+
+ // getAndClearTetherOffloadStats is called after all offload rules have already been deleted
+ // for the given upstream interface. Before starting to do cleanup stuff in this function, use
+ // synchronizeKernelRCU to make sure that all the current running eBPF programs are finished
+ // on all CPUs, especially the unfinished packet processing. After synchronizeKernelRCU
+ // returned, we can safely read or delete on the stats map or the limit map.
+ if (int res = bpf::synchronizeKernelRCU()) {
+ // Error log but don't return error. Do as much cleanup as possible.
+ ALOGE("synchronize_rcu() failed: %s", strerror(-res));
+ }
+
+ const auto stats = mBpfStatsMap.readValue(ifIndex);
+ if (!stats.ok()) {
+ return Error(stats.error().code()) << "Fail to get stats for interface index " << ifIndex;
+ }
+
+ auto res = mBpfStatsMap.deleteValue(ifIndex);
+ if (!res.ok()) {
+ return Error(res.error().code()) << "Fail to delete stats for interface index " << ifIndex;
+ }
+
+ res = mBpfLimitMap.deleteValue(ifIndex);
+ if (!res.ok()) {
+ return Error(res.error().code()) << "Fail to delete limit for interface index " << ifIndex;
+ }
+
+ return TetherOffloadStats{.ifIndex = static_cast<int>(ifIndex),
+ .rxBytes = static_cast<int64_t>(stats.value().rxBytes),
+ .rxPackets = static_cast<int64_t>(stats.value().rxPackets),
+ .txBytes = static_cast<int64_t>(stats.value().txBytes),
+ .txPackets = static_cast<int64_t>(stats.value().txPackets)};
+}
+
void TetherController::dumpIfaces(DumpWriter& dw) {
dw.println("Interface pairs:");
@@ -937,6 +1212,90 @@
}
}
+namespace {
+
+std::string l2ToString(const uint8_t* addr, size_t len) {
+ std::string str;
+
+ if (len == 0) return str;
+
+ StringAppendF(&str, "%02x", addr[0]);
+ for (size_t i = 1; i < len; i++) {
+ StringAppendF(&str, ":%02x", addr[i]);
+ }
+
+ return str;
+}
+
+} // namespace
+
+void TetherController::dumpBpf(DumpWriter& dw) {
+ if (!mBpfIngressMap.isValid() || !mBpfStatsMap.isValid() || !mBpfLimitMap.isValid()) {
+ dw.println("BPF not supported");
+ return;
+ }
+
+ dw.println("BPF ingress map: iif(iface) v6addr -> oif(iface) srcmac dstmac ethertype [pmtu]");
+ const auto printIngressMap = [&dw](const TetherIngressKey& key, const TetherIngressValue& value,
+ const BpfMap<TetherIngressKey, TetherIngressValue>&) {
+ char addr[INET6_ADDRSTRLEN];
+ std::string src = l2ToString(value.macHeader.h_source, sizeof(value.macHeader.h_source));
+ std::string dst = l2ToString(value.macHeader.h_dest, sizeof(value.macHeader.h_dest));
+ inet_ntop(AF_INET6, &key.neigh6, addr, sizeof(addr));
+
+ char iifStr[IFNAMSIZ] = "?";
+ char oifStr[IFNAMSIZ] = "?";
+ if_indextoname(key.iif, iifStr);
+ if_indextoname(value.oif, oifStr);
+ dw.println("%u(%s) %s -> %u(%s) %s %s %04x [%u]", key.iif, iifStr, addr, value.oif, oifStr,
+ src.c_str(), dst.c_str(), ntohs(value.macHeader.h_proto), value.pmtu);
+
+ return Result<void>();
+ };
+
+ dw.incIndent();
+ auto ret = mBpfIngressMap.iterateWithValue(printIngressMap);
+ if (!ret.ok()) {
+ dw.println("Error printing BPF ingress map: %s", ret.error().message().c_str());
+ }
+ dw.decIndent();
+
+ dw.println("BPF stats (downlink): iif(iface) -> packets bytes errors");
+ const auto printStatsMap = [&dw](const uint32_t& key, const TetherStatsValue& value,
+ const BpfMap<uint32_t, TetherStatsValue>&) {
+ char iifStr[IFNAMSIZ] = "?";
+ if_indextoname(key, iifStr);
+ dw.println("%u(%s) -> %" PRIu64 " %" PRIu64 " %" PRIu64, key, iifStr, value.rxPackets,
+ value.rxBytes, value.rxErrors);
+
+ return Result<void>();
+ };
+
+ dw.incIndent();
+ ret = mBpfStatsMap.iterateWithValue(printStatsMap);
+ if (!ret.ok()) {
+ dw.println("Error printing BPF stats map: %s", ret.error().message().c_str());
+ }
+ dw.decIndent();
+
+ dw.println("BPF limit: iif(iface) -> bytes");
+ const auto printLimitMap = [&dw](const uint32_t& key, const uint64_t& value,
+ const BpfMap<uint32_t, uint64_t>&) {
+ char iifStr[IFNAMSIZ] = "?";
+ if_indextoname(key, iifStr);
+ dw.println("%u(%s) -> %" PRIu64, key, iifStr, value);
+
+ return Result<void>();
+ };
+
+ dw.incIndent();
+ ret = mBpfLimitMap.iterateWithValue(printLimitMap);
+ if (!ret.ok()) {
+ dw.println("Error printing BPF limit map: %s", ret.error().message().c_str());
+ }
+ dw.decIndent();
+}
+
void TetherController::dump(DumpWriter& dw) {
std::lock_guard guard(lock);
@@ -954,6 +1313,8 @@
}
dumpIfaces(dw);
+ dw.println("");
+ dumpBpf(dw);
}
} // namespace net
diff --git a/server/TetherController.h b/server/TetherController.h
index 585686a..bcd2ee6 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -72,6 +72,11 @@
int sendAllState(int daemonFd) const;
} mDnsmasqState{};
+ // BPF maps, initialized by maybeInitMaps.
+ bpf::BpfMap<TetherIngressKey, TetherIngressValue> mBpfIngressMap;
+ bpf::BpfMap<uint32_t, TetherStatsValue> mBpfStatsMap;
+ bpf::BpfMap<uint32_t, uint64_t> mBpfLimitMap;
+
public:
TetherController();
~TetherController() = default;
@@ -100,6 +105,11 @@
int disableNat(const char* intIface, const char* extIface);
int setupIptablesHooks();
+ base::Result<void> addOffloadRule(const TetherOffloadRuleParcel& rule);
+ base::Result<void> removeOffloadRule(const TetherOffloadRuleParcel& rule);
+
+ int setTetherOffloadInterfaceQuota(int ifIndex, int64_t maxBytes);
+
class TetherStats {
public:
TetherStats() = default;
@@ -128,9 +138,20 @@
}
};
+ struct TetherOffloadStats {
+ int ifIndex;
+ int64_t rxBytes;
+ int64_t rxPackets;
+ int64_t txBytes;
+ int64_t txPackets;
+ };
+
typedef std::vector<TetherStats> TetherStatsList;
+ typedef std::vector<TetherOffloadStats> TetherOffloadStatsList;
netdutils::StatusOr<TetherStatsList> getTetherStats();
+ netdutils::StatusOr<TetherOffloadStatsList> getTetherOffloadStats();
+ base::Result<TetherOffloadStats> getAndClearTetherOffloadStats(int ifIndex);
/*
* extraProcessingInfo: contains raw parsed data, and error info.
@@ -152,6 +173,7 @@
void dump(netdutils::DumpWriter& dw);
void dumpIfaces(netdutils::DumpWriter& dw);
+ void dumpBpf(netdutils::DumpWriter& dw);
private:
bool setIpFwdEnabled();
@@ -173,6 +195,11 @@
int setForwardRules(bool set, const char *intIface, const char *extIface);
int setTetherCountingRules(bool add, const char *intIface, const char *extIface);
+ base::Result<void> setBpfLimit(uint32_t ifIndex, uint64_t limit);
+ void maybeInitMaps();
+ void maybeStartBpf(const char* extIface);
+ void maybeStopBpf(const char* extIface);
+
static void addStats(TetherStatsList& statsList, const TetherStats& stats);
// For testing.
diff --git a/server/TetherControllerTest.cpp b/server/TetherControllerTest.cpp
index e700f60..db9892f 100644
--- a/server/TetherControllerTest.cpp
+++ b/server/TetherControllerTest.cpp
@@ -38,13 +38,28 @@
using android::base::Join;
using android::base::StringPrintf;
+using android::bpf::BpfMap;
using android::netdutils::StatusOr;
+using ::testing::Contains;
using TetherStats = android::net::TetherController::TetherStats;
using TetherStatsList = android::net::TetherController::TetherStatsList;
+using TetherOffloadStats = android::net::TetherController::TetherOffloadStats;
+using TetherOffloadStatsList = android::net::TetherController::TetherOffloadStatsList;
namespace android {
namespace net {
+constexpr int TEST_MAP_SIZE = 10;
+
+// Comparison for TetherOffloadStats. Need to override operator== because class TetherOffloadStats
+// doesn't have one.
+// TODO: once C++20 is used, use default operator== in TetherOffloadStats and remove the overriding
+// here.
+bool operator==(const TetherOffloadStats& lhs, const TetherOffloadStats& rhs) {
+ return lhs.ifIndex == rhs.ifIndex && lhs.rxBytes == rhs.rxBytes && lhs.txBytes == rhs.txBytes &&
+ lhs.rxPackets == rhs.rxPackets && lhs.txPackets == rhs.txPackets;
+}
+
class TetherControllerTest : public IptablesBaseTest {
public:
TetherControllerTest() {
@@ -53,6 +68,38 @@
protected:
TetherController mTetherCtrl;
+ BpfMap<uint32_t, TetherStatsValue> mFakeTetherStatsMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
+ BpfMap<uint32_t, uint64_t> mFakeTetherLimitMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
+
+ void SetUp() {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ ASSERT_TRUE(mFakeTetherStatsMap.isValid());
+ ASSERT_TRUE(mFakeTetherLimitMap.isValid());
+
+ mTetherCtrl.mBpfStatsMap = mFakeTetherStatsMap;
+ ASSERT_TRUE(mTetherCtrl.mBpfStatsMap.isValid());
+ mTetherCtrl.mBpfLimitMap = mFakeTetherLimitMap;
+ ASSERT_TRUE(mTetherCtrl.mBpfLimitMap.isValid());
+ }
+
+ std::string toString(const TetherOffloadStatsList& statsList) {
+ std::string result;
+ for (const auto& stats : statsList) {
+ result += StringPrintf("%d, %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n",
+ stats.ifIndex, stats.rxBytes, stats.rxPackets, stats.txBytes,
+ stats.txPackets);
+ }
+ return result;
+ }
+
+ void updateMaps(uint32_t ifaceIndex, uint64_t rxBytes, uint64_t rxPackets, uint64_t txBytes,
+ uint64_t txPackets) {
+ // {rx, tx}Errors in |tetherStats| are set zero because getTetherStats doesn't use them.
+ const TetherStatsValue tetherStats = {rxPackets, rxBytes, 0 /*unused*/,
+ txPackets, txBytes, 0 /*unused*/};
+ ASSERT_RESULT_OK(mFakeTetherStatsMap.writeValue(ifaceIndex, tetherStats, BPF_ANY));
+ };
int setDefaults() {
return mTetherCtrl.setDefaults();
@@ -438,5 +485,64 @@
EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
}
+TEST_F(TetherControllerTest, TestTetherOffloadGetStats) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ updateMaps(101, 100, 10, 200, 20);
+ updateMaps(102, 300, 30, 400, 40);
+ const TetherOffloadStats expected0{101, 100, 10, 200, 20};
+ const TetherOffloadStats expected1{102, 300, 30, 400, 40};
+
+ const StatusOr<TetherOffloadStatsList> result = mTetherCtrl.getTetherOffloadStats();
+ ASSERT_OK(result);
+ const TetherOffloadStatsList& actual = result.value();
+ ASSERT_EQ(2U, actual.size());
+ EXPECT_THAT(actual, Contains(expected0)) << toString(actual);
+ EXPECT_THAT(actual, Contains(expected1)) << toString(actual);
+ clearIptablesRestoreOutput();
+}
+
+TEST_F(TetherControllerTest, TestTetherOffloadSetQuota) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ const uint32_t ifindex = 100;
+ const uint64_t minQuota = 0;
+ const uint64_t maxQuota = std::numeric_limits<int64_t>::max();
+ const uint64_t infinityQuota = std::numeric_limits<uint64_t>::max();
+
+ // Create a stats entry with zeroes in the first time set limit.
+ ASSERT_EQ(0, mTetherCtrl.setTetherOffloadInterfaceQuota(ifindex, minQuota));
+ const StatusOr<TetherOffloadStatsList> result = mTetherCtrl.getTetherOffloadStats();
+ ASSERT_OK(result);
+ const TetherOffloadStatsList& actual = result.value();
+ ASSERT_EQ(1U, actual.size());
+ EXPECT_THAT(actual, Contains(TetherOffloadStats{ifindex, 0, 0, 0, 0})) << toString(actual);
+
+ // Verify the quota with the boundary {min, max, infinity}.
+ const uint64_t rxBytes = 1000;
+ const uint64_t txBytes = 2000;
+ updateMaps(ifindex, rxBytes, 0 /*unused*/, txBytes, 0 /*unused*/);
+
+ for (const uint64_t quota : {minQuota, maxQuota, infinityQuota}) {
+ ASSERT_EQ(0, mTetherCtrl.setTetherOffloadInterfaceQuota(ifindex, quota));
+ base::Result<uint64_t> result = mFakeTetherLimitMap.readValue(ifindex);
+ ASSERT_RESULT_OK(result);
+
+ const uint64_t expectedQuota =
+ (quota == infinityQuota) ? infinityQuota : quota + rxBytes + txBytes;
+ EXPECT_EQ(expectedQuota, result.value());
+ }
+
+ // The valid range of interface index is 1..max_int64.
+ const uint32_t invalidIfindex = 0;
+ int ret = mTetherCtrl.setTetherOffloadInterfaceQuota(invalidIfindex /*bad*/, infinityQuota);
+ ASSERT_EQ(-ENODEV, ret);
+
+ // The valid range of quota is 0..max_int64 or -1 (unlimited).
+ const uint64_t invalidQuota = std::numeric_limits<int64_t>::min();
+ ret = mTetherCtrl.setTetherOffloadInterfaceQuota(ifindex, invalidQuota /*bad*/);
+ ASSERT_EQ(-ERANGE, ret);
+}
+
} // namespace net
} // namespace android
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 1f678cb..3839962 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -52,16 +52,13 @@
#include "netdutils/DumpWriter.h"
#include "qtaguid/qtaguid.h"
+using namespace android::bpf; // NOLINT(google-build-using-namespace): grandfathered
+
namespace android {
namespace net {
using base::StringPrintf;
using base::unique_fd;
-using bpf::getSocketCookie;
-using bpf::NONEXISTENT_COOKIE;
-using bpf::OVERFLOW_COUNTERSET;
-using bpf::retrieveProgram;
-using bpf::synchronizeKernelRCU;
using netdutils::DumpWriter;
using netdutils::extract;
using netdutils::ScopedIndent;
@@ -103,7 +100,6 @@
FLAG_MSG_TRANS(matchType, DOZABLE_MATCH, match);
FLAG_MSG_TRANS(matchType, STANDBY_MATCH, match);
FLAG_MSG_TRANS(matchType, POWERSAVE_MATCH, match);
- FLAG_MSG_TRANS(matchType, RESTRICTED_MATCH, match);
FLAG_MSG_TRANS(matchType, IIF_MATCH, match);
if (match) {
return StringPrintf("Unknown match: %u", match);
@@ -171,11 +167,14 @@
}
TrafficController::TrafficController()
- : mPerUidStatsEntriesLimit(PER_UID_STATS_ENTRIES_LIMIT),
+ : mBpfEnabled(isBpfSupported()),
+ mPerUidStatsEntriesLimit(PER_UID_STATS_ENTRIES_LIMIT),
mTotalUidStatsEntriesLimit(TOTAL_UID_STATS_ENTRIES_LIMIT) {}
TrafficController::TrafficController(uint32_t perUidLimit, uint32_t totalLimit)
- : mPerUidStatsEntriesLimit(perUidLimit), mTotalUidStatsEntriesLimit(totalLimit) {}
+ : mBpfEnabled(isBpfSupported()),
+ mPerUidStatsEntriesLimit(perUidLimit),
+ mTotalUidStatsEntriesLimit(totalLimit) {}
Status TrafficController::initMaps() {
std::lock_guard guard(mMutex);
@@ -248,6 +247,10 @@
}
Status TrafficController::start() {
+ if (!mBpfEnabled) {
+ return netdutils::status::ok;
+ }
+
/* When netd restarts from a crash without total system reboot, the program
* is still attached to the cgroup, detach it so the program can be freed
* and we can load and attach new program into the target cgroup.
@@ -311,6 +314,11 @@
return -EPERM;
}
+ if (!mBpfEnabled) {
+ if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
+ return 0;
+ }
+
uint64_t sock_cookie = getSocketCookie(sockFd);
if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
UidTagValue newKey = {.uid = (uint32_t)uid, .tag = tag};
@@ -374,6 +382,10 @@
int TrafficController::untagSocket(int sockFd) {
std::lock_guard guard(mMutex);
+ if (!mBpfEnabled) {
+ if (legacy_untagSocket(sockFd)) return -errno;
+ return 0;
+ }
uint64_t sock_cookie = getSocketCookie(sockFd);
if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
@@ -391,6 +403,11 @@
std::lock_guard guard(mMutex);
if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
+ if (!mBpfEnabled) {
+ if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
+ return 0;
+ }
+
// The default counter set for all uid is 0, so deleting the current counterset for that uid
// will automatically set it to 0.
if (counterSetNum == 0) {
@@ -419,6 +436,11 @@
std::lock_guard guard(mMutex);
if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
+ if (!mBpfEnabled) {
+ if (legacy_deleteTagData(tag, uid)) return -errno;
+ return 0;
+ }
+
// First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
// the tags related to the uid if the tag is 0.
const auto deleteMatchedCookieEntries = [uid, tag](const uint64_t& key,
@@ -479,6 +501,8 @@
}
int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
+ if (!mBpfEnabled) return 0;
+
IfaceValue iface;
if (ifaceIndex == 0) {
ALOGE("Unknown interface %s(%d)", name, ifaceIndex);
@@ -497,10 +521,10 @@
Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
FirewallType type) {
std::lock_guard guard(mMutex);
- if ((rule == ALLOW && type == ALLOWLIST) || (rule == DENY && type == DENYLIST)) {
- RETURN_IF_NOT_OK(addRule(uid, match));
- } else if ((rule == ALLOW && type == DENYLIST) || (rule == DENY && type == ALLOWLIST)) {
- RETURN_IF_NOT_OK(removeRule(uid, match));
+ if ((rule == ALLOW && type == WHITELIST) || (rule == DENY && type == BLACKLIST)) {
+ RETURN_IF_NOT_OK(addRule(mUidOwnerMap, uid, match));
+ } else if ((rule == ALLOW && type == BLACKLIST) || (rule == DENY && type == WHITELIST)) {
+ RETURN_IF_NOT_OK(removeRule(mUidOwnerMap, uid, match));
} else {
//Cannot happen.
return statusFromErrno(EINVAL, "");
@@ -508,17 +532,29 @@
return netdutils::status::ok;
}
-Status TrafficController::removeRule(uint32_t uid, UidOwnerMatchType match) {
- auto oldMatch = mUidOwnerMap.readValue(uid);
+UidOwnerMatchType TrafficController::jumpOpToMatch(BandwidthController::IptJumpOp jumpHandling) {
+ switch (jumpHandling) {
+ case BandwidthController::IptJumpReject:
+ return PENALTY_BOX_MATCH;
+ case BandwidthController::IptJumpReturn:
+ return HAPPY_BOX_MATCH;
+ case BandwidthController::IptJumpNoAdd:
+ return NO_MATCH;
+ }
+}
+
+Status TrafficController::removeRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
+ UidOwnerMatchType match) {
+ auto oldMatch = map.readValue(uid);
if (oldMatch.ok()) {
UidOwnerValue newMatch = {
.iif = (match == IIF_MATCH) ? 0 : oldMatch.value().iif,
.rule = static_cast<uint8_t>(oldMatch.value().rule & ~match),
};
if (newMatch.rule == 0) {
- RETURN_IF_NOT_OK(mUidOwnerMap.deleteValue(uid));
+ RETURN_IF_NOT_OK(map.deleteValue(uid));
} else {
- RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
+ RETURN_IF_NOT_OK(map.writeValue(uid, newMatch, BPF_ANY));
}
} else {
return statusFromErrno(ENOENT, StringPrintf("uid: %u does not exist in map", uid));
@@ -526,42 +562,55 @@
return netdutils::status::ok;
}
-Status TrafficController::addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif) {
+Status TrafficController::addRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
+ UidOwnerMatchType match, uint32_t iif) {
// iif should be non-zero if and only if match == MATCH_IIF
if (match == IIF_MATCH && iif == 0) {
return statusFromErrno(EINVAL, "Interface match must have nonzero interface index");
} else if (match != IIF_MATCH && iif != 0) {
return statusFromErrno(EINVAL, "Non-interface match must have zero interface index");
}
- auto oldMatch = mUidOwnerMap.readValue(uid);
+ auto oldMatch = map.readValue(uid);
if (oldMatch.ok()) {
UidOwnerValue newMatch = {
.iif = iif ? iif : oldMatch.value().iif,
.rule = static_cast<uint8_t>(oldMatch.value().rule | match),
};
- RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
+ RETURN_IF_NOT_OK(map.writeValue(uid, newMatch, BPF_ANY));
} else {
UidOwnerValue newMatch = {
.iif = iif,
.rule = static_cast<uint8_t>(match),
};
- RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
+ RETURN_IF_NOT_OK(map.writeValue(uid, newMatch, BPF_ANY));
}
return netdutils::status::ok;
}
-Status TrafficController::updateUidOwnerMap(const std::vector<uint32_t>& appUids,
- UidOwnerMatchType matchType,
+Status TrafficController::updateUidOwnerMap(const std::vector<std::string>& appStrUids,
+ BandwidthController::IptJumpOp jumpHandling,
BandwidthController::IptOp op) {
std::lock_guard guard(mMutex);
- for (uint32_t uid : appUids) {
+ UidOwnerMatchType match = jumpOpToMatch(jumpHandling);
+ if (match == NO_MATCH) {
+ return statusFromErrno(
+ EINVAL, StringPrintf("invalid IptJumpOp: %d, command: %d", jumpHandling, match));
+ }
+ for (const auto& appStrUid : appStrUids) {
+ char* endPtr;
+ long uid = strtol(appStrUid.c_str(), &endPtr, 10);
+ if ((errno == ERANGE && (uid == LONG_MAX || uid == LONG_MIN)) ||
+ (endPtr == appStrUid.c_str()) || (*endPtr != '\0')) {
+ return statusFromErrno(errno, "invalid uid string:" + appStrUid);
+ }
+
if (op == BandwidthController::IptOpDelete) {
- RETURN_IF_NOT_OK(removeRule(uid, matchType));
+ RETURN_IF_NOT_OK(removeRule(mUidOwnerMap, uid, match));
} else if (op == BandwidthController::IptOpInsert) {
- RETURN_IF_NOT_OK(addRule(uid, matchType));
+ RETURN_IF_NOT_OK(addRule(mUidOwnerMap, uid, match));
} else {
// Cannot happen.
- return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, matchType));
+ return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, match));
}
}
return netdutils::status::ok;
@@ -569,6 +618,10 @@
int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
FirewallType type) {
+ if (!mBpfEnabled) {
+ ALOGE("bpf is not set up, should use iptables rule");
+ return -ENOSYS;
+ }
Status res;
switch (chain) {
case DOZABLE:
@@ -580,9 +633,6 @@
case POWERSAVE:
res = updateOwnerMapEntry(POWERSAVE_MATCH, uid, rule, type);
break;
- case RESTRICTED:
- res = updateOwnerMapEntry(RESTRICTED_MATCH, uid, rule, type);
- break;
case NONE:
default:
return -EINVAL;
@@ -610,24 +660,28 @@
RETURN_IF_NOT_OK(mUidOwnerMap.iterate(getUidsToDelete));
for(auto uid : uidsToDelete) {
- RETURN_IF_NOT_OK(removeRule(uid, match));
+ RETURN_IF_NOT_OK(removeRule(mUidOwnerMap, uid, match));
}
for (auto uid : uids) {
- RETURN_IF_NOT_OK(addRule(uid, match));
+ RETURN_IF_NOT_OK(addRule(mUidOwnerMap, uid, match));
}
return netdutils::status::ok;
}
Status TrafficController::addUidInterfaceRules(const int iif,
const std::vector<int32_t>& uidsToAdd) {
+ if (!mBpfEnabled) {
+ ALOGW("UID ingress interface filtering not possible without BPF owner match");
+ return statusFromErrno(EOPNOTSUPP, "eBPF not supported");
+ }
if (!iif) {
return statusFromErrno(EINVAL, "Interface rule must specify interface");
}
std::lock_guard guard(mMutex);
for (auto uid : uidsToAdd) {
- netdutils::Status result = addRule(uid, IIF_MATCH, iif);
+ netdutils::Status result = addRule(mUidOwnerMap, uid, IIF_MATCH, iif);
if (!isOk(result)) {
ALOGW("addRule failed(%d): uid=%d iif=%d", result.code(), uid, iif);
}
@@ -636,10 +690,14 @@
}
Status TrafficController::removeUidInterfaceRules(const std::vector<int32_t>& uidsToDelete) {
+ if (!mBpfEnabled) {
+ ALOGW("UID ingress interface filtering not possible without BPF owner match");
+ return statusFromErrno(EOPNOTSUPP, "eBPF not supported");
+ }
std::lock_guard guard(mMutex);
for (auto uid : uidsToDelete) {
- netdutils::Status result = removeRule(uid, IIF_MATCH);
+ netdutils::Status result = removeRule(mUidOwnerMap, uid, IIF_MATCH);
if (!isOk(result)) {
ALOGW("removeRule failed(%d): uid=%d", result.code(), uid);
}
@@ -647,10 +705,10 @@
return netdutils::status::ok;
}
-int TrafficController::replaceUidOwnerMap(const std::string& name, bool isAllowlist __unused,
+int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist __unused,
const std::vector<int32_t>& uids) {
- // FirewallRule rule = isAllowlist ? ALLOW : DENY;
- // FirewallType type = isAllowlist ? ALLOWLIST : DENYLIST;
+ // FirewallRule rule = isWhitelist ? ALLOW : DENY;
+ // FirewallType type = isWhitelist ? WHITELIST : BLACKLIST;
Status res;
if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
res = replaceRulesInMap(DOZABLE_MATCH, uids);
@@ -658,8 +716,6 @@
res = replaceRulesInMap(STANDBY_MATCH, uids);
} else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
res = replaceRulesInMap(POWERSAVE_MATCH, uids);
- } else if (!name.compare(FirewallController::LOCAL_RESTRICTED)) {
- res = replaceRulesInMap(RESTRICTED_MATCH, uids);
} else {
ALOGE("unknown chain name: %s", name.c_str());
return -EINVAL;
@@ -693,9 +749,6 @@
case POWERSAVE:
match = POWERSAVE_MATCH;
break;
- case RESTRICTED:
- match = RESTRICTED_MATCH;
- break;
default:
return -EINVAL;
}
@@ -708,9 +761,17 @@
return -res.code();
}
+bool TrafficController::getBpfEnabled() {
+ return mBpfEnabled;
+}
+
Status TrafficController::swapActiveStatsMap() {
std::lock_guard guard(mMutex);
+ if (!mBpfEnabled) {
+ return statusFromErrno(EOPNOTSUPP, "This device doesn't have eBPF support");
+ }
+
uint32_t key = CURRENT_STATS_MAP_CONFIGURATION_KEY;
auto oldConfiguration = mConfigurationMap.readValue(key);
if (!oldConfiguration.ok()) {
@@ -753,9 +814,12 @@
// Clean up all permission information for the related uid if all the
// packages related to it are uninstalled.
mPrivilegedUser.erase(uid);
- Status ret = mUidPermissionMap.deleteValue(uid);
- if (!isOk(ret) && ret.code() != ENOENT) {
- ALOGE("Failed to clean up the permission for %u: %s", uid, strerror(ret.code()));
+ if (mBpfEnabled) {
+ Status ret = mUidPermissionMap.deleteValue(uid);
+ if (!isOk(ret) && ret.code() != ENOENT) {
+ ALOGE("Failed to clean up the permission for %u: %s", uid,
+ strerror(ret.code()));
+ }
}
}
return;
@@ -770,6 +834,10 @@
mPrivilegedUser.erase(uid);
}
+ // Skip the bpf map operation if not supported.
+ if (!mBpfEnabled) {
+ continue;
+ }
// The map stores all the permissions that the UID has, except if the only permission
// the UID has is the INTERNET permission, then the UID should not appear in the map.
if (permission != INetd::PERMISSION_INTERNET) {
@@ -825,6 +893,12 @@
dw.println("TrafficController");
ScopedIndent indentPreBpfModule(dw);
+ dw.println("BPF module status: %s", mBpfEnabled ? "enabled" : "disabled");
+ dw.println("BPF support level: %s", BpfLevelToString(getBpfSupportLevel()).c_str());
+
+ if (!mBpfEnabled) {
+ return;
+ }
dw.blankline();
dw.println("mCookieTagMap status: %s",
@@ -854,10 +928,10 @@
getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
dw.println("xt_bpf egress program status: %s",
getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
- dw.println("xt_bpf bandwidth allowlist program status: %s",
- getProgramStatus(XT_BPF_ALLOWLIST_PROG_PATH).c_str());
- dw.println("xt_bpf bandwidth denylist program status: %s",
- getProgramStatus(XT_BPF_DENYLIST_PROG_PATH).c_str());
+ dw.println("xt_bpf bandwidth whitelist program status: %s",
+ getProgramStatus(XT_BPF_WHITELIST_PROG_PATH).c_str());
+ dw.println("xt_bpf bandwidth blacklist program status: %s",
+ getProgramStatus(XT_BPF_BLACKLIST_PROG_PATH).c_str());
if (!verbose) {
return;
diff --git a/server/TrafficController.h b/server/TrafficController.h
index 2e79959..a2539a9 100644
--- a/server/TrafficController.h
+++ b/server/TrafficController.h
@@ -78,6 +78,12 @@
int deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) EXCLUDES(mMutex);
/*
+ * Check if the current device have the bpf traffic stats accounting service
+ * running.
+ */
+ bool getBpfEnabled();
+
+ /*
* Swap the stats map config from current active stats map to the idle one.
*/
netdutils::Status swapActiveStatsMap() EXCLUDES(mMutex);
@@ -91,7 +97,7 @@
int removeUidOwnerRule(const uid_t uid);
- int replaceUidOwnerMap(const std::string& name, bool isAllowlist,
+ int replaceUidOwnerMap(const std::string& name, bool isWhitelist,
const std::vector<int32_t>& uids);
netdutils::Status updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
@@ -106,9 +112,9 @@
EXCLUDES(mMutex);
netdutils::Status removeUidInterfaceRules(const std::vector<int32_t>& uids) EXCLUDES(mMutex);
- netdutils::Status updateUidOwnerMap(const std::vector<uint32_t>& appStrUids,
- UidOwnerMatchType matchType, BandwidthController::IptOp op)
- EXCLUDES(mMutex);
+ netdutils::Status updateUidOwnerMap(const std::vector<std::string>& appStrUids,
+ BandwidthController::IptJumpOp jumpHandling,
+ BandwidthController::IptOp op) EXCLUDES(mMutex);
static const String16 DUMP_KEYWORD;
int toggleUidOwnerMap(ChildChain chain, bool enable) EXCLUDES(mMutex);
@@ -177,7 +183,7 @@
* the map right now:
* - Entry with UID_RULES_CONFIGURATION_KEY:
* Store the configuration for the current uid rules. It indicates the device
- * is in doze/powersave/standby/restricted mode.
+ * is in doze/powersave/standby mode.
* - Entry with CURRENT_STATS_MAP_CONFIGURATION_KEY:
* Stores the current live stats map that kernel program is writing to.
* Userspace can do scraping and cleaning job on the other one depending on the
@@ -197,10 +203,13 @@
std::unique_ptr<NetlinkListenerInterface> mSkDestroyListener;
- netdutils::Status removeRule(uint32_t uid, UidOwnerMatchType match) REQUIRES(mMutex);
+ netdutils::Status removeRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
+ UidOwnerMatchType match) REQUIRES(mMutex);
- netdutils::Status addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif = 0)
- REQUIRES(mMutex);
+ netdutils::Status addRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
+ UidOwnerMatchType match, uint32_t iif = 0) REQUIRES(mMutex);
+
+ bool mBpfEnabled;
// mMutex guards all accesses to mConfigurationMap, mUidOwnerMap, mUidPermissionMap,
// mStatsMapA, mStatsMapB and mPrivilegedUser. It is designed to solve the following
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
index 159fb08..3cde9be 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -16,7 +16,6 @@
* TrafficControllerTest.cpp - unit tests for TrafficController.cpp
*/
-#include <cstdint>
#include <string>
#include <vector>
@@ -75,6 +74,7 @@
void SetUp() {
std::lock_guard guard(mTc.mMutex);
+ SKIP_IF_BPF_NOT_SUPPORTED;
ASSERT_EQ(0, setrlimitForTest());
mFakeCookieTagMap.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(uint64_t), sizeof(UidTagValue),
@@ -165,30 +165,30 @@
void checkUidOwnerRuleForChain(ChildChain chain, UidOwnerMatchType match) {
uint32_t uid = TEST_UID;
- EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, DENYLIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, BLACKLIST));
Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
EXPECT_RESULT_OK(value);
EXPECT_TRUE(value.value().rule & match);
uid = TEST_UID2;
- EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, ALLOWLIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, WHITELIST));
value = mFakeUidOwnerMap.readValue(uid);
EXPECT_RESULT_OK(value);
EXPECT_TRUE(value.value().rule & match);
- EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, ALLOWLIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, WHITELIST));
value = mFakeUidOwnerMap.readValue(uid);
EXPECT_FALSE(value.ok());
EXPECT_EQ(ENOENT, value.error().code());
uid = TEST_UID;
- EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, DENYLIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, BLACKLIST));
value = mFakeUidOwnerMap.readValue(uid);
EXPECT_FALSE(value.ok());
EXPECT_EQ(ENOENT, value.error().code());
uid = TEST_UID3;
- EXPECT_EQ(-ENOENT, mTc.changeUidOwnerRule(chain, uid, ALLOW, DENYLIST));
+ EXPECT_EQ(-ENOENT, mTc.changeUidOwnerRule(chain, uid, ALLOW, BLACKLIST));
value = mFakeUidOwnerMap.readValue(uid);
EXPECT_FALSE(value.ok());
EXPECT_EQ(ENOENT, value.error().code());
@@ -211,18 +211,18 @@
void checkUidMapReplace(const std::string& name, const std::vector<int32_t>& uids,
UidOwnerMatchType match) {
- bool isAllowlist = true;
- EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isAllowlist, uids));
+ bool isWhitelist = true;
+ EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isWhitelist, uids));
checkEachUidValue(uids, match);
- isAllowlist = false;
- EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isAllowlist, uids));
+ isWhitelist = false;
+ EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isWhitelist, uids));
checkEachUidValue(uids, match);
}
-
- void expectUidOwnerMapValues(const std::vector<uint32_t>& appUids, uint8_t expectedRule,
+ void expectUidOwnerMapValues(const std::vector<std::string>& appStrUids, uint8_t expectedRule,
uint32_t expectedIif) {
- for (uint32_t uid : appUids) {
+ for (const std::string& strUid : appStrUids) {
+ uint32_t uid = stoi(strUid);
Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
EXPECT_RESULT_OK(value);
EXPECT_EQ(expectedRule, value.value().rule)
@@ -315,6 +315,8 @@
};
TEST_F(TrafficControllerTest, TestTagSocketV4) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uint64_t sockCookie;
int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie, TEST_UID, TEST_TAG);
@@ -324,6 +326,8 @@
}
TEST_F(TrafficControllerTest, TestReTagSocket) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uint64_t sockCookie;
int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie, TEST_UID, TEST_TAG);
@@ -332,6 +336,8 @@
}
TEST_F(TrafficControllerTest, TestTagTwoSockets) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uint64_t sockCookie1;
uint64_t sockCookie2;
int v4socket1 = setUpSocketAndTag(AF_INET, &sockCookie1, TEST_TAG, TEST_UID, TEST_UID);
@@ -345,6 +351,8 @@
}
TEST_F(TrafficControllerTest, TestTagSocketV6) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uint64_t sockCookie;
int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie, TEST_UID, TEST_TAG);
@@ -354,12 +362,16 @@
}
TEST_F(TrafficControllerTest, TestTagInvalidSocket) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
int invalidSocket = -1;
ASSERT_GT(0, mTc.tagSocket(invalidSocket, TEST_TAG, TEST_UID, TEST_UID));
expectMapEmpty(mFakeCookieTagMap);
}
TEST_F(TrafficControllerTest, TestTagSocketWithoutPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
ASSERT_NE(-1, sock);
ASSERT_EQ(-EPERM, mTc.tagSocket(sock, TEST_TAG, TEST_UID, TEST_UID2));
@@ -367,6 +379,8 @@
}
TEST_F(TrafficControllerTest, TestTagSocketWithPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
// Grant permission to calling uid.
std::vector<uid_t> callingUid = {TEST_UID2};
mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, callingUid);
@@ -385,6 +399,8 @@
}
TEST_F(TrafficControllerTest, TestUntagInvalidSocket) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
int invalidSocket = -1;
ASSERT_GT(0, mTc.untagSocket(invalidSocket));
int v4socket = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
@@ -393,6 +409,8 @@
}
TEST_F(TrafficControllerTest, TestTagSocketReachLimitFail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t uid = TEST_UID;
StatsKey tagStatsMapKey[4];
for (int i = 0; i < 3; i++) {
@@ -404,6 +422,8 @@
}
TEST_F(TrafficControllerTest, TestTagSocketReachTotalLimitFail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
StatsKey tagStatsMapKey[4];
for (int i = 0; i < 4; i++) {
uint64_t cookie = TEST_COOKIE + i;
@@ -415,6 +435,8 @@
}
TEST_F(TrafficControllerTest, TestSetCounterSet) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
ASSERT_EQ(0, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, callingUid));
@@ -428,6 +450,8 @@
}
TEST_F(TrafficControllerTest, TestSetCounterSetWithoutPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
ASSERT_EQ(-EPERM, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, TEST_UID2));
uid_t uid = TEST_UID;
ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
@@ -435,6 +459,8 @@
}
TEST_F(TrafficControllerTest, TestSetInvalidCounterSet) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
ASSERT_GT(0, mTc.setCounterSet(OVERFLOW_COUNTERSET, TEST_UID, callingUid));
@@ -444,6 +470,8 @@
}
TEST_F(TrafficControllerTest, TestDeleteTagDataWithoutPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uint64_t cookie = 1;
uid_t uid = TEST_UID;
uint32_t tag = TEST_TAG;
@@ -455,6 +483,8 @@
}
TEST_F(TrafficControllerTest, TestDeleteTagData) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie = 1;
@@ -480,6 +510,8 @@
}
TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie = 1;
@@ -497,6 +529,8 @@
}
TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie1 = 1;
@@ -525,6 +559,8 @@
}
TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie1 = 1;
@@ -566,156 +602,174 @@
}
TEST_F(TrafficControllerTest, TestUpdateOwnerMapEntry) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
uint32_t uid = TEST_UID;
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, DENYLIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, BLACKLIST)));
Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
ASSERT_RESULT_OK(value);
ASSERT_TRUE(value.value().rule & STANDBY_MATCH);
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, ALLOW, ALLOWLIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, ALLOW, WHITELIST)));
value = mFakeUidOwnerMap.readValue(uid);
ASSERT_RESULT_OK(value);
ASSERT_TRUE(value.value().rule & DOZABLE_MATCH);
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, DENY, ALLOWLIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, DENY, WHITELIST)));
value = mFakeUidOwnerMap.readValue(uid);
ASSERT_RESULT_OK(value);
ASSERT_FALSE(value.value().rule & DOZABLE_MATCH);
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, DENYLIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, BLACKLIST)));
ASSERT_FALSE(mFakeUidOwnerMap.readValue(uid).ok());
uid = TEST_UID2;
- ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, DENYLIST)));
+ ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, BLACKLIST)));
ASSERT_FALSE(mFakeUidOwnerMap.readValue(uid).ok());
}
TEST_F(TrafficControllerTest, TestChangeUidOwnerRule) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
checkUidOwnerRuleForChain(DOZABLE, DOZABLE_MATCH);
checkUidOwnerRuleForChain(STANDBY, STANDBY_MATCH);
checkUidOwnerRuleForChain(POWERSAVE, POWERSAVE_MATCH);
- checkUidOwnerRuleForChain(RESTRICTED, RESTRICTED_MATCH);
- ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(NONE, TEST_UID, ALLOW, ALLOWLIST));
- ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(INVALID_CHAIN, TEST_UID, ALLOW, ALLOWLIST));
+ ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(NONE, TEST_UID, ALLOW, WHITELIST));
+ ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(INVALID_CHAIN, TEST_UID, ALLOW, WHITELIST));
}
TEST_F(TrafficControllerTest, TestReplaceUidOwnerMap) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<int32_t> uids = {TEST_UID, TEST_UID2, TEST_UID3};
checkUidMapReplace("fw_dozable", uids, DOZABLE_MATCH);
checkUidMapReplace("fw_standby", uids, STANDBY_MATCH);
checkUidMapReplace("fw_powersave", uids, POWERSAVE_MATCH);
- checkUidMapReplace("fw_restricted", uids, RESTRICTED_MATCH);
ASSERT_EQ(-EINVAL, mTc.replaceUidOwnerMap("unknow", true, uids));
}
TEST_F(TrafficControllerTest, TestReplaceSameChain) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<int32_t> uids = {TEST_UID, TEST_UID2, TEST_UID3};
checkUidMapReplace("fw_dozable", uids, DOZABLE_MATCH);
std::vector<int32_t> newUids = {TEST_UID2, TEST_UID3};
checkUidMapReplace("fw_dozable", newUids, DOZABLE_MATCH);
}
-TEST_F(TrafficControllerTest, TestDenylistUidMatch) {
- std::vector<uint32_t> appUids = {1000, 1001, 10012};
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues(appUids, PENALTY_BOX_MATCH, 0);
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
+TEST_F(TrafficControllerTest, TestBlacklistUidMatch) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+ BandwidthController::IptOpInsert)));
+ expectUidOwnerMapValues(appStrUids, PENALTY_BOX_MATCH, 0);
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+ BandwidthController::IptOpDelete)));
expectMapEmpty(mFakeUidOwnerMap);
}
-TEST_F(TrafficControllerTest, TestAllowlistUidMatch) {
- std::vector<uint32_t> appUids = {1000, 1001, 10012};
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH, 0);
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
+TEST_F(TrafficControllerTest, TestWhitelistUidMatch) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+ BandwidthController::IptOpInsert)));
+ expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH, 0);
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+ BandwidthController::IptOpDelete)));
expectMapEmpty(mFakeUidOwnerMap);
}
TEST_F(TrafficControllerTest, TestReplaceMatchUid) {
- std::vector<uint32_t> appUids = {1000, 1001, 10012};
- // Add appUids to the denylist and expect that their values are all PENALTY_BOX_MATCH.
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues(appUids, PENALTY_BOX_MATCH, 0);
+ SKIP_IF_BPF_NOT_SUPPORTED;
- // Add the same UIDs to the allowlist and expect that we get PENALTY_BOX_MATCH |
+ std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
+ // Add appStrUids to the blacklist and expect that their values are all PENALTY_BOX_MATCH.
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+ BandwidthController::IptOpInsert)));
+ expectUidOwnerMapValues(appStrUids, PENALTY_BOX_MATCH, 0);
+
+ // Add the same UIDs to the whitelist and expect that we get PENALTY_BOX_MATCH |
// HAPPY_BOX_MATCH.
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH | PENALTY_BOX_MATCH, 0);
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+ BandwidthController::IptOpInsert)));
+ expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH | PENALTY_BOX_MATCH, 0);
- // Remove the same UIDs from the allowlist and check the PENALTY_BOX_MATCH is still there.
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
- expectUidOwnerMapValues(appUids, PENALTY_BOX_MATCH, 0);
+ // Remove the same UIDs from the whitelist and check the PENALTY_BOX_MATCH is still there.
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+ BandwidthController::IptOpDelete)));
+ expectUidOwnerMapValues(appStrUids, PENALTY_BOX_MATCH, 0);
- // Remove the same UIDs from the denylist and check the map is empty.
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
+ // Remove the same UIDs from the blacklist and check the map is empty.
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+ BandwidthController::IptOpDelete)));
ASSERT_FALSE(mFakeUidOwnerMap.getFirstKey().ok());
}
TEST_F(TrafficControllerTest, TestDeleteWrongMatchSilentlyFails) {
- std::vector<uint32_t> appUids = {1000, 1001, 10012};
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
// If the uid does not exist in the map, trying to delete a rule about it will fail.
- ASSERT_FALSE(isOk(
- mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
+ ASSERT_FALSE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+ BandwidthController::IptOpDelete)));
expectMapEmpty(mFakeUidOwnerMap);
- // Add denylist rules for appUids.
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH, 0);
+ // Add blacklist rules for appStrUids.
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
+ BandwidthController::IptOpInsert)));
+ expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH, 0);
- // Delete (non-existent) denylist rules for appUids, and check that this silently does
- // nothing if the uid is in the map but does not have denylist match. This is required because
- // NetworkManagementService will try to remove a uid from denylist after adding it to the
- // allowlist and if the remove fails it will not update the uid status.
- ASSERT_TRUE(isOk(
- mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
- expectUidOwnerMapValues(appUids, HAPPY_BOX_MATCH, 0);
+ // Delete (non-existent) blacklist rules for appStrUids, and check that this silently does
+ // nothing if the uid is in the map but does not have blacklist match. This is required because
+ // NetworkManagementService will try to remove a uid from blacklist after adding it to the
+ // whitelist and if the remove fails it will not update the uid status.
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
+ BandwidthController::IptOpDelete)));
+ expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH, 0);
}
TEST_F(TrafficControllerTest, TestAddUidInterfaceFilteringRules) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
int iif0 = 15;
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif0, {1000, 1001})));
- expectUidOwnerMapValues({1000, 1001}, IIF_MATCH, iif0);
+ expectUidOwnerMapValues({"1000", "1001"}, IIF_MATCH, iif0);
// Add some non-overlapping new uids. They should coexist with existing rules
int iif1 = 16;
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {2000, 2001})));
- expectUidOwnerMapValues({1000, 1001}, IIF_MATCH, iif0);
- expectUidOwnerMapValues({2000, 2001}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"1000", "1001"}, IIF_MATCH, iif0);
+ expectUidOwnerMapValues({"2000", "2001"}, IIF_MATCH, iif1);
// Overwrite some existing uids
int iif2 = 17;
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif2, {1000, 2000})));
- expectUidOwnerMapValues({1001}, IIF_MATCH, iif0);
- expectUidOwnerMapValues({2001}, IIF_MATCH, iif1);
- expectUidOwnerMapValues({1000, 2000}, IIF_MATCH, iif2);
+ expectUidOwnerMapValues({"1001"}, IIF_MATCH, iif0);
+ expectUidOwnerMapValues({"2001"}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"1000", "2000"}, IIF_MATCH, iif2);
}
TEST_F(TrafficControllerTest, TestRemoveUidInterfaceFilteringRules) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
int iif0 = 15;
int iif1 = 16;
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif0, {1000, 1001})));
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {2000, 2001})));
- expectUidOwnerMapValues({1000, 1001}, IIF_MATCH, iif0);
- expectUidOwnerMapValues({2000, 2001}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"1000", "1001"}, IIF_MATCH, iif0);
+ expectUidOwnerMapValues({"2000", "2001"}, IIF_MATCH, iif1);
// Rmove some uids
ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({1001, 2001})));
- expectUidOwnerMapValues({1000}, IIF_MATCH, iif0);
- expectUidOwnerMapValues({2000}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"1000"}, IIF_MATCH, iif0);
+ expectUidOwnerMapValues({"2000"}, IIF_MATCH, iif1);
checkEachUidValue({1000, 2000}, IIF_MATCH); // Make sure there are only two uids remaining
// Remove non-existent uids shouldn't fail
ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({2000, 3000})));
- expectUidOwnerMapValues({1000}, IIF_MATCH, iif0);
+ expectUidOwnerMapValues({"1000"}, IIF_MATCH, iif0);
checkEachUidValue({1000}, IIF_MATCH); // Make sure there are only one uid remaining
// Remove everything
@@ -724,65 +778,72 @@
}
TEST_F(TrafficControllerTest, TestUidInterfaceFilteringRulesCoexistWithExistingMatches) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
// Set up existing PENALTY_BOX_MATCH rules
- ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({1000, 1001, 10012}, PENALTY_BOX_MATCH,
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({"1000", "1001", "10012"},
+ BandwidthController::IptJumpReject,
BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues({1000, 1001, 10012}, PENALTY_BOX_MATCH, 0);
+ expectUidOwnerMapValues({"1000", "1001", "10012"}, PENALTY_BOX_MATCH, 0);
// Add some partially-overlapping uid owner rules and check result
int iif1 = 32;
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {10012, 10013, 10014})));
- expectUidOwnerMapValues({1000, 1001}, PENALTY_BOX_MATCH, 0);
- expectUidOwnerMapValues({10012}, PENALTY_BOX_MATCH | IIF_MATCH, iif1);
- expectUidOwnerMapValues({10013, 10014}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"1000", "1001"}, PENALTY_BOX_MATCH, 0);
+ expectUidOwnerMapValues({"10012"}, PENALTY_BOX_MATCH | IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10013", "10014"}, IIF_MATCH, iif1);
// Removing some PENALTY_BOX_MATCH rules should not change uid interface rule
- ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({1001, 10012}, PENALTY_BOX_MATCH,
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({"1001", "10012"}, BandwidthController::IptJumpReject,
BandwidthController::IptOpDelete)));
- expectUidOwnerMapValues({1000}, PENALTY_BOX_MATCH, 0);
- expectUidOwnerMapValues({10012, 10013, 10014}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"1000"}, PENALTY_BOX_MATCH, 0);
+ expectUidOwnerMapValues({"10012", "10013", "10014"}, IIF_MATCH, iif1);
// Remove all uid interface rules
ASSERT_TRUE(isOk(mTc.removeUidInterfaceRules({10012, 10013, 10014})));
- expectUidOwnerMapValues({1000}, PENALTY_BOX_MATCH, 0);
+ expectUidOwnerMapValues({"1000"}, PENALTY_BOX_MATCH, 0);
// Make sure these are the only uids left
checkEachUidValue({1000}, PENALTY_BOX_MATCH);
}
TEST_F(TrafficControllerTest, TestUidInterfaceFilteringRulesCoexistWithNewMatches) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
int iif1 = 56;
// Set up existing uid interface rules
ASSERT_TRUE(isOk(mTc.addUidInterfaceRules(iif1, {10001, 10002})));
- expectUidOwnerMapValues({10001, 10002}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10001", "10002"}, IIF_MATCH, iif1);
// Add some partially-overlapping doze rules
EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_dozable", true, {10002, 10003}));
- expectUidOwnerMapValues({10001}, IIF_MATCH, iif1);
- expectUidOwnerMapValues({10002}, DOZABLE_MATCH | IIF_MATCH, iif1);
- expectUidOwnerMapValues({10003}, DOZABLE_MATCH, 0);
+ expectUidOwnerMapValues({"10001"}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10002"}, DOZABLE_MATCH | IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10003"}, DOZABLE_MATCH, 0);
// Introduce a third rule type (powersave) on various existing UIDs
EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_powersave", true, {10000, 10001, 10002, 10003}));
- expectUidOwnerMapValues({10000}, POWERSAVE_MATCH, 0);
- expectUidOwnerMapValues({10001}, POWERSAVE_MATCH | IIF_MATCH, iif1);
- expectUidOwnerMapValues({10002}, POWERSAVE_MATCH | DOZABLE_MATCH | IIF_MATCH, iif1);
- expectUidOwnerMapValues({10003}, POWERSAVE_MATCH | DOZABLE_MATCH, 0);
+ expectUidOwnerMapValues({"10000"}, POWERSAVE_MATCH, 0);
+ expectUidOwnerMapValues({"10001"}, POWERSAVE_MATCH | IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10002"}, POWERSAVE_MATCH | DOZABLE_MATCH | IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10003"}, POWERSAVE_MATCH | DOZABLE_MATCH, 0);
// Remove all doze rules
EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_dozable", true, {}));
- expectUidOwnerMapValues({10000}, POWERSAVE_MATCH, 0);
- expectUidOwnerMapValues({10001}, POWERSAVE_MATCH | IIF_MATCH, iif1);
- expectUidOwnerMapValues({10002}, POWERSAVE_MATCH | IIF_MATCH, iif1);
- expectUidOwnerMapValues({10003}, POWERSAVE_MATCH, 0);
+ expectUidOwnerMapValues({"10000"}, POWERSAVE_MATCH, 0);
+ expectUidOwnerMapValues({"10001"}, POWERSAVE_MATCH | IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10002"}, POWERSAVE_MATCH | IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10003"}, POWERSAVE_MATCH, 0);
// Remove all powersave rules, expect ownerMap to only have uid interface rules left
EXPECT_EQ(0, mTc.replaceUidOwnerMap("fw_powersave", true, {}));
- expectUidOwnerMapValues({10001, 10002}, IIF_MATCH, iif1);
+ expectUidOwnerMapValues({"10001", "10002"}, IIF_MATCH, iif1);
// Make sure these are the only uids left
checkEachUidValue({10001, 10002}, IIF_MATCH);
}
TEST_F(TrafficControllerTest, TestGrantInternetPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_INTERNET, appUids);
@@ -791,6 +852,8 @@
}
TEST_F(TrafficControllerTest, TestRevokeInternetPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
@@ -798,6 +861,8 @@
}
TEST_F(TrafficControllerTest, TestPermissionUninstalled) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
@@ -817,6 +882,8 @@
}
TEST_F(TrafficControllerTest, TestGrantUpdateStatsPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
@@ -829,6 +896,8 @@
}
TEST_F(TrafficControllerTest, TestRevokeUpdateStatsPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, appUids);
@@ -845,6 +914,8 @@
}
TEST_F(TrafficControllerTest, TestGrantWrongPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_NONE, appUids);
@@ -853,6 +924,8 @@
}
TEST_F(TrafficControllerTest, TestGrantDuplicatePermissionSlientlyFail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<uid_t> appUids = {TEST_UID, TEST_UID2, TEST_UID3};
mTc.setPermissionForUids(INetd::PERMISSION_INTERNET, appUids);
diff --git a/server/UidRanges.cpp b/server/UidRanges.cpp
index 093a1e2..883a13f 100644
--- a/server/UidRanges.cpp
+++ b/server/UidRanges.cpp
@@ -127,35 +127,8 @@
mRanges.erase(end, mRanges.end());
}
-bool UidRanges::isOverlapped(const UidRangeParcel& r1, const UidRangeParcel& r2) const {
- return (r1.stop >= r2.start) && (r1.start <= r2.stop);
-}
-
-bool UidRanges::overlapsSelf() const {
- // Compare each element one by one
- for (size_t i = 0; i < mRanges.size(); i++) {
- for (size_t j = i + 1; j < mRanges.size(); j++) {
- if (isOverlapped(mRanges[i], mRanges[j])) {
- return true;
- }
- }
- }
- return false;
-}
-
-bool UidRanges::overlaps(const UidRanges& other) const {
- for (const auto& thisRange : mRanges) {
- for (const auto& inputRange : other.getRanges()) {
- if (isOverlapped(thisRange, inputRange)) {
- return true;
- }
- }
- }
- return false;
-}
-
std::string UidRanges::toString() const {
- std::string s("uids{ ");
+ std::string s("UidRanges{ ");
for (const auto &range : mRanges) {
if (length(range) == 0) {
StringAppendF(&s, "<BAD: %u-%u> ", range.start, range.stop);
diff --git a/server/UidRanges.h b/server/UidRanges.h
index 99e7a99..28d3c6b 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -28,9 +28,6 @@
class UidRanges {
public:
- static constexpr int DEFAULT_SUB_PRIORITY = 0;
- static constexpr int LOWEST_SUB_PRIORITY = 999;
-
UidRanges() {}
UidRanges(const std::vector<android::net::UidRangeParcel>& ranges);
@@ -43,16 +40,7 @@
void add(const UidRanges& other);
void remove(const UidRanges& other);
- // check if 'mRanges' has uid overlap between elements.
- bool overlapsSelf() const;
- // check if this object has uid overlap with the input object.
- bool overlaps(const UidRanges& other) const;
- bool empty() const { return mRanges.empty(); }
-
private:
- // a utility to check if two UidRangeParcels have uid overlap.
- bool isOverlapped(const UidRangeParcel& r1, const UidRangeParcel& r2) const;
-
std::vector<UidRangeParcel> mRanges;
};
diff --git a/server/UnreachableNetwork.cpp b/server/UnreachableNetwork.cpp
deleted file mode 100644
index 2f801f0..0000000
--- a/server/UnreachableNetwork.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-#define LOG_TAG "Netd"
-
-#include "UnreachableNetwork.h"
-
-#include "RouteController.h"
-
-namespace android {
-namespace net {
-
-// The unreachable network is used to reject traffic. It is used for system purposes only.
-UnreachableNetwork::UnreachableNetwork(unsigned netId) : Network(netId) {}
-
-int UnreachableNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
- if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
- return -EINVAL;
- }
-
- int ret = RouteController::addUsersToUnreachableNetwork(mNetId, {{subPriority, uidRanges}});
- if (ret) {
- ALOGE("failed to add users to unreachable network");
- return ret;
- }
- addToUidRangeMap(uidRanges, subPriority);
- return 0;
-}
-
-int UnreachableNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
- if (!isValidSubPriority(subPriority)) return -EINVAL;
-
- int ret =
- RouteController::removeUsersFromUnreachableNetwork(mNetId, {{subPriority, uidRanges}});
- if (ret) {
- ALOGE("failed to remove users from unreachable network");
- return ret;
- }
- removeFromUidRangeMap(uidRanges, subPriority);
- return 0;
-}
-
-bool UnreachableNetwork::isValidSubPriority(uint32_t priority) {
- return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
- priority <= UidRanges::LOWEST_SUB_PRIORITY;
-}
-
-} // namespace net
-} // namespace android
diff --git a/server/UnreachableNetwork.h b/server/UnreachableNetwork.h
deleted file mode 100644
index f1547d6..0000000
--- a/server/UnreachableNetwork.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-#pragma once
-
-#include "Network.h"
-
-namespace android::net {
-
-class UnreachableNetwork : public Network {
- public:
- explicit UnreachableNetwork(unsigned netId);
- [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
- [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
- bool isUnreachable() override { return true; }
- bool canAddUsers() override { return true; }
-
- private:
- std::string getTypeString() const override { return "UNREACHABLE"; };
- bool isValidSubPriority(uint32_t priority) override;
-};
-
-} // namespace android::net
\ No newline at end of file
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 1906e20..33791c6 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -20,6 +20,7 @@
#include "VirtualNetwork.h"
+#include "SockDiag.h"
#include "RouteController.h"
#include "log/log.h"
@@ -27,48 +28,78 @@
namespace android {
namespace net {
-VirtualNetwork::VirtualNetwork(unsigned netId, bool secure) : Network(netId, secure) {}
+VirtualNetwork::VirtualNetwork(unsigned netId, bool secure) : Network(netId), mSecure(secure) {}
VirtualNetwork::~VirtualNetwork() {}
-int VirtualNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
- if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
- return -EINVAL;
+bool VirtualNetwork::isSecure() const {
+ return mSecure;
+}
+
+bool VirtualNetwork::appliesToUser(uid_t uid) const {
+ return mUidRanges.hasUid(uid);
+}
+
+
+int VirtualNetwork::maybeCloseSockets(bool add, const UidRanges& uidRanges,
+ const std::set<uid_t>& protectableUsers) {
+ if (!mSecure) {
+ return 0;
}
+ SockDiag sd;
+ if (!sd.open()) {
+ return -EBADFD;
+ }
+
+ if (int ret = sd.destroySockets(uidRanges, protectableUsers, true /* excludeLoopback */)) {
+ ALOGE("Failed to close sockets while %s %s to network %d: %s",
+ add ? "adding" : "removing", uidRanges.toString().c_str(), mNetId, strerror(-ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+int VirtualNetwork::addUsers(const UidRanges& uidRanges, const std::set<uid_t>& protectableUsers) {
+ maybeCloseSockets(true, uidRanges, protectableUsers);
+
for (const std::string& interface : mInterfaces) {
- int ret = RouteController::addUsersToVirtualNetwork(mNetId, interface.c_str(), mSecure,
- {{subPriority, uidRanges}});
- if (ret) {
+ if (int ret = RouteController::addUsersToVirtualNetwork(mNetId, interface.c_str(), mSecure,
+ uidRanges)) {
ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- addToUidRangeMap(uidRanges, subPriority);
+ mUidRanges.add(uidRanges);
return 0;
}
-int VirtualNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
- if (!isValidSubPriority(subPriority)) return -EINVAL;
+int VirtualNetwork::removeUsers(const UidRanges& uidRanges,
+ const std::set<uid_t>& protectableUsers) {
+ maybeCloseSockets(false, uidRanges, protectableUsers);
for (const std::string& interface : mInterfaces) {
- int ret = RouteController::removeUsersFromVirtualNetwork(mNetId, interface.c_str(), mSecure,
- {{subPriority, uidRanges}});
- if (ret) {
+ if (int ret = RouteController::removeUsersFromVirtualNetwork(mNetId, interface.c_str(),
+ mSecure, uidRanges)) {
ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- removeFromUidRangeMap(uidRanges, subPriority);
+ mUidRanges.remove(uidRanges);
return 0;
}
+Network::Type VirtualNetwork::getType() const {
+ return VIRTUAL;
+}
+
int VirtualNetwork::addInterface(const std::string& interface) {
if (hasInterface(interface)) {
return 0;
}
if (int ret = RouteController::addInterfaceToVirtualNetwork(mNetId, interface.c_str(), mSecure,
- mUidRangeMap)) {
+ mUidRanges)) {
ALOGE("failed to add interface %s to VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -81,7 +112,7 @@
return 0;
}
if (int ret = RouteController::removeInterfaceFromVirtualNetwork(mNetId, interface.c_str(),
- mSecure, mUidRangeMap)) {
+ mSecure, mUidRanges)) {
ALOGE("failed to remove interface %s from VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -89,10 +120,5 @@
return 0;
}
-bool VirtualNetwork::isValidSubPriority(uint32_t priority) {
- // Only supports default subsidiary permissions.
- return priority == UidRanges::DEFAULT_SUB_PRIORITY;
-}
-
} // namespace net
} // namespace android
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index 20c9e2c..20c8dee 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -19,6 +19,7 @@
#include <set>
#include "Network.h"
+#include "UidRanges.h"
namespace android::net {
@@ -33,16 +34,23 @@
public:
VirtualNetwork(unsigned netId, bool secure);
virtual ~VirtualNetwork();
- [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
- [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
- bool isVirtual() override { return true; }
- bool canAddUsers() override { return true; }
+
+ bool isSecure() const;
+ bool appliesToUser(uid_t uid) const;
+
+ [[nodiscard]] int addUsers(const UidRanges& uidRanges, const std::set<uid_t>& protectableUsers);
+ [[nodiscard]] int removeUsers(const UidRanges& uidRanges,
+ const std::set<uid_t>& protectableUsers);
private:
- std::string getTypeString() const override { return "VIRTUAL"; };
+ Type getType() const override;
[[nodiscard]] int addInterface(const std::string& interface) override;
[[nodiscard]] int removeInterface(const std::string& interface) override;
- bool isValidSubPriority(uint32_t priority) override;
+ int maybeCloseSockets(bool add, const UidRanges& uidRanges,
+ const std::set<uid_t>& protectableUsers);
+
+ const bool mSecure;
+ UidRanges mUidRanges;
};
} // namespace android::net
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 24168a2..33a2aa2 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -646,69 +646,20 @@
return ret;
}
-netdutils::Status XfrmController::ipSecMigrate(int32_t transformId, int32_t selAddrFamily,
- int32_t direction,
- const std::string& oldSourceAddress,
- const std::string& oldDestinationAddress,
- const std::string& newSourceAddress,
- const std::string& newDestinationAddress,
- int32_t xfrmInterfaceId) {
- ALOGD("XfrmController:%s, line=%d", __FUNCTION__, __LINE__);
- ALOGD("transformId=%d", transformId);
- ALOGD("selAddrFamily=%d", selAddrFamily);
- ALOGD("direction=%d", direction);
- ALOGD("oldSourceAddress=%s", oldSourceAddress.c_str());
- ALOGD("oldDestinationAddress=%s", oldDestinationAddress.c_str());
- ALOGD("newSourceAddress=%s", newSourceAddress.c_str());
- ALOGD("newDestinationAddress=%s", newDestinationAddress.c_str());
- ALOGD("xfrmInterfaceId=%d", xfrmInterfaceId);
-
- XfrmSocketImpl sock;
- Status socketStatus = sock.open();
- if (!socketStatus.ok()) {
- ALOGD("Sock open failed for XFRM, line=%d", __LINE__);
- return socketStatus;
- }
-
- XfrmMigrateInfo migrateInfo{};
- Status ret =
- fillXfrmCommonInfo(oldSourceAddress, oldDestinationAddress, 0 /* spi */, 0 /* mark */,
- 0 /* markMask */, transformId, xfrmInterfaceId, &migrateInfo);
-
- if (!ret.ok()) {
- ALOGD("Failed to fill in XfrmCommonInfo, line=%d", __LINE__);
- return ret;
- }
-
- migrateInfo.selAddrFamily = selAddrFamily;
- migrateInfo.direction = static_cast<XfrmDirection>(direction);
-
- ret = fillXfrmEndpointPair(newSourceAddress, newDestinationAddress,
- &migrateInfo.newEndpointInfo);
- if (!ret.ok()) {
- ALOGD("Failed to fill in XfrmEndpointPair, line=%d", __LINE__);
- return ret;
- }
-
- ret = migrate(migrateInfo, sock);
-
- if (!ret.ok()) {
- ALOGD("Failed to migrate Security Association, line=%d", __LINE__);
- }
- return ret;
-}
-
-netdutils::Status XfrmController::fillXfrmEndpointPair(const std::string& sourceAddress,
- const std::string& destinationAddress,
- XfrmEndpointPair* endpointPair) {
+netdutils::Status XfrmController::fillXfrmCommonInfo(const std::string& sourceAddress,
+ const std::string& destinationAddress,
+ int32_t spi, int32_t markValue,
+ int32_t markMask, int32_t transformId,
+ int32_t xfrmInterfaceId,
+ XfrmCommonInfo* info) {
// Use the addresses to determine the address family and do validation
xfrm_address_t sourceXfrmAddr{}, destXfrmAddr{};
StatusOr<int> sourceFamily, destFamily;
sourceFamily = convertToXfrmAddr(sourceAddress, &sourceXfrmAddr);
destFamily = convertToXfrmAddr(destinationAddress, &destXfrmAddr);
if (!isOk(sourceFamily) || !isOk(destFamily)) {
- return netdutils::statusFromErrno(
- EINVAL, "Invalid address " + sourceAddress + "/" + destinationAddress);
+ return netdutils::statusFromErrno(EINVAL, "Invalid address " + sourceAddress + "/" +
+ destinationAddress);
}
if (destFamily.value() == AF_UNSPEC ||
@@ -718,24 +669,10 @@
return netdutils::statusFromErrno(EINVAL, "Invalid or mismatched address families");
}
- endpointPair->addrFamily = destFamily.value();
+ info->addrFamily = destFamily.value();
- endpointPair->dstAddr = destXfrmAddr;
- endpointPair->srcAddr = sourceXfrmAddr;
-
- return netdutils::status::ok;
-}
-
-netdutils::Status XfrmController::fillXfrmCommonInfo(const std::string& sourceAddress,
- const std::string& destinationAddress,
- int32_t spi, int32_t markValue,
- int32_t markMask, int32_t transformId,
- int32_t xfrmInterfaceId,
- XfrmCommonInfo* info) {
- Status ret = fillXfrmEndpointPair(sourceAddress, destinationAddress, info);
- if (!isOk(ret)) {
- return ret;
- }
+ info->dstAddr = destXfrmAddr;
+ info->srcAddr = sourceXfrmAddr;
return fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId, info);
}
@@ -784,7 +721,6 @@
}
spInfo.selAddrFamily = spInfo.addrFamily;
- spInfo.direction = static_cast<XfrmDirection>(direction);
// Allow dual stack sockets. Dual stack sockets are guaranteed to never have an AF_INET source
// address; the source address would instead be an IPv4-mapped address. Thus, disallow AF_INET
@@ -801,7 +737,7 @@
xfrm_user_tmpl tmpl;
} policy{};
- fillUserSpInfo(spInfo, &policy.info);
+ fillUserSpInfo(spInfo, static_cast<XfrmDirection>(direction), &policy.info);
fillUserTemplate(spInfo, &policy.tmpl);
LOG_HEX("XfrmUserPolicy", reinterpret_cast<char*>(&policy), sizeof(policy));
@@ -917,18 +853,18 @@
// separately for IPv4 and IPv6 policies, and thus only need to map a single inner address
// family to the outer address families.
spInfo.selAddrFamily = selAddrFamily;
- spInfo.direction = static_cast<XfrmDirection>(direction);
if (msgType == XFRM_MSG_DELPOLICY) {
RETURN_IF_NOT_OK(fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId,
&spInfo));
- return deleteTunnelModeSecurityPolicy(spInfo, sock);
+ return deleteTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction));
} else {
RETURN_IF_NOT_OK(fillXfrmCommonInfo(tmplSrcAddress, tmplDstAddress, spi, markValue,
markMask, transformId, xfrmInterfaceId, &spInfo));
- return updateTunnelModeSecurityPolicy(spInfo, sock, msgType);
+ return updateTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction),
+ msgType);
}
}
@@ -1025,7 +961,7 @@
len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
iov[MARK_PAD].iov_len = NLA_ALIGN(len) - len;
- len = iov[OUTPUT_MARK].iov_len = fillNlAttrXfrmOutputMark(record, &xfrmoutputmark);
+ len = iov[OUTPUT_MARK].iov_len = fillNlAttrXfrmOutputMark(record.netId, &xfrmoutputmark);
iov[OUTPUT_MARK_PAD].iov_len = NLA_ALIGN(len) - len;
len = iov[ENCAP].iov_len = fillNlAttrXfrmEncapTmpl(record, &encap);
@@ -1174,24 +1110,6 @@
return sock.sendMessage(XFRM_MSG_DELSA, NETLINK_REQUEST_FLAGS, 0, &iov);
}
-netdutils::Status XfrmController::migrate(const XfrmMigrateInfo& record, const XfrmSocket& sock) {
- xfrm_userpolicy_id xfrm_policyid{};
- nlattr_xfrm_user_migrate xfrm_migrate{};
-
- __kernel_size_t lenPolicyId = fillUserPolicyId(record, &xfrm_policyid);
- __kernel_size_t lenXfrmMigrate = fillNlAttrXfrmMigrate(record, &xfrm_migrate);
-
- std::vector<iovec> iov = {
- {nullptr, 0}, // reserved for the eventual addition of a NLMSG_HDR
- {&xfrm_policyid, lenPolicyId},
- {kPadBytes, NLMSG_ALIGN(lenPolicyId) - lenPolicyId},
- {&xfrm_migrate, lenXfrmMigrate},
- {kPadBytes, NLMSG_ALIGN(lenXfrmMigrate) - lenXfrmMigrate},
- };
-
- return sock.sendMessage(XFRM_MSG_MIGRATE, NETLINK_REQUEST_FLAGS, 0, &iov);
-}
-
netdutils::Status XfrmController::allocateSpi(const XfrmSaInfo& record, uint32_t minSpi,
uint32_t maxSpi, uint32_t* outSpi,
const XfrmSocket& sock) {
@@ -1242,6 +1160,7 @@
netdutils::Status XfrmController::updateTunnelModeSecurityPolicy(const XfrmSpInfo& record,
const XfrmSocket& sock,
+ XfrmDirection direction,
uint16_t msgType) {
xfrm_userpolicy_info userpolicy{};
nlattr_user_tmpl usertmpl{};
@@ -1273,7 +1192,7 @@
};
int len;
- len = iov[USERPOLICY].iov_len = fillUserSpInfo(record, &userpolicy);
+ len = iov[USERPOLICY].iov_len = fillUserSpInfo(record, direction, &userpolicy);
iov[USERPOLICY_PAD].iov_len = NLMSG_ALIGN(len) - len;
len = iov[USERTMPL].iov_len = fillNlAttrUserTemplate(record, &usertmpl);
@@ -1289,7 +1208,8 @@
}
netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSpInfo& record,
- const XfrmSocket& sock) {
+ const XfrmSocket& sock,
+ XfrmDirection direction) {
xfrm_userpolicy_id policyid{};
nlattr_xfrm_mark xfrmmark{};
nlattr_xfrm_interface_id xfrm_if_id{};
@@ -1314,7 +1234,7 @@
{kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
};
- int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, &policyid);
+ int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, direction, &policyid);
iov[USERPOLICYID_PAD].iov_len = NLMSG_ALIGN(len) - len;
len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
@@ -1326,14 +1246,15 @@
return sock.sendMessage(XFRM_MSG_DELPOLICY, NETLINK_REQUEST_FLAGS, 0, &iov);
}
-int XfrmController::fillUserSpInfo(const XfrmSpInfo& record, xfrm_userpolicy_info* usersp) {
+int XfrmController::fillUserSpInfo(const XfrmSpInfo& record, XfrmDirection direction,
+ xfrm_userpolicy_info* usersp) {
fillXfrmSelector(record.selAddrFamily, &usersp->sel);
fillXfrmLifetimeDefaults(&usersp->lft);
fillXfrmCurLifetimeDefaults(&usersp->curlft);
/* if (index) index & 0x3 == dir -- must be true
* xfrm_user.c:verify_newpolicy_info() */
usersp->index = 0;
- usersp->dir = static_cast<uint8_t>(record.direction);
+ usersp->dir = static_cast<uint8_t>(direction);
usersp->action = XFRM_POLICY_ALLOW;
usersp->flags = XFRM_POLICY_LOCALOK;
usersp->share = XFRM_SHARE_UNIQUE;
@@ -1381,30 +1302,24 @@
// This function sets the output mark (or set-mark in newer kernels) to that of the underlying
// Network's netid. This allows outbound IPsec Tunnel mode packets to be correctly directed to a
-// preselected underlying Network. Outbound packets are marked as protected from VPNs and have a
-// network explicitly selected to prevent interference or routing loops. Also sets permission flag
-// to PERMISSION_SYSTEM to allow use of background/restricted networks. Inbound packets have all
-// the flags and fields cleared to simulate the decapsulated packet being a fresh, unseen packet.
-int XfrmController::fillNlAttrXfrmOutputMark(const XfrmSaInfo& record,
+// preselected underlying Network. Packet as marked as protected from VPNs and have a network
+// explicitly selected to prevent interference or routing loops. Also set permission flag to
+// PERMISSION_SYSTEM to ensure we can use background/restricted networks. Permission to use
+// restricted networks is checked in IpSecService.
+int XfrmController::fillNlAttrXfrmOutputMark(const __u32 underlyingNetId,
nlattr_xfrm_output_mark* output_mark) {
- // Only set for tunnel mode transforms
- if (record.mode != XfrmMode::TUNNEL) {
+ // Do not set if we were not given an output mark
+ if (underlyingNetId == 0) {
return 0;
}
Fwmark fwmark;
+ fwmark.netId = underlyingNetId;
- // Only outbound transforms have an underlying network set.
- if (record.netId != 0) {
- fwmark.netId = record.netId;
- fwmark.permission = PERMISSION_SYSTEM;
- fwmark.explicitlySelected = true;
- fwmark.protectedFromVpn = true;
- }
-
- // Else (inbound transforms), reset to default mark (empty); UID billing for inbound tunnel mode
- // transforms are exclusively done on inner packet, and therefore can never have been set.
-
+ // TODO: Rework this to more accurately follow the underlying network
+ fwmark.permission = PERMISSION_SYSTEM;
+ fwmark.explicitlySelected = true;
+ fwmark.protectedFromVpn = true;
output_mark->outputMark = fwmark.intValue;
int len = NLA_HDRLEN + sizeof(__u32);
@@ -1425,28 +1340,11 @@
return len;
}
-int XfrmController::fillNlAttrXfrmMigrate(const XfrmMigrateInfo& record,
- nlattr_xfrm_user_migrate* migrate) {
- migrate->migrate.old_daddr = record.dstAddr;
- migrate->migrate.old_saddr = record.srcAddr;
- migrate->migrate.new_daddr = record.newEndpointInfo.dstAddr;
- migrate->migrate.new_saddr = record.newEndpointInfo.srcAddr;
- migrate->migrate.proto = IPPROTO_ESP;
- migrate->migrate.mode = static_cast<uint8_t>(XfrmMode::TUNNEL);
- migrate->migrate.reqid = record.transformId;
- migrate->migrate.old_family = record.addrFamily;
- migrate->migrate.new_family = record.newEndpointInfo.addrFamily;
-
- int len = NLA_HDRLEN + sizeof(xfrm_user_migrate);
- fillXfrmNlaHdr(&migrate->hdr, XFRMA_MIGRATE, len);
-
- return len;
-}
-
-int XfrmController::fillUserPolicyId(const XfrmSpInfo& record, xfrm_userpolicy_id* usersp) {
+int XfrmController::fillUserPolicyId(const XfrmSpInfo& record, XfrmDirection direction,
+ xfrm_userpolicy_id* usersp) {
// For DELPOLICY, when index is absent, selector is needed to match the policy
fillXfrmSelector(record.selAddrFamily, &usersp->sel);
- usersp->dir = static_cast<uint8_t>(record.direction);
+ usersp->dir = static_cast<uint8_t>(direction);
return sizeof(*usersp);
}
diff --git a/server/XfrmController.h b/server/XfrmController.h
index 4f167c5..15eef3d 100644
--- a/server/XfrmController.h
+++ b/server/XfrmController.h
@@ -107,19 +107,15 @@
uint16_t dstPort;
};
-struct XfrmEndpointPair {
+// minimally sufficient structure to match either an SA or a Policy
+struct XfrmCommonInfo {
xfrm_address_t dstAddr; // network order
xfrm_address_t srcAddr;
int addrFamily; // AF_INET or AF_INET6
-};
-
-// minimally sufficient structure to match either an SA or a Policy
-struct XfrmCommonInfo : XfrmEndpointPair {
int transformId; // requestId
int spi;
xfrm_mark mark;
int xfrm_if_id;
- XfrmMode mode;
};
struct XfrmSaInfo : XfrmCommonInfo {
@@ -127,18 +123,14 @@
XfrmAlgo crypt;
XfrmAlgo aead;
int netId;
+ XfrmMode mode;
XfrmEncap encap;
};
-struct XfrmSpInfo : XfrmCommonInfo {
+struct XfrmSpInfo : XfrmSaInfo {
// Address family in XfrmCommonInfo used for template/SA matching, need separate addrFamily
// for selectors
int selAddrFamily; // AF_INET or AF_INET6
- XfrmDirection direction;
-};
-
-struct XfrmMigrateInfo : XfrmSpInfo {
- XfrmEndpointPair newEndpointInfo;
};
/*
@@ -268,13 +260,6 @@
static netdutils::Status ipSecRemoveTunnelInterface(const std::string& deviceName);
- // Only available for Tunnel must already have a matching tunnel SA and policy
- static netdutils::Status ipSecMigrate(int32_t transformId, int32_t selAddrFamily,
- int32_t direction, const std::string& oldSourceAddress,
- const std::string& oldDestinationAddress,
- const std::string& newSourceAddress,
- const std::string& newDestinationAddress,
- int32_t xfrmInterfaceId);
void dump(netdutils::DumpWriter& dw);
// Some XFRM netlink attributes comprise a header, a struct, and some data
@@ -344,13 +329,6 @@
__u32 if_id;
};
- // Container for the content of an XFRMA_MIGRATE netlink attribute.
- // Exposed for testing
- struct nlattr_xfrm_user_migrate {
- nlattr hdr;
- xfrm_user_migrate migrate;
- };
-
// Exposed for testing
struct nlattr_payload_u32 {
nlattr hdr;
@@ -360,9 +338,6 @@
private:
static bool isXfrmIntfSupported();
- static netdutils::Status fillXfrmEndpointPair(const std::string& sourceAddress,
- const std::string& destinationAddress,
- XfrmEndpointPair* info);
// helper functions for filling in the XfrmCommonInfo (and XfrmSaInfo) structure
static netdutils::Status fillXfrmCommonInfo(const std::string& sourceAddress,
const std::string& destinationAddress, int32_t spi,
@@ -398,15 +373,15 @@
static int fillUserSaId(const XfrmCommonInfo& record, xfrm_usersa_id* said);
static void fillUserTemplate(const XfrmSpInfo& record, xfrm_user_tmpl* tmpl);
- static int fillUserSpInfo(const XfrmSpInfo& record, xfrm_userpolicy_info* usersp);
+ static int fillUserSpInfo(const XfrmSpInfo& record, XfrmDirection direction,
+ xfrm_userpolicy_info* usersp);
static int fillNlAttrUserTemplate(const XfrmSpInfo& record, nlattr_user_tmpl* tmpl);
- static int fillUserPolicyId(const XfrmSpInfo& record, xfrm_userpolicy_id* policy_id);
+ static int fillUserPolicyId(const XfrmSpInfo& record, XfrmDirection direction,
+ xfrm_userpolicy_id* policy_id);
static int fillNlAttrXfrmMark(const XfrmCommonInfo& record, nlattr_xfrm_mark* mark);
- static int fillNlAttrXfrmOutputMark(const XfrmSaInfo& record,
+ static int fillNlAttrXfrmOutputMark(const __u32 underlyingNetId,
nlattr_xfrm_output_mark* output_mark);
static int fillNlAttrXfrmIntfId(const __u32 intf_id_value, nlattr_xfrm_interface_id* intf_id);
- static int fillNlAttrXfrmMigrate(const XfrmMigrateInfo& record,
- nlattr_xfrm_user_migrate* migrate);
static netdutils::Status allocateSpi(const XfrmSaInfo& record, uint32_t minSpi, uint32_t maxSpi,
uint32_t* outSpi, const XfrmSocket& sock);
@@ -419,10 +394,11 @@
int32_t xfrmInterfaceId, int32_t msgType);
static netdutils::Status updateTunnelModeSecurityPolicy(const XfrmSpInfo& record,
const XfrmSocket& sock,
+ XfrmDirection direction,
uint16_t msgType);
static netdutils::Status deleteTunnelModeSecurityPolicy(const XfrmSpInfo& record,
- const XfrmSocket& sock);
- static netdutils::Status migrate(const XfrmMigrateInfo& record, const XfrmSocket& sock);
+ const XfrmSocket& sock,
+ XfrmDirection direction);
static netdutils::Status flushInterfaces();
static netdutils::Status flushSaDb(const XfrmSocket& s);
static netdutils::Status flushPolicyDb(const XfrmSocket& s);
diff --git a/server/aidl_api/netd_aidl_interface/1/.hash b/server/aidl_api/netd_aidl_interface/1/.hash
new file mode 100644
index 0000000..d33e903
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/1/.hash
@@ -0,0 +1 @@
+69c2ac134efbb31e9591d7e5c3640fb839e23bdb
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl
new file mode 100644
index 0000000..664c643
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/1/android/net/INetd.aidl
@@ -0,0 +1,132 @@
+package android.net;
+interface INetd {
+ boolean isAlive();
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ void networkCreatePhysical(int netId, int permission);
+ void networkCreateVpn(int netId, boolean secure);
+ void networkDestroy(int netId);
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+ void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
+ void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
+ boolean tetherApplyDnsInterfaces();
+ android.net.TetherStatsParcel[] tetherGetStats();
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+ int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
+ void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
+ void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
+ void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+ void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+ void clatdStop(in @utf8InCpp String ifName);
+ boolean ipfwdEnabled();
+ @utf8InCpp String[] ipfwdGetRequesterList();
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+ void bandwidthSetGlobalAlert(long bytes);
+ void bandwidthAddNaughtyApp(int uid);
+ void bandwidthRemoveNaughtyApp(int uid);
+ void bandwidthAddNiceApp(int uid);
+ void bandwidthRemoveNiceApp(int uid);
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+ void tetherStop();
+ boolean tetherIsEnabled();
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+ @utf8InCpp String[] tetherInterfaceList();
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+ @utf8InCpp String[] tetherDnsList();
+ void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ int networkGetDefault();
+ void networkSetDefault(int netId);
+ void networkClearDefault();
+ void networkSetPermissionForNetwork(int netId, int permission);
+ void networkSetPermissionForUser(int permission, in int[] uids);
+ void networkClearPermissionForUser(in int[] uids);
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+ void networkSetProtectAllow(int uid);
+ void networkSetProtectDeny(int uid);
+ boolean networkCanProtect(int uid);
+ void firewallSetFirewallType(int firewalltype);
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+ void firewallEnableChildChain(int childChain, boolean enable);
+ @utf8InCpp String[] interfaceGetList();
+ android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+ void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+ void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+ const int LOCAL_NET_ID = 99;
+ const String NEXTHOP_NONE = "";
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ const String NEXTHOP_THROW = "throw";
+ const int PERMISSION_NONE = 0;
+ const int PERMISSION_NETWORK = 1;
+ const int PERMISSION_SYSTEM = 2;
+ const int NO_PERMISSIONS = 0;
+ const int PERMISSION_INTERNET = 4;
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+ const int PERMISSION_UNINSTALLED = -1;
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_RULE_ALLOW = 1;
+ const int FIREWALL_RULE_DENY = 2;
+ const int FIREWALL_CHAIN_NONE = 0;
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..18631ff
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/1/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,14 @@
+package android.net;
+interface INetdUnsolicitedEventListener {
+ oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
+ oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+ oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+ oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAdded(@utf8InCpp String ifName);
+ oneway void onInterfaceRemoved(@utf8InCpp String ifName);
+ oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
+ oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..93407dc
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/1/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,8 @@
+package android.net;
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ @utf8InCpp String[] flags;
+}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..d1782bb
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/1/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,8 @@
+package android.net;
+parcelable TetherStatsParcel {
+ @utf8InCpp String iface;
+ long rxBytes;
+ long rxPackets;
+ long txBytes;
+ long txPackets;
+}
diff --git a/server/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..d3bc7ed
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/1/android/net/UidRangeParcel.aidl
@@ -0,0 +1,5 @@
+package android.net;
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/2/.hash b/server/aidl_api/netd_aidl_interface/2/.hash
new file mode 100644
index 0000000..5fc5b2d
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/2/.hash
@@ -0,0 +1 @@
+e395d63302c47e7d2dac0d503045779029ff598b
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl
new file mode 100644
index 0000000..0e2d5f4
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/2/android/net/INetd.aidl
@@ -0,0 +1,153 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+interface INetd {
+ boolean isAlive();
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ void networkCreatePhysical(int netId, int permission);
+ void networkCreateVpn(int netId, boolean secure);
+ void networkDestroy(int netId);
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+ void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
+ void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
+ boolean tetherApplyDnsInterfaces();
+ android.net.TetherStatsParcel[] tetherGetStats();
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+ int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
+ void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
+ void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
+ void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+ void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+ void clatdStop(in @utf8InCpp String ifName);
+ boolean ipfwdEnabled();
+ @utf8InCpp String[] ipfwdGetRequesterList();
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+ void bandwidthSetGlobalAlert(long bytes);
+ void bandwidthAddNaughtyApp(int uid);
+ void bandwidthRemoveNaughtyApp(int uid);
+ void bandwidthAddNiceApp(int uid);
+ void bandwidthRemoveNiceApp(int uid);
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+ void tetherStop();
+ boolean tetherIsEnabled();
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+ @utf8InCpp String[] tetherInterfaceList();
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+ @utf8InCpp String[] tetherDnsList();
+ void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ int networkGetDefault();
+ void networkSetDefault(int netId);
+ void networkClearDefault();
+ void networkSetPermissionForNetwork(int netId, int permission);
+ void networkSetPermissionForUser(int permission, in int[] uids);
+ void networkClearPermissionForUser(in int[] uids);
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+ void networkSetProtectAllow(int uid);
+ void networkSetProtectDeny(int uid);
+ boolean networkCanProtect(int uid);
+ void firewallSetFirewallType(int firewalltype);
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+ void firewallEnableChildChain(int childChain, boolean enable);
+ @utf8InCpp String[] interfaceGetList();
+ android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+ void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+ void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
+ void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
+ void firewallRemoveUidInterfaceRules(in int[] uids);
+ void trafficSwapActiveStatsMap();
+ IBinder getOemNetd();
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+ const int LOCAL_NET_ID = 99;
+ const String NEXTHOP_NONE = "";
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ const String NEXTHOP_THROW = "throw";
+ const int PERMISSION_NONE = 0;
+ const int PERMISSION_NETWORK = 1;
+ const int PERMISSION_SYSTEM = 2;
+ const int NO_PERMISSIONS = 0;
+ const int PERMISSION_INTERNET = 4;
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+ const int PERMISSION_UNINSTALLED = -1;
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_RULE_ALLOW = 1;
+ const int FIREWALL_RULE_DENY = 2;
+ const int FIREWALL_CHAIN_NONE = 0;
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..621f1cf
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/2/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+interface INetdUnsolicitedEventListener {
+ oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
+ oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+ oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+ oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAdded(@utf8InCpp String ifName);
+ oneway void onInterfaceRemoved(@utf8InCpp String ifName);
+ oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
+ oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..18de61f
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/2/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ @utf8InCpp String[] flags;
+}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..c0ba676
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/2/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable TetherStatsParcel {
+ @utf8InCpp String iface;
+ long rxBytes;
+ long rxPackets;
+ long txBytes;
+ long txPackets;
+}
diff --git a/server/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..c2c35db
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/2/android/net/UidRangeParcel.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/.hash b/server/aidl_api/netd_aidl_interface/3/.hash
new file mode 100644
index 0000000..59cf708
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/.hash
@@ -0,0 +1 @@
+e17c1f9b2068b539b22e3a4a447edea3c80aee4b
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl
new file mode 100644
index 0000000..135b738
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/INetd.aidl
@@ -0,0 +1,161 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetd {
+ boolean isAlive();
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ void networkCreatePhysical(int netId, int permission);
+ void networkCreateVpn(int netId, boolean secure);
+ void networkDestroy(int netId);
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+ void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
+ void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
+ boolean tetherApplyDnsInterfaces();
+ android.net.TetherStatsParcel[] tetherGetStats();
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+ int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
+ void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
+ void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
+ void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+ void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+ void clatdStop(in @utf8InCpp String ifName);
+ boolean ipfwdEnabled();
+ @utf8InCpp String[] ipfwdGetRequesterList();
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+ void bandwidthSetGlobalAlert(long bytes);
+ void bandwidthAddNaughtyApp(int uid);
+ void bandwidthRemoveNaughtyApp(int uid);
+ void bandwidthAddNiceApp(int uid);
+ void bandwidthRemoveNiceApp(int uid);
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+ void tetherStop();
+ boolean tetherIsEnabled();
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+ @utf8InCpp String[] tetherInterfaceList();
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+ @utf8InCpp String[] tetherDnsList();
+ void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ int networkGetDefault();
+ void networkSetDefault(int netId);
+ void networkClearDefault();
+ void networkSetPermissionForNetwork(int netId, int permission);
+ void networkSetPermissionForUser(int permission, in int[] uids);
+ void networkClearPermissionForUser(in int[] uids);
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+ void networkSetProtectAllow(int uid);
+ void networkSetProtectDeny(int uid);
+ boolean networkCanProtect(int uid);
+ void firewallSetFirewallType(int firewalltype);
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+ void firewallEnableChildChain(int childChain, boolean enable);
+ @utf8InCpp String[] interfaceGetList();
+ android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+ void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+ void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
+ void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
+ void firewallRemoveUidInterfaceRules(in int[] uids);
+ void trafficSwapActiveStatsMap();
+ IBinder getOemNetd();
+ void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
+ android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
+ void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
+ void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+ const int LOCAL_NET_ID = 99;
+ const String NEXTHOP_NONE = "";
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ const String NEXTHOP_THROW = "throw";
+ const int PERMISSION_NONE = 0;
+ const int PERMISSION_NETWORK = 1;
+ const int PERMISSION_SYSTEM = 2;
+ const int NO_PERMISSIONS = 0;
+ const int PERMISSION_INTERNET = 4;
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+ const int PERMISSION_UNINSTALLED = -1;
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_RULE_ALLOW = 1;
+ const int FIREWALL_RULE_DENY = 2;
+ const int FIREWALL_CHAIN_NONE = 0;
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..4459363
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetdUnsolicitedEventListener {
+ oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
+ oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+ oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+ oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAdded(@utf8InCpp String ifName);
+ oneway void onInterfaceRemoved(@utf8InCpp String ifName);
+ oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
+ oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..01e0f95
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ @utf8InCpp String[] flags;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl
new file mode 100644
index 0000000..62be838
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable MarkMaskParcel {
+ int mark;
+ int mask;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl
new file mode 100644
index 0000000..5e0ee62
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/RouteInfoParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable RouteInfoParcel {
+ @utf8InCpp String destination;
+ @utf8InCpp String ifName;
+ @utf8InCpp String nextHop;
+ int mtu;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl
new file mode 100644
index 0000000..b136454
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherConfigParcel {
+ boolean usingLegacyDnsProxy;
+ @utf8InCpp String[] dhcpRanges;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 0000000..3abf0f8
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherOffloadRuleParcel {
+ int inputInterfaceIndex;
+ int outputInterfaceIndex;
+ byte[] destination;
+ int prefixLength;
+ byte[] srcL2Address;
+ byte[] dstL2Address;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..71ffb9b
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherStatsParcel {
+ @utf8InCpp String iface;
+ long rxBytes;
+ long rxPackets;
+ long txBytes;
+ long txPackets;
+}
diff --git a/server/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..84ff457
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/3/android/net/UidRangeParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/.hash b/server/aidl_api/netd_aidl_interface/4/.hash
new file mode 100644
index 0000000..0c3f810
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/.hash
@@ -0,0 +1 @@
+63adaa5098e4d8621e90c5a84f7cb93505c79311
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl
new file mode 100644
index 0000000..47e2931
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/INetd.aidl
@@ -0,0 +1,164 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetd {
+ boolean isAlive();
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ void networkCreatePhysical(int netId, int permission);
+ void networkCreateVpn(int netId, boolean secure);
+ void networkDestroy(int netId);
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+ void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
+ void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
+ boolean tetherApplyDnsInterfaces();
+ android.net.TetherStatsParcel[] tetherGetStats();
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+ int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
+ void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
+ void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
+ void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+ void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+ void clatdStop(in @utf8InCpp String ifName);
+ boolean ipfwdEnabled();
+ @utf8InCpp String[] ipfwdGetRequesterList();
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+ void bandwidthSetGlobalAlert(long bytes);
+ void bandwidthAddNaughtyApp(int uid);
+ void bandwidthRemoveNaughtyApp(int uid);
+ void bandwidthAddNiceApp(int uid);
+ void bandwidthRemoveNiceApp(int uid);
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+ void tetherStop();
+ boolean tetherIsEnabled();
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+ @utf8InCpp String[] tetherInterfaceList();
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+ @utf8InCpp String[] tetherDnsList();
+ void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ int networkGetDefault();
+ void networkSetDefault(int netId);
+ void networkClearDefault();
+ void networkSetPermissionForNetwork(int netId, int permission);
+ void networkSetPermissionForUser(int permission, in int[] uids);
+ void networkClearPermissionForUser(in int[] uids);
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+ void networkSetProtectAllow(int uid);
+ void networkSetProtectDeny(int uid);
+ boolean networkCanProtect(int uid);
+ void firewallSetFirewallType(int firewalltype);
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+ void firewallEnableChildChain(int childChain, boolean enable);
+ @utf8InCpp String[] interfaceGetList();
+ android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+ void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+ void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
+ void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
+ void firewallRemoveUidInterfaceRules(in int[] uids);
+ void trafficSwapActiveStatsMap();
+ IBinder getOemNetd();
+ void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
+ android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
+ void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
+ void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
+ android.net.TetherStatsParcel[] tetherOffloadGetStats();
+ void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
+ android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+ const int LOCAL_NET_ID = 99;
+ const String NEXTHOP_NONE = "";
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ const String NEXTHOP_THROW = "throw";
+ const int PERMISSION_NONE = 0;
+ const int PERMISSION_NETWORK = 1;
+ const int PERMISSION_SYSTEM = 2;
+ const int NO_PERMISSIONS = 0;
+ const int PERMISSION_INTERNET = 4;
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+ const int PERMISSION_UNINSTALLED = -1;
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_RULE_ALLOW = 1;
+ const int FIREWALL_RULE_DENY = 2;
+ const int FIREWALL_CHAIN_NONE = 0;
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..4459363
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetdUnsolicitedEventListener {
+ oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
+ oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+ oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+ oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAdded(@utf8InCpp String ifName);
+ oneway void onInterfaceRemoved(@utf8InCpp String ifName);
+ oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
+ oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..01e0f95
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ @utf8InCpp String[] flags;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl
new file mode 100644
index 0000000..62be838
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable MarkMaskParcel {
+ int mark;
+ int mask;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl
new file mode 100644
index 0000000..5e0ee62
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/RouteInfoParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable RouteInfoParcel {
+ @utf8InCpp String destination;
+ @utf8InCpp String ifName;
+ @utf8InCpp String nextHop;
+ int mtu;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl
new file mode 100644
index 0000000..b136454
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherConfigParcel {
+ boolean usingLegacyDnsProxy;
+ @utf8InCpp String[] dhcpRanges;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 0000000..c9d8458
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherOffloadRuleParcel {
+ int inputInterfaceIndex;
+ int outputInterfaceIndex;
+ byte[] destination;
+ int prefixLength;
+ byte[] srcL2Address;
+ byte[] dstL2Address;
+ int pmtu = 1500;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..0b0960e
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherStatsParcel {
+ @utf8InCpp String iface;
+ long rxBytes;
+ long rxPackets;
+ long txBytes;
+ long txPackets;
+ int ifIndex = 0;
+}
diff --git a/server/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..84ff457
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/4/android/net/UidRangeParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
new file mode 100644
index 0000000..47e2931
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
@@ -0,0 +1,164 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetd {
+ boolean isAlive();
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ void networkCreatePhysical(int netId, int permission);
+ void networkCreateVpn(int netId, boolean secure);
+ void networkDestroy(int netId);
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+ void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
+ void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
+ boolean tetherApplyDnsInterfaces();
+ android.net.TetherStatsParcel[] tetherGetStats();
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+ int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
+ void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
+ void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
+ void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+ void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+ void clatdStop(in @utf8InCpp String ifName);
+ boolean ipfwdEnabled();
+ @utf8InCpp String[] ipfwdGetRequesterList();
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+ void bandwidthSetGlobalAlert(long bytes);
+ void bandwidthAddNaughtyApp(int uid);
+ void bandwidthRemoveNaughtyApp(int uid);
+ void bandwidthAddNiceApp(int uid);
+ void bandwidthRemoveNiceApp(int uid);
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+ void tetherStop();
+ boolean tetherIsEnabled();
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+ @utf8InCpp String[] tetherInterfaceList();
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+ @utf8InCpp String[] tetherDnsList();
+ void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ int networkGetDefault();
+ void networkSetDefault(int netId);
+ void networkClearDefault();
+ void networkSetPermissionForNetwork(int netId, int permission);
+ void networkSetPermissionForUser(int permission, in int[] uids);
+ void networkClearPermissionForUser(in int[] uids);
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+ void networkSetProtectAllow(int uid);
+ void networkSetProtectDeny(int uid);
+ boolean networkCanProtect(int uid);
+ void firewallSetFirewallType(int firewalltype);
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+ void firewallEnableChildChain(int childChain, boolean enable);
+ @utf8InCpp String[] interfaceGetList();
+ android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+ void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+ void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
+ void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
+ void firewallRemoveUidInterfaceRules(in int[] uids);
+ void trafficSwapActiveStatsMap();
+ IBinder getOemNetd();
+ void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
+ android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
+ void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
+ void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
+ android.net.TetherStatsParcel[] tetherOffloadGetStats();
+ void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
+ android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+ const int LOCAL_NET_ID = 99;
+ const String NEXTHOP_NONE = "";
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ const String NEXTHOP_THROW = "throw";
+ const int PERMISSION_NONE = 0;
+ const int PERMISSION_NETWORK = 1;
+ const int PERMISSION_SYSTEM = 2;
+ const int NO_PERMISSIONS = 0;
+ const int PERMISSION_INTERNET = 4;
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+ const int PERMISSION_UNINSTALLED = -1;
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_RULE_ALLOW = 1;
+ const int FIREWALL_RULE_DENY = 2;
+ const int FIREWALL_CHAIN_NONE = 0;
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..4459363
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetdUnsolicitedEventListener {
+ oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
+ oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+ oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+ oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAdded(@utf8InCpp String ifName);
+ oneway void onInterfaceRemoved(@utf8InCpp String ifName);
+ oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
+ oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..01e0f95
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ @utf8InCpp String[] flags;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
new file mode 100644
index 0000000..62be838
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable MarkMaskParcel {
+ int mark;
+ int mask;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
new file mode 100644
index 0000000..5e0ee62
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable RouteInfoParcel {
+ @utf8InCpp String destination;
+ @utf8InCpp String ifName;
+ @utf8InCpp String nextHop;
+ int mtu;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
new file mode 100644
index 0000000..b136454
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherConfigParcel {
+ boolean usingLegacyDnsProxy;
+ @utf8InCpp String[] dhcpRanges;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 0000000..c9d8458
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherOffloadRuleParcel {
+ int inputInterfaceIndex;
+ int outputInterfaceIndex;
+ byte[] destination;
+ int prefixLength;
+ byte[] srcL2Address;
+ byte[] dstL2Address;
+ int pmtu = 1500;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..0b0960e
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherStatsParcel {
+ @utf8InCpp String iface;
+ long rxBytes;
+ long rxPackets;
+ long txBytes;
+ long txPackets;
+ int ifIndex = 0;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..84ff457
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_event_listener_interface/1/.hash b/server/aidl_api/netd_event_listener_interface/1/.hash
new file mode 100644
index 0000000..f39f730
--- /dev/null
+++ b/server/aidl_api/netd_event_listener_interface/1/.hash
@@ -0,0 +1 @@
+8e27594d285ca7c567d87e8cf74766c27647e02b
diff --git a/server/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl b/server/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl
new file mode 100644
index 0000000..9898a67
--- /dev/null
+++ b/server/aidl_api/netd_event_listener_interface/1/android/net/metrics/INetdEventListener.aidl
@@ -0,0 +1,34 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.metrics;
+interface INetdEventListener {
+ oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid);
+ oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated);
+ oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid);
+ oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
+ oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs);
+ oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength);
+ const int EVENT_GETADDRINFO = 1;
+ const int EVENT_GETHOSTBYNAME = 2;
+ const int EVENT_GETHOSTBYADDR = 3;
+ const int EVENT_RES_NSEND = 4;
+ const int REPORTING_LEVEL_NONE = 0;
+ const int REPORTING_LEVEL_METRICS = 1;
+ const int REPORTING_LEVEL_FULL = 2;
+ const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10;
+}
diff --git a/server/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl b/server/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl
new file mode 100644
index 0000000..d71c3f2
--- /dev/null
+++ b/server/aidl_api/netd_event_listener_interface/current/android/net/metrics/INetdEventListener.aidl
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.metrics;
+/* @hide */
+interface INetdEventListener {
+ oneway void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses, int ipAddressesCount, int uid);
+ oneway void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname, boolean validated);
+ oneway void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid);
+ oneway void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
+ oneway void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets, in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs);
+ oneway void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString, int prefixLength);
+ const int EVENT_GETADDRINFO = 1;
+ const int EVENT_GETHOSTBYNAME = 2;
+ const int EVENT_GETHOSTBYADDR = 3;
+ const int EVENT_RES_NSEND = 4;
+ const int REPORTING_LEVEL_NONE = 0;
+ const int REPORTING_LEVEL_METRICS = 1;
+ const int REPORTING_LEVEL_FULL = 2;
+ const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10;
+}
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
new file mode 100644
index 0000000..3b221cf
--- /dev/null
+++ b/server/binder/android/net/INetd.aidl
@@ -0,0 +1,1312 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+package android.net;
+
+import android.net.INetdUnsolicitedEventListener;
+import android.net.InterfaceConfigurationParcel;
+import android.net.MarkMaskParcel;
+import android.net.RouteInfoParcel;
+import android.net.TetherConfigParcel;
+import android.net.TetherOffloadRuleParcel;
+import android.net.TetherStatsParcel;
+import android.net.UidRangeParcel;
+
+/** {@hide} */
+interface INetd {
+ /**
+ * Returns true if the service is responding.
+ */
+ boolean isAlive();
+
+ /**
+ * Replaces the contents of the specified UID-based firewall chain.
+ *
+ * The chain may be a whitelist chain or a blacklist chain. A blacklist chain contains DROP
+ * rules for the specified UIDs and a RETURN rule at the end. A whitelist chain contains RETURN
+ * rules for the system UID range (0 to {@code UID_APP} - 1), RETURN rules for for the specified
+ * UIDs, and a DROP rule at the end. The chain will be created if it does not exist.
+ *
+ * @param chainName The name of the chain to replace.
+ * @param isWhitelist Whether this is a whitelist or blacklist chain.
+ * @param uids The list of UIDs to allow/deny.
+ * @return true if the chain was successfully replaced, false otherwise.
+ */
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName,
+ boolean isWhitelist,
+ in int[] uids);
+
+ /**
+ * Enables or disables data saver mode on costly network interfaces.
+ *
+ * - When disabled, all packets to/from apps in the penalty box chain are rejected on costly
+ * interfaces. Traffic to/from other apps or on other network interfaces is allowed.
+ * - When enabled, only apps that are in the happy box chain and not in the penalty box chain
+ * are allowed network connectivity on costly interfaces. All other packets on these
+ * interfaces are rejected. The happy box chain always contains all system UIDs; to disallow
+ * traffic from system UIDs, place them in the penalty box chain.
+ *
+ * By default, data saver mode is disabled. This command has no effect but might still return an
+ * error) if {@code enable} is the same as the current value.
+ *
+ * @param enable whether to enable or disable data saver mode.
+ * @return true if the if the operation was successful, false otherwise.
+ */
+ boolean bandwidthEnableDataSaver(boolean enable);
+
+ /**
+ * Creates a physical network (i.e., one containing physical interfaces.
+ *
+ * @param netId the networkId to create.
+ * @param permission the permission necessary to use the network. Must be one of
+ * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkCreatePhysical(int netId, int permission);
+
+ /**
+ * Creates a VPN network.
+ *
+ * @param netId the network to create.
+ * @param secure whether unprivileged apps are allowed to bypass the VPN.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkCreateVpn(int netId, boolean secure);
+
+ /**
+ * Destroys a network. Any interfaces added to the network are removed, and the network ceases
+ * to be the default network.
+ *
+ * @param netId the network to destroy.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkDestroy(int netId);
+
+ /**
+ * Adds an interface to a network. The interface must not be assigned to any network, including
+ * the specified network.
+ *
+ * @param netId the network to add the interface to.
+ * @param interface the name of the interface to add.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+
+ /**
+ * Adds an interface to a network. The interface must be assigned to the specified network.
+ *
+ * @param netId the network to remove the interface from.
+ * @param interface the name of the interface to remove.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+
+ /**
+ * Adds the specified UID ranges to the specified network. The network must be a VPN. Traffic
+ * from the UID ranges will be routed through the VPN.
+ *
+ * @param netId the network ID of the network to add the ranges to.
+ * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to add. The ranges
+ * must not overlap with existing ranges routed to this network.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkAddUidRanges(int netId, in UidRangeParcel[] uidRanges);
+
+ /**
+ * Adds the specified UID ranges to the specified network. The network must be a VPN. Traffic
+ * from the UID ranges will no longer be routed through the VPN.
+ *
+ * @param netId the network ID of the network to remove the ranges from.
+ * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to add. The ranges
+ * must already be routed to this network.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkRemoveUidRanges(int netId, in UidRangeParcel[] uidRanges);
+
+ /**
+ * Adds or removes one rule for each supplied UID range to prohibit all network activity outside
+ * of secure VPN.
+ *
+ * When a UID is covered by one of these rules, traffic sent through any socket that is not
+ * protected or explicitly overriden by the system will be rejected. The kernel will respond
+ * with an ICMP prohibit message.
+ *
+ * Initially, there are no such rules. Any rules that are added will only last until the next
+ * restart of netd or the device.
+ *
+ * @param add {@code true} if the specified UID ranges should be denied access to any network
+ * which is not secure VPN by adding rules, {@code false} to remove existing rules.
+ * @param uidRanges a set of non-overlapping, contiguous ranges of UIDs to which to apply or
+ * remove this restriction.
+ * <p> Added rules should not overlap with existing rules. Likewise, removed rules should
+ * each correspond to an existing rule.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkRejectNonSecureVpn(boolean add, in UidRangeParcel[] uidRanges);
+
+ /**
+ * Administratively closes sockets belonging to the specified UIDs.
+ */
+ void socketDestroy(in UidRangeParcel[] uidRanges, in int[] exemptUids);
+
+ /**
+ * Instruct the tethering DNS server to reevaluated serving interfaces.
+ * This is needed to for the DNS server to observe changes in the set
+ * of potential listening IP addresses. (Listening on wildcard addresses
+ * can turn the device into an open resolver; b/7530468)
+ *
+ * TODO: Return something richer than just a boolean.
+ */
+ boolean tetherApplyDnsInterfaces();
+
+ /**
+ * Return tethering statistics.
+ *
+ * @return an array of TetherStatsParcel, where each entry contains the upstream interface
+ * name and its tethering statistics since netd startup.
+ * There will only ever be one entry for a given interface.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ TetherStatsParcel[] tetherGetStats();
+
+ /**
+ * Add/Remove and IP address from an interface.
+ *
+ * @param ifName the interface name
+ * @param addrString the IP address to add/remove as a string literal
+ * @param prefixLength the prefix length associated with this IP address
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString,
+ int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString,
+ int prefixLength);
+
+ /**
+ * Set and get /proc/sys/net interface configuration parameters.
+ *
+ * @param ipversion One of IPV4/IPV6 integers, indicating the desired IP version directory.
+ * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory.
+ * @param ifname The interface name portion of the path; may also be "all" or "default".
+ * @param parameter The parameter name portion of the path.
+ * @param value The value string to be written into the assembled path.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname,
+ in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname,
+ in @utf8InCpp String parameter, in @utf8InCpp String value);
+
+ /**
+ * Sets owner of socket ParcelFileDescriptor to the new UID, checking to ensure that the caller's
+ * uid is that of the old owner's, and that this is a UDP-encap socket
+ *
+ * @param ParcelFileDescriptor socket Socket file descriptor
+ * @param int newUid UID of the new socket fd owner
+ */
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+
+ /**
+ * Reserve an SPI from the kernel
+ *
+ * @param transformId a unique identifier for allocated resources
+ * @param sourceAddress InetAddress as string for the sending endpoint
+ * @param destinationAddress InetAddress as string for the receiving endpoint
+ * @param spi a requested 32-bit unique ID or 0 to request random allocation
+ * @return the SPI that was allocated or 0 if failed
+ */
+ int ipSecAllocateSpi(
+ int transformId,
+ in @utf8InCpp String sourceAddress,
+ in @utf8InCpp String destinationAddress,
+ int spi);
+
+ /**
+ * Create an IpSec Security Association describing how ip(v6) traffic will be encrypted
+ * or decrypted.
+ *
+ * @param transformId a unique identifier for allocated resources
+ * @param mode either Transport or Tunnel mode
+ * @param sourceAddress InetAddress as string for the sending endpoint
+ * @param destinationAddress InetAddress as string for the receiving endpoint
+ * @param underlyingNetId the netId of the network to which the SA is applied. Only accepted for
+ * tunnel mode SAs.
+ * @param spi a 32-bit unique ID allocated to the user
+ * @param markValue a 32-bit unique ID chosen by the user
+ * @param markMask a 32-bit mask chosen by the user
+ * @param authAlgo a string identifying the authentication algorithm to be used
+ * @param authKey a byte array containing the authentication key
+ * @param authTruncBits the truncation length of the MAC produced by the authentication algorithm
+ * @param cryptAlgo a string identifying the encryption algorithm to be used
+ * @param cryptKey a byte arrray containing the encryption key
+ * @param cryptTruncBits unused parameter
+ * @param aeadAlgo a string identifying the authenticated encryption algorithm to be used
+ * @param aeadKey a byte arrray containing the key to be used in authenticated encryption
+ * @param aeadIcvBits the truncation length of the ICV produced by the authentication algorithm
+ * (similar to authTruncBits in function)
+ * @param encapType encapsulation type used (if any) for the udp encap socket
+ * @param encapLocalPort the port number on the host to be used in encap packets
+ * @param encapRemotePort the port number of the remote to be used for encap packets
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ * Only accepted for tunnel mode SAs.
+ */
+ void ipSecAddSecurityAssociation(
+ int transformId,
+ int mode,
+ in @utf8InCpp String sourceAddress,
+ in @utf8InCpp String destinationAddress,
+ int underlyingNetId,
+ int spi,
+ int markValue,
+ int markMask,
+ in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits,
+ in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits,
+ in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits,
+ int encapType,
+ int encapLocalPort,
+ int encapRemotePort,
+ int interfaceId);
+
+ /**
+ * Delete a previously created security association identified by the provided parameters
+ *
+ * @param transformId a unique identifier for allocated resources
+ * @param sourceAddress InetAddress as string for the sending endpoint
+ * @param destinationAddress InetAddress as string for the receiving endpoint
+ * @param spi a requested 32-bit unique ID allocated to the user
+ * @param markValue a 32-bit unique ID chosen by the user
+ * @param markMask a 32-bit mask chosen by the user
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ */
+ void ipSecDeleteSecurityAssociation(
+ int transformId,
+ in @utf8InCpp String sourceAddress,
+ in @utf8InCpp String destinationAddress,
+ int spi,
+ int markValue,
+ int markMask,
+ int interfaceId);
+
+ /**
+ * Apply a previously created SA to a specified socket, starting IPsec on that socket
+ *
+ * @param socket a user-provided socket that will have IPsec applied
+ * @param transformId a unique identifier for allocated resources
+ * @param direction DIRECTION_IN or DIRECTION_OUT
+ * @param sourceAddress InetAddress as string for the sending endpoint
+ * @param destinationAddress InetAddress as string for the receiving endpoint
+ * @param spi a 32-bit unique ID allocated to the user (socket owner)
+ */
+ void ipSecApplyTransportModeTransform(
+ in ParcelFileDescriptor socket,
+ int transformId,
+ int direction,
+ in @utf8InCpp String sourceAddress,
+ in @utf8InCpp String destinationAddress,
+ int spi);
+
+ /**
+ * Remove an IPsec SA from a given socket. This will allow unencrypted traffic to flow
+ * on that socket if a transform had been previously applied.
+ *
+ * @param socket a user-provided socket from which to remove any IPsec configuration
+ */
+ void ipSecRemoveTransportModeTransform(
+ in ParcelFileDescriptor socket);
+
+ /**
+ * Adds an IPsec global policy.
+ *
+ * @param transformId a unique identifier for allocated resources
+ * @param selAddrFamily the address family identifier for the selector
+ * @param direction DIRECTION_IN or DIRECTION_OUT
+ * @param tmplSrcAddress InetAddress as string for the sending endpoint
+ * @param tmplDstAddress InetAddress as string for the receiving endpoint
+ * @param spi a 32-bit unique ID allocated to the user
+ * @param markValue a 32-bit unique ID chosen by the user
+ * @param markMask a 32-bit mask chosen by the user
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ */
+ void ipSecAddSecurityPolicy(
+ int transformId,
+ int selAddrFamily,
+ int direction,
+ in @utf8InCpp String tmplSrcAddress,
+ in @utf8InCpp String tmplDstAddress,
+ int spi,
+ int markValue,
+ int markMask,
+ int interfaceId);
+
+ /**
+ * Updates an IPsec global policy.
+ *
+ * @param transformId a unique identifier for allocated resources
+ * @param selAddrFamily the address family identifier for the selector
+ * @param direction DIRECTION_IN or DIRECTION_OUT
+ * @param tmplSrcAddress InetAddress as string for the sending endpoint
+ * @param tmplDstAddress InetAddress as string for the receiving endpoint
+ * @param spi a 32-bit unique ID allocated to the user
+ * @param markValue a 32-bit unique ID chosen by the user
+ * @param markMask a 32-bit mask chosen by the user
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ */
+ void ipSecUpdateSecurityPolicy(
+ int transformId,
+ int selAddrFamily,
+ int direction,
+ in @utf8InCpp String tmplSrcAddress,
+ in @utf8InCpp String tmplDstAddress,
+ int spi,
+ int markValue,
+ int markMask,
+ int interfaceId);
+
+ /**
+ * Deletes an IPsec global policy.
+ *
+ * Deletion of global policies does not do any matching based on the templates, thus
+ * template source/destination addresses are not needed (as opposed to add/update).
+ *
+ * @param transformId a unique identifier for allocated resources
+ * @param selAddrFamily the address family identifier for the selector
+ * @param direction DIRECTION_IN or DIRECTION_OUT
+ * @param markValue a 32-bit unique ID chosen by the user
+ * @param markMask a 32-bit mask chosen by the user
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ */
+ void ipSecDeleteSecurityPolicy(
+ int transformId,
+ int selAddrFamily,
+ int direction,
+ int markValue,
+ int markMask,
+ int interfaceId);
+
+ // This could not be declared as @uft8InCpp; thus, when used in native code it must be
+ // converted from a UTF-16 string to an ASCII string.
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+
+ /**
+ * Add a IPsec Tunnel Interface.
+ *
+ * @param devName a unique identifier that represents the name of the device
+ * @param localAddress InetAddress as string for the local endpoint
+ * @param remoteAddress InetAddress as string for the remote endpoint
+ * @param iKey, to match Policies and SAs for input packets.
+ * @param oKey, to match Policies and SAs for output packets.
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ */
+ void ipSecAddTunnelInterface(
+ in @utf8InCpp String deviceName,
+ in @utf8InCpp String localAddress,
+ in @utf8InCpp String remoteAddress,
+ int iKey,
+ int oKey,
+ int interfaceId);
+
+ /**
+ * Update a IPsec Tunnel Interface.
+ *
+ * @param devName a unique identifier that represents the name of the device
+ * @param localAddress InetAddress as string for the local endpoint
+ * @param remoteAddress InetAddress as string for the remote endpoint
+ * @param iKey, to match Policies and SAs for input packets.
+ * @param oKey, to match Policies and SAs for output packets.
+ * @param interfaceId the identifier for the IPsec tunnel interface.
+ */
+ void ipSecUpdateTunnelInterface(
+ in @utf8InCpp String deviceName,
+ in @utf8InCpp String localAddress,
+ in @utf8InCpp String remoteAddress,
+ int iKey,
+ int oKey,
+ int interfaceId);
+
+ /**
+ * Removes a IPsec Tunnel Interface.
+ *
+ * @param devName a unique identifier that represents the name of the device
+ */
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+
+ /**
+ * Request notification of wakeup packets arriving on an interface. Notifications will be
+ * delivered to INetdEventListener.onWakeupEvent().
+ *
+ * @param ifName the interface
+ * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent
+ */
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+
+ /**
+ * Stop notification of wakeup packets arriving on an interface.
+ *
+ * @param ifName the interface
+ * @param prefix arbitrary string used to identify wakeup sources in onWakeupEvent
+ */
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ /**
+ * Set IPv6 address generation mode. IPv6 should be disabled before changing mode.
+ *
+ * @param mode SLAAC address generation mechanism to use
+ */
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+
+ /**
+ * Add idletimer for specific interface
+ *
+ * @param ifName Name of target interface
+ * @param timeout The time in seconds that will trigger idletimer
+ * @param classLabel The unique identifier for this idletimer
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void idletimerAddInterface(
+ in @utf8InCpp String ifName,
+ int timeout,
+ in @utf8InCpp String classLabel);
+
+ /**
+ * Remove idletimer for specific interface
+ *
+ * @param ifName Name of target interface
+ * @param timeout The time in seconds that will trigger idletimer
+ * @param classLabel The unique identifier for this idletimer
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void idletimerRemoveInterface(
+ in @utf8InCpp String ifName,
+ int timeout,
+ in @utf8InCpp String classLabel);
+
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+
+ /**
+ * Offers to detect sockets sending data not wrapped inside a layer of SSL/TLS encryption.
+ *
+ * @param uid Uid of the app
+ * @param policyPenalty The penalty policy of the app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+
+ /**
+ * Start clatd
+ *
+ * @param ifName interface name to start clatd
+ * @param nat64Prefix the NAT64 prefix, e.g., "2001:db8:64::/96".
+ * @return a string, the IPv6 address that will be used for 464xlat.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+
+ /**
+ * Stop clatd
+ *
+ * @param ifName interface name to stop clatd
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void clatdStop(in @utf8InCpp String ifName);
+
+ /**
+ * Get status of IP forwarding
+ *
+ * @return true if IP forwarding is enabled, false otherwise.
+ */
+ boolean ipfwdEnabled();
+
+ /**
+ * Get requester list of IP forwarding
+ *
+ * @return An array of strings containing requester list of IP forwarding
+ */
+ @utf8InCpp String[] ipfwdGetRequesterList();
+
+ /**
+ * Enable IP forwarding for specific requester
+ *
+ * @param requester requester name to enable IP forwarding. It is a unique name which will be
+ * stored in Netd to make sure if any requester needs IP forwarding.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+
+ /**
+ * Disable IP forwarding for specific requester
+ *
+ * @param requester requester name to disable IP forwarding. This name should match the
+ * names which are set by ipfwdEnableForwarding.
+ * IP forwarding would be disabled if it is the last requester.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+
+ /**
+ * Add forwarding ip rule
+ *
+ * @param fromIface interface name to add forwarding ip rule
+ * @param toIface interface name to add forwarding ip rule
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+
+ /**
+ * Remove forwarding ip rule
+ *
+ * @param fromIface interface name to remove forwarding ip rule
+ * @param toIface interface name to remove forwarding ip rule
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+
+ /**
+ * Set quota for interface
+ *
+ * @param ifName Name of target interface
+ * @param bytes Quota value in bytes
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+
+ /**
+ * Remove quota for interface
+ *
+ * @param ifName Name of target interface
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+
+ /**
+ * Set alert for interface
+ *
+ * @param ifName Name of target interface
+ * @param bytes Alert value in bytes
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+
+ /**
+ * Remove alert for interface
+ *
+ * @param ifName Name of target interface
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+
+ /**
+ * Set global alert
+ *
+ * @param bytes Alert value in bytes
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthSetGlobalAlert(long bytes);
+
+ /**
+ * Add naughty app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthAddNaughtyApp(int uid);
+
+ /**
+ * Remove naughty app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthRemoveNaughtyApp(int uid);
+
+ /**
+ * Add nice app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthAddNiceApp(int uid);
+
+ /**
+ * Remove nice app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void bandwidthRemoveNiceApp(int uid);
+
+ /**
+ * Start tethering
+ *
+ * @param dhcpRanges dhcp ranges to set.
+ * dhcpRanges might contain many addresss {addr1, addr2, aadr3, addr4...}
+ * Netd splits them into ranges: addr1-addr2, addr3-addr4, etc.
+ * An odd number of addrs will fail.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+
+ /**
+ * Stop tethering
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherStop();
+
+ /**
+ * Get status of tethering
+ *
+ * @return true if tethering is enabled, false otherwise.
+ */
+ boolean tetherIsEnabled();
+
+ /**
+ * Setup interface for tethering
+ *
+ * @param ifName interface name to add
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+
+ /**
+ * Reset interface for tethering
+ *
+ * @param ifName interface name to remove
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+
+ /**
+ * Get the interface list which is stored in netd
+ * The list contains the interfaces managed by tetherInterfaceAdd/tetherInterfaceRemove
+ *
+ * @return An array of strings containing interface list result
+ */
+ @utf8InCpp String[] tetherInterfaceList();
+
+ /**
+ * Set DNS forwarder server
+ *
+ * @param netId the upstream network to forward DNS queries to
+ * @param dnsAddrs DNS server address to set
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+
+ /**
+ * Return the DNS list set by tetherDnsSet
+ *
+ * @return An array of strings containing the list of DNS servers
+ */
+ @utf8InCpp String[] tetherDnsList();
+
+ const int LOCAL_NET_ID = 99;
+
+ // Route does not specify a next hop
+ const String NEXTHOP_NONE = "";
+ // Route next hop is unreachable
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ // Route next hop is throw
+ const String NEXTHOP_THROW = "throw";
+
+ /**
+ * Add a route for specific network
+ *
+ * @param netId the network to add the route to
+ * @param ifName the name of interface of the route.
+ * This interface should be assigned to the netID.
+ * @param destination the destination of the route
+ * @param nextHop The route's next hop address,
+ * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkAddRoute(
+ int netId,
+ in @utf8InCpp String ifName,
+ in @utf8InCpp String destination,
+ in @utf8InCpp String nextHop);
+
+ /**
+ * Remove a route for specific network
+ *
+ * @param netId the network to remove the route from
+ * @param ifName the name of interface of the route.
+ * This interface should be assigned to the netID.
+ * @param destination the destination of the route
+ * @param nextHop The route's next hop address,
+ * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkRemoveRoute(
+ int netId,
+ in @utf8InCpp String ifName,
+ in @utf8InCpp String destination,
+ in @utf8InCpp String nextHop);
+
+ /**
+ * Add a route to legacy routing table for specific network
+ *
+ * @param netId the network to add the route to
+ * @param ifName the name of interface of the route.
+ * This interface should be assigned to the netID.
+ * @param destination the destination of the route
+ * @param nextHop The route's next hop address,
+ * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
+ * @param uid uid of the user
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkAddLegacyRoute(
+ int netId,
+ in @utf8InCpp String ifName,
+ in @utf8InCpp String destination,
+ in @utf8InCpp String nextHop,
+ int uid);
+
+ /**
+ * Remove a route from legacy routing table for specific network
+ *
+ * @param netId the network to remove the route from
+ * @param ifName the name of interface of the route.
+ * This interface should be assigned to the netID.
+ * @param destination the destination of the route
+ * @param nextHop The route's next hop address,
+ * or it could be either NEXTHOP_NONE, NEXTHOP_UNREACHABLE, NEXTHOP_THROW.
+ * @param uid uid of the user
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkRemoveLegacyRoute(
+ int netId,
+ in @utf8InCpp String ifName,
+ in @utf8InCpp String destination,
+ in @utf8InCpp String nextHop,
+ int uid);
+
+ /**
+ * Get default network
+ *
+ * @return netId of default network
+ */
+ int networkGetDefault();
+
+ /**
+ * Set network as default network
+ *
+ * @param netId the network to set as the default
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkSetDefault(int netId);
+
+ /**
+ * Clear default network
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkClearDefault();
+
+ /**
+ * PERMISSION_NONE is used for regular networks and apps. TODO: use PERMISSION_INTERNET
+ * for this instead, and use PERMISSION_NONE to indicate no network permissions at all.
+ */
+ const int PERMISSION_NONE = 0;
+
+ /**
+ * PERMISSION_NETWORK represents the CHANGE_NETWORK_STATE permission.
+ */
+ const int PERMISSION_NETWORK = 1;
+
+ /**
+ * PERMISSION_SYSTEM represents the ability to use restricted networks. This is mostly
+ * equivalent to the CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+ */
+ const int PERMISSION_SYSTEM = 2;
+
+ /**
+ * NO_PERMISSIONS indicates that this app is installed and doesn't have either
+ * PERMISSION_INTERNET or PERMISSION_UPDATE_DEVICE_STATS.
+ * TODO: use PERMISSION_NONE to represent this case
+ */
+ const int NO_PERMISSIONS = 0;
+
+ /**
+ * PERMISSION_INTERNET indicates that the app can create AF_INET and AF_INET6 sockets
+ */
+ const int PERMISSION_INTERNET = 4;
+
+ /**
+ * PERMISSION_UPDATE_DEVICE_STATS is used for system UIDs and privileged apps
+ * that have the UPDATE_DEVICE_STATS permission
+ */
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+
+ /**
+ * PERMISSION_UNINSTALLED is used when an app is uninstalled from the device. All internet
+ * related permissions need to be cleaned
+ */
+ const int PERMISSION_UNINSTALLED = -1;
+
+
+ /**
+ * Sets the permission required to access a specific network.
+ *
+ * @param netId the network to set
+ * @param permission network permission to use
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkSetPermissionForNetwork(int netId, int permission);
+
+ /**
+ * Assigns network access permissions to the specified users.
+ *
+ * @param permission network permission to use
+ * @param uids uid of users to set permission
+ */
+ void networkSetPermissionForUser(int permission, in int[] uids);
+
+ /**
+ * Clears network access permissions for the specified users.
+ *
+ * @param uids uid of users to clear permission
+ */
+ void networkClearPermissionForUser(in int[] uids);
+
+ /**
+ * Assigns android.permission.INTERNET and/or android.permission.UPDATE_DEVICE_STATS to the uids
+ * specified. Or remove all permissions from the uids.
+ *
+ * @param permission The permission to grant, it could be either PERMISSION_INTERNET and/or
+ * PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
+ * revoke all permissions for the uids.
+ * @param uids uid of users to grant permission
+ */
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+
+ /**
+ * Gives the specified user permission to protect sockets from VPNs.
+ * Typically used by VPN apps themselves, to ensure that the sockets
+ * they use to communicate with the VPN server aren't routed through
+ * the VPN network.
+ *
+ * @param uid uid of user to set
+ */
+ void networkSetProtectAllow(int uid);
+
+ /**
+ * Removes the permission to protect sockets from VPN.
+ *
+ * @param uid uid of user to set
+ */
+ void networkSetProtectDeny(int uid);
+
+ /**
+ * Get the status of network protect for user
+ *
+ * @param uids uid of user
+ * @return true if the user can protect sockets from VPN, false otherwise.
+ */
+ boolean networkCanProtect(int uid);
+
+ // Whitelist only allows packets from specific UID/Interface
+ const int FIREWALL_WHITELIST = 0;
+ // Blacklist blocks packets from specific UID/Interface
+ const int FIREWALL_BLACKLIST = 1;
+
+ /**
+ * Set type of firewall
+ * Type whitelist only allows packets from specific UID/Interface
+ * Type blacklist blocks packets from specific UID/Interface
+ *
+ * @param firewalltype type of firewall, either FIREWALL_WHITELIST or FIREWALL_BLACKLIST
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void firewallSetFirewallType(int firewalltype);
+
+ // Specify allow Rule which allows packets
+ const int FIREWALL_RULE_ALLOW = 1;
+ // Specify deny Rule which drops packets
+ const int FIREWALL_RULE_DENY = 2;
+
+ // No specific chain is chosen, use general firewall chain(fw_input, fw_output)
+ const int FIREWALL_CHAIN_NONE = 0;
+ // Specify DOZABLE chain(fw_dozable) which is used in dozable mode
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ // Specify STANDBY chain(fw_standby) which is used in standby mode
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ // Specify POWERSAVE chain(fw_powersave) which is used in power save mode
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+
+ /**
+ * Set firewall rule for interface
+ *
+ * @param ifName the interface to allow/deny
+ * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+
+ /**
+ * Set firewall rule for uid
+ *
+ * @param childChain target chain
+ * @param uid uid to allow/deny
+ * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+
+ /**
+ * Enable/Disable target firewall child chain
+ *
+ * @param childChain target chain to enable
+ * @param enable whether to enable or disable child chain.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void firewallEnableChildChain(int childChain, boolean enable);
+
+ /**
+ * Get interface list
+ *
+ * @return An array of strings containing all the interfaces on the system.
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ @utf8InCpp String[] interfaceGetList();
+
+ // Must be kept in sync with constant in InterfaceConfiguration.java
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+
+ /**
+ * Get interface configuration
+ *
+ * @param ifName interface name
+ * @return An InterfaceConfigurationParcel for the specified interface.
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+
+ /**
+ * Set interface configuration
+ *
+ * @param cfg Interface configuration to set
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void interfaceSetCfg(in InterfaceConfigurationParcel cfg);
+
+ /**
+ * Set interface IPv6 privacy extensions
+ *
+ * @param ifName interface name
+ * @param enable whether to enable or disable this setting.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+
+ /**
+ * Clear all IP addresses on the given interface
+ *
+ * @param ifName interface name
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * POSIX errno.
+ */
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+
+ /**
+ * Enable or disable IPv6 on the given interface
+ *
+ * @param ifName interface name
+ * @param enable whether to enable or disable this setting.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+
+ /**
+ * Set interface MTU
+ *
+ * @param ifName interface name
+ * @param mtu MTU value
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+
+ /**
+ * Add forwarding rule/stats on given interface.
+ *
+ * @param intIface downstream interface
+ * @param extIface upstream interface
+ */
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+
+ /**
+ * Remove forwarding rule/stats on given interface.
+ *
+ * @param intIface downstream interface
+ * @param extIface upstream interface
+ */
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+
+ /**
+ * Set the values of tcp_{rmem,wmem}.
+ *
+ * @param rmemValues the target values of tcp_rmem, each value is separated by spaces
+ * @param wmemValues the target values of tcp_wmem, each value is separated by spaces
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+
+ /**
+ * Register unsolicited event listener
+ * Netd supports multiple unsolicited event listeners.
+ *
+ * @param listener unsolicited event listener to register
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void registerUnsolicitedEventListener(INetdUnsolicitedEventListener listener);
+
+ /**
+ * Add ingress interface filtering rules to a list of UIDs
+ *
+ * For a given uid, once a filtering rule is added, the kernel will only allow packets from the
+ * whitelisted interface and loopback to be sent to the list of UIDs.
+ *
+ * Calling this method on one or more UIDs with an existing filtering rule but a different
+ * interface name will result in the filtering rule being updated to allow the new interface
+ * instead. Otherwise calling this method will not affect existing rules set on other UIDs.
+ *
+ * @param ifName the name of the interface on which the filtering rules will allow packets to
+ be received.
+ * @param uids an array of UIDs which the filtering rules will be set
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
+
+ /**
+ * Remove ingress interface filtering rules from a list of UIDs
+ *
+ * Clear the ingress interface filtering rules from the list of UIDs which were previously set
+ * by firewallAddUidInterfaceRules(). Ignore any uid which does not have filtering rule.
+ *
+ * @param uids an array of UIDs from which the filtering rules will be removed
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void firewallRemoveUidInterfaceRules(in int[] uids);
+
+ /**
+ * Request netd to change the current active network stats map.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void trafficSwapActiveStatsMap();
+
+ /**
+ * Retrieves OEM netd listener interface
+ *
+ * @return a IBinder object, it could be casted to oem specific interface.
+ */
+ IBinder getOemNetd();
+
+ /**
+ * Start tethering with given configuration
+ *
+ * @param config config to start tethering.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherStartWithConfiguration(in TetherConfigParcel config);
+
+
+ /**
+ * Get the fwmark and its net id mask for the given network id.
+ *
+ * @param netId the network to get the fwmark and mask for.
+ * @return A MarkMaskParcel of the given network id.
+ */
+ MarkMaskParcel getFwmarkForNetwork(int netId);
+
+ /**
+ * Add a route for specific network
+ *
+ * @param netId the network to add the route to
+ * @param routeInfo parcelable with route information
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+
+ /**
+ * Update a route for specific network
+ *
+ * @param routeInfo parcelable with route information
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+
+ /**
+ * Remove a route for specific network
+ *
+ * @param routeInfo parcelable with route information
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+
+ /**
+ * Adds a tethering offload rule, or updates it if it already exists.
+ *
+ * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be updated
+ * if the input interface and destination prefix match. Otherwise, a new rule will be created.
+ *
+ * @param rule The rule to add or update.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherOffloadRuleAdd(in TetherOffloadRuleParcel rule);
+
+ /**
+ * Deletes a tethering offload rule.
+ *
+ * Currently, only downstream /128 IPv6 entries are supported. An existing rule will be deleted
+ * if the destination IP address and the source interface match. It is not an error if there is
+ * no matching rule to delete.
+ *
+ * @param rule The rule to delete.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherOffloadRuleRemove(in TetherOffloadRuleParcel rule);
+
+ /**
+ * Return BPF tethering offload statistics.
+ *
+ * @return an array of TetherStatsParcel's, where each entry contains the upstream interface
+ * index and its tethering statistics since tethering was first started.
+ * There will only ever be one entry for a given interface index.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ TetherStatsParcel[] tetherOffloadGetStats();
+
+ /**
+ * Set a per-interface quota for tethering offload.
+ *
+ * @param ifIndex Index of upstream interface
+ * @param quotaBytes The quota defined as the number of bytes, starting from zero and counting
+ * from *now*. A value of QUOTA_UNLIMITED (-1) indicates there is no limit.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
+
+ /**
+ * Return BPF tethering offload statistics and clear the stats for a given upstream.
+ *
+ * Must only be called once all offload rules have already been deleted for the given upstream
+ * interface. The existing stats will be fetched and returned. The stats and the limit for the
+ * given upstream interface will be deleted as well.
+ *
+ * The stats and limit for a given upstream interface must be initialized (using
+ * tetherOffloadSetInterfaceQuota) before any offload will occur on that interface.
+ *
+ * @param ifIndex Index of upstream interface.
+ * @return TetherStatsParcel, which contains the given upstream interface index and its
+ * tethering statistics since tethering was first started on that upstream interface.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
+}
diff --git a/server/binder/android/net/INetdUnsolicitedEventListener.aidl b/server/binder/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..652a79c
--- /dev/null
+++ b/server/binder/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2018, 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.
+ */
+
+package android.net;
+
+/**
+ * Unsolicited netd events which are reported by the kernel via netlink.
+ * This one-way interface groups asynchronous notifications sent
+ * by netd to any process that registered itself via INetd.registerUnsolEventListener.
+ *
+ * {@hide}
+ */
+oneway interface INetdUnsolicitedEventListener {
+
+ /**
+ * Notifies that an interface has been idle/active for a certain period of time.
+ * It is the event for idletimer.
+ *
+ * @param isActive true for active status, false for idle
+ * @param timerLabel unique identifier of the idletimer.
+ * Since NMS only set the identifier as int, only report event with int label.
+ * @param timestampNs kernel timestamp of this event, 0 for no timestamp
+ * @param uid uid of this event, -1 for no uid.
+ * It represents the uid that was responsible for waking the radio.
+ */
+ void onInterfaceClassActivityChanged(
+ boolean isActive,
+ int timerLabel,
+ long timestampNs,
+ int uid);
+
+ /**
+ * Notifies that a specific interface reached its quota limit.
+ *
+ * @param alertName alert name of the quota limit
+ * @param ifName interface which reached the limit
+ */
+ void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+
+ /**
+ * Provides information on IPv6 DNS servers on a specific interface.
+ *
+ * @param ifName interface name
+ * @param lifetimeS lifetime for the DNS servers in seconds
+ * @param servers the address of servers.
+ * e.g. IpV6: "2001:4860:4860::6464"
+ *
+ */
+ void onInterfaceDnsServerInfo(
+ @utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+
+ /**
+ * Notifies that an address has updated on a specific interface.
+ *
+ * @param addr address that is being updated
+ * @param ifName the name of the interface on which the address is configured
+ * @param flags address flags, see ifa_flags in if_addr.h
+ * @param scope current scope of the address
+ */
+ void onInterfaceAddressUpdated(
+ @utf8InCpp String addr,
+ @utf8InCpp String ifName,
+ int flags,
+ int scope);
+
+ /**
+ * Notifies that an address has been removed on a specific interface.
+ *
+ * @param addr address of this change
+ * @param ifName the name of the interface that changed addresses
+ * @param flags address flags, see ifa_flags in if_addr.h
+ * @param scope address address scope
+ */
+ void onInterfaceAddressRemoved(
+ @utf8InCpp String addr,
+ @utf8InCpp String ifName,
+ int flags,
+ int scope);
+
+ /**
+ * Notifies that an interface has been added.
+ *
+ * @param ifName the name of the added interface
+ */
+ void onInterfaceAdded(@utf8InCpp String ifName);
+
+ /**
+ * Notifies that an interface has been removed.
+ *
+ * @param ifName the name of the removed interface
+ */
+ void onInterfaceRemoved(@utf8InCpp String ifName);
+
+ /**
+ * Notifies that the status of the specific interface has changed.
+ *
+ * @param ifName the name of the interface that changed status
+ * @param up true for interface up, false for down
+ */
+ void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+
+ /**
+ * Notifies that the link state of the specific interface has changed.
+ *
+ * @param ifName the name of the interface whose link state has changed
+ * @param up true for interface link state up, false for link state down
+ */
+ void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+
+ /**
+ * Notifies that an IP route has changed.
+ *
+ * @param updated true for update, false for remove
+ * @param route destination prefix of this route, e.g., "2001:db8::/64"
+ * @param gateway address of gateway, empty string for no gateway
+ * @param ifName interface name of this route, empty string for no interface
+ */
+ void onRouteChanged(
+ boolean updated,
+ @utf8InCpp String route,
+ @utf8InCpp String gateway,
+ @utf8InCpp String ifName);
+
+ /**
+ * Notifies that kernel has detected a socket sending data not wrapped
+ * inside a layer of SSL/TLS encryption.
+ *
+ * @param uid uid of this event
+ * @param hex packet content in hex format
+ */
+ void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/server/binder/android/net/InterfaceConfigurationParcel.aidl b/server/binder/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..c20792c
--- /dev/null
+++ b/server/binder/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.net;
+
+/**
+ * Configuration details for a network interface.
+ *
+ * {@hide}
+ */
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ /**
+ * Interface flags, String versions of IFF_* defined in netd/if.h
+ */
+ @utf8InCpp String[] flags;
+}
diff --git a/server/binder/android/net/MarkMaskParcel.aidl b/server/binder/android/net/MarkMaskParcel.aidl
new file mode 100644
index 0000000..932b7bf
--- /dev/null
+++ b/server/binder/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.net;
+
+/**
+ * Structure that stores a firewall mark and its mask.
+ *
+ * {@hide}
+ */
+parcelable MarkMaskParcel {
+ // The fwmark.
+ int mark;
+ // Net id mask of fwmark.
+ int mask;
+}
diff --git a/server/binder/android/net/RouteInfoParcel.aidl b/server/binder/android/net/RouteInfoParcel.aidl
new file mode 100644
index 0000000..fcc86e3
--- /dev/null
+++ b/server/binder/android/net/RouteInfoParcel.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.net;
+
+parcelable RouteInfoParcel {
+ // The destination of the route.
+ @utf8InCpp String destination;
+ // The name of interface of the route. This interface should be assigned to the netID.
+ @utf8InCpp String ifName;
+ // The route's next hop address, or one of the NEXTHOP_* constants defined in INetd.aidl.
+ @utf8InCpp String nextHop;
+ // The MTU of the route.
+ int mtu;
+}
diff --git a/server/binder/android/net/TetherConfigParcel.aidl b/server/binder/android/net/TetherConfigParcel.aidl
new file mode 100644
index 0000000..9f371ce
--- /dev/null
+++ b/server/binder/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.net;
+
+/**
+ * The configuration to start tethering.
+ *
+ * {@hide}
+ */
+parcelable TetherConfigParcel {
+ // Whether to enable or disable legacy DNS proxy server.
+ boolean usingLegacyDnsProxy;
+ // DHCP ranges to set.
+ // dhcpRanges might contain many addresss {addr1, addr2, addr3, addr4...}
+ // Netd splits them into ranges: addr1-addr2, addr3-addr4, etc.
+ // An odd number of addrs will fail.
+ @utf8InCpp String[] dhcpRanges;
+}
diff --git a/server/binder/android/net/TetherOffloadRuleParcel.aidl b/server/binder/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 0000000..c549e61
--- /dev/null
+++ b/server/binder/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.net;
+
+/**
+ * Represents a forwarding rule for tethering offload.
+ *
+ * {@hide}
+ */
+parcelable TetherOffloadRuleParcel {
+ /** The interface index of the input interface. */
+ int inputInterfaceIndex;
+
+ /** The interface index of the output interface. */
+ int outputInterfaceIndex;
+
+ /** The base IP address of the destination prefix as a byte array. */
+ byte[] destination;
+
+ /** The destination prefix length. */
+ int prefixLength;
+
+ /** The source link-layer address. Currently, must be a 6-byte MAC address.*/
+ byte[] srcL2Address;
+
+ /** The destination link-layer address. Currently, must be a 6-byte MAC address. */
+ byte[] dstL2Address;
+
+ /** The outbound path mtu. */
+ int pmtu = 1500;
+}
diff --git a/server/binder/android/net/TetherStatsParcel.aidl b/server/binder/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..6bf60a8
--- /dev/null
+++ b/server/binder/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.net;
+
+/**
+ * The statistics of tethering interface
+ *
+ * {@hide}
+ */
+parcelable TetherStatsParcel {
+ /**
+ * Parcel representing tethering interface statistics.
+ *
+ * This parcel is used by tetherGetStats, tetherOffloadGetStats and
+ * tetherOffloadGetAndClearStats in INetd.aidl. tetherGetStats uses this parcel to return the
+ * tethering statistics since netd startup and presents the interface via its interface name.
+ * Both tetherOffloadGetStats and tetherOffloadGetAndClearStats use this parcel to return
+ * the tethering statistics since tethering was first started. They present the interface via
+ * its interface index. Note that the interface must be presented by either interface name
+ * |iface| or interface index |ifIndex| in this parcel. The unused interface name is set to
+ * an empty string "" by default and the unused interface index is set to 0 by default.
+ */
+
+ /** The interface name. */
+ @utf8InCpp String iface;
+
+ /** Total number of received bytes. */
+ long rxBytes;
+
+ /** Total number of received packets. */
+ long rxPackets;
+
+ /** Total number of transmitted bytes. */
+ long txBytes;
+
+ /** Total number of transmitted packets. */
+ long txPackets;
+
+ /** The interface index. */
+ int ifIndex = 0;
+}
diff --git a/server/binder/android/net/UidRangeParcel.aidl b/server/binder/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..08fd491
--- /dev/null
+++ b/server/binder/android/net/UidRangeParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.net;
+
+/**
+ * An inclusive range of UIDs.
+ *
+ * {@hide}
+ */
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
\ No newline at end of file
diff --git a/server/binder/android/net/metrics/INetdEventListener.aidl b/server/binder/android/net/metrics/INetdEventListener.aidl
new file mode 100644
index 0000000..ef1b2cb
--- /dev/null
+++ b/server/binder/android/net/metrics/INetdEventListener.aidl
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+
+package android.net.metrics;
+
+/**
+ * Logs netd events.
+ *
+ * {@hide}
+ */
+oneway interface INetdEventListener {
+ const int EVENT_GETADDRINFO = 1;
+ const int EVENT_GETHOSTBYNAME = 2;
+ const int EVENT_GETHOSTBYADDR = 3;
+ const int EVENT_RES_NSEND = 4;
+
+ const int REPORTING_LEVEL_NONE = 0;
+ const int REPORTING_LEVEL_METRICS = 1;
+ const int REPORTING_LEVEL_FULL = 2;
+
+ // Maximum number of IP addresses logged for DNS lookups before we truncate the full list.
+ const int DNS_REPORTED_IP_ADDRESSES_LIMIT = 10;
+
+ /**
+ * Logs a DNS lookup function call (getaddrinfo and gethostbyname).
+ *
+ * @param netId the ID of the network the lookup was performed on.
+ * @param eventType one of the EVENT_* constants in this interface.
+ * @param returnCode the return value of the function call.
+ * @param latencyMs the latency of the function call.
+ * @param hostname the name that was looked up.
+ * @param ipAddresses (possibly a subset of) the IP addresses returned.
+ * At most {@link #DNS_REPORTED_IP_ADDRESSES_LIMIT} addresses are logged.
+ * @param ipAddressesCount the number of IP addresses returned. May be different from the length
+ * of ipAddresses if there were too many addresses to log.
+ * @param uid the UID of the application that performed the query.
+ */
+ void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
+ @utf8InCpp String hostname, in @utf8InCpp String[] ipAddresses,
+ int ipAddressesCount, int uid);
+
+ /**
+ * Represents a private DNS validation success or failure.
+ *
+ * @param netId the ID of the network the validation was performed on.
+ * @param ipAddress the IP address for which validation was performed.
+ * @param hostname the hostname for which validation was performed.
+ * @param validated whether or not validation was successful.
+ */
+ void onPrivateDnsValidationEvent(int netId, String ipAddress, String hostname,
+ boolean validated);
+
+ /**
+ * Logs a single connect library call.
+ *
+ * @param netId the ID of the network the connect was performed on.
+ * @param error 0 if the connect call succeeded, otherwise errno if it failed.
+ * @param latencyMs the latency of the connect call.
+ * @param ipAddr destination IP address.
+ * @param port destination port number.
+ * @param uid the UID of the application that performed the connection.
+ */
+ void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, int uid);
+
+ /**
+ * Logs a single RX packet which caused the main CPU to exit sleep state.
+ * @param prefix arbitrary string provided via wakeupAddInterface()
+ * @param uid UID of the destination process or -1 if no UID is available.
+ * @param ethertype of the RX packet encoded in an int in native order, or -1 if not available.
+ * @param ipNextHeader ip protocol of the RX packet as IPPROTO_* number,
+ or -1 if the packet was not IPv4 or IPv6.
+ * @param dstHw destination hardware address, or 0 if not available.
+ * @param srcIp source IP address, or null if not available.
+ * @param dstIp destination IP address, or null if not available.
+ * @param srcPort src port of RX packet in native order, or -1 if the packet was not UDP or TCP.
+ * @param dstPort dst port of RX packet in native order, or -1 if the packet was not UDP or TCP.
+ * @param timestampNs receive timestamp for the offending packet. In units of nanoseconds and
+ * synchronized to CLOCK_MONOTONIC.
+ */
+ void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, in byte[] dstHw,
+ String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs);
+
+ /**
+ * An event sent after every Netlink sock_diag poll performed by Netd. This reported batch
+ * groups TCP socket stats aggregated by network id. Per-network data are stored in a
+ * structure-of-arrays style where networkIds, sentPackets, lostPackets, rttUs, and
+ * sentAckDiffMs have the same length. Stats for the i-th network is spread across all these
+ * arrays at index i.
+ * @param networkIds an array of network ids for which there was tcp socket stats to collect in
+ * the last sock_diag poll.
+ * @param sentPackets an array of packet sent across all TCP sockets still alive and new
+ TCP sockets since the last sock_diag poll, summed per network id.
+ * @param lostPackets, an array of packet lost across all TCP sockets still alive and new
+ TCP sockets since the last sock_diag poll, summed per network id.
+ * @param rttUs an array of smoothed round trip times in microseconds, averaged across all TCP
+ sockets since the last sock_diag poll for a given network id.
+ * @param sentAckDiffMs an array of milliseconds duration between the last packet sent and the
+ last ack received for a socket, averaged across all TCP sockets for a network id.
+ */
+ void onTcpSocketStatsEvent(in int[] networkIds, in int[] sentPackets,
+ in int[] lostPackets, in int[] rttUs, in int[] sentAckDiffMs);
+
+ /**
+ * Represents adding or removing a NAT64 prefix.
+ *
+ * @param netId the ID of the network the prefix was discovered on.
+ * @param added true if the NAT64 prefix was added, or false if the NAT64 prefix was removed.
+ * There is only one prefix at a time for each netId. If a prefix is added, it replaces
+ * the previous-added prefix.
+ * @param prefixString the detected NAT64 prefix as a string literal.
+ * @param prefixLength the prefix length associated with this NAT64 prefix.
+ */
+ void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString,
+ int prefixLength);
+}
diff --git a/server/main.cpp b/server/main.cpp
index bc48ac2..4949ff6 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -110,9 +110,7 @@
gLog.info("netd 1.0 starting");
android::net::process::removePidFile(PID_FILE_PATH);
- gLog.info("Pid file removed");
android::net::process::blockSigPipe();
- gLog.info("SIGPIPE is blocked");
// Before we do anything that could fork, mark CLOEXEC the UNIX sockets that we get from init.
// FrameworkListener does this on initialization as well, but we only initialize these
@@ -120,19 +118,16 @@
for (const auto& sock :
{DNSPROXYLISTENER_SOCKET_NAME, FwmarkServer::SOCKET_NAME, MDnsSdListener::SOCKET_NAME}) {
setCloseOnExec(sock);
- gLog.info("setCloseOnExec(%s)", sock);
}
// Make sure BPF programs are loaded before doing anything
android::bpf::waitForProgsLoaded();
- gLog.info("BPF programs are loaded");
NetlinkManager *nm = NetlinkManager::Instance();
if (nm == nullptr) {
ALOGE("Unable to create NetlinkManager");
exit(1);
};
- gLog.info("NetlinkManager instanced");
gCtls = new android::net::Controllers();
gCtls->init();
diff --git a/tests/Android.bp b/tests/Android.bp
index c5d9bb5..3baaa18 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -13,15 +13,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_test_library {
name: "libnetd_test_tun_interface",
defaults: ["netd_defaults"],
@@ -52,7 +43,7 @@
"libnetutils",
"libsysutils",
"libutils",
- "netd_aidl_interface-V7-cpp",
+ "netd_aidl_interface-cpp",
],
}
@@ -95,7 +86,6 @@
"libnetutils",
"libprocessgroup",
"libssl",
- "libsysutils",
"libutils",
],
static_libs: [
@@ -107,8 +97,8 @@
"libnetdbpf",
"libnetdutils",
"libqtaguid",
- "netd_aidl_interface-V7-cpp",
- "netd_event_listener_interface-V1-cpp",
+ "netd_aidl_interface-unstable-cpp",
+ "netd_event_listener_interface-cpp",
"oemnetd_aidl_interface-cpp",
],
compile_multilib: "both",
@@ -121,7 +111,7 @@
},
},
sanitize: {
- address: false,
+ address: true,
recover: [ "all" ],
},
}
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
index 2aa8df0..c4e8c5f 100644
--- a/tests/benchmarks/Android.bp
+++ b/tests/benchmarks/Android.bp
@@ -1,14 +1,5 @@
// APCT build target for metrics tests
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_netd_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_netd_license"],
-}
-
cc_benchmark {
name: "netd_benchmark",
defaults: ["netd_defaults"],
@@ -22,10 +13,10 @@
],
static_libs: [
"libnetd_test_dnsresponder_ndk",
- "dnsresolver_aidl_interface-lateststable-ndk",
+ "dnsresolver_aidl_interface-lateststable-ndk_platform",
"netd_aidl_interface-lateststable-cpp", // system/netd/server/UidRanges.h
- "netd_aidl_interface-lateststable-ndk",
- "netd_event_listener_interface-lateststable-ndk",
+ "netd_aidl_interface-lateststable-ndk_platform",
+ "netd_event_listener_interface-lateststable-ndk_platform",
],
aidl: {
include_dirs: ["system/netd/server/binder"],
diff --git a/tests/benchmarks/bpf_benchmark.cpp b/tests/benchmarks/bpf_benchmark.cpp
index bf4bd54..12aaf95 100644
--- a/tests/benchmarks/bpf_benchmark.cpp
+++ b/tests/benchmarks/bpf_benchmark.cpp
@@ -34,7 +34,7 @@
};
BENCHMARK_DEFINE_F(BpfBenchMark, MapWriteNewEntry)(benchmark::State& state) {
- for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
+ for (auto _ : state) {
// TODO(b/147676069) assert
mBpfTestMap.writeValue(state.range(0), state.range(0), BPF_NOEXIST);
}
@@ -45,7 +45,7 @@
// TODO(b/147676069) assert
mBpfTestMap.writeValue(i, i, BPF_NOEXIST);
}
- for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
+ for (auto _ : state) {
// TODO(b/147676069) assert
mBpfTestMap.writeValue(state.range(0), state.range(0) + 1, BPF_EXIST);
}
@@ -56,7 +56,7 @@
// TODO(b/147676069) assert
mBpfTestMap.writeValue(i, i, BPF_NOEXIST);
}
- for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
+ for (auto _ : state) {
// TODO(b/147676069) assert
mBpfTestMap.deleteValue(state.range(0));
// TODO(b/147676069) assert
@@ -65,7 +65,7 @@
}
BENCHMARK_DEFINE_F(BpfBenchMark, WaitForRcu)(benchmark::State& state) {
- for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
+ for (auto _ : state) {
int ret = android::bpf::synchronizeKernelRCU();
if (ret) {
state.SkipWithError(
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 22d1f22..2a6bb7c 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -24,10 +24,7 @@
#include <cstdlib>
#include <iostream>
#include <mutex>
-#include <regex>
#include <set>
-#include <string>
-#include <thread>
#include <vector>
#include <dirent.h>
@@ -60,13 +57,11 @@
#include <gtest/gtest.h>
#include <netdbpf/bpf_shared.h>
#include <netutils/ifc.h>
-#include <utils/Errors.h>
#include "Fwmark.h"
#include "InterfaceController.h"
#include "NetdClient.h"
#include "NetdConstants.h"
#include "NetworkController.h"
-#include "RouteController.h"
#include "SockDiag.h"
#include "TestUnsolService.h"
#include "XfrmController.h"
@@ -95,7 +90,6 @@
using android::String8;
using android::base::Join;
using android::base::make_scope_guard;
-using android::base::ReadFdToString;
using android::base::ReadFileToString;
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -105,28 +99,11 @@
using android::net::InterfaceConfigurationParcel;
using android::net::InterfaceController;
using android::net::MarkMaskParcel;
-using android::net::NativeNetworkConfig;
-using android::net::NativeNetworkType;
-using android::net::NativeVpnType;
-using android::net::RULE_PRIORITY_BYPASSABLE_VPN;
-using android::net::RULE_PRIORITY_DEFAULT_NETWORK;
-using android::net::RULE_PRIORITY_EXPLICIT_NETWORK;
-using android::net::RULE_PRIORITY_OUTPUT_INTERFACE;
-using android::net::RULE_PRIORITY_PROHIBIT_NON_VPN;
-using android::net::RULE_PRIORITY_SECURE_VPN;
-using android::net::RULE_PRIORITY_TETHERING;
-using android::net::RULE_PRIORITY_UID_DEFAULT_NETWORK;
-using android::net::RULE_PRIORITY_UID_DEFAULT_UNREACHABLE;
-using android::net::RULE_PRIORITY_UID_EXPLICIT_NETWORK;
-using android::net::RULE_PRIORITY_UID_IMPLICIT_NETWORK;
-using android::net::RULE_PRIORITY_VPN_FALLTHROUGH;
using android::net::SockDiag;
using android::net::TetherOffloadRuleParcel;
using android::net::TetherStatsParcel;
using android::net::TunInterface;
using android::net::UidRangeParcel;
-using android::net::UidRanges;
-using android::net::netd::aidl::NativeUidRangeConfig;
using android::netdutils::IPAddress;
using android::netdutils::ScopedAddrinfo;
using android::netdutils::sSyscalls;
@@ -136,29 +113,18 @@
static const char* IP_RULE_V6 = "-6";
static const int TEST_NETID1 = 65501;
static const int TEST_NETID2 = 65502;
-static const int TEST_NETID3 = 65503;
-static const int TEST_NETID4 = 65504;
-static const int TEST_DUMP_NETID = 65123;
static const char* DNSMASQ = "dnsmasq";
// Use maximum reserved appId for applications to avoid conflict with existing
// uids.
static const int TEST_UID1 = 99999;
static const int TEST_UID2 = 99998;
-static const int TEST_UID3 = 99997;
-static const int TEST_UID4 = 99996;
-static const int TEST_UID5 = 99995;
-static const int TEST_UID6 = 99994;
constexpr int BASE_UID = AID_USER_OFFSET * 5;
static const std::string NO_SOCKET_ALLOW_RULE("! owner UID match 0-4294967294");
static const std::string ESP_ALLOW_RULE("esp");
-static const in6_addr V6_ADDR = {
- {// 2001:db8:cafe::8888
- .u6_addr8 = {0x20, 0x01, 0x0d, 0xb8, 0xca, 0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88}}};
-
class NetdBinderTest : public ::testing::Test {
public:
NetdBinderTest() {
@@ -176,8 +142,6 @@
void TearDown() override {
mNetd->networkDestroy(TEST_NETID1);
mNetd->networkDestroy(TEST_NETID2);
- mNetd->networkDestroy(TEST_NETID3);
- mNetd->networkDestroy(TEST_NETID4);
setNetworkForProcess(NETID_UNSET);
// Restore default network
if (mStoredDefaultNetwork >= 0) mNetd->networkSetDefault(mStoredDefaultNetwork);
@@ -189,20 +153,14 @@
static void SetUpTestCase() {
ASSERT_EQ(0, sTun.init());
ASSERT_EQ(0, sTun2.init());
- ASSERT_EQ(0, sTun3.init());
- ASSERT_EQ(0, sTun4.init());
ASSERT_LE(sTun.name().size(), static_cast<size_t>(IFNAMSIZ));
ASSERT_LE(sTun2.name().size(), static_cast<size_t>(IFNAMSIZ));
- ASSERT_LE(sTun3.name().size(), static_cast<size_t>(IFNAMSIZ));
- ASSERT_LE(sTun4.name().size(), static_cast<size_t>(IFNAMSIZ));
}
static void TearDownTestCase() {
// Closing the socket removes the interface and IP addresses.
sTun.destroy();
sTun2.destroy();
- sTun3.destroy();
- sTun4.destroy();
}
static void fakeRemoteSocketPair(unique_fd* clientSocket, unique_fd* serverSocket,
@@ -211,22 +169,6 @@
void createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetId = TEST_NETID2,
int fallthroughNetId = TEST_NETID1);
- void createAndSetDefaultNetwork(int netId, const std::string& interface,
- int permission = INetd::PERMISSION_NONE);
-
- void createPhysicalNetwork(int netId, const std::string& interface,
- int permission = INetd::PERMISSION_NONE);
-
- void createDefaultAndOtherPhysicalNetwork(int defaultNetId, int otherNetId);
-
- void createVpnAndOtherPhysicalNetwork(int systemDefaultNetId, int otherNetId, int vpnNetId,
- bool secure);
-
- void createVpnAndAppDefaultNetworkWithUid(int systemDefaultNetId, int appDefaultNetId,
- int vpnNetId, bool secure,
- std::vector<UidRangeParcel>&& appDefaultUidRanges,
- std::vector<UidRangeParcel>&& vpnUidRanges);
-
protected:
// Use -1 to represent that default network was not modified because
// real netId must be an unsigned value.
@@ -234,14 +176,10 @@
sp<INetd> mNetd;
static TunInterface sTun;
static TunInterface sTun2;
- static TunInterface sTun3;
- static TunInterface sTun4;
};
TunInterface NetdBinderTest::sTun;
TunInterface NetdBinderTest::sTun2;
-TunInterface NetdBinderTest::sTun3;
-TunInterface NetdBinderTest::sTun4;
class TimedOperation : public Stopwatch {
public:
@@ -261,62 +199,67 @@
ASSERT_TRUE(isAlive);
}
-namespace {
-
-NativeNetworkConfig makeNativeNetworkConfig(int netId, NativeNetworkType networkType,
- int permission, bool secure) {
- NativeNetworkConfig config = {};
- config.netId = netId;
- config.networkType = networkType;
- config.permission = permission;
- config.secure = secure;
- // The vpnType doesn't matter in AOSP. Just pick a well defined one from INetd.
- config.vpnType = NativeVpnType::PLATFORM;
- return config;
+static bool iptablesNoSocketAllowRuleExists(const char *chainName){
+ return iptablesRuleExists(IPTABLES_PATH, chainName, NO_SOCKET_ALLOW_RULE) &&
+ iptablesRuleExists(IP6TABLES_PATH, chainName, NO_SOCKET_ALLOW_RULE);
}
-} // namespace
+static bool iptablesEspAllowRuleExists(const char *chainName){
+ return iptablesRuleExists(IPTABLES_PATH, chainName, ESP_ALLOW_RULE) &&
+ iptablesRuleExists(IP6TABLES_PATH, chainName, ESP_ALLOW_RULE);
+}
-bool testNetworkExistsButCannotConnect(const sp<INetd>& netd, TunInterface& ifc, const int netId) {
- // If this network exists, we should definitely not be able to create it.
- // Note that this networkCreate is never allowed to create reserved network IDs, so
- // this call may fail for other reasons than the network already existing.
- const auto& config = makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_FALSE(netd->networkCreate(config).isOk());
- // Test if the network exist by adding interface. INetd has no dedicated method to query. When
- // the network exists and the interface can be added, the function succeeds. When the network
- // exists but the interface cannot be added, it fails with EINVAL, otherwise it is ENONET.
- binder::Status status = netd->networkAddInterface(netId, ifc.name());
- if (status.isOk()) { // clean up
- EXPECT_TRUE(netd->networkRemoveInterface(netId, ifc.name()).isOk());
- } else if (status.serviceSpecificErrorCode() == ENONET) {
- return false;
+TEST_F(NetdBinderTest, FirewallReplaceUidChain) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ std::string chainName = StringPrintf("netd_binder_test_%u", arc4random_uniform(10000));
+ const int kNumUids = 500;
+ std::vector<int32_t> noUids(0);
+ std::vector<int32_t> uids(kNumUids);
+ for (int i = 0; i < kNumUids; i++) {
+ uids[i] = randomUid();
}
- const sockaddr_in6 sin6 = {.sin6_family = AF_INET6,
- .sin6_addr = {{.u6_addr32 = {htonl(0x20010db8), 0, 0, 0}}},
- .sin6_port = 53};
- const int s = socket(AF_INET6, SOCK_DGRAM, 0);
- EXPECT_NE(-1, s);
- if (s == -1) return true;
- Fwmark fwmark;
- fwmark.explicitlySelected = true;
- fwmark.netId = netId;
- EXPECT_EQ(0, setsockopt(s, SOL_SOCKET, SO_MARK, &fwmark.intValue, sizeof(fwmark.intValue)));
- const int ret = connect(s, (struct sockaddr*)&sin6, sizeof(sin6));
- const int err = errno;
- EXPECT_EQ(-1, ret);
- EXPECT_EQ(ENETUNREACH, err);
- close(s);
- return true;
-}
+ bool ret;
+ {
+ TimedOperation op(StringPrintf("Programming %d-UID whitelist chain", kNumUids));
+ mNetd->firewallReplaceUidChain(chainName, true, uids, &ret);
+ }
+ EXPECT_EQ(true, ret);
+ EXPECT_EQ((int) uids.size() + 9, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+ EXPECT_EQ((int) uids.size() + 15, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
+ EXPECT_EQ(true, iptablesNoSocketAllowRuleExists(chainName.c_str()));
+ EXPECT_EQ(true, iptablesEspAllowRuleExists(chainName.c_str()));
+ {
+ TimedOperation op("Clearing whitelist chain");
+ mNetd->firewallReplaceUidChain(chainName, false, noUids, &ret);
+ }
+ EXPECT_EQ(true, ret);
+ EXPECT_EQ(5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+ EXPECT_EQ(5, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
-TEST_F(NetdBinderTest, InitialNetworksExist) {
- EXPECT_TRUE(testNetworkExistsButCannotConnect(mNetd, sTun, INetd::DUMMY_NET_ID));
- EXPECT_TRUE(testNetworkExistsButCannotConnect(mNetd, sTun, INetd::LOCAL_NET_ID));
- EXPECT_TRUE(testNetworkExistsButCannotConnect(mNetd, sTun, INetd::UNREACHABLE_NET_ID));
- EXPECT_FALSE(testNetworkExistsButCannotConnect(mNetd, sTun, 77 /* not exist */));
+ {
+ TimedOperation op(StringPrintf("Programming %d-UID blacklist chain", kNumUids));
+ mNetd->firewallReplaceUidChain(chainName, false, uids, &ret);
+ }
+ EXPECT_EQ(true, ret);
+ EXPECT_EQ((int) uids.size() + 5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+ EXPECT_EQ((int) uids.size() + 5, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
+ EXPECT_EQ(false, iptablesNoSocketAllowRuleExists(chainName.c_str()));
+ EXPECT_EQ(false, iptablesEspAllowRuleExists(chainName.c_str()));
+
+ {
+ TimedOperation op("Clearing blacklist chain");
+ mNetd->firewallReplaceUidChain(chainName, false, noUids, &ret);
+ }
+ EXPECT_EQ(true, ret);
+ EXPECT_EQ(5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+ EXPECT_EQ(5, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
+
+ // Check that the call fails if iptables returns an error.
+ std::string veryLongStringName = "netd_binder_test_UnacceptablyLongIptablesChainName";
+ mNetd->firewallReplaceUidChain(veryLongStringName, true, noUids, &ret);
+ EXPECT_EQ(false, ret);
}
TEST_F(NetdBinderTest, IpSecTunnelInterface) {
@@ -564,22 +507,14 @@
}
static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
- const std::string& action, const char* ipVersion,
- const char* oif) {
+ const std::string& action, const char* ipVersion) {
// Output looks like this:
- // "<priority>:\tfrom all iif lo oif netdc0ca6 uidrange 500000-500000 lookup netdc0ca6"
- // "<priority>:\tfrom all fwmark 0x0/0x20000 iif lo uidrange 1000-2000 prohibit"
+ // "12500:\tfrom all fwmark 0x0/0x20000 iif lo uidrange 1000-2000 prohibit"
std::vector<std::string> rules = listIpRules(ipVersion);
std::string prefix = StringPrintf("%" PRIu32 ":", priority);
- std::string suffix;
- if (oif) {
- suffix = StringPrintf(" iif lo oif %s uidrange %d-%d %s\n", oif, range.start, range.stop,
- action.c_str());
- } else {
- suffix = StringPrintf(" iif lo uidrange %d-%d %s\n", range.start, range.stop,
- action.c_str());
- }
+ std::string suffix =
+ StringPrintf(" iif lo uidrange %d-%d %s\n", range.start, range.stop, action.c_str());
for (const auto& line : rules) {
if (android::base::StartsWith(line, prefix) && android::base::EndsWith(line, suffix)) {
return true;
@@ -588,18 +523,12 @@
return false;
}
-// Overloads function with oif parameter for VPN rules compare.
-static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
- const std::string& action, const char* oif) {
- bool existsIp4 = ipRuleExistsForRange(priority, range, action, IP_RULE_V4, oif);
- bool existsIp6 = ipRuleExistsForRange(priority, range, action, IP_RULE_V6, oif);
- EXPECT_EQ(existsIp4, existsIp6);
- return existsIp4;
-}
-
static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
const std::string& action) {
- return ipRuleExistsForRange(priority, range, action, nullptr);
+ bool existsIp4 = ipRuleExistsForRange(priority, range, action, IP_RULE_V4);
+ bool existsIp6 = ipRuleExistsForRange(priority, range, action, IP_RULE_V6);
+ EXPECT_EQ(existsIp4, existsIp6);
+ return existsIp4;
}
namespace {
@@ -612,31 +541,14 @@
return res;
}
-NativeUidRangeConfig makeNativeUidRangeConfig(unsigned netId,
- std::vector<UidRangeParcel>&& uidRanges,
- uint32_t subPriority) {
- NativeUidRangeConfig res;
- res.netId = netId;
- res.uidRanges = uidRanges;
- res.subPriority = subPriority;
-
- return res;
-}
-
} // namespace
TEST_F(NetdBinderTest, NetworkInterfaces) {
- auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
-
- config.networkType = NativeNetworkType::VIRTUAL;
- config.secure = true;
- EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
-
- config.netId = TEST_NETID2;
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ EXPECT_EQ(EEXIST, mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE)
+ .serviceSpecificErrorCode());
+ EXPECT_EQ(EEXIST, mNetd->networkCreateVpn(TEST_NETID1, true).serviceSpecificErrorCode());
+ EXPECT_TRUE(mNetd->networkCreateVpn(TEST_NETID2, true).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
EXPECT_EQ(EBUSY,
@@ -649,49 +561,51 @@
}
TEST_F(NetdBinderTest, NetworkUidRules) {
- auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::VIRTUAL,
- INetd::PERMISSION_NONE, true);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
+ const uint32_t RULE_PRIORITY_SECURE_VPN = 12000;
+
+ EXPECT_TRUE(mNetd->networkCreateVpn(TEST_NETID1, true).isOk());
+ EXPECT_EQ(EEXIST, mNetd->networkCreateVpn(TEST_NETID1, true).serviceSpecificErrorCode());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
std::vector<UidRangeParcel> uidRanges = {makeUidRangeParcel(BASE_UID + 8005, BASE_UID + 8012),
makeUidRangeParcel(BASE_UID + 8090, BASE_UID + 8099)};
UidRangeParcel otherRange = makeUidRangeParcel(BASE_UID + 8190, BASE_UID + 8299);
- std::string action = StringPrintf("lookup %s ", sTun.name().c_str());
+ std::string suffix = StringPrintf("lookup %s ", sTun.name().c_str());
EXPECT_TRUE(mNetd->networkAddUidRanges(TEST_NETID1, uidRanges).isOk());
- EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], action));
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, otherRange, action));
+ EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], suffix));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, otherRange, suffix));
EXPECT_TRUE(mNetd->networkRemoveUidRanges(TEST_NETID1, uidRanges).isOk());
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], action));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], suffix));
EXPECT_TRUE(mNetd->networkAddUidRanges(TEST_NETID1, uidRanges).isOk());
- EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], action));
+ EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], suffix));
EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], action));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], suffix));
EXPECT_EQ(ENONET, mNetd->networkDestroy(TEST_NETID1).serviceSpecificErrorCode());
}
TEST_F(NetdBinderTest, NetworkRejectNonSecureVpn) {
+ constexpr uint32_t RULE_PRIORITY = 12500;
+
std::vector<UidRangeParcel> uidRanges = {makeUidRangeParcel(BASE_UID + 150, BASE_UID + 224),
makeUidRangeParcel(BASE_UID + 226, BASE_UID + 300)};
// Make sure no rules existed before calling commands.
for (auto const& range : uidRanges) {
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_PROHIBIT_NON_VPN, range, "prohibit"));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit"));
}
// Create two valid rules.
ASSERT_TRUE(mNetd->networkRejectNonSecureVpn(true, uidRanges).isOk());
for (auto const& range : uidRanges) {
- EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_PROHIBIT_NON_VPN, range, "prohibit"));
+ EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit"));
}
// Remove the rules.
ASSERT_TRUE(mNetd->networkRejectNonSecureVpn(false, uidRanges).isOk());
for (auto const& range : uidRanges) {
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_PROHIBIT_NON_VPN, range, "prohibit"));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit"));
}
// Fail to remove the rules a second time after they are already deleted.
@@ -788,72 +702,6 @@
checkSocketpairClosed(clientSocket, acceptedSocket);
}
-TEST_F(NetdBinderTest, SocketDestroyLinkLocal) {
- // Add the same link-local address to two interfaces.
- const char* kLinkLocalAddress = "fe80::ace:d00d";
-
- const struct addrinfo hints = {
- .ai_family = AF_INET6,
- .ai_socktype = SOCK_STREAM,
- .ai_flags = AI_NUMERICHOST,
- };
-
- binder::Status status = mNetd->interfaceAddAddress(sTun.name(), kLinkLocalAddress, 64);
- EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- status = mNetd->interfaceAddAddress(sTun2.name(), kLinkLocalAddress, 64);
- EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-
- // Bind a listening socket to the address on each of two interfaces.
- // The sockets must be open at the same time, because this test checks that SOCK_DESTROY only
- // destroys the sockets on the interface where the address is deleted.
- struct addrinfo* addrinfoList = nullptr;
- int ret = getaddrinfo(kLinkLocalAddress, nullptr, &hints, &addrinfoList);
- ScopedAddrinfo addrinfoCleanup(addrinfoList);
- ASSERT_EQ(0, ret);
-
- socklen_t len = addrinfoList[0].ai_addrlen;
- sockaddr_in6 sin6_1 = *reinterpret_cast<sockaddr_in6*>(addrinfoList[0].ai_addr);
- sockaddr_in6 sin6_2 = sin6_1;
- sin6_1.sin6_scope_id = if_nametoindex(sTun.name().c_str());
- sin6_2.sin6_scope_id = if_nametoindex(sTun2.name().c_str());
-
- int s1 = socket(AF_INET6, SOCK_STREAM, 0);
- ASSERT_EQ(0, bind(s1, reinterpret_cast<sockaddr*>(&sin6_1), len));
- ASSERT_EQ(0, getsockname(s1, reinterpret_cast<sockaddr*>(&sin6_1), &len));
-
- int s2 = socket(AF_INET6, SOCK_STREAM, 0);
- ASSERT_EQ(0, bind(s2, reinterpret_cast<sockaddr*>(&sin6_2), len));
- ASSERT_EQ(0, getsockname(s2, reinterpret_cast<sockaddr*>(&sin6_2), &len));
-
- ASSERT_EQ(0, listen(s1, 10));
- ASSERT_EQ(0, listen(s2, 10));
-
- // Connect one client socket to each and accept the connections.
- int c1 = socket(AF_INET6, SOCK_STREAM, 0);
- int c2 = socket(AF_INET6, SOCK_STREAM, 0);
- ASSERT_EQ(0, connect(c1, reinterpret_cast<sockaddr*>(&sin6_1), len));
- ASSERT_EQ(0, connect(c2, reinterpret_cast<sockaddr*>(&sin6_2), len));
- int a1 = accept(s1, nullptr, 0);
- ASSERT_NE(-1, a1);
- int a2 = accept(s2, nullptr, 0);
- ASSERT_NE(-1, a2);
-
- // Delete the address on sTun2.
- status = mNetd->interfaceDelAddress(sTun2.name(), kLinkLocalAddress, 64);
- EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-
- // The sockets on sTun2 are closed, but the ones on sTun1 remain open.
- char buf[1024];
- EXPECT_EQ(-1, read(c2, buf, sizeof(buf)));
- EXPECT_EQ(ECONNABORTED, errno);
- // The blocking read above ensures that SOCK_DESTROY has completed.
-
- EXPECT_EQ(3, write(a1, "foo", 3));
- EXPECT_EQ(3, read(c1, buf, sizeof(buf)));
- EXPECT_EQ(-1, write(a2, "foo", 3));
- EXPECT_TRUE(errno == ECONNABORTED || errno == ECONNRESET);
-}
-
namespace {
int netmaskToPrefixLength(const uint8_t *buf, size_t buflen) {
@@ -972,7 +820,6 @@
{"2001:db8::1", 64, 0, 0},
{"2001:db8::2", 65, 0, 0},
{"2001:db8::3", 128, 0, 0},
- {"fe80::1234", 64, 0, 0},
{"2001:db8::4", 129, EINVAL, EINVAL},
{"foo:bar::bad", 64, EINVAL, EINVAL},
{"2001:db8::1/64", 64, EINVAL, EINVAL},
@@ -1028,7 +875,7 @@
}
TEST_F(NetdBinderTest, GetProcSysNet) {
- const char* LOOPBACK = "lo";
+ const char LOOPBACK[] = "lo";
static const struct {
const int ipversion;
const int which;
@@ -1243,7 +1090,7 @@
void expectIdletimerInterfaceRuleExists(const std::string& ifname, int timeout,
const std::string& classLabel) {
std::string IdletimerRule =
- StringPrintf("timeout:%u label:%s send_nl_msg", timeout, classLabel.c_str());
+ StringPrintf("timeout:%u label:%s send_nl_msg:1", timeout, classLabel.c_str());
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
EXPECT_TRUE(iptablesIdleTimerInterfaceRuleExists(binary, IDLETIMER_RAW_PREROUTING, ifname,
IdletimerRule, RAW_TABLE));
@@ -1255,7 +1102,7 @@
void expectIdletimerInterfaceRuleNotExists(const std::string& ifname, int timeout,
const std::string& classLabel) {
std::string IdletimerRule =
- StringPrintf("timeout:%u label:%s send_nl_msg", timeout, classLabel.c_str());
+ StringPrintf("timeout:%u label:%s send_nl_msg:1", timeout, classLabel.c_str());
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
EXPECT_FALSE(iptablesIdleTimerInterfaceRuleExists(binary, IDLETIMER_RAW_PREROUTING, ifname,
IdletimerRule, RAW_TABLE));
@@ -1408,9 +1255,7 @@
EXPECT_EQ(ENODEV, status.serviceSpecificErrorCode());
// ... so create a test physical network and add our tun to it.
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Prefix must be 96 bits long.
@@ -1500,8 +1345,7 @@
}
void expectIpfwdRuleExists(const char* fromIf, const char* toIf) {
- std::string ipfwdRule =
- StringPrintf("%u:\tfrom all iif %s lookup %s ", RULE_PRIORITY_TETHERING, fromIf, toIf);
+ std::string ipfwdRule = StringPrintf("18000:\tfrom all iif %s lookup %s ", fromIf, toIf);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_TRUE(ipRuleIpfwdExists(ipVersion, ipfwdRule));
@@ -1509,8 +1353,7 @@
}
void expectIpfwdRuleNotExists(const char* fromIf, const char* toIf) {
- std::string ipfwdRule =
- StringPrintf("%u:\tfrom all iif %s lookup %s ", RULE_PRIORITY_TETHERING, fromIf, toIf);
+ std::string ipfwdRule = StringPrintf("18000:\tfrom all iif %s lookup %s ", fromIf, toIf);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_FALSE(ipRuleIpfwdExists(ipVersion, ipfwdRule));
@@ -1574,13 +1417,9 @@
TEST_F(NetdBinderTest, TestIpfwdAddRemoveInterfaceForward) {
// Add test physical network
- auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
-
- config.netId = TEST_NETID2;
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID2, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID2, sTun2.name()).isOk());
binder::Status status = mNetd->ipfwdAddInterfaceForward(sTun.name(), sTun2.name());
@@ -1598,6 +1437,7 @@
constexpr char BANDWIDTH_OUTPUT[] = "bw_OUTPUT";
constexpr char BANDWIDTH_FORWARD[] = "bw_FORWARD";
constexpr char BANDWIDTH_NAUGHTY[] = "bw_penalty_box";
+constexpr char BANDWIDTH_NICE[] = "bw_happy_box";
constexpr char BANDWIDTH_ALERT[] = "bw_global_alert";
// TODO: Move iptablesTargetsExists and listIptablesRuleByTable to the top.
@@ -1690,15 +1530,29 @@
expectXtQuotaValueEqual(globalAlertName, alertBytes);
}
+void expectBandwidthManipulateSpecialAppRuleExists(const char* chain, const char* target, int uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesTargetsExists(binary, 1, FILTER_TABLE, chain, target, uidRule));
+ }
+}
+
+void expectBandwidthManipulateSpecialAppRuleDoesNotExist(const char* chain, int uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesRuleExists(binary, chain, uidRule));
+ }
+}
+
} // namespace
TEST_F(NetdBinderTest, BandwidthSetRemoveInterfaceQuota) {
long testQuotaBytes = 5550;
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
binder::Status status = mNetd->bandwidthSetInterfaceQuota(sTun.name(), testQuotaBytes);
@@ -1716,9 +1570,7 @@
TEST_F(NetdBinderTest, BandwidthSetRemoveInterfaceAlert) {
long testAlertBytes = 373;
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Need to have a prior interface quota set to set an alert
binder::Status status = mNetd->bandwidthSetInterfaceQuota(sTun.name(), testAlertBytes);
@@ -1752,6 +1604,34 @@
expectBandwidthGlobalAlertRuleExists(testAlertBytes);
}
+TEST_F(NetdBinderTest, BandwidthManipulateSpecialApp) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ int32_t uid = randomUid();
+ static const char targetReject[] = "REJECT";
+ static const char targetReturn[] = "RETURN";
+
+ // add NaughtyApp
+ binder::Status status = mNetd->bandwidthAddNaughtyApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleExists(BANDWIDTH_NAUGHTY, targetReject, uid);
+
+ // remove NaughtyApp
+ status = mNetd->bandwidthRemoveNaughtyApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleDoesNotExist(BANDWIDTH_NAUGHTY, uid);
+
+ // add NiceApp
+ status = mNetd->bandwidthAddNiceApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleExists(BANDWIDTH_NICE, targetReturn, uid);
+
+ // remove NiceApp
+ status = mNetd->bandwidthRemoveNiceApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleDoesNotExist(BANDWIDTH_NICE, uid);
+}
+
namespace {
std::string ipRouteString(const std::string& ifName, const std::string& dst,
@@ -1815,8 +1695,7 @@
void expectNetworkDefaultIpRuleExists(const char* ifName) {
std::string networkDefaultRule =
- StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo lookup %s",
- RULE_PRIORITY_DEFAULT_NETWORK, ifName);
+ StringPrintf("22000:\tfrom all fwmark 0x0/0xffff iif lo lookup %s", ifName);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_TRUE(ipRuleExists(ipVersion, networkDefaultRule));
@@ -1824,8 +1703,7 @@
}
void expectNetworkDefaultIpRuleDoesNotExist() {
- std::string networkDefaultRule =
- StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo", RULE_PRIORITY_DEFAULT_NETWORK);
+ static const char networkDefaultRule[] = "22000:\tfrom all fwmark 0x0/0xffff iif lo";
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_FALSE(ipRuleExists(ipVersion, networkDefaultRule));
@@ -1836,19 +1714,16 @@
std::string networkPermissionRule = "";
switch (permission) {
case INetd::PERMISSION_NONE:
- networkPermissionRule =
- StringPrintf("%u:\tfrom all fwmark 0x1ffdd/0x1ffff iif lo lookup %s",
- RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
+ networkPermissionRule = StringPrintf(
+ "13000:\tfrom all fwmark 0x1ffdd/0x1ffff iif lo lookup %s", ifName);
break;
case INetd::PERMISSION_NETWORK:
- networkPermissionRule =
- StringPrintf("%u:\tfrom all fwmark 0x5ffdd/0x5ffff iif lo lookup %s",
- RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
+ networkPermissionRule = StringPrintf(
+ "13000:\tfrom all fwmark 0x5ffdd/0x5ffff iif lo lookup %s", ifName);
break;
case INetd::PERMISSION_SYSTEM:
- networkPermissionRule =
- StringPrintf("%u:\tfrom all fwmark 0xdffdd/0xdffff iif lo lookup %s",
- RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
+ networkPermissionRule = StringPrintf(
+ "13000:\tfrom all fwmark 0xdffdd/0xdffff iif lo lookup %s", ifName);
break;
}
@@ -1929,9 +1804,7 @@
const std::vector<int32_t> testUids = {testUid};
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Setup route for testing nextHop
@@ -2085,9 +1958,7 @@
TEST_F(NetdBinderTest, NetworkPermissionDefault) {
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Get current default network NetId
@@ -2408,8 +2279,13 @@
constexpr char FIREWALL_INPUT[] = "fw_INPUT";
constexpr char FIREWALL_OUTPUT[] = "fw_OUTPUT";
constexpr char FIREWALL_FORWARD[] = "fw_FORWARD";
+constexpr char FIREWALL_DOZABLE[] = "fw_dozable";
+constexpr char FIREWALL_POWERSAVE[] = "fw_powersave";
+constexpr char FIREWALL_STANDBY[] = "fw_standby";
+constexpr char targetReturn[] = "RETURN";
+constexpr char targetDrop[] = "DROP";
-void expectFirewallAllowlistMode() {
+void expectFirewallWhitelistMode() {
static const char dropRule[] = "DROP all";
static const char rejectRule[] = "REJECT all";
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
@@ -2419,7 +2295,7 @@
}
}
-void expectFirewallDenylistMode() {
+void expectFirewallBlacklistMode() {
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_INPUT));
EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_OUTPUT));
@@ -2481,45 +2357,126 @@
}
}
+bool iptablesFirewallUidFirstRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedTarget,
+ const std::string& expectedRule) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, FILTER_TABLE, chainName);
+ int firstRuleIndex = 2;
+ if (rules.size() < 4) return false;
+ if (rules[firstRuleIndex].find(expectedTarget) != std::string::npos) {
+ if (rules[firstRuleIndex].find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool iptablesFirewallUidLastRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedTarget,
+ const std::string& expectedRule) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, FILTER_TABLE, chainName);
+ int lastRuleIndex = rules.size() - 1;
+ if (lastRuleIndex < 0) return false;
+ if (rules[lastRuleIndex].find(expectedTarget) != std::string::npos) {
+ if (rules[lastRuleIndex].find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void expectFirewallUidFirstRuleExists(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_TRUE(iptablesFirewallUidFirstRuleExists(binary, chainName, targetReturn, uidRule));
+}
+
+void expectFirewallUidFirstRuleDoesNotExist(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_FALSE(iptablesFirewallUidFirstRuleExists(binary, chainName, targetReturn, uidRule));
+}
+
+void expectFirewallUidLastRuleExists(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_TRUE(iptablesFirewallUidLastRuleExists(binary, chainName, targetDrop, uidRule));
+}
+
+void expectFirewallUidLastRuleDoesNotExist(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_FALSE(iptablesFirewallUidLastRuleExists(binary, chainName, targetDrop, uidRule));
+}
+
+bool iptablesFirewallChildChainsLastRuleExists(const char* binary, const char* chainName) {
+ std::vector<std::string> inputRules =
+ listIptablesRuleByTable(binary, FILTER_TABLE, FIREWALL_INPUT);
+ std::vector<std::string> outputRules =
+ listIptablesRuleByTable(binary, FILTER_TABLE, FIREWALL_OUTPUT);
+ int inputLastRuleIndex = inputRules.size() - 1;
+ int outputLastRuleIndex = outputRules.size() - 1;
+
+ if (inputLastRuleIndex < 0 || outputLastRuleIndex < 0) return false;
+ if (inputRules[inputLastRuleIndex].find(chainName) != std::string::npos) {
+ if (outputRules[outputLastRuleIndex].find(chainName) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void expectFirewallChildChainsLastRuleExists(const char* chainRule) {
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_TRUE(iptablesFirewallChildChainsLastRuleExists(binary, chainRule));
+}
+
+void expectFirewallChildChainsLastRuleDoesNotExist(const char* chainRule) {
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesRuleExists(binary, FIREWALL_INPUT, chainRule));
+ EXPECT_FALSE(iptablesRuleExists(binary, FIREWALL_OUTPUT, chainRule));
+ }
+}
+
} // namespace
TEST_F(NetdBinderTest, FirewallSetFirewallType) {
- binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
+ binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallAllowlistMode();
+ expectFirewallWhitelistMode();
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallDenylistMode();
+ expectFirewallBlacklistMode();
// set firewall type blacklist twice
- mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
+ mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallDenylistMode();
+ expectFirewallBlacklistMode();
// set firewall type whitelist twice
- mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
+ mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallAllowlistMode();
+ expectFirewallWhitelistMode();
// reset firewall type to default
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallDenylistMode();
+ expectFirewallBlacklistMode();
}
TEST_F(NetdBinderTest, FirewallSetInterfaceRule) {
// setinterfaceRule is not supported in BLACKLIST MODE
- binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
+ binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
status = mNetd->firewallSetInterfaceRule(sTun.name(), INetd::FIREWALL_RULE_ALLOW);
EXPECT_FALSE(status.isOk()) << status.exceptionMessage();
// set WHITELIST mode first
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
status = mNetd->firewallSetInterfaceRule(sTun.name(), INetd::FIREWALL_RULE_ALLOW);
@@ -2531,9 +2488,113 @@
expectFireWallInterfaceRuleAllowDoesNotExist(sTun.name());
// reset firewall mode to default
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallDenylistMode();
+ expectFirewallBlacklistMode();
+}
+
+TEST_F(NetdBinderTest, FirewallSetUidRule) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ int32_t uid = randomUid();
+
+ // Doze allow
+ binder::Status status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_DOZABLE, uid,
+ INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleExists(FIREWALL_DOZABLE, uid);
+
+ // Doze deny
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_DOZABLE, uid,
+ INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_DOZABLE, uid);
+
+ // Powersave allow
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_POWERSAVE, uid,
+ INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleExists(FIREWALL_POWERSAVE, uid);
+
+ // Powersave deny
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_POWERSAVE, uid,
+ INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_POWERSAVE, uid);
+
+ // Standby deny
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_STANDBY, uid,
+ INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleExists(FIREWALL_STANDBY, uid);
+
+ // Standby allow
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_STANDBY, uid,
+ INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleDoesNotExist(FIREWALL_STANDBY, uid);
+
+ // None deny in BLACKLIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleExists(FIREWALL_INPUT, uid);
+ expectFirewallUidLastRuleExists(FIREWALL_OUTPUT, uid);
+
+ // None allow in BLACKLIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleDoesNotExist(FIREWALL_INPUT, uid);
+ expectFirewallUidLastRuleDoesNotExist(FIREWALL_OUTPUT, uid);
+
+ // set firewall type whitelist twice
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallWhitelistMode();
+
+ // None allow in WHITELIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleExists(FIREWALL_INPUT, uid);
+ expectFirewallUidFirstRuleExists(FIREWALL_OUTPUT, uid);
+
+ // None deny in WHITELIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_INPUT, uid);
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_OUTPUT, uid);
+
+ // reset firewall mode to default
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallBlacklistMode();
+}
+
+TEST_F(NetdBinderTest, FirewallEnableDisableChildChains) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ binder::Status status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_DOZABLE, true);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleExists(FIREWALL_DOZABLE);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_STANDBY, true);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleExists(FIREWALL_STANDBY);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_POWERSAVE, true);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleExists(FIREWALL_POWERSAVE);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_DOZABLE, false);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_DOZABLE);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_STANDBY, false);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_STANDBY);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_POWERSAVE, false);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_POWERSAVE);
}
namespace {
@@ -2736,9 +2797,7 @@
InterfaceConfigurationParcel interfaceCfgResult;
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
binder::Status status = mNetd->interfaceGetCfg(sTun.name(), &interfaceCfgResult);
@@ -2757,9 +2816,7 @@
std::vector<std::string> downFlags = {"down"};
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Set tun interface down.
@@ -2797,9 +2854,7 @@
std::vector<std::string> noFlags{};
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
auto interfaceCfg = makeInterfaceCfgParcel(sTun.name(), testAddr, testPrefixLength, noFlags);
@@ -2817,9 +2872,7 @@
TEST_F(NetdBinderTest, InterfaceSetEnableIPv6) {
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// disable
@@ -2840,9 +2893,7 @@
const int testMtu = 1200;
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
binder::Status status = mNetd->interfaceSetMtu(sTun.name(), testMtu);
@@ -3008,6 +3059,8 @@
} // namespace
TEST_F(NetdBinderTest, TestInternetPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::vector<int32_t> appUids = {TEST_UID1, TEST_UID2};
mNetd->trafficSetNetPermForUids(INetd::PERMISSION_INTERNET, appUids);
@@ -3128,9 +3181,7 @@
}
// Add test physical network
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
for (const auto& td : kTestData) {
@@ -3220,16 +3271,11 @@
sTun2.init();
// Create physical network with fallthroughNetId but not set it as default network
- auto config = makeNativeNetworkConfig(fallthroughNetId, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(fallthroughNetId, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(fallthroughNetId, sTun.name()).isOk());
// Create VPN with vpnNetId
- config.netId = vpnNetId;
- config.networkType = NativeNetworkType::VIRTUAL;
- config.secure = secure;
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreateVpn(vpnNetId, secure).isOk());
// Add uid to VPN
EXPECT_TRUE(mNetd->networkAddUidRanges(vpnNetId, {makeUidRangeParcel(uid, uid)}).isOk());
@@ -3241,68 +3287,12 @@
EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "2001:db8::/32", "").isOk());
}
-void NetdBinderTest::createAndSetDefaultNetwork(int netId, const std::string& interface,
- int permission) {
- // backup current default network.
- ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk());
-
- const auto& config =
- makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL, permission, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(netId, interface).isOk());
- EXPECT_TRUE(mNetd->networkSetDefault(netId).isOk());
-}
-
-void NetdBinderTest::createPhysicalNetwork(int netId, const std::string& interface,
- int permission) {
- const auto& config =
- makeNativeNetworkConfig(netId, NativeNetworkType::PHYSICAL, permission, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(netId, interface).isOk());
-}
-
-// 1. Create a physical network on sTun, and set it as the system default network.
-// 2. Create another physical network on sTun2.
-void NetdBinderTest::createDefaultAndOtherPhysicalNetwork(int defaultNetId, int otherNetId) {
- createAndSetDefaultNetwork(defaultNetId, sTun.name());
- EXPECT_TRUE(mNetd->networkAddRoute(defaultNetId, sTun.name(), "::/0", "").isOk());
-
- createPhysicalNetwork(otherNetId, sTun2.name());
- EXPECT_TRUE(mNetd->networkAddRoute(otherNetId, sTun2.name(), "::/0", "").isOk());
-}
-
-// 1. Create a system default network and a physical network.
-// 2. Create a VPN on sTun3.
-void NetdBinderTest::createVpnAndOtherPhysicalNetwork(int systemDefaultNetId, int otherNetId,
- int vpnNetId, bool secure) {
- createDefaultAndOtherPhysicalNetwork(systemDefaultNetId, otherNetId);
-
- auto config = makeNativeNetworkConfig(vpnNetId, NativeNetworkType::VIRTUAL,
- INetd::PERMISSION_NONE, secure);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(vpnNetId, sTun3.name()).isOk());
- EXPECT_TRUE(mNetd->networkAddRoute(vpnNetId, sTun3.name(), "2001:db8::/32", "").isOk());
-}
-
-// 1. Create system default network, a physical network (for per-app default), and a VPN.
-// 2. Add per-app uid ranges and VPN ranges.
-void NetdBinderTest::createVpnAndAppDefaultNetworkWithUid(
- int systemDefaultNetId, int appDefaultNetId, int vpnNetId, bool secure,
- std::vector<UidRangeParcel>&& appDefaultUidRanges,
- std::vector<UidRangeParcel>&& vpnUidRanges) {
- createVpnAndOtherPhysicalNetwork(systemDefaultNetId, appDefaultNetId, vpnNetId, secure);
- // add per-app uid ranges.
- EXPECT_TRUE(mNetd->networkAddUidRanges(appDefaultNetId, appDefaultUidRanges).isOk());
- // add VPN uid ranges.
- EXPECT_TRUE(mNetd->networkAddUidRanges(vpnNetId, vpnUidRanges).isOk());
-}
-
namespace {
class ScopedUidChange {
public:
explicit ScopedUidChange(uid_t uid) : mInputUid(uid) {
- mStoredUid = geteuid();
+ mStoredUid = getuid();
if (mInputUid == mStoredUid) return;
EXPECT_TRUE(seteuid(uid) == 0);
}
@@ -3316,6 +3306,8 @@
uid_t mStoredUid;
};
+constexpr uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 21000;
+
void clearQueue(int tunFd) {
char buf[4096];
int ret;
@@ -3324,18 +3316,17 @@
} while (ret > 0);
}
-void checkDataReceived(int udpSocket, int tunFd, sockaddr* dstAddr, int addrLen) {
+void checkDataReceived(int udpSocket, int tunFd) {
char buf[4096] = {};
// Clear tunFd's queue before write something because there might be some
// arbitrary packets in the queue. (e.g. ICMPv6 packet)
clearQueue(tunFd);
- EXPECT_EQ(4, sendto(udpSocket, "foo", sizeof("foo"), 0, dstAddr, addrLen));
+ EXPECT_EQ(4, write(udpSocket, "foo", sizeof("foo")));
// TODO: extract header and verify data
EXPECT_GT(read(tunFd, buf, sizeof(buf)), 0);
}
-bool sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, int tunFd,
- bool doConnect = true) {
+bool sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, int tunFd) {
ScopedUidChange scopedUidChange(uid);
unique_fd testSocket(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (testSocket < 0) return false;
@@ -3345,51 +3336,15 @@
.sin6_port = 42,
.sin6_addr = dstAddr,
};
- if (doConnect && connect(testSocket, (sockaddr*)&dst6, sizeof(dst6)) == -1) return false;
-
+ int res = connect(testSocket, (sockaddr*)&dst6, sizeof(dst6));
socklen_t fwmarkLen = sizeof(fwmark->intValue);
EXPECT_NE(-1, getsockopt(testSocket, SOL_SOCKET, SO_MARK, &(fwmark->intValue), &fwmarkLen));
+ if (res == -1) return false;
char addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &dstAddr, addr, INET6_ADDRSTRLEN);
- SCOPED_TRACE(StringPrintf("sendIPv6Packet, addr: %s, uid: %u, doConnect: %s", addr, uid,
- doConnect ? "true" : "false"));
- if (doConnect) {
- checkDataReceived(testSocket, tunFd, nullptr, 0);
- } else {
- checkDataReceived(testSocket, tunFd, (sockaddr*)&dst6, sizeof(dst6));
- }
- return true;
-}
-
-// Send an IPv6 packet from the uid. Expect to fail and get specified errno.
-bool sendIPv6PacketFromUidFail(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, bool doConnect,
- int expectedErr) {
- ScopedUidChange scopedUidChange(uid);
- unique_fd s(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- if (s < 0) return false;
-
- const sockaddr_in6 dst6 = {
- .sin6_family = AF_INET6,
- .sin6_port = 42,
- .sin6_addr = dstAddr,
- };
- if (doConnect) {
- if (connect(s, (sockaddr*)&dst6, sizeof(dst6)) == 0) return false;
- if (errno != expectedErr) return false;
- }
-
- socklen_t fwmarkLen = sizeof(fwmark->intValue);
- EXPECT_NE(-1, getsockopt(s, SOL_SOCKET, SO_MARK, &(fwmark->intValue), &fwmarkLen));
-
- char addr[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &dstAddr, addr, INET6_ADDRSTRLEN);
- SCOPED_TRACE(StringPrintf("sendIPv6PacketFail, addr: %s, uid: %u, doConnect: %s", addr, uid,
- doConnect ? "true" : "false"));
- if (!doConnect) {
- if (sendto(s, "foo", sizeof("foo"), 0, (sockaddr*)&dst6, sizeof(dst6)) == 0) return false;
- if (errno != expectedErr) return false;
- }
+ SCOPED_TRACE(StringPrintf("sendIPv6PacketFromUid, addr: %s, uid: %u", addr, uid));
+ checkDataReceived(testSocket, tunFd);
return true;
}
@@ -3522,24 +3477,24 @@
// Save current default network.
ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk());
+ in6_addr v6Addr = {
+ {// 2001:db8:cafe::8888
+ .u6_addr8 = {0x20, 0x01, 0x0d, 0xb8, 0xca, 0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88}}};
// Add test physical network 1 and set as default network.
- auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "2001:db8::/32", "").isOk());
EXPECT_TRUE(mNetd->networkSetDefault(TEST_NETID1).isOk());
// Add test physical network 2
- config.netId = TEST_NETID2;
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID2, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID2, sTun2.name()).isOk());
// Get fwmark for network 1.
MarkMaskParcel maskMarkNet1;
ASSERT_TRUE(mNetd->getFwmarkForNetwork(TEST_NETID1, &maskMarkNet1).isOk());
- uint32_t fwmarkTcp = createIpv6SocketAndCheckMark(SOCK_STREAM, V6_ADDR);
- uint32_t fwmarkUdp = createIpv6SocketAndCheckMark(SOCK_DGRAM, V6_ADDR);
+ uint32_t fwmarkTcp = createIpv6SocketAndCheckMark(SOCK_STREAM, v6Addr);
+ uint32_t fwmarkUdp = createIpv6SocketAndCheckMark(SOCK_DGRAM, v6Addr);
EXPECT_EQ(maskMarkNet1.mark, static_cast<int>(fwmarkTcp & maskMarkNet1.mask));
EXPECT_EQ(maskMarkNet1.mark, static_cast<int>(fwmarkUdp & maskMarkNet1.mask));
@@ -3574,8 +3529,9 @@
} // namespace
-// TODO: probably remove the test because TetherOffload* binder calls are deprecated.
-TEST_F(NetdBinderTest, DISABLED_TetherOffloadRule) {
+TEST_F(NetdBinderTest, TetherOffloadRule) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
// TODO: Perhaps verify invalid interface index once the netd handle the error in methods.
constexpr uint32_t kIfaceInt = 101;
constexpr uint32_t kIfaceExt = 102;
@@ -3689,27 +3645,7 @@
return false;
}
-static bool tcQdiscExists(const std::string& interface) {
- std::string command = StringPrintf("tc qdisc show dev %s", interface.c_str());
- std::vector<std::string> lines = runCommand(command);
- for (const auto& line : lines) {
- if (StartsWith(line, "qdisc clsact ffff:")) return true;
- }
- return false;
-}
-
-static bool tcFilterExists(const std::string& interface) {
- std::string command = StringPrintf("tc filter show dev %s ingress", interface.c_str());
- std::vector<std::string> lines = runCommand(command);
- const std::basic_regex regex("^filter .* bpf .* prog_offload_schedcls_tether_.*$");
- for (const auto& line : lines) {
- if (std::regex_match(Trim(line), regex)) return true;
- }
- return false;
-}
-
-// TODO: probably remove the test because TetherOffload* binder calls are deprecated.
-TEST_F(NetdBinderTest, DISABLED_TetherOffloadForwarding) {
+TEST_F(NetdBinderTest, TetherOffloadForwarding) {
SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED;
constexpr const char* kDownstreamPrefix = "2001:db8:2::/64";
@@ -3736,12 +3672,9 @@
// Use one of the test's tun interfaces as upstream.
// It must be part of a network or it will not have the clsact attached.
- const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
int fd1 = sTun.getFdForTesting();
- EXPECT_TRUE(tcQdiscExists(sTun.name()));
// Create our own tap as a downstream.
TunInterface tap;
@@ -3759,7 +3692,6 @@
status = mNetd->tetherInterfaceAdd(tap.name());
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
expectTetherInterfaceConfigureForIPv6Router(tap.name());
- EXPECT_TRUE(tcQdiscExists(tap.name()));
// Can't easily use INetd::NEXTHOP_NONE because it is a String16 constant. Use "" instead.
status = mNetd->networkAddRoute(INetd::LOCAL_NET_ID, tap.name(), kDownstreamPrefix, "");
@@ -3770,7 +3702,6 @@
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
status = mNetd->ipfwdAddInterfaceForward(tap.name(), sTun.name());
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- EXPECT_TRUE(tcFilterExists(sTun.name()));
std::vector<uint8_t> kDummyMac = {02, 00, 00, 00, 00, 00};
uint8_t* daddr = reinterpret_cast<uint8_t*>(&pkt.hdr.daddr);
@@ -3822,880 +3753,3 @@
EXPECT_TRUE(mNetd->networkRemoveInterface(INetd::LOCAL_NET_ID, tap.name()).isOk());
EXPECT_TRUE(mNetd->networkRemoveInterface(TEST_NETID1, sTun.name()).isOk());
}
-
-namespace {
-
-std::vector<std::string> dumpService(const sp<IBinder>& binder) {
- unique_fd localFd, remoteFd;
- bool success = Pipe(&localFd, &remoteFd);
- EXPECT_TRUE(success) << "Failed to open pipe for dumping: " << strerror(errno);
- if (!success) return {};
-
- // dump() blocks until another thread has consumed all its output.
- std::thread dumpThread = std::thread([binder, remoteFd{std::move(remoteFd)}]() {
- android::status_t ret = binder->dump(remoteFd, {});
- EXPECT_EQ(android::OK, ret) << "Error dumping service: " << android::statusToString(ret);
- });
-
- std::string dumpContent;
-
- EXPECT_TRUE(ReadFdToString(localFd.get(), &dumpContent))
- << "Error during dump: " << strerror(errno);
- dumpThread.join();
-
- std::stringstream dumpStream(std::move(dumpContent));
- std::vector<std::string> lines;
- std::string line;
- while (std::getline(dumpStream, line)) {
- lines.push_back(line);
- }
-
- return lines;
-}
-
-} // namespace
-
-TEST_F(NetdBinderTest, TestServiceDump) {
- sp<IBinder> binder = INetd::asBinder(mNetd);
- ASSERT_NE(nullptr, binder);
-
- struct TestData {
- // Expected contents of the dump command.
- const std::string output;
- // A regex that might be helpful in matching relevant lines in the output.
- // Used to make it easier to add test cases for this code.
- const std::string hintRegex;
- };
- std::vector<TestData> testData;
-
- // Send some IPCs and for each one add an element to testData telling us what to expect.
- const auto& config = makeNativeNetworkConfig(TEST_DUMP_NETID, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- testData.push_back(
- {"networkCreate(NativeNetworkConfig{netId: 65123, networkType: PHYSICAL, "
- "permission: 0, secure: false, vpnType: PLATFORM})",
- "networkCreate.*65123"});
-
- EXPECT_EQ(EEXIST, mNetd->networkCreate(config).serviceSpecificErrorCode());
- testData.push_back(
- {"networkCreate(NativeNetworkConfig{netId: 65123, networkType: PHYSICAL, "
- "permission: 0, secure: false, vpnType: PLATFORM}) "
- "-> ServiceSpecificException(17, \"File exists\")",
- "networkCreate.*65123.*17"});
-
- EXPECT_TRUE(mNetd->networkAddInterface(TEST_DUMP_NETID, sTun.name()).isOk());
- testData.push_back({StringPrintf("networkAddInterface(65123, %s)", sTun.name().c_str()),
- StringPrintf("networkAddInterface.*65123.*%s", sTun.name().c_str())});
-
- android::net::RouteInfoParcel parcel;
- parcel.ifName = sTun.name();
- parcel.destination = "2001:db8:dead:beef::/64";
- parcel.nextHop = "fe80::dead:beef";
- parcel.mtu = 1234;
- EXPECT_TRUE(mNetd->networkAddRouteParcel(TEST_DUMP_NETID, parcel).isOk());
- testData.push_back(
- {StringPrintf("networkAddRouteParcel(65123, RouteInfoParcel{destination:"
- " 2001:db8:dead:beef::/64, ifName: %s, nextHop: fe80::dead:beef,"
- " mtu: 1234})",
- sTun.name().c_str()),
- "networkAddRouteParcel.*65123.*dead:beef"});
-
- EXPECT_TRUE(mNetd->networkDestroy(TEST_DUMP_NETID).isOk());
- testData.push_back({"networkDestroy(65123)", "networkDestroy.*65123"});
-
- // Send the service dump request to netd.
- std::vector<std::string> lines = dumpService(binder);
-
- // Basic regexp to match dump output lines. Matches the beginning and end of the line, and
- // puts the output of the command itself into the first match group.
- // Example: " 11-05 00:23:39.481 myCommand(args) <2.02ms>".
- const std::basic_regex lineRegex(
- "^ [0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}[.][0-9]{3} "
- "(.*)"
- " <[0-9]+[.][0-9]{2}ms>$");
-
- // For each element of testdata, check that the expected output appears in the dump output.
- // If not, fail the test and use hintRegex to print similar lines to assist in debugging.
- for (const TestData& td : testData) {
- const bool found = std::any_of(lines.begin(), lines.end(), [&](const std::string& line) {
- std::smatch match;
- if (!std::regex_match(line, match, lineRegex)) return false;
- return (match.size() == 2) && (match[1].str() == td.output);
- });
- EXPECT_TRUE(found) << "Didn't find line '" << td.output << "' in dumpsys output.";
- if (found) continue;
- std::cerr << "Similar lines" << std::endl;
- for (const auto& line : lines) {
- if (std::regex_search(line, std::basic_regex(td.hintRegex))) {
- std::cerr << line << std::endl;
- }
- }
- }
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadRuleAdd) {
- TetherOffloadRuleParcel emptyRule;
- auto status = mNetd->tetherOffloadRuleAdd(emptyRule);
- ASSERT_FALSE(status.isOk());
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadRuleRemove) {
- TetherOffloadRuleParcel emptyRule;
- auto status = mNetd->tetherOffloadRuleRemove(emptyRule);
- ASSERT_FALSE(status.isOk());
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadGetStats) {
- std::vector<TetherStatsParcel> tetherStatsList;
- auto status = mNetd->tetherOffloadGetStats(&tetherStatsList);
- ASSERT_FALSE(status.isOk());
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadSetInterfaceQuota) {
- auto status = mNetd->tetherOffloadSetInterfaceQuota(0 /* ifIndex */, 0 /* quotaBytes */);
- ASSERT_FALSE(status.isOk());
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-TEST_F(NetdBinderTest, DeprecatedTetherOffloadGetAndClearStats) {
- TetherStatsParcel tetherStats;
- auto status = mNetd->tetherOffloadGetAndClearStats(0 /* ifIndex */, &tetherStats);
- ASSERT_FALSE(status.isOk());
- ASSERT_EQ(status.exceptionCode(), binder::Status::EX_UNSUPPORTED_OPERATION);
-}
-
-namespace {
-
-// aliases for better reading
-#define SYSTEM_DEFAULT_NETID TEST_NETID1
-#define APP_DEFAULT_NETID TEST_NETID2
-#define VPN_NETID TEST_NETID3
-
-void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRangeParcel>& uidRanges,
- const std::string& iface, uint32_t subPriority) {
- ASSERT_EQ(expectedResults.size(), uidRanges.size());
- if (iface.size()) {
- std::string action = StringPrintf("lookup %s ", iface.c_str());
- for (unsigned long i = 0; i < uidRanges.size(); i++) {
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority,
- uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority,
- uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_NETWORK + subPriority,
- uidRanges[i], action));
- }
- } else {
- std::string action = "unreachable";
- for (unsigned long i = 0; i < uidRanges.size(); i++) {
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority,
- uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority,
- uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_UNREACHABLE + subPriority,
- uidRanges[i], action));
- }
- }
-}
-
-void verifyAppUidRules(std::vector<bool>&& expectedResults, NativeUidRangeConfig& uidRangeConfig,
- const std::string& iface) {
- verifyAppUidRules(move(expectedResults), uidRangeConfig.uidRanges, iface,
- uidRangeConfig.subPriority);
-}
-
-void verifyVpnUidRules(std::vector<bool>&& expectedResults, NativeUidRangeConfig& uidRangeConfig,
- const std::string& iface, bool secure) {
- ASSERT_EQ(expectedResults.size(), uidRangeConfig.uidRanges.size());
- std::string action = StringPrintf("lookup %s ", iface.c_str());
-
- uint32_t priority;
- if (secure) {
- priority = RULE_PRIORITY_SECURE_VPN;
- } else {
- priority = RULE_PRIORITY_BYPASSABLE_VPN;
- }
- for (unsigned long i = 0; i < uidRangeConfig.uidRanges.size(); i++) {
- EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(priority + uidRangeConfig.subPriority,
- uidRangeConfig.uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_EXPLICIT_NETWORK + uidRangeConfig.subPriority,
- uidRangeConfig.uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_OUTPUT_INTERFACE + uidRangeConfig.subPriority,
- uidRangeConfig.uidRanges[i], action, iface.c_str()));
- }
-}
-
-constexpr int SUB_PRIORITY_1 = UidRanges::DEFAULT_SUB_PRIORITY + 1;
-constexpr int SUB_PRIORITY_2 = UidRanges::DEFAULT_SUB_PRIORITY + 2;
-
-constexpr int IMPLICITLY_SELECT = 0;
-constexpr int EXPLICITLY_SELECT = 1;
-constexpr int UNCONNECTED_SOCKET = 2;
-
-// 1. Send data with the specified UID, on a connected or unconnected socket.
-// 2. Verify if data is received from the specified fd. The fd should belong to a TUN, which has
-// been assigned to the test network.
-// 3. Verify if fwmark of data is correct.
-// Note: This is a helper function used by per-app default network tests. It does not implement full
-// fwmark logic in netd, and it's currently sufficient. Extension may be required for more
-// complicated tests.
-void expectPacketSentOnNetId(uid_t uid, unsigned netId, int fd, int selectionMode) {
- Fwmark fwmark;
- const bool doConnect = (selectionMode != UNCONNECTED_SOCKET);
- EXPECT_TRUE(sendIPv6PacketFromUid(uid, V6_ADDR, &fwmark, fd, doConnect));
-
- Fwmark expected;
- expected.netId = netId;
- expected.explicitlySelected = (selectionMode == EXPLICITLY_SELECT);
- if (uid == AID_ROOT && selectionMode == EXPLICITLY_SELECT) {
- expected.protectedFromVpn = true;
- } else {
- expected.protectedFromVpn = false;
- }
- if (selectionMode == UNCONNECTED_SOCKET) {
- expected.permission = PERMISSION_NONE;
- } else {
- expected.permission = (uid == AID_ROOT) ? PERMISSION_SYSTEM : PERMISSION_NONE;
- }
-
- EXPECT_EQ(expected.intValue, fwmark.intValue);
-}
-
-void expectUnreachableError(uid_t uid, unsigned netId, int selectionMode) {
- Fwmark fwmark;
- const bool doConnect = (selectionMode != UNCONNECTED_SOCKET);
- EXPECT_TRUE(sendIPv6PacketFromUidFail(uid, V6_ADDR, &fwmark, doConnect, ENETUNREACH));
-
- Fwmark expected;
- expected.netId = netId;
- expected.explicitlySelected = (selectionMode == EXPLICITLY_SELECT);
- if (uid == AID_ROOT && selectionMode == EXPLICITLY_SELECT) {
- expected.protectedFromVpn = true;
- } else {
- expected.protectedFromVpn = false;
- }
- if (selectionMode == UNCONNECTED_SOCKET) {
- expected.permission = PERMISSION_NONE;
- } else {
- expected.permission = (uid == AID_ROOT) ? PERMISSION_SYSTEM : PERMISSION_NONE;
- }
-
- EXPECT_EQ(expected.intValue, fwmark.intValue);
-}
-
-} // namespace
-
-// Verify whether API reject overlapped UID ranges
-TEST_F(NetdBinderTest, PerAppDefaultNetwork_OverlappedUidRanges) {
- const auto& config = makeNativeNetworkConfig(APP_DEFAULT_NETID, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(APP_DEFAULT_NETID, sTun.name()).isOk());
-
- std::vector<UidRangeParcel> uidRanges = {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1),
- makeUidRangeParcel(BASE_UID + 10, BASE_UID + 12)};
- EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID, uidRanges).isOk());
-
- binder::Status status;
- status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(BASE_UID + 9, BASE_UID + 10)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(BASE_UID + 11, BASE_UID + 11)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(BASE_UID + 12, BASE_UID + 13)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(BASE_UID + 9, BASE_UID + 13)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- std::vector<UidRangeParcel> selfOverlappedUidRanges = {
- makeUidRangeParcel(BASE_UID + 20, BASE_UID + 20),
- makeUidRangeParcel(BASE_UID + 20, BASE_UID + 21)};
- status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID, selfOverlappedUidRanges);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-}
-
-// Verify whether IP rules for app default network are correctly configured.
-TEST_F(NetdBinderTest, PerAppDefaultNetwork_VerifyIpRules) {
- const auto& config = makeNativeNetworkConfig(APP_DEFAULT_NETID, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(APP_DEFAULT_NETID, sTun.name()).isOk());
-
- std::vector<UidRangeParcel> uidRanges = {makeUidRangeParcel(BASE_UID + 8005, BASE_UID + 8012),
- makeUidRangeParcel(BASE_UID + 8090, BASE_UID + 8099)};
-
- EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID, uidRanges).isOk());
- verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, sTun.name(),
- UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(0)}).isOk());
- verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, sTun.name(),
- UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(1)}).isOk());
- verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, sTun.name(),
- UidRanges::DEFAULT_SUB_PRIORITY);
-
- EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID, uidRanges).isOk());
- verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, "",
- UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(0)}).isOk());
- verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, "",
- UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(1)}).isOk());
- verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, "",
- UidRanges::DEFAULT_SUB_PRIORITY);
-}
-
-// Verify whether packets go through the right network with and without per-app default network.
-// Meaning of Fwmark bits (from Fwmark.h):
-// 0x0000ffff - Network ID
-// 0x00010000 - Explicit mark bit
-// 0x00020000 - VPN protect bit
-// 0x000c0000 - Permission bits
-TEST_F(NetdBinderTest, PerAppDefaultNetwork_ImplicitlySelectNetwork) {
- createDefaultAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID);
-
- int systemDefaultFd = sTun.getFdForTesting();
- int appDefaultFd = sTun2.getFdForTesting();
-
- // Connections go through the system default network.
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
-
- // Add TEST_UID1 to per-app default network.
- EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, APP_DEFAULT_NETID, appDefaultFd, IMPLICITLY_SELECT);
-
- // Remove TEST_UID1 from per-app default network.
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
-
- // Prohibit TEST_UID1 from using the default network.
- EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
- expectUnreachableError(TEST_UID1, INetd::UNREACHABLE_NET_ID, IMPLICITLY_SELECT);
-
- // restore IP rules
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
-}
-
-// Verify whether packets go through the right network when app explicitly selects a network.
-TEST_F(NetdBinderTest, PerAppDefaultNetwork_ExplicitlySelectNetwork) {
- createDefaultAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID);
-
- int systemDefaultFd = sTun.getFdForTesting();
- int appDefaultFd = sTun2.getFdForTesting();
-
- // Explicitly select the system default network.
- setNetworkForProcess(SYSTEM_DEFAULT_NETID);
- // Connections go through the system default network.
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
-
- // Set TEST_UID1 to default unreachable, which won't affect the explicitly selected network.
- // Connections go through the system default network.
- EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
-
- // restore IP rules
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
-
- // Add TEST_UID1 to per-app default network, which won't affect the explicitly selected network.
- EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
-
- // Explicitly select the per-app default network.
- setNetworkForProcess(APP_DEFAULT_NETID);
- // Connections go through the per-app default network.
- expectPacketSentOnNetId(AID_ROOT, APP_DEFAULT_NETID, appDefaultFd, EXPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID1, APP_DEFAULT_NETID, appDefaultFd, EXPLICITLY_SELECT);
-}
-
-// Verify whether packets go through the right network if app does not implicitly or explicitly
-// select any network.
-TEST_F(NetdBinderTest, PerAppDefaultNetwork_UnconnectedSocket) {
- createDefaultAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID);
-
- int systemDefaultFd = sTun.getFdForTesting();
- int appDefaultFd = sTun2.getFdForTesting();
-
- // Connections go through the system default network.
- expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
- expectPacketSentOnNetId(TEST_UID1, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
-
- // Add TEST_UID1 to per-app default network. Traffic should go through the per-app default
- // network if UID is in range. Otherwise, go through the system default network.
- EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
- expectPacketSentOnNetId(TEST_UID1, NETID_UNSET, appDefaultFd, UNCONNECTED_SOCKET);
-
- // Set TEST_UID1's default network to unreachable. Its traffic should still go through the
- // per-app default network. Other traffic go through the system default network.
- // PS: per-app default network take precedence over unreachable network. This should happens
- // only in the transition period when both rules are briefly set.
- EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
- expectPacketSentOnNetId(TEST_UID1, NETID_UNSET, appDefaultFd, UNCONNECTED_SOCKET);
-
- // Remove TEST_UID1's default network from OEM-paid network. Its traffic should get ENETUNREACH
- // error. Other traffic still go through the system default network.
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
- expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
- expectUnreachableError(TEST_UID1, NETID_UNSET, UNCONNECTED_SOCKET);
-
- // restore IP rules
- EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
-}
-
-TEST_F(NetdBinderTest, PerAppDefaultNetwork_PermissionCheck) {
- createPhysicalNetwork(APP_DEFAULT_NETID, sTun2.name(), INetd::PERMISSION_SYSTEM);
-
- { // uid is not in app range. Can not set network for process.
- ScopedUidChange scopedUidChange(TEST_UID1);
- EXPECT_EQ(-EACCES, setNetworkForProcess(APP_DEFAULT_NETID));
- }
-
- EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
- .isOk());
-
- { // uid is in app range. Can set network for process.
- ScopedUidChange scopedUidChange(TEST_UID1);
- EXPECT_EQ(0, setNetworkForProcess(APP_DEFAULT_NETID));
- }
-}
-
-class VpnParameterizedTest : public NetdBinderTest, public testing::WithParamInterface<bool> {};
-
-// Exercise secure and bypassable VPN.
-INSTANTIATE_TEST_SUITE_P(PerAppDefaultNetwork, VpnParameterizedTest, testing::Bool(),
- [](const testing::TestParamInfo<bool>& info) {
- return info.param ? "SecureVPN" : "BypassableVPN";
- });
-
-// Verify per-app default network + VPN.
-TEST_P(VpnParameterizedTest, ImplicitlySelectNetwork) {
- const bool isSecureVPN = GetParam();
- createVpnAndAppDefaultNetworkWithUid(
- SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID, isSecureVPN,
- {makeUidRangeParcel(TEST_UID2, TEST_UID1)} /* app range */,
- {makeUidRangeParcel(TEST_UID3, TEST_UID2)} /* VPN range */);
-
- int systemDefaultFd = sTun.getFdForTesting();
- int appDefaultFd = sTun2.getFdForTesting();
- int vpnFd = sTun3.getFdForTesting();
-
- // uid is neither in app range, nor in VPN range. Traffic goes through system default network.
- expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
- // uid is in VPN range, not in app range. Traffic goes through VPN.
- expectPacketSentOnNetId(TEST_UID3, (isSecureVPN ? SYSTEM_DEFAULT_NETID : VPN_NETID), vpnFd,
- IMPLICITLY_SELECT);
- // uid is in app range, not in VPN range. Traffic goes through per-app default network.
- expectPacketSentOnNetId(TEST_UID1, APP_DEFAULT_NETID, appDefaultFd, IMPLICITLY_SELECT);
- // uid is in both app and VPN range. Traffic goes through VPN.
- expectPacketSentOnNetId(TEST_UID2, (isSecureVPN ? APP_DEFAULT_NETID : VPN_NETID), vpnFd,
- IMPLICITLY_SELECT);
-}
-
-class VpnAndSelectNetworkParameterizedTest
- : public NetdBinderTest,
- public testing::WithParamInterface<std::tuple<bool, int>> {};
-
-// Exercise the combination of different VPN types and different user selected networks. e.g.
-// secure VPN + select on system default network
-// secure VPN + select on app default network
-// secure VPN + select on VPN
-// bypassable VPN + select on system default network
-// ...
-INSTANTIATE_TEST_SUITE_P(PerAppDefaultNetwork, VpnAndSelectNetworkParameterizedTest,
- testing::Combine(testing::Bool(),
- testing::Values(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID,
- VPN_NETID)),
- [](const testing::TestParamInfo<std::tuple<bool, int>>& info) {
- const std::string vpnType = std::get<0>(info.param)
- ? std::string("SecureVPN")
- : std::string("BypassableVPN");
- std::string selectedNetwork;
- switch (std::get<1>(info.param)) {
- case SYSTEM_DEFAULT_NETID:
- selectedNetwork = "SystemDefaultNetwork";
- break;
- case APP_DEFAULT_NETID:
- selectedNetwork = "AppDefaultNetwork";
- break;
- case VPN_NETID:
- selectedNetwork = "VPN";
- break;
- default:
- selectedNetwork = "InvalidParameter"; // Should not happen.
- }
- return vpnType + "_select" + selectedNetwork;
- });
-
-TEST_P(VpnAndSelectNetworkParameterizedTest, ExplicitlySelectNetwork) {
- bool isSecureVPN;
- int selectedNetId;
- std::tie(isSecureVPN, selectedNetId) = GetParam();
- createVpnAndAppDefaultNetworkWithUid(
- SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID, isSecureVPN,
- {makeUidRangeParcel(TEST_UID2, TEST_UID1)} /* app range */,
- {makeUidRangeParcel(TEST_UID3, TEST_UID2)} /* VPN range */);
-
- int expectedFd = -1;
- switch (selectedNetId) {
- case SYSTEM_DEFAULT_NETID:
- expectedFd = sTun.getFdForTesting();
- break;
- case APP_DEFAULT_NETID:
- expectedFd = sTun2.getFdForTesting();
- break;
- case VPN_NETID:
- expectedFd = sTun3.getFdForTesting();
- break;
- default:
- GTEST_LOG_(ERROR) << "unexpected netId:" << selectedNetId; // Should not happen.
- }
-
- // In all following permutations, Traffic should go through the specified network if a process
- // can select network for itself. The fwmark should contain process UID and the explicit select
- // bit.
- { // uid is neither in app range, nor in VPN range. Permission bits, protect bit, and explicit
- // select bit are all set because of AID_ROOT.
- ScopedUidChange scopedUidChange(AID_ROOT);
- EXPECT_EQ(0, setNetworkForProcess(selectedNetId));
- expectPacketSentOnNetId(AID_ROOT, selectedNetId, expectedFd, EXPLICITLY_SELECT);
- }
- { // uid is in VPN range, not in app range.
- ScopedUidChange scopedUidChange(TEST_UID3);
- // Cannot select non-VPN networks when uid is subject to secure VPN.
- if (isSecureVPN && selectedNetId != VPN_NETID) {
- EXPECT_EQ(-EPERM, setNetworkForProcess(selectedNetId));
- } else {
- EXPECT_EQ(0, setNetworkForProcess(selectedNetId));
- expectPacketSentOnNetId(TEST_UID3, selectedNetId, expectedFd, EXPLICITLY_SELECT);
- }
- }
- { // uid is in app range, not in VPN range.
- ScopedUidChange scopedUidChange(TEST_UID1);
- // Cannot select the VPN because the VPN does not applies to the UID.
- if (selectedNetId == VPN_NETID) {
- EXPECT_EQ(-EPERM, setNetworkForProcess(selectedNetId));
- } else {
- EXPECT_EQ(0, setNetworkForProcess(selectedNetId));
- expectPacketSentOnNetId(TEST_UID1, selectedNetId, expectedFd, EXPLICITLY_SELECT);
- }
- }
- { // uid is in both app range and VPN range.
- ScopedUidChange scopedUidChange(TEST_UID2);
- // Cannot select non-VPN networks when uid is subject to secure VPN.
- if (isSecureVPN && selectedNetId != VPN_NETID) {
- EXPECT_EQ(-EPERM, setNetworkForProcess(selectedNetId));
- } else {
- EXPECT_EQ(0, setNetworkForProcess(selectedNetId));
- expectPacketSentOnNetId(TEST_UID2, selectedNetId, expectedFd, EXPLICITLY_SELECT);
- }
- }
-}
-
-TEST_P(VpnParameterizedTest, UnconnectedSocket) {
- const bool isSecureVPN = GetParam();
- createVpnAndAppDefaultNetworkWithUid(
- SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID, isSecureVPN,
- {makeUidRangeParcel(TEST_UID2, TEST_UID1)} /* app range */,
- {makeUidRangeParcel(TEST_UID3, TEST_UID2)} /* VPN range */);
-
- int systemDefaultFd = sTun.getFdForTesting();
- int appDefaultFd = sTun2.getFdForTesting();
- int vpnFd = sTun3.getFdForTesting();
-
- // uid is neither in app range, nor in VPN range. Traffic goes through system default network.
- expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
- // uid is in VPN range, not in app range. Traffic goes through VPN.
- expectPacketSentOnNetId(TEST_UID3, NETID_UNSET, vpnFd, UNCONNECTED_SOCKET);
- // uid is in app range, not in VPN range. Traffic goes through per-app default network.
- expectPacketSentOnNetId(TEST_UID1, NETID_UNSET, appDefaultFd, UNCONNECTED_SOCKET);
- // uid is in both app and VPN range. Traffic goes through VPN.
- expectPacketSentOnNetId(TEST_UID2, NETID_UNSET, vpnFd, UNCONNECTED_SOCKET);
-}
-
-TEST_F(NetdBinderTest, NetworkCreate) {
- auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
- INetd::PERMISSION_NONE, false);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkDestroy(config.netId).isOk());
-
- config.networkType = NativeNetworkType::VIRTUAL;
- config.secure = true;
- config.vpnType = NativeVpnType::OEM;
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
-
- // invalid network type
- auto wrongConfig = makeNativeNetworkConfig(TEST_NETID2, static_cast<NativeNetworkType>(-1),
- INetd::PERMISSION_NONE, false);
- EXPECT_EQ(EINVAL, mNetd->networkCreate(wrongConfig).serviceSpecificErrorCode());
-
- // invalid VPN type
- wrongConfig.networkType = NativeNetworkType::VIRTUAL;
- wrongConfig.vpnType = static_cast<NativeVpnType>(-1);
- EXPECT_EQ(EINVAL, mNetd->networkCreate(wrongConfig).serviceSpecificErrorCode());
-}
-
-// Verifies valid and invalid inputs on networkAddUidRangesParcel method.
-TEST_F(NetdBinderTest, UidRangeSubPriority_ValidateInputs) {
- createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID,
- /*isSecureVPN=*/true);
- // Invalid priority -1 on a physical network.
- NativeUidRangeConfig uidRangeConfig =
- makeNativeUidRangeConfig(APP_DEFAULT_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)},
- UidRanges::DEFAULT_SUB_PRIORITY - 1);
- binder::Status status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- // Invalid priority 1000 on a physical network.
- uidRangeConfig.subPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
- status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- // Virtual networks support only default priority.
- uidRangeConfig.netId = VPN_NETID;
- uidRangeConfig.subPriority = SUB_PRIORITY_1;
- status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- // For a single network, identical UID ranges with different priorities are allowed.
- uidRangeConfig.netId = APP_DEFAULT_NETID;
- uidRangeConfig.subPriority = SUB_PRIORITY_1;
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig).isOk());
- uidRangeConfig.subPriority = SUB_PRIORITY_2;
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig).isOk());
-
- // For a single network, identical UID ranges with the same priority is invalid.
- status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
- // Overlapping ranges is invalid.
- uidRangeConfig.uidRanges = {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1),
- makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)};
- status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-}
-
-// Examines whether IP rules for app default network with subsidiary priorities are correctly added
-// and removed.
-TEST_F(NetdBinderTest, UidRangeSubPriority_VerifyPhysicalNwIpRules) {
- createPhysicalNetwork(TEST_NETID1, sTun.name());
- EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
- createPhysicalNetwork(TEST_NETID2, sTun2.name());
- EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "::/0", "").isOk());
-
- // Adds priority 1 setting
- NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
- TEST_NETID1, {makeUidRangeParcel(BASE_UID, BASE_UID)}, SUB_PRIORITY_1);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
- verifyAppUidRules({true}, uidRangeConfig1, sTun.name());
- // Adds priority 2 setting
- NativeUidRangeConfig uidRangeConfig2 = makeNativeUidRangeConfig(
- TEST_NETID2, {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)}, SUB_PRIORITY_2);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
- verifyAppUidRules({true}, uidRangeConfig2, sTun2.name());
- // Adds another priority 2 setting
- NativeUidRangeConfig uidRangeConfig3 = makeNativeUidRangeConfig(
- INetd::UNREACHABLE_NET_ID, {makeUidRangeParcel(BASE_UID + 2, BASE_UID + 2)},
- SUB_PRIORITY_2);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig3).isOk());
- verifyAppUidRules({true}, uidRangeConfig3, "");
-
- // Removes.
- EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
- verifyAppUidRules({false}, uidRangeConfig1, sTun.name());
- verifyAppUidRules({true}, uidRangeConfig2, sTun2.name());
- verifyAppUidRules({true}, uidRangeConfig3, "");
- EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig2).isOk());
- verifyAppUidRules({false}, uidRangeConfig1, sTun.name());
- verifyAppUidRules({false}, uidRangeConfig2, sTun2.name());
- verifyAppUidRules({true}, uidRangeConfig3, "");
- EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig3).isOk());
- verifyAppUidRules({false}, uidRangeConfig1, sTun.name());
- verifyAppUidRules({false}, uidRangeConfig2, sTun2.name());
- verifyAppUidRules({false}, uidRangeConfig3, "");
-}
-
-// Verify uid range rules on virtual network.
-TEST_P(VpnParameterizedTest, UidRangeSubPriority_VerifyVpnIpRules) {
- const bool isSecureVPN = GetParam();
- constexpr int VPN_NETID2 = TEST_NETID2;
-
- // Create 2 VPNs, using sTun and sTun2.
- auto config = makeNativeNetworkConfig(VPN_NETID, NativeNetworkType::VIRTUAL,
- INetd::PERMISSION_NONE, isSecureVPN);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID, sTun.name()).isOk());
-
- config = makeNativeNetworkConfig(VPN_NETID2, NativeNetworkType::VIRTUAL, INetd::PERMISSION_NONE,
- isSecureVPN);
- EXPECT_TRUE(mNetd->networkCreate(config).isOk());
- EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID2, sTun2.name()).isOk());
-
- // Assign uid ranges to different VPNs. Check if rules match.
- NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
- VPN_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)}, UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
- verifyVpnUidRules({true}, uidRangeConfig1, sTun.name(), isSecureVPN);
-
- NativeUidRangeConfig uidRangeConfig2 =
- makeNativeUidRangeConfig(VPN_NETID2, {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)},
- UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
- verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN);
-
- // Remove uid configs one-by-one. Check if rules match.
- EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
- verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN);
- verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN);
- EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig2).isOk());
- verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN);
- verifyVpnUidRules({false}, uidRangeConfig2, sTun2.name(), isSecureVPN);
-}
-
-// Verify if packets go through the right network when subsidiary priority and VPN works together.
-//
-// Test config:
-// +----------+------------------------+-------------------------------------------+
-// | Priority | UID | Assigned Network |
-// +----------+------------------------+-------------------------------------------+
-// | 0 | TEST_UID1 | VPN bypassable (VPN_NETID) |
-// +----------+------------------------+-------------------------------------------+
-// | 1 | TEST_UID1, TEST_UID2, | Physical Network 1 (APP_DEFAULT_1_NETID) |
-// | 1 | TEST_UID3 | Physical Network 2 (APP_DEFAULT_2_NETID) |
-// | 1 | TEST_UID5 | Unreachable Network (UNREACHABLE_NET_ID) |
-// +----------+------------------------+-------------------------------------------+
-// | 2 | TEST_UID3 | Physical Network 1 (APP_DEFAULT_1_NETID) |
-// | 2 | TEST_UID4, TEST_UID5 | Physical Network 2 (APP_DEFAULT_2_NETID) |
-// +----------+------------------------+-------------------------------------------+
-//
-// Expected results:
-// +-----------+------------------------+
-// | UID | Using Network |
-// +-----------+------------------------+
-// | TEST_UID1 | VPN |
-// | TEST_UID2 | Physical Network 1 |
-// | TEST_UID3 | Physical Network 2 |
-// | TEST_UID4 | Physical Network 2 |
-// | TEST_UID5 | Unreachable Network |
-// | TEST_UID6 | System Default Network |
-// +-----------+------------------------+
-//
-// SYSTEM_DEFAULT_NETID uses sTun.
-// APP_DEFAULT_1_NETID uses sTun2.
-// VPN_NETID uses sTun3.
-// APP_DEFAULT_2_NETID uses sTun4.
-//
-TEST_F(NetdBinderTest, UidRangeSubPriority_ImplicitlySelectNetwork) {
- constexpr int APP_DEFAULT_1_NETID = TEST_NETID2;
- constexpr int APP_DEFAULT_2_NETID = TEST_NETID4;
-
- // Creates 4 networks.
- createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_1_NETID, VPN_NETID,
- /*isSecureVPN=*/false);
- createPhysicalNetwork(APP_DEFAULT_2_NETID, sTun4.name());
- EXPECT_TRUE(mNetd->networkAddRoute(APP_DEFAULT_2_NETID, sTun4.name(), "::/0", "").isOk());
-
- // Adds VPN setting.
- NativeUidRangeConfig uidRangeConfigVpn = makeNativeUidRangeConfig(
- VPN_NETID, {makeUidRangeParcel(TEST_UID1, TEST_UID1)}, UidRanges::DEFAULT_SUB_PRIORITY);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfigVpn).isOk());
-
- // Adds uidRangeConfig1 setting.
- NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
- APP_DEFAULT_1_NETID,
- {makeUidRangeParcel(TEST_UID1, TEST_UID1), makeUidRangeParcel(TEST_UID2, TEST_UID2)},
- SUB_PRIORITY_1);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
- uidRangeConfig1.netId = APP_DEFAULT_2_NETID;
- uidRangeConfig1.uidRanges = {makeUidRangeParcel(TEST_UID3, TEST_UID3)};
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
- uidRangeConfig1.netId = INetd::UNREACHABLE_NET_ID;
- uidRangeConfig1.uidRanges = {makeUidRangeParcel(TEST_UID5, TEST_UID5)};
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
-
- // Adds uidRangeConfig2 setting.
- NativeUidRangeConfig uidRangeConfig2 = makeNativeUidRangeConfig(
- APP_DEFAULT_1_NETID, {makeUidRangeParcel(TEST_UID3, TEST_UID3)}, SUB_PRIORITY_2);
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
- uidRangeConfig2.netId = APP_DEFAULT_2_NETID;
- uidRangeConfig2.uidRanges = {makeUidRangeParcel(TEST_UID4, TEST_UID4),
- makeUidRangeParcel(TEST_UID5, TEST_UID5)};
- EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
-
- int systemDefaultFd = sTun.getFdForTesting();
- int appDefault_1_Fd = sTun2.getFdForTesting();
- int vpnFd = sTun3.getFdForTesting();
- int appDefault_2_Fd = sTun4.getFdForTesting();
- // Verify routings.
- expectPacketSentOnNetId(TEST_UID1, VPN_NETID, vpnFd, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID2, APP_DEFAULT_1_NETID, appDefault_1_Fd, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID3, APP_DEFAULT_2_NETID, appDefault_2_Fd, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID4, APP_DEFAULT_2_NETID, appDefault_2_Fd, IMPLICITLY_SELECT);
- expectUnreachableError(TEST_UID5, INetd::UNREACHABLE_NET_ID, IMPLICITLY_SELECT);
- expectPacketSentOnNetId(TEST_UID6, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
-
- // Remove test rules from the unreachable network.
- EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
-}
\ No newline at end of file
diff --git a/tests/bpf_base_test.cpp b/tests/bpf_base_test.cpp
index 7ab4290..f28c5f8 100644
--- a/tests/bpf_base_test.cpp
+++ b/tests/bpf_base_test.cpp
@@ -56,13 +56,25 @@
};
TEST_F(BpfBasicTest, TestCgroupMounted) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
std::string cg2_path;
+#if 0
+ // This is the correct way to fetch cg2_path, but it occasionally hits ASAN
+ // problems due to memory allocated in non ASAN code being freed later by us
ASSERT_EQ(true, CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cg2_path));
+#else
+ ASSERT_EQ(true, CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, nullptr));
+ // Constant derived from //system/core/libprocessgroup/profiles/cgroups.json
+ cg2_path = "/dev/cg2_bpf";
+#endif
ASSERT_EQ(0, access(cg2_path.c_str(), R_OK));
ASSERT_EQ(0, access((cg2_path + "/cgroup.controllers").c_str(), R_OK));
}
TEST_F(BpfBasicTest, TestTrafficControllerSetUp) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
ASSERT_EQ(0, access(BPF_EGRESS_PROG_PATH, R_OK));
ASSERT_EQ(0, access(BPF_INGRESS_PROG_PATH, R_OK));
ASSERT_EQ(0, access(XT_BPF_INGRESS_PROG_PATH, R_OK));
@@ -85,6 +97,8 @@
}
TEST_F(BpfBasicTest, TestTagSocket) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
BpfMap<uint64_t, UidTagValue> cookieTagMap(COOKIE_TAG_MAP_PATH);
ASSERT_LE(0, cookieTagMap.getMap());
int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
@@ -103,6 +117,8 @@
}
TEST_F(BpfBasicTest, TestCloseSocketWithoutUntag) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
BpfMap<uint64_t, UidTagValue> cookieTagMap(COOKIE_TAG_MAP_PATH);
ASSERT_LE(0, cookieTagMap.getMap());
int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
@@ -128,6 +144,8 @@
}
TEST_F(BpfBasicTest, TestChangeCounterSet) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
BpfMap<uint32_t, uint8_t> uidCounterSetMap(UID_COUNTERSET_MAP_PATH);
ASSERT_LE(0, uidCounterSetMap.getMap());
ASSERT_EQ(0, qtaguid_setCounterSet(TEST_COUNTERSET, TEST_UID));
@@ -142,6 +160,8 @@
}
TEST_F(BpfBasicTest, TestDeleteTagData) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
BpfMap<StatsKey, StatsValue> statsMapA(STATS_MAP_A_PATH);
ASSERT_LE(0, statsMapA.getMap());
BpfMap<StatsKey, StatsValue> statsMapB(STATS_MAP_B_PATH);
diff --git a/tests/netd_test.cpp b/tests/netd_test.cpp
index fcd538e..dd25f96 100644
--- a/tests/netd_test.cpp
+++ b/tests/netd_test.cpp
@@ -48,22 +48,6 @@
ASSERT_EQ(ENODATA, errno);
}
-// If this test fails most likely your device is lacking device/oem specific
-// selinux genfscon rules, something like .../vendor/.../genfs_contexts:
-// genfscon sysfs /devices/platform/.../net u:object_r:sysfs_net:s0
-// Easiest debugging is via:
-// adb root && sleep 1 && adb shell 'ls -Z /sys/class/net/*/mtu'
-// and look for the mislabeled item(s).
-// Everything should be 'u:object_r:sysfs_net:s0'
-//
-// Another useful command is:
-// adb root && sleep 1 && adb shell find /sys > dump.out
-// or in particular:
-// adb root && sleep 1 && adb shell find /sys | egrep '/net$'
-// which might (among other things) print out something like:
-// /sys/devices/platform/11110000.usb/11110000.dwc3/gadget/net
-// which means you need to add:
-// genfscon sysfs /devices/platform/11110000.usb/11110000.dwc3/gadget/net u:object_r:sysfs_net:s0
TEST(NetdSELinuxTest, CheckProperMTULabels) {
// Since we expect the egrep regexp to filter everything out,
// we thus expect no matches and thus a return code of 1
@@ -121,5 +105,195 @@
nsTest(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWNET, true, thread);
}
+// Test for presence of kernel patch:
+// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
+// on 4.14+ kernels.
+TEST(NetdBpfTest, testBpfSkbChangeHeadAboveMTU) {
+ SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED;
+
+ constexpr int mtu = 1500;
+
+ errno = 0;
+
+ // Amusingly can't use SIOC... on tun/tap fds.
+ int rv = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GE(rv, 3);
+ unique_fd unixfd(rv);
+
+ rv = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GE(rv, 3);
+ unique_fd tun(rv);
+
+ rv = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GE(rv, 3);
+ unique_fd tap(rv);
+
+ struct ifreq tun_ifr = {
+ .ifr_flags = IFF_TUN | IFF_NO_PI,
+ .ifr_name = "tun_bpftest",
+ };
+
+ struct ifreq tap_ifr = {
+ .ifr_flags = IFF_TAP | IFF_NO_PI,
+ .ifr_name = "tap_bpftest",
+ };
+
+ rv = ioctl(tun, TUNSETIFF, &tun_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ rv = ioctl(tap, TUNSETIFF, &tap_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ // prevents kernel from sending us spurious ipv6 packets
+ rv = open("/proc/sys/net/ipv6/conf/tap_bpftest/disable_ipv6", O_WRONLY);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GE(rv, 3);
+ unique_fd f(rv);
+
+ rv = write(f, "1\n", 2);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 2);
+
+ rv = close(f.release());
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ int tunif = if_nametoindex(tun_ifr.ifr_name);
+ ASSERT_GE(tunif, 2);
+
+ int tapif = if_nametoindex(tap_ifr.ifr_name);
+ ASSERT_GE(tapif, 2);
+
+ tun_ifr.ifr_mtu = mtu;
+ rv = ioctl(unixfd, SIOCSIFMTU, &tun_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ tap_ifr.ifr_mtu = mtu;
+ rv = ioctl(unixfd, SIOCSIFMTU, &tap_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ rv = ioctl(unixfd, SIOCGIFFLAGS, &tun_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ rv = ioctl(unixfd, SIOCGIFFLAGS, &tap_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ tun_ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+
+ tap_ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+
+ rv = ioctl(unixfd, SIOCSIFFLAGS, &tun_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ rv = ioctl(unixfd, SIOCSIFFLAGS, &tap_ifr);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, 0);
+
+ rv = tcQdiscAddDevClsact(tunif);
+ ASSERT_EQ(rv, 0);
+
+ int bpfFd = getTetherIngressProgFd(/* ethernet */ false);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GE(bpfFd, 3);
+
+ rv = tcFilterAddDevIngressTether(tunif, bpfFd, /* ethernet*/ false);
+ ASSERT_EQ(rv, 0);
+
+ bpf::BpfMap<TetherIngressKey, TetherIngressValue> bpfIngressMap;
+ bpf::BpfMap<uint32_t, TetherStatsValue> bpfStatsMap;
+ bpf::BpfMap<uint32_t, uint64_t> bpfLimitMap;
+
+ rv = getTetherIngressMapFd();
+ ASSERT_GE(rv, 3);
+ bpfIngressMap.reset(rv);
+
+ rv = getTetherStatsMapFd();
+ ASSERT_GE(rv, 3);
+ bpfStatsMap.reset(rv);
+
+ rv = getTetherLimitMapFd();
+ ASSERT_GE(rv, 3);
+ bpfLimitMap.reset(rv);
+
+ TetherIngressKey key = {
+ .iif = static_cast<uint32_t>(tunif),
+ //.neigh6 = ,
+ };
+
+ ethhdr hdr = {
+ .h_proto = htons(ETH_P_IPV6),
+ };
+
+ TetherIngressValue value = {
+ .oif = static_cast<uint32_t>(tapif),
+ .macHeader = hdr,
+ .pmtu = mtu,
+ };
+
+#define ASSERT_OK(status) ASSERT_TRUE((status).ok())
+
+ ASSERT_OK(bpfIngressMap.writeValue(key, value, BPF_ANY));
+
+ uint32_t k = tunif;
+ TetherStatsValue stats = {};
+ ASSERT_OK(bpfStatsMap.writeValue(k, stats, BPF_NOEXIST));
+
+ uint64_t limit = ~0uLL;
+ ASSERT_OK(bpfLimitMap.writeValue(k, limit, BPF_NOEXIST));
+
+ // minimal 'acceptable' 40-byte hoplimit 255 IPv6 packet, src ip 2000::
+ uint8_t pkt[mtu] = {
+ 0x60, 0, 0, 0, 0, 40, 0, 255, 0x20,
+ };
+
+ // Iterate over all packet sizes from minimal ipv6 packet to mtu.
+ // Tethering ebpf program should forward the packet from tun to tap interface.
+ // TUN is L3, TAP is L2, so it will add a 14 byte ethernet header.
+ for (int pkt_size = 40; pkt_size <= mtu; ++pkt_size) {
+ rv = write(tun, pkt, pkt_size);
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(rv, pkt_size);
+
+ struct pollfd p = {
+ .fd = tap,
+ .events = POLLIN,
+ };
+
+ rv = poll(&p, 1, 1000 /*milliseconds*/);
+ if (rv == 0) {
+ // we hit a timeout at this packet size, log it
+ EXPECT_EQ(pkt_size, -1);
+ // this particular packet size is where it fails without the oneline kernel fix
+ if (pkt_size + ETH_HLEN == mtu + 1) EXPECT_EQ("detected missing kernel patch", "");
+ break;
+ }
+ EXPECT_EQ(errno, 0);
+ EXPECT_EQ(rv, 1);
+ EXPECT_EQ(p.revents, POLLIN);
+
+ // use a buffer 1 byte larger then what we expect so we don't simply get truncated down
+ uint8_t buf[ETH_HLEN + mtu + 1];
+ rv = read(tap, buf, sizeof(buf));
+ EXPECT_EQ(errno, 0);
+ EXPECT_EQ(rv, ETH_HLEN + pkt_size);
+ errno = 0;
+ if (rv < 0) break;
+ }
+
+ ASSERT_OK(bpfIngressMap.deleteValue(key));
+ ASSERT_OK(bpfStatsMap.deleteValue(k));
+ ASSERT_OK(bpfLimitMap.deleteValue(k));
+}
+
} // namespace net
} // namespace android
diff --git a/tests/netlink_listener_test.cpp b/tests/netlink_listener_test.cpp
index 249bdfb..46394ca 100644
--- a/tests/netlink_listener_test.cpp
+++ b/tests/netlink_listener_test.cpp
@@ -45,7 +45,7 @@
// A test tag arbitrarily selected.
constexpr uint32_t TEST_TAG = 0xFF0F0F0F;
-constexpr uint32_t SOCK_CLOSE_WAIT_US = 30 * 1000;
+constexpr uint32_t SOCK_CLOSE_WAIT_US = 20 * 1000;
constexpr uint32_t ENOBUFS_POLL_WAIT_US = 10 * 1000;
using android::base::Result;
@@ -67,11 +67,15 @@
BpfMap<uint64_t, UidTagValue> mCookieTagMap;
void SetUp() {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
mCookieTagMap.reset(android::bpf::mapRetrieveRW(COOKIE_TAG_MAP_PATH));
ASSERT_TRUE(mCookieTagMap.isValid());
}
void TearDown() {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
const auto deleteTestCookieEntries = [](const uint64_t& key, const UidTagValue& value,
BpfMap<uint64_t, UidTagValue>& map) {
if ((value.uid == TEST_UID) && (value.tag == TEST_TAG)) {
@@ -99,7 +103,7 @@
return mCookieTagMap.iterateWithValue(checkGarbageTags);
}
- bool checkMassiveSocketDestroy(int totalNumber, bool expectError) {
+ void checkMassiveSocketDestroy(int totalNumber, bool expectError) {
std::unique_ptr<android::net::NetlinkListenerInterface> skDestroyListener;
auto result = android::net::TrafficController::makeSkDestroyListener();
if (!isOk(result)) {
@@ -137,36 +141,25 @@
// If ENOBUFS triggered, check it only called into the handler once, ie.
// that the netlink handler is not spinning.
int currentErrorCount = rxErrorCount;
- // 0 error count is acceptable because the system has chances to close all sockets
- // normally.
- EXPECT_LE(0, rxErrorCount);
- if (!rxErrorCount) return true;
-
+ EXPECT_LT(0, rxErrorCount);
usleep(ENOBUFS_POLL_WAIT_US);
EXPECT_EQ(currentErrorCount, rxErrorCount);
} else {
EXPECT_RESULT_OK(checkNoGarbageTagsExist());
EXPECT_EQ(0, rxErrorCount);
}
- return false;
}
};
TEST_F(NetlinkListenerTest, TestAllSocketUntagged) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
checkMassiveSocketDestroy(10, false);
checkMassiveSocketDestroy(100, false);
}
-// Disabled because flaky on blueline-userdebug; this test relies on the main thread
-// winning a race against the NetlinkListener::run() thread. There's no way to ensure
-// things will be scheduled the same way across all architectures and test environments.
-TEST_F(NetlinkListenerTest, DISABLED_TestSkDestroyError) {
- bool needRetry = false;
- int retryCount = 0;
- do {
- needRetry = checkMassiveSocketDestroy(32500, true);
- if (needRetry) retryCount++;
- } while (needRetry && retryCount < 3);
- // Should review test if it can always close all sockets correctly.
- EXPECT_GT(3, retryCount);
+TEST_F(NetlinkListenerTest, TestSkDestroyError) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ checkMassiveSocketDestroy(32500, true);
}