summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-07-15 01:32:26 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-07-15 01:32:26 +0000
commit6deef8577df2a8ebe6629ffaea613675f23dc96e (patch)
tree389d5f648f0e28282ce9b077d1c0ff513f88b78c
parent003524e75b847376b361f310443405bdb6d37c6d (diff)
parent163acedd1d32a31aed0b323f93dc45db9fb5d0bf (diff)
downloadnetd-android12-mainline-conscrypt-release.tar.gz
Snap for 7550844 from 163acedd1d32a31aed0b323f93dc45db9fb5d0bf to mainline-conscrypt-releaseandroid-mainline-12.0.0_r8android-mainline-12.0.0_r25android12-mainline-conscrypt-release
Change-Id: Ia6b8f05aecc20a5310b105262b265709d183ae89
-rw-r--r--Android.bp31
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--OWNERS1
-rw-r--r--bpf_progs/Android.bp22
-rw-r--r--bpf_progs/bpf_net_helpers.h14
-rw-r--r--bpf_progs/clatd.c31
-rw-r--r--bpf_progs/netd.c25
-rw-r--r--bpf_progs/offload.c204
-rw-r--r--client/Android.bp19
-rw-r--r--include/binder_utils/BinderUtil.h43
-rw-r--r--libnetdbpf/Android.bp9
-rw-r--r--libnetdbpf/BpfNetworkStatsTest.cpp23
-rw-r--r--libnetdbpf/include/netdbpf/bpf_shared.h131
-rw-r--r--libnetdutils/Android.bp10
-rw-r--r--libnetdutils/OperationLimiterTest.cpp73
-rw-r--r--libnetdutils/include/netdutils/OperationLimiter.h104
-rw-r--r--netutils_wrappers/Android.bp10
-rw-r--r--netutils_wrappers/NetUtilsWrapper-1.0.cpp2
-rw-r--r--server/Android.bp112
-rw-r--r--server/BandwidthController.cpp133
-rw-r--r--server/BandwidthController.h24
-rw-r--r--server/BandwidthControllerTest.cpp149
-rw-r--r--server/ClatdController.cpp148
-rw-r--r--server/ClatdController.h15
-rw-r--r--server/ClatdControllerTest.cpp1
-rw-r--r--server/Controllers.cpp7
-rw-r--r--server/DummyNetwork.cpp25
-rw-r--r--server/DummyNetwork.h4
-rw-r--r--server/FirewallController.cpp89
-rw-r--r--server/FirewallController.h10
-rw-r--r--server/FirewallControllerTest.cpp151
-rw-r--r--server/IdletimerController.cpp20
-rw-r--r--server/IdletimerControllerTest.cpp18
-rw-r--r--server/IptablesRestoreControllerTest.cpp97
-rw-r--r--server/LocalNetwork.cpp7
-rw-r--r--server/LocalNetwork.h2
-rw-r--r--server/NdcDispatcher.cpp22
-rw-r--r--server/NetdConstants.cpp3
-rw-r--r--server/NetdNativeService.cpp138
-rw-r--r--server/NetdNativeService.h10
-rw-r--r--server/NetlinkHandler.cpp6
-rw-r--r--server/Network.cpp90
-rw-r--r--server/Network.h44
-rw-r--r--server/NetworkController.cpp172
-rw-r--r--server/NetworkController.h18
-rw-r--r--server/OemNetdListener.cpp14
-rw-r--r--server/OemNetdListener.h6
-rw-r--r--server/OffloadUtils.cpp68
-rw-r--r--server/OffloadUtils.h82
-rw-r--r--server/OffloadUtilsTest.cpp156
-rw-r--r--server/PhysicalNetwork.cpp41
-rw-r--r--server/PhysicalNetwork.h7
-rw-r--r--server/RouteController.cpp302
-rw-r--r--server/RouteController.h84
-rw-r--r--server/RouteControllerTest.cpp8
-rw-r--r--server/SockDiag.cpp38
-rw-r--r--server/SockDiag.h4
-rw-r--r--server/SockDiagTest.cpp2
-rw-r--r--server/TetherController.cpp367
-rw-r--r--server/TetherController.h27
-rw-r--r--server/TetherControllerTest.cpp106
-rw-r--r--server/TrafficController.cpp170
-rw-r--r--server/TrafficController.h25
-rw-r--r--server/TrafficControllerTest.cpp275
-rw-r--r--server/UidRanges.cpp29
-rw-r--r--server/UidRanges.h12
-rw-r--r--server/UnreachableNetwork.cpp62
-rw-r--r--server/UnreachableNetwork.h36
-rw-r--r--server/VirtualNetwork.cpp68
-rw-r--r--server/VirtualNetwork.h20
-rw-r--r--server/XfrmController.cpp180
-rw-r--r--server/XfrmController.h48
-rw-r--r--server/aidl_api/netd_aidl_interface/5/.hash1
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl167
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl32
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl26
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl23
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl24
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl23
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl27
-rw-r--r--server/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl24
-rw-r--r--server/aidl_api/netd_aidl_interface/6/.hash1
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl198
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl48
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl42
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl43
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl41
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl40
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl44
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl43
-rw-r--r--server/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl40
-rw-r--r--server/aidl_api/netd_aidl_interface/7/.hash1
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl200
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl48
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl42
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl43
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl41
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl40
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl44
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl43
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl40
-rw-r--r--server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl41
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl50
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl43
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl39
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl41
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl28
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl29
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl41
-rw-r--r--server/binder/android/net/INetd.aidl104
-rw-r--r--server/binder/android/net/NativeNetworkConfig.aidl52
-rw-r--r--server/binder/android/net/NativeNetworkType.aidl30
-rw-r--r--server/binder/android/net/NativeVpnType.aidl40
-rw-r--r--server/binder/android/net/UidRangeParcel.aidl3
-rw-r--r--server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl41
-rw-r--r--server/main.cpp5
-rw-r--r--tests/Android.bp18
-rw-r--r--tests/benchmarks/Android.bp17
-rw-r--r--tests/benchmarks/bpf_benchmark.cpp8
-rw-r--r--tests/binder_test.cpp1718
-rw-r--r--tests/bpf_base_test.cpp20
-rw-r--r--tests/netd_test.cpp206
-rw-r--r--tests/netlink_listener_test.cpp33
136 files changed, 5754 insertions, 3216 deletions
diff --git a/Android.bp b/Android.bp
index 01a8e77e..0838a8dd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,6 +1,27 @@
+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 {
@@ -38,12 +59,22 @@ cc_defaults {
"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
deleted file mode 100644
index e69de29b..00000000
--- a/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/OWNERS b/OWNERS
index 7d617ec0..94e70d50 100644
--- a/OWNERS
+++ b/OWNERS
@@ -8,3 +8,4 @@ nuccachen@google.com
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 8ce924b9..1311ca90 100644
--- a/bpf_progs/Android.bp
+++ b/bpf_progs/Android.bp
@@ -14,6 +14,15 @@
// 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: ["."],
@@ -47,16 +56,3 @@ bpf {
"system/netd/libnetdutils/include",
],
}
-
-bpf {
- name: "offload.o",
- srcs: ["offload.c"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- include_dirs: [
- "system/netd/libnetdbpf/include",
- "system/netd/libnetdutils/include",
- ],
-}
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index d4dc5f85..d978f3a2 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -26,9 +26,15 @@
static uint64_t (*bpf_get_socket_cookie)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_cookie;
static uint32_t (*bpf_get_socket_uid)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_uid;
+
+static int (*bpf_skb_pull_data)(struct __sk_buff* skb, __u32 len) = (void*)BPF_FUNC_skb_pull_data;
+
static int (*bpf_skb_load_bytes)(struct __sk_buff* skb, int off, void* to,
int len) = (void*)BPF_FUNC_skb_load_bytes;
+static int (*bpf_skb_store_bytes)(struct __sk_buff* skb, __u32 offset, const void* from, __u32 len,
+ __u64 flags) = (void*)BPF_FUNC_skb_store_bytes;
+
static int64_t (*bpf_csum_diff)(__be32* from, __u32 from_size, __be32* to, __u32 to_size,
__wsum seed) = (void*)BPF_FUNC_csum_diff;
@@ -41,6 +47,8 @@ static int (*bpf_l3_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 fro
static int (*bpf_l4_csum_replace)(struct __sk_buff* skb, __u32 offset, __u64 from, __u64 to,
__u64 flags) = (void*)BPF_FUNC_l4_csum_replace;
static int (*bpf_redirect)(__u32 ifindex, __u64 flags) = (void*)BPF_FUNC_redirect;
+static int (*bpf_redirect_map)(const struct bpf_map_def* map, __u32 key,
+ __u64 flags) = (void*)BPF_FUNC_redirect_map;
static int (*bpf_skb_change_head)(struct __sk_buff* skb, __u32 head_room,
__u64 flags) = (void*)BPF_FUNC_skb_change_head;
@@ -58,4 +66,10 @@ static inline __always_inline __unused bool is_received_skb(struct __sk_buff* sk
skb->pkt_type == PACKET_MULTICAST;
}
+// try to make the first 'len' header bytes readable via direct packet access
+static inline __always_inline void try_make_readable(struct __sk_buff* skb, int len) {
+ if (len > skb->len) len = skb->len;
+ if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len);
+}
+
#endif // NETDBPF_BPF_NET_HELPERS_H
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index e7586928..31e05222 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_ingress_map, HASH, ClatIngressKey, ClatIngressValue, 16)
+DEFINE_BPF_MAP(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 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,6 +46,9 @@ static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet)
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;
@@ -72,7 +75,7 @@ static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet)
return TC_ACT_OK;
}
- ClatIngressKey k = {
+ ClatIngress6Key k = {
.iif = skb->ifindex,
.pfx96.in6_u.u6_addr32 =
{
@@ -83,7 +86,7 @@ static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet)
.local6 = ip6->daddr,
};
- ClatIngressValue* v = bpf_clat_ingress_map_lookup_elem(&k);
+ ClatIngress6Value* v = bpf_clat_ingress6_map_lookup_elem(&k);
if (!v) return TC_ACT_OK;
@@ -176,25 +179,25 @@ static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet)
return TC_ACT_OK;
}
-SEC("schedcls/ingress/clat_ether")
-int sched_cls_ingress_clat_ether(struct __sk_buff* skb) {
+DEFINE_BPF_PROG("schedcls/ingress6/clat_ether", AID_ROOT, AID_ROOT, sched_cls_ingress6_clat_ether)
+(struct __sk_buff* skb) {
return nat64(skb, true);
}
-SEC("schedcls/ingress/clat_rawip")
-int sched_cls_ingress_clat_rawip(struct __sk_buff* skb) {
+DEFINE_BPF_PROG("schedcls/ingress6/clat_rawip", AID_ROOT, AID_ROOT, sched_cls_ingress6_clat_rawip)
+(struct __sk_buff* skb) {
return nat64(skb, false);
}
-DEFINE_BPF_MAP(clat_egress_map, HASH, ClatEgressKey, ClatEgressValue, 16)
+DEFINE_BPF_MAP(clat_egress4_map, HASH, ClatEgress4Key, ClatEgress4Value, 16)
-SEC("schedcls/egress/clat_ether")
-int sched_cls_egress_clat_ether(struct __sk_buff* skb) {
+DEFINE_BPF_PROG("schedcls/egress4/clat_ether", AID_ROOT, AID_ROOT, sched_cls_egress4_clat_ether)
+(struct __sk_buff* skb) {
return TC_ACT_OK;
}
-SEC("schedcls/egress/clat_rawip")
-int sched_cls_egress_clat_rawip(struct __sk_buff* skb) {
+DEFINE_BPF_PROG("schedcls/egress4/clat_rawip", AID_ROOT, AID_ROOT, sched_cls_egress4_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;
@@ -248,12 +251,12 @@ int sched_cls_egress_clat_rawip(struct __sk_buff* skb) {
return TC_ACT_OK;
}
- ClatEgressKey k = {
+ ClatEgress4Key k = {
.iif = skb->ifindex,
.local4.s_addr = ip4->saddr,
};
- ClatEgressValue* v = bpf_clat_egress_map_lookup_elem(&k);
+ ClatEgress4Value* v = bpf_clat_egress4_map_lookup_elem(&k);
if (!v) return TC_ACT_OK;
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index f3470280..e9e1477f 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -203,9 +203,12 @@ static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, int direc
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 whitelisted interface
+ // Drops packets not coming from lo nor the allowlisted interface
if (allowed_iif && skb->ifindex != 1 && skb->ifindex != allowed_iif) {
return BPF_DROP_UNLESS_DNS;
}
@@ -280,13 +283,13 @@ static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int
return match;
}
-SEC("cgroupskb/ingress/stats")
-int bpf_cgroup_ingress(struct __sk_buff* skb) {
+DEFINE_BPF_PROG("cgroupskb/ingress/stats", AID_ROOT, AID_ROOT, bpf_cgroup_ingress)
+(struct __sk_buff* skb) {
return bpf_traffic_account(skb, BPF_INGRESS);
}
-SEC("cgroupskb/egress/stats")
-int bpf_cgroup_egress(struct __sk_buff* skb) {
+DEFINE_BPF_PROG("cgroupskb/egress/stats", AID_ROOT, AID_ROOT, bpf_cgroup_egress)
+(struct __sk_buff* skb) {
return bpf_traffic_account(skb, BPF_EGRESS);
}
@@ -315,7 +318,7 @@ DEFINE_BPF_PROG("skfilter/ingress/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_ingres
return BPF_MATCH;
}
-DEFINE_BPF_PROG("skfilter/whitelist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_whitelist_prog)
+DEFINE_BPF_PROG("skfilter/allowlist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_allowlist_prog)
(struct __sk_buff* skb) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
if (is_system_uid(sock_uid)) return BPF_MATCH;
@@ -327,16 +330,16 @@ DEFINE_BPF_PROG("skfilter/whitelist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_whit
if ((sock_uid == 65534) && !bpf_get_socket_cookie(skb) && is_received_skb(skb))
return BPF_MATCH;
- UidOwnerValue* whitelistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
- if (whitelistMatch) return whitelistMatch->rule & HAPPY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
+ UidOwnerValue* allowlistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
+ if (allowlistMatch) return allowlistMatch->rule & HAPPY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
return BPF_NOMATCH;
}
-DEFINE_BPF_PROG("skfilter/blacklist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_blacklist_prog)
+DEFINE_BPF_PROG("skfilter/denylist/xtbpf", AID_ROOT, AID_NET_ADMIN, xt_bpf_denylist_prog)
(struct __sk_buff* skb) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
- UidOwnerValue* blacklistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
- if (blacklistMatch) return blacklistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
+ UidOwnerValue* denylistMatch = bpf_uid_owner_map_lookup_elem(&sock_uid);
+ if (denylistMatch) return denylistMatch->rule & PENALTY_BOX_MATCH ? BPF_MATCH : BPF_NOMATCH;
return BPF_NOMATCH;
}
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
deleted file mode 100644
index 16dbe1dd..00000000
--- a/bpf_progs/offload.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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.
- */
-
-#include <linux/if.h>
-#include <linux/ip.h>
-#include <linux/ipv6.h>
-#include <linux/pkt_cls.h>
-#include <linux/tcp.h>
-
-#include "bpf_helpers.h"
-#include "bpf_net_helpers.h"
-#include "netdbpf/bpf_shared.h"
-
-DEFINE_BPF_MAP_GRW(tether_ingress_map, HASH, TetherIngressKey, TetherIngressValue, 64,
- AID_NETWORK_STACK)
-
-// Tethering stats, indexed by upstream interface.
-DEFINE_BPF_MAP_GRW(tether_stats_map, HASH, uint32_t, TetherStatsValue, 16, AID_NETWORK_STACK)
-
-// Tethering data limit, indexed by upstream interface.
-// (tethering allowed when stats[iif].rxBytes + stats[iif].txBytes < limit[iif])
-DEFINE_BPF_MAP_GRW(tether_limit_map, HASH, uint32_t, uint64_t, 16, AID_NETWORK_STACK)
-
-static inline __always_inline int do_forward(struct __sk_buff* skb, bool is_ethernet) {
- int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
- void* data = (void*)(long)skb->data;
- const void* data_end = (void*)(long)skb->data_end;
- struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet
- struct ipv6hdr* ip6 = is_ethernet ? (void*)(eth + 1) : data;
-
- // Must be meta-ethernet IPv6 frame
- if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
-
- // Must have (ethernet and) ipv6 header
- if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
-
- // Ethertype - if present - must be IPv6
- if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
-
- // IP version must be 6
- if (ip6->version != 6) return TC_ACT_OK;
-
- // Cannot decrement during forward if already zero or would be zero,
- // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
- if (ip6->hop_limit <= 1) return TC_ACT_OK;
-
- // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
- __be32 src32 = ip6->saddr.s6_addr32[0];
- if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP
- (src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast
- return TC_ACT_OK;
-
- TetherIngressKey k = {
- .iif = skb->ifindex,
- .neigh6 = ip6->daddr,
- };
-
- TetherIngressValue* v = bpf_tether_ingress_map_lookup_elem(&k);
-
- // If we don't find any offload information then simply let the core stack handle it...
- if (!v) return TC_ACT_OK;
-
- uint32_t stat_and_limit_k = skb->ifindex;
-
- TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
-
- // If we don't have anywhere to put stats, then abort...
- if (!stat_v) return TC_ACT_OK;
-
- uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k);
-
- // If we don't have a limit, then abort...
- if (!limit_v) return TC_ACT_OK;
-
- // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort...
- const int pmtu = v->pmtu;
- if (pmtu < IPV6_MIN_MTU) return TC_ACT_OK;
-
- // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default
- // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
- // undercount, which is still better then not accounting for this overhead at all.
- // Note: this really shouldn't be device/path mtu at all, but rather should be
- // derived from this particular connection's mss (ie. from gro segment size).
- // This would require a much newer kernel with newer ebpf accessors.
- // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
- uint64_t packets = 1;
- uint64_t bytes = skb->len;
- if (bytes > pmtu) {
- const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
- const int mss = pmtu - tcp_overhead;
- const uint64_t payload = bytes - tcp_overhead;
- packets = (payload + mss - 1) / mss;
- bytes = tcp_overhead * packets + payload;
- }
-
- // Are we past the limit? If so, then abort...
- // Note: will not overflow since u64 is 936 years even at 5Gbps.
- // Do not drop here. Offload is just that, whenever we fail to handle
- // a packet we let the core stack deal with things.
- // (The core stack needs to handle limits correctly anyway,
- // since we don't offload all traffic in both directions)
- if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) return TC_ACT_OK;
-
- if (!is_ethernet) {
- is_ethernet = true;
- l2_header_size = sizeof(struct ethhdr);
- // Try to inject an ethernet header, and simply return if we fail
- if (bpf_skb_change_head(skb, l2_header_size, /*flags*/ 0)) {
- __sync_fetch_and_add(&stat_v->rxErrors, 1);
- return TC_ACT_OK;
- }
-
- // bpf_skb_change_head() invalidates all pointers - reload them
- data = (void*)(long)skb->data;
- data_end = (void*)(long)skb->data_end;
- eth = data;
- ip6 = (void*)(eth + 1);
-
- // I do not believe this can ever happen, but keep the verifier happy...
- if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_SHOT;
- };
-
- // CHECKSUM_COMPLETE is a 16-bit one's complement sum,
- // thus corrections for it need to be done in 16-byte chunks at even offsets.
- // IPv6 nexthdr is at offset 6, while hop limit is at offset 7
- uint8_t old_hl = ip6->hop_limit;
- --ip6->hop_limit;
- uint8_t new_hl = ip6->hop_limit;
-
- // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error
- // (-ENOTSUPP) if it isn't.
- bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl));
-
- __sync_fetch_and_add(&stat_v->rxPackets, packets);
- __sync_fetch_and_add(&stat_v->rxBytes, bytes);
-
- // Overwrite any mac header with the new one
- *eth = v->macHeader;
-
- // Redirect to forwarded interface.
- //
- // Note that bpf_redirect() cannot fail unless you pass invalid flags.
- // The redirect actually happens after the ebpf program has already terminated,
- // and can fail for example for mtu reasons at that point in time, but there's nothing
- // we can do about it here.
- return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
-}
-
-SEC("schedcls/ingress/tether_ether")
-int sched_cls_ingress_tether_ether(struct __sk_buff* skb) {
- return do_forward(skb, true);
-}
-
-// Note: section names must be unique to prevent programs from appending to each other,
-// so instead the bpf loader will strip everything past the final $ symbol when actually
-// pinning the program into the filesystem.
-//
-// bpf_skb_change_head() is only present on 4.14+ and 2 trivial kernel patches are needed:
-// ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
-// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
-// (the first of those has already been upstreamed)
-//
-// 5.4 kernel support was only added to Android Common Kernel in R,
-// and thus a 5.4 kernel always supports this.
-//
-// Hence, this mandatory (must load successfully) implementation for 5.4+ kernels:
-DEFINE_BPF_PROG_KVER("schedcls/ingress/tether_rawip$5_4", AID_ROOT, AID_ROOT,
- sched_cls_ingress_tether_rawip_5_4, KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return do_forward(skb, false);
-}
-
-// and this identical optional (may fail to load) implementation for [4.14..5.4) patched kernels:
-DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$4_14", AID_ROOT, AID_ROOT,
- sched_cls_ingress_tether_rawip_4_14, KVER(4, 14, 0),
- KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return do_forward(skb, false);
-}
-
-// and define a no-op stub for [4.9,4.14) and unpatched [4.14,5.4) kernels.
-// (if the above real 4.14+ program loaded successfully, then bpfloader will have already pinned
-// it at the same location this one would be pinned at and will thus skip loading this stub)
-DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$stub", AID_ROOT, AID_ROOT,
- sched_cls_ingress_tether_rawip_stub, KVER_NONE, KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return TC_ACT_OK;
-}
-
-LICENSE("Apache 2.0");
-CRITICAL("netd");
diff --git a/client/Android.bp b/client/Android.bp
index 53afc977..b8eb56c4 100644
--- a/client/Android.bp
+++ b/client/Android.bp
@@ -12,6 +12,15 @@
// 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: [
@@ -22,7 +31,6 @@ cc_library {
"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: [
@@ -32,6 +40,10 @@ cc_library {
sanitize: {
cfi: true,
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
}
cc_test {
@@ -44,16 +56,13 @@ cc_test {
include_dirs: [
"system/netd/include",
],
- header_libs: [
- "libnetd_resolv_headers",
- ],
static_libs: [
"libgmock",
"libbase",
"libnetd_client",
],
sanitize: {
- address: true,
+ address: false,
recover: [ "all" ],
},
}
diff --git a/include/binder_utils/BinderUtil.h b/include/binder_utils/BinderUtil.h
index 6b41465a..469fa681 100644
--- a/include/binder_utils/BinderUtil.h
+++ b/include/binder_utils/BinderUtil.h
@@ -16,9 +16,8 @@
#pragma once
-#include <android-base/stringprintf.h>
-#include <json/value.h>
-#include <json/writer.h>
+#include <android-base/strings.h>
+#include <fmt/format.h>
#ifdef ANDROID_BINDER_STATUS_H
#define IS_BINDER_OK(__ex__) (__ex__ == ::android::binder::Status::EX_NONE)
@@ -59,31 +58,26 @@ std::string exceptionToString(int32_t exception) {
using LogFn = std::function<void(const std::string& msg)>;
-void binderCallLogFn(const Json::Value& logTransaction, const LogFn& logFn) {
+template <typename LogType>
+void binderCallLogFn(const LogType& log, 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 = !returnArgs.empty();
- output.append(logTransaction["method_name"].asString() + "("s);
+ hasReturnArgs = !log.result.empty();
+ output.append(log.method_name + "("s);
// input args
- 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) {
+ 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) {
output.append(", "s);
}
}
output.append(")"s);
- const int exceptionCode =
- TO_EXCEPTION(logTransaction["binder_status"]["exception_code"].asInt());
+ const int exceptionCode = TO_EXCEPTION(log.exception_code);
if (hasReturnArgs || !IS_BINDER_OK(exceptionCode)) {
output.append(" -> "s);
@@ -92,18 +86,17 @@ void binderCallLogFn(const Json::Value& logTransaction, const LogFn& logFn) {
// return status
if (!IS_BINDER_OK(exceptionCode)) {
// an exception occurred
- 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()));
+ const int errCode = log.service_specific_error_code;
+ output.append(fmt::format("{}({}, \"{}\")", exceptionToString(exceptionCode),
+ (errCode != 0) ? errCode : exceptionCode, log.exception_message));
}
// return args
if (hasReturnArgs) {
- output.append(::android::base::StringPrintf("{%s}", fastWriter.write(returnArgs).c_str()));
+ output.append("{" + log.result + "}");
}
// duration time
- output.append(
- ::android::base::StringPrintf(" <%.2fms>", logTransaction["duration_ms"].asFloat()));
- logFn(output);
+ 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));
}
diff --git a/libnetdbpf/Android.bp b/libnetdbpf/Android.bp
index 72e0fec1..7c0207ce 100644
--- a/libnetdbpf/Android.bp
+++ b/libnetdbpf/Android.bp
@@ -14,6 +14,15 @@
// 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 a9581ce7..fb8f0ec6 100644
--- a/libnetdbpf/BpfNetworkStatsTest.cpp
+++ b/libnetdbpf/BpfNetworkStatsTest.cpp
@@ -78,7 +78,6 @@ class BpfNetworkStatsHelperTest : public testing::Test {
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);
@@ -140,8 +139,6 @@ class BpfNetworkStatsHelperTest : public testing::Test {
// 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};
@@ -171,8 +168,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
}
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};
@@ -193,8 +188,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestBpfIterateMap) {
}
TEST_F(BpfNetworkStatsHelperTest, TestUidStatsNoTraffic) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
StatsValue value1 = {
.rxPackets = 0,
.rxBytes = 0,
@@ -207,8 +200,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestUidStatsNoTraffic) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -249,8 +240,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -294,8 +283,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
StatsValue value1 = {
@@ -331,8 +318,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
StatsValue value1 = {
@@ -368,8 +353,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
}
TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
StatsValue value1 = {
.rxPackets = TEST_PACKET0,
@@ -412,8 +395,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -451,8 +432,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
}
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);
@@ -543,8 +522,6 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortedAndGrouped) {
// 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 6f318799..2fcb612d 100644
--- a/libnetdbpf/include/netdbpf/bpf_shared.h
+++ b/libnetdbpf/include/netdbpf/bpf_shared.h
@@ -14,20 +14,26 @@
* limitations under the License.
*/
-#ifndef NETDBPF_BPF_SHARED_H
-#define NETDBPF_BPF_SHARED_H
+#pragma once
+#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 and netd
+// 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.")
typedef struct {
uint32_t uid;
uint32_t tag;
} UidTagValue;
+STRUCT_SIZE(UidTagValue, 2 * 4); // 8
typedef struct {
uint32_t uid;
@@ -35,6 +41,7 @@ typedef struct {
uint32_t counterSet;
uint32_t ifaceIndex;
} StatsKey;
+STRUCT_SIZE(StatsKey, 4 * 4); // 16
typedef struct {
uint64_t rxPackets;
@@ -42,10 +49,12 @@ typedef struct {
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;
@@ -89,26 +98,26 @@ const int IFACE_STATS_MAP_SIZE = 1000;
const int CONFIGURATION_MAP_SIZE = 2;
const int UID_OWNER_MAP_SIZE = 2000;
-#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_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 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 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,
@@ -117,7 +126,8 @@ enum UidOwnerMatchType {
DOZABLE_MATCH = (1 << 2),
STANDBY_MATCH = (1 << 3),
POWERSAVE_MATCH = (1 << 4),
- IIF_MATCH = (1 << 5),
+ RESTRICTED_MATCH = (1 << 5),
+ IIF_MATCH = (1 << 6),
};
enum BpfPermissionMatch {
@@ -141,84 +151,55 @@ typedef struct {
// 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.
- uint8_t rule;
+ uint32_t rule;
} UidOwnerValue;
+STRUCT_SIZE(UidOwnerValue, 2 * 4); // 8
#define UID_RULES_CONFIGURATION_KEY 1
#define CURRENT_STATS_MAP_CONFIGURATION_KEY 2
-#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_NAME "prog_clatd_schedcls_ingress6_clat_rawip"
+#define CLAT_INGRESS6_PROG_ETHER_NAME "prog_clatd_schedcls_ingress6_clat_ether"
-#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_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_MAP_PATH BPF_PATH "/map_clatd_clat_ingress_map"
+#define CLAT_INGRESS6_MAP_PATH BPF_PATH "map_clatd_clat_ingress6_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
-} ClatIngressKey;
+} ClatIngress6Key;
+STRUCT_SIZE(ClatIngress6Key, 4 + 2 * 16); // 36
typedef struct {
uint32_t oif; // The output interface to redirect to (0 means don't redirect)
struct in_addr local4; // The destination IPv4 address
-} ClatIngressValue;
+} ClatIngress6Value;
+STRUCT_SIZE(ClatIngress6Value, 4 + 4); // 8
-#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_NAME "prog_clatd_schedcls_egress4_clat_rawip"
+#define CLAT_EGRESS4_PROG_ETHER_NAME "prog_clatd_schedcls_egress4_clat_ether"
-#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_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_MAP_PATH BPF_PATH "/map_clatd_clat_egress_map"
+#define CLAT_EGRESS4_MAP_PATH BPF_PATH "map_clatd_clat_egress4_map"
typedef struct {
uint32_t iif; // The input interface index
struct in_addr local4; // The source IPv4 address
-} ClatEgressKey;
+} ClatEgress4Key;
+STRUCT_SIZE(ClatEgress4Key, 4 + 4); // 8
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
-} ClatEgressValue;
+ uint8_t pad[3];
+} ClatEgress4Value;
+STRUCT_SIZE(ClatEgress4Value, 4 + 2 * 16 + 1 + 3); // 40
-#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
+#undef STRUCT_SIZE
diff --git a/libnetdutils/Android.bp b/libnetdutils/Android.bp
index 00bdc74f..31f2c53b 100644
--- a/libnetdutils/Android.bp
+++ b/libnetdutils/Android.bp
@@ -1,3 +1,12 @@
+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: [
@@ -44,7 +53,6 @@ cc_test {
"InternetAddressesTest.cpp",
"LogTest.cpp",
"MemBlockTest.cpp",
- "OperationLimiterTest.cpp",
"SliceTest.cpp",
"StatusTest.cpp",
"SyscallsTest.cpp",
diff --git a/libnetdutils/OperationLimiterTest.cpp b/libnetdutils/OperationLimiterTest.cpp
deleted file mode 100644
index 8d72d752..00000000
--- a/libnetdutils/OperationLimiterTest.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 992a8498..00000000
--- a/libnetdutils/include/netdutils/OperationLimiter.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 af7d8c3b..fdf802f4 100644
--- a/netutils_wrappers/Android.bp
+++ b/netutils_wrappers/Android.bp
@@ -1,3 +1,12 @@
+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"],
@@ -23,6 +32,7 @@ cc_binary {
],
sanitize: {
cfi: true,
+ memtag_heap: true,
},
}
diff --git a/netutils_wrappers/NetUtilsWrapper-1.0.cpp b/netutils_wrappers/NetUtilsWrapper-1.0.cpp
index cdc454e3..d81b0ec6 100644
--- a/netutils_wrappers/NetUtilsWrapper-1.0.cpp
+++ b/netutils_wrappers/NetUtilsWrapper-1.0.cpp
@@ -73,8 +73,6 @@ const char *EXPECTED_REGEXPS[] = {
// 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 36ad42c3..9c89041a 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -1,8 +1,18 @@
+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",
+ "netd_aidl_interface-V7-java",
],
apex_available: [
"//apex_available:platform", // used from services.net
@@ -12,6 +22,35 @@ java_library {
],
}
+cc_library_static {
+ name: "netd_event_listener_interface-lateststable-ndk_platform",
+ whole_static_libs: [
+ "netd_event_listener_interface-V1-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-V7-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-V7-cpp",
+ ],
+}
+
aidl_interface {
name: "netd_aidl_interface",
local_include_dir: "binder",
@@ -21,11 +60,16 @@ aidl_interface {
"binder/android/net/INetdUnsolicitedEventListener.aidl",
"binder/android/net/InterfaceConfigurationParcel.aidl",
"binder/android/net/MarkMaskParcel.aidl",
+ "binder/android/net/NativeNetworkConfig.aidl",
+ "binder/android/net/NativeNetworkType.aidl",
+ "binder/android/net/NativeVpnType.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",
+ // Add new AIDL classes in android.net.netd.aidl to consist with other network modules.
+ "binder/android/net/netd/aidl/**/*.aidl",
],
backend: {
cpp: {
@@ -43,20 +87,32 @@ aidl_interface {
// this is part of updatable modules(NetworkStack) which targets 29(Q)
min_sdk_version: "29",
},
+ ndk: {
+ apex_available: [
+ "//apex_available:platform",
+ ],
+ // This is necessary for the DnsResovler tests to run in Android Q.
+ // Soong would recognize this value and produce the Q compatible aidl library.
+ min_sdk_version: "29",
+ },
},
versions: [
"1",
"2",
"3",
"4",
+ "5",
+ "6",
+ "7",
],
}
java_library {
name: "netd_event_listener_interface-lateststable-java",
sdk_version: "system_current",
+ min_sdk_version: "29",
static_libs: [
- "netd_event_listener_interface-java",
+ "netd_event_listener_interface-V1-java",
],
apex_available: [
"//apex_available:platform",
@@ -81,6 +137,15 @@ aidl_interface {
],
min_sdk_version: "29",
},
+ java: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth.updatable",
+ "com.android.wifi",
+ "com.android.tethering",
+ ],
+ min_sdk_version: "29",
+ },
},
}
@@ -98,27 +163,6 @@ aidl_interface {
],
}
-// 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 {
@@ -177,8 +221,9 @@ cc_library_static {
"libpcap",
"libqtaguid",
"libssl",
- "netd_aidl_interface-cpp",
- "netd_event_listener_interface-cpp",
+ "libsysutils",
+ "netd_aidl_interface-V7-cpp",
+ "netd_event_listener_interface-V1-cpp",
],
aidl: {
export_aidl_headers: true,
@@ -198,7 +243,6 @@ cc_binary {
"bpfloader",
"clatd.o",
"netd.o",
- "offload.o",
],
shared_libs: [
"android.system.net.netd@1.0",
@@ -209,7 +253,6 @@ cc_binary {
"libcutils",
"libdl",
"libhidlbase",
- "libjsoncpp",
"liblog",
"libmdnssd",
"libnetd_resolv",
@@ -222,8 +265,8 @@ cc_binary {
"libselinux",
"libsysutils",
"libutils",
- "netd_aidl_interface-cpp",
- "netd_event_listener_interface-cpp",
+ "netd_aidl_interface-V7-cpp",
+ "netd_event_listener_interface-V1-cpp",
"oemnetd_aidl_interface-cpp",
],
static_libs: [
@@ -245,6 +288,7 @@ cc_binary {
"PhysicalNetwork.cpp",
"PppController.cpp",
"Process.cpp",
+ "UnreachableNetwork.cpp",
"VirtualNetwork.cpp",
"main.cpp",
"oem_iptables_hook.cpp",
@@ -271,8 +315,8 @@ cc_binary {
"liblog",
"libutils",
"libbinder",
- "dnsresolver_aidl_interface-cpp",
- "netd_aidl_interface-cpp",
+ "dnsresolver_aidl_interface-V7-cpp",
+ "netd_aidl_interface-V6-cpp",
],
srcs: [
"ndc.cpp",
@@ -281,6 +325,7 @@ cc_binary {
],
sanitize: {
cfi: true,
+ memtag_heap: true,
},
}
@@ -318,8 +363,8 @@ cc_test {
"libnetd_server",
"libnetd_test_tun_interface",
"libqtaguid",
- "netd_aidl_interface-unstable-cpp",
- "netd_event_listener_interface-cpp",
+ "netd_aidl_interface-V7-cpp",
+ "netd_event_listener_interface-V1-cpp",
],
shared_libs: [
"libbase",
@@ -334,4 +379,5 @@ cc_test {
"libsysutils",
"libutils",
],
+ // tidy: false, // cuts test build time by almost 1 minute
}
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index e1ce56f2..1b46234a 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -70,6 +70,7 @@ const char BandwidthController::LOCAL_GLOBAL_ALERT[] = "bw_global_alert";
auto BandwidthController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
using android::base::Join;
+using android::base::StartsWith;
using android::base::StringAppendF;
using android::base::StringPrintf;
using android::net::FirewallController;
@@ -83,9 +84,6 @@ namespace {
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
@@ -120,12 +118,12 @@ const char NICE_CHAIN[] = "bw_happy_box";
* iptables -A bw_costly_iface0 -j bw_penalty_box
*
* * Penalty box, happy box and data saver.
- * - 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_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_data_saver implements data usage restrictions.
- * - 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
+ * - 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
* takes precedence over data saver.
*
* * bw_penalty_box handling:
@@ -149,12 +147,8 @@ const char NICE_CHAIN[] = "bw_happy_box";
*/
const std::string COMMIT_AND_CLOSE = "COMMIT\n";
-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);
+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);
static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
/*
@@ -212,7 +206,8 @@ static const uint32_t uidBillingMask = Fwmark::getUidBillingMask();
* See go/ipsec-data-accounting for more information.
*/
-std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
+std::vector<std::string> getBasicAccountingCommands() {
+ // clang-format off
std::vector<std::string> ipt_basic_accounting_commands = {
"*filter",
@@ -221,29 +216,14 @@ std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
"-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",
- useBpf ? BPF_PENALTY_BOX_MATCH_BLACKLIST_COMMAND : "",
- "-A bw_penalty_box -j bw_happy_box", "-A bw_happy_box -j bw_data_saver",
+ ("-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",
"-A bw_data_saver -j RETURN",
- useBpf ? BPF_HAPPY_BOX_MATCH_WHITELIST_COMMAND : HAPPY_BOX_MATCH_WHITELIST_COMMAND,
+ ("-I bw_happy_box -m bpf --object-pinned " XT_BPF_ALLOWLIST_PROG_PATH " -j RETURN"),
"COMMIT",
"*raw",
@@ -262,8 +242,7 @@ std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
//
// 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.
- useBpf ? "-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH
- : "-A bw_raw_PREROUTING -m owner --socket-exists",
+ ("-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH),
"COMMIT",
"*mangle",
@@ -279,22 +258,14 @@ std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
// 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
- useBpf ? "-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH
- : "-A bw_mangle_POSTROUTING -m owner --socket-exists",
+ ("-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH),
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() {
}
@@ -321,7 +292,7 @@ int BandwidthController::enableBandwidthControl() {
flushCleanTables(false);
- std::string commands = Join(getBasicAccountingCommands(mBpfSupported), '\n');
+ std::string commands = Join(getBasicAccountingCommands(), '\n');
return iptablesRestoreFunction(V4V6, commands, nullptr);
}
@@ -352,63 +323,29 @@ int BandwidthController::enableDataSaver(bool enable) {
return ret;
}
-// 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::addNaughtyApps(const std::vector<uint32_t>& appUids) {
+ return manipulateSpecialApps(appUids, PENALTY_BOX_MATCH, IptOpInsert);
}
-// 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::removeNaughtyApps(const std::vector<uint32_t>& appUids) {
+ return manipulateSpecialApps(appUids, PENALTY_BOX_MATCH, IptOpDelete);
}
-// 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::addNiceApps(const std::vector<uint32_t>& appUids) {
+ return manipulateSpecialApps(appUids, HAPPY_BOX_MATCH, IptOpInsert);
}
-// 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::removeNiceApps(const std::vector<uint32_t>& appUids) {
+ return manipulateSpecialApps(appUids, HAPPY_BOX_MATCH, IptOpDelete);
}
-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();
- }
- 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));
+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());
}
- StringAppendF(&cmd, "COMMIT\n");
- return iptablesRestoreFunction(V4V6, cmd, nullptr);
+ return status.code();
}
int BandwidthController::setInterfaceSharedQuota(const std::string& iface, int64_t maxBytes) {
@@ -835,11 +772,11 @@ void BandwidthController::parseAndFlushCostlyTables(const std::string& ruleList,
// Find and flush all rules starting with "-N bw_costly_<iface>" except "-N bw_costly_shared".
while (std::getline(stream, rule, '\n')) {
- if (rule.find(NEW_CHAIN_COMMAND) != 0) continue;
+ if (!StartsWith(rule, NEW_CHAIN_COMMAND)) continue;
chainName = rule.substr(NEW_CHAIN_COMMAND.size());
ALOGV("parse chainName=<%s> orig line=<%s>", chainName.c_str(), rule.c_str());
- if (chainName.find("bw_costly_") != 0 || chainName == std::string("bw_costly_shared")) {
+ if (!StartsWith(chainName, "bw_costly_") || chainName == std::string("bw_costly_shared")) {
continue;
}
@@ -874,8 +811,6 @@ inline const char *BandwidthController::jumpToString(IptJumpOp jumpHandling) {
* 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 b8691dcc..414e91b8 100644
--- a/server/BandwidthController.h
+++ b/server/BandwidthController.h
@@ -24,6 +24,7 @@
#include <mutex>
#include "NetdConstants.h"
+#include "netdbpf/bpf_shared.h"
class BandwidthController {
public:
@@ -32,7 +33,6 @@ public:
BandwidthController();
int setupIptablesHooks();
- void setBpfEnabled(bool isEnabled);
int enableBandwidthControl();
int disableBandwidthControl();
@@ -46,16 +46,10 @@ public:
int getInterfaceQuota(const std::string& iface, int64_t* bytes);
int removeInterfaceQuota(const std::string& iface);
- // 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 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);
int setGlobalAlert(int64_t bytes);
int removeGlobalAlert();
@@ -75,7 +69,7 @@ public:
static const char LOCAL_MANGLE_POSTROUTING[];
static const char LOCAL_GLOBAL_ALERT[];
- enum IptJumpOp { IptJumpReject, IptJumpReturn, IptJumpNoAdd };
+ enum IptJumpOp { IptJumpReject, IptJumpReturn };
enum IptOp { IptOpInsert, IptOpDelete };
private:
@@ -96,8 +90,8 @@ public:
std::string makeDataSaverCommand(IptablesTarget target, bool enable);
- int manipulateSpecialApps(const std::vector<std::string>& appStrUids, const std::string& chain,
- IptJumpOp jumpHandling, IptOp appOp);
+ int manipulateSpecialApps(const std::vector<uint32_t>& appStrUids, UidOwnerMatchType matchType,
+ IptOp appOp);
int runIptablesAlertCmd(IptOp op, const std::string& alertName, int64_t bytes);
int runIptablesAlertFwdCmd(IptOp op, const std::string& alertName, int64_t bytes);
@@ -132,8 +126,6 @@ public:
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 115a0da5..d635daf0 100644
--- a/server/BandwidthControllerTest.cpp
+++ b/server/BandwidthControllerTest.cpp
@@ -50,73 +50,6 @@ using android::net::TunInterface;
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() {
@@ -195,23 +128,6 @@ protected:
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;
};
@@ -247,12 +163,46 @@ TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
EXPECT_TRUE(isPowerOfTwo);
}
-TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithBpf) {
- checkBandwithControl(true);
-}
+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");
+
+ // ... 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
-TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithoutBpf) {
- checkBandwithControl(false);
+ mBw.enableBandwidthControl();
+ expectSetupCommands(expectedClean, expectedAccounting);
}
TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
@@ -512,24 +462,3 @@ TEST_F(BandwidthControllerTest, CostlyAlert) {
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 90afa3a4..847a6db6 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -73,51 +73,23 @@ namespace net {
void ClatdController::init(void) {
std::lock_guard guard(mutex);
- // 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;
- }
-
- // 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();
+ int rv = getClatEgress4MapFd();
if (rv < 0) {
- ALOGE("getClatEgressMapFd() failure: %s", strerror(-rv));
- mClatEbpfMode = ClatEbpfDisabled;
+ ALOGE("getClatEgress4MapFd() failure: %s", strerror(-rv));
return;
}
- mClatEgressMap.reset(rv);
+ mClatEgress4Map.reset(rv);
- rv = getClatIngressMapFd();
+ rv = getClatIngress6MapFd();
if (rv < 0) {
- ALOGE("getClatIngressMapFd() failure: %s", strerror(-rv));
- mClatEbpfMode = ClatEbpfDisabled;
- mClatEgressMap.reset(-1);
+ ALOGE("getClatIngress6MapFd() failure: %s", strerror(-rv));
+ mClatEgress4Map.reset(-1);
return;
}
- mClatIngressMap.reset(rv);
+ mClatIngress6Map.reset(rv);
- mClatEgressMap.clear();
- mClatIngressMap.clear();
+ mClatEgress4Map.clear();
+ mClatIngress6Map.clear();
}
bool ClatdController::isIpv4AddressFree(in_addr_t addr) {
@@ -226,8 +198,6 @@ int ClatdController::generateIpv6Address(const char* iface, const in_addr v4,
}
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,
@@ -236,54 +206,54 @@ void ClatdController::maybeStartBpf(const ClatdTracker& tracker) {
}
// This program will be attached to the v4-* interface which is a TUN and thus always rawip.
- int rv = getClatEgressProgFd(RAWIP);
+ int rv = getClatEgress4ProgFd(RAWIP);
if (rv < 0) {
- ALOGE("getClatEgressProgFd(RAWIP) failure: %s", strerror(-rv));
+ ALOGE("getClatEgress4ProgFd(RAWIP) failure: %s", strerror(-rv));
return;
}
unique_fd txRawIpProgFd(rv);
- rv = getClatIngressProgFd(isEthernet.value());
+ rv = getClatIngress6ProgFd(isEthernet.value());
if (rv < 0) {
- ALOGE("getClatIngressProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
+ ALOGE("getClatIngress6ProgFd(%d) failure: %s", isEthernet.value(), strerror(-rv));
return;
}
unique_fd rxProgFd(rv);
- ClatEgressKey txKey = {
+ ClatEgress4Key txKey = {
.iif = tracker.v4ifIndex,
.local4 = tracker.v4,
};
- ClatEgressValue txValue = {
+ ClatEgress4Value txValue = {
.oif = tracker.ifIndex,
.local6 = tracker.v6,
.pfx96 = tracker.pfx96,
.oifIsEthernet = isEthernet.value(),
};
- auto ret = mClatEgressMap.writeValue(txKey, txValue, BPF_ANY);
+ auto ret = mClatEgress4Map.writeValue(txKey, txValue, BPF_ANY);
if (!ret.ok()) {
- ALOGE("mClatEgressMap.writeValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatEgress4Map.writeValue failure: %s", strerror(ret.error().code()));
return;
}
- ClatIngressKey rxKey = {
+ ClatIngress6Key rxKey = {
.iif = tracker.ifIndex,
.pfx96 = tracker.pfx96,
.local6 = tracker.v6,
};
- ClatIngressValue rxValue = {
+ ClatIngress6Value rxValue = {
// TODO: move all the clat code to eBPF and remove the tun interface entirely.
.oif = tracker.v4ifIndex,
.local4 = tracker.v4,
};
- ret = mClatIngressMap.writeValue(rxKey, rxValue, BPF_ANY);
+ ret = mClatIngress6Map.writeValue(rxKey, rxValue, BPF_ANY);
if (!ret.ok()) {
- ALOGE("mClatIngressMap.writeValue failure: %s", strerror(ret.error().code()));
- ret = mClatEgressMap.deleteValue(txKey);
+ ALOGE("mClatIngress6Map.writeValue failure: %s", strerror(ret.error().code()));
+ ret = mClatEgress4Map.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
@@ -298,47 +268,37 @@ void ClatdController::maybeStartBpf(const ClatdTracker& tracker) {
if (rv) {
ALOGE("tcQdiscAddDevClsact(%d[%s]) failure: %s", tracker.v4ifIndex, tracker.v4iface,
strerror(-rv));
- ret = mClatEgressMap.deleteValue(txKey);
+ ret = mClatEgress4Map.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
- ret = mClatIngressMap.deleteValue(rxKey);
+ ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngress6Map.deleteValue(rxKey);
if (!ret.ok())
- ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
rv = tcFilterAddDevEgressClatIpv4(tracker.v4ifIndex, txRawIpProgFd, RAWIP);
if (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));
- }
+ 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 = mClatEgressMap.deleteValue(txKey);
+ ret = mClatEgress4Map.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
- ret = mClatIngressMap.deleteValue(rxKey);
+ ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngress6Map.deleteValue(rxKey);
if (!ret.ok())
- ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
rv = tcFilterAddDevIngressClatIpv6(tracker.ifIndex, rxProgFd, isEthernet.value());
if (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));
- }
+ 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,
@@ -348,12 +308,12 @@ void ClatdController::maybeStartBpf(const ClatdTracker& tracker) {
// 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 = mClatEgressMap.deleteValue(txKey);
+ ret = mClatEgress4Map.deleteValue(txKey);
if (!ret.ok())
- ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
- ret = mClatIngressMap.deleteValue(rxKey);
+ ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngress6Map.deleteValue(rxKey);
if (!ret.ok())
- ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
return;
}
@@ -372,8 +332,6 @@ void ClatdController::setIptablesDropRule(bool add, const char* iface, const cha
}
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,
@@ -389,22 +347,22 @@ void ClatdController::maybeStopBpf(const ClatdTracker& tracker) {
// We cleanup the maps last, so scanning through them can be used to
// determine what still needs cleanup.
- ClatEgressKey txKey = {
+ ClatEgress4Key txKey = {
.iif = tracker.v4ifIndex,
.local4 = tracker.v4,
};
- auto ret = mClatEgressMap.deleteValue(txKey);
- if (!ret.ok()) ALOGE("mClatEgressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ auto ret = mClatEgress4Map.deleteValue(txKey);
+ if (!ret.ok()) ALOGE("mClatEgress4Map.deleteValue failure: %s", strerror(ret.error().code()));
- ClatIngressKey rxKey = {
+ ClatIngress6Key rxKey = {
.iif = tracker.ifIndex,
.pfx96 = tracker.pfx96,
.local6 = tracker.v6,
};
- ret = mClatIngressMap.deleteValue(rxKey);
- if (!ret.ok()) ALOGE("mClatIngressMap.deleteValue failure: %s", strerror(ret.error().code()));
+ ret = mClatIngress6Map.deleteValue(rxKey);
+ if (!ret.ok()) ALOGE("mClatIngress6Map.deleteValue failure: %s", strerror(ret.error().code()));
}
// Finds the tracker of the clatd running on interface |interface|, or nullptr if clatd has not been
@@ -619,14 +577,14 @@ int ClatdController::stopClatd(const std::string& interface) {
}
void ClatdController::dumpEgress(DumpWriter& dw) {
- if (!mClatEgressMap.isValid()) return; // if unsupported just don't dump anything
+ if (!mClatEgress4Map.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 ClatEgressKey& key, const ClatEgressValue& value,
- const BpfMap<ClatEgressKey, ClatEgressValue>&) {
+ const auto printClatMap = [&dw](const ClatEgress4Key& key, const ClatEgress4Value& value,
+ const BpfMap<ClatEgress4Key, ClatEgress4Value>&) {
char iifStr[IFNAMSIZ] = "?";
char local4Str[INET_ADDRSTRLEN] = "?";
char local6Str[INET6_ADDRSTRLEN] = "?";
@@ -643,21 +601,21 @@ void ClatdController::dumpEgress(DumpWriter& dw) {
pfx96Str, value.oif, oifStr, value.oifIsEthernet ? "ether" : "rawip");
return Result<void>();
};
- auto res = mClatEgressMap.iterateWithValue(printClatMap);
+ auto res = mClatEgress4Map.iterateWithValue(printClatMap);
if (!res.ok()) {
dw.println("Error printing BPF map: %s", res.error().message().c_str());
}
}
void ClatdController::dumpIngress(DumpWriter& dw) {
- if (!mClatIngressMap.isValid()) return; // if unsupported just don't dump anything
+ if (!mClatIngress6Map.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 ClatIngressKey& key, const ClatIngressValue& value,
- const BpfMap<ClatIngressKey, ClatIngressValue>&) {
+ const auto printClatMap = [&dw](const ClatIngress6Key& key, const ClatIngress6Value& value,
+ const BpfMap<ClatIngress6Key, ClatIngress6Value>&) {
char iifStr[IFNAMSIZ] = "?";
char pfx96Str[INET6_ADDRSTRLEN] = "?";
char local6Str[INET6_ADDRSTRLEN] = "?";
@@ -674,7 +632,7 @@ void ClatdController::dumpIngress(DumpWriter& dw) {
value.oif, oifStr);
return Result<void>();
};
- auto res = mClatIngressMap.iterateWithValue(printClatMap);
+ auto res = mClatIngress6Map.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 2c139580..4b7c60bb 100644
--- a/server/ClatdController.h
+++ b/server/ClatdController.h
@@ -89,19 +89,8 @@ class ClatdController {
in6_addr* v6);
static void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix);
- 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);
+ bpf::BpfMap<ClatEgress4Key, ClatEgress4Value> mClatEgress4Map GUARDED_BY(mutex);
+ bpf::BpfMap<ClatIngress6Key, ClatIngress6Value> mClatIngress6Map 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 dc71a033..d3a2aa73 100644
--- a/server/ClatdControllerTest.cpp
+++ b/server/ClatdControllerTest.cpp
@@ -69,7 +69,6 @@ class ClatdControllerTest : public IptablesBaseTest {
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 5af8a91e..1f2bac22 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -285,10 +285,15 @@ void Controllers::init() {
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 6cd6791d..186072db 100644
--- a/server/DummyNetwork.cpp
+++ b/server/DummyNetwork.cpp
@@ -14,17 +14,22 @@
* limitations under the License.
*/
-#include "DummyNetwork.h"
+#define LOG_TAG "Netd"
-#include "RouteController.h"
+#include "DummyNetwork.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) {
@@ -34,17 +39,5 @@ DummyNetwork::DummyNetwork(unsigned netId) : Network(netId) {
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 5823ce54..8f9960b2 100644
--- a/server/DummyNetwork.h
+++ b/server/DummyNetwork.h
@@ -27,9 +27,7 @@ class DummyNetwork : public Network {
virtual ~DummyNetwork();
private:
- Type getType() const override;
- [[nodiscard]] int addInterface(const std::string& interface) override;
- [[nodiscard]] int removeInterface(const std::string& interface) override;
+ std::string getTypeString() const override { return "DUMMY"; };
};
} // namespace android::net
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 3c070ce9..0a0f8d82 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -53,10 +53,6 @@ constexpr const uid_t kDefaultMaximumUid = UID_MAX - 1; // UID_MAX defined as U
// 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 {
@@ -73,6 +69,7 @@ const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
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
@@ -87,20 +84,22 @@ const char* FirewallController::ICMPV6_TYPES[] = {
};
FirewallController::FirewallController(void) : mMaxUid(discoverMaximumValidUid(kUidMapProcFile)) {
- // If no rules are set, it's in BLACKLIST mode
- mFirewallType = BLACKLIST;
+ // If no rules are set, it's in DENYLIST mode
+ mFirewallType = DENYLIST;
mIfaceRules = {};
}
int FirewallController::setupIptablesHooks(void) {
int res = 0;
- mUseBpfOwnerMatch = getBpfOwnerStatus();
+ // mUseBpfOwnerMatch should be removed, but it is still depended upon by test code.
+ mUseBpfOwnerMatch = true;
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;
}
@@ -110,7 +109,7 @@ int FirewallController::setFirewallType(FirewallType ftype) {
// flush any existing rules
resetFirewall();
- if (ftype == WHITELIST) {
+ if (ftype == ALLOWLIST) {
// create default rule to drop all traffic
std::string command =
"*filter\n"
@@ -121,14 +120,14 @@ int FirewallController::setFirewallType(FirewallType ftype) {
res = execIptablesRestore(V4V6, command.c_str());
}
- // Set this after calling disableFirewall(), since it defaults to WHITELIST there
+ // Set this after calling disableFirewall(), since it defaults to ALLOWLIST there
mFirewallType = ftype;
}
return res ? -EREMOTEIO : 0;
}
int FirewallController::resetFirewall(void) {
- mFirewallType = WHITELIST;
+ mFirewallType = ALLOWLIST;
mIfaceRules.clear();
// flush any existing rules
@@ -155,6 +154,9 @@ int FirewallController::enableChildChains(ChildChain chain, bool enable) {
case POWERSAVE:
name = LOCAL_POWERSAVE;
break;
+ case RESTRICTED:
+ name = LOCAL_RESTRICTED;
+ break;
default:
return res;
}
@@ -178,8 +180,8 @@ int FirewallController::isFirewallEnabled(void) {
}
int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
- if (mFirewallType == BLACKLIST) {
- // Unsupported in BLACKLIST mode
+ if (mFirewallType == DENYLIST) {
+ // Unsupported in DENYLIST mode
return -EINVAL;
}
@@ -214,15 +216,17 @@ int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
FirewallType FirewallController::getFirewallType(ChildChain chain) {
switch(chain) {
case DOZABLE:
- return WHITELIST;
+ return ALLOWLIST;
case STANDBY:
- return BLACKLIST;
+ return DENYLIST;
case POWERSAVE:
- return WHITELIST;
+ return ALLOWLIST;
+ case RESTRICTED:
+ return ALLOWLIST;
case NONE:
return mFirewallType;
default:
- return BLACKLIST;
+ return DENYLIST;
}
}
@@ -230,11 +234,11 @@ int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule)
const char* op;
const char* target;
FirewallType firewallType = getFirewallType(chain);
- if (firewallType == WHITELIST) {
+ if (firewallType == ALLOWLIST) {
target = "RETURN";
// When adding, insert RETURN rules at the front, before the catch-all DROP at the end.
op = (rule == ALLOW)? "-I" : "-D";
- } else { // BLACKLIST mode
+ } else { // DENYLIST mode
target = "DROP";
// When adding, append DROP rules at the end, after the RETURN rule that matches TCP RSTs.
op = (rule == DENY)? "-A" : "-D";
@@ -243,16 +247,19 @@ int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule)
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 };
+ chainNames = {LOCAL_POWERSAVE};
+ break;
+ case RESTRICTED:
+ chainNames = {LOCAL_RESTRICTED};
break;
case NONE:
- chainNames = { LOCAL_INPUT, LOCAL_OUTPUT };
+ chainNames = {LOCAL_INPUT, LOCAL_OUTPUT};
break;
default:
ALOGW("Unknown child chain: %d", chain);
@@ -274,7 +281,7 @@ int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule)
int FirewallController::createChain(const char* chain, FirewallType type) {
static const std::vector<int32_t> NO_UIDS;
- return replaceUidChain(chain, type == WHITELIST, NO_UIDS);
+ return replaceUidChain(chain, type == ALLOWLIST, NO_UIDS);
}
/* static */
@@ -290,18 +297,18 @@ std::string FirewallController::makeCriticalCommands(IptablesTarget target, cons
return commands;
}
-std::string FirewallController::makeUidRules(IptablesTarget target, const char *name,
- bool isWhitelist, const std::vector<int32_t>& uids) {
+std::string FirewallController::makeUidRules(IptablesTarget target, const char* name,
+ bool isAllowlist, const std::vector<int32_t>& uids) {
std::string commands;
StringAppendF(&commands, "*filter\n:%s -\n", name);
- // Whitelist chains have UIDs at the beginning, and new UIDs are added with '-I'.
- if (isWhitelist) {
+ // Allowlist chains have UIDs at the beginning, and new UIDs are added with '-I'.
+ if (isAllowlist) {
for (auto uid : uids) {
StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j RETURN\n", name, uid);
}
- // Always whitelist system UIDs.
+ // Always allowlist system UIDs.
StringAppendF(&commands,
"-A %s -m owner --uid-owner %d-%d -j RETURN\n", name, 0, MAX_SYSTEM_UID);
@@ -310,7 +317,7 @@ std::string FirewallController::makeUidRules(IptablesTarget target, const char *
StringAppendF(&commands,
"-A %s -m owner ! --uid-owner %d-%u -j RETURN\n", name, 0, mMaxUid);
- // Always whitelist traffic with protocol ESP, or no known socket - required for IPSec
+ // Always allowlist traffic with protocol ESP, or no known socket - required for IPSec
StringAppendF(&commands, "-A %s -p esp -j RETURN\n", name);
}
@@ -322,20 +329,20 @@ std::string FirewallController::makeUidRules(IptablesTarget target, const char *
// access. Both incoming and outgoing RSTs are allowed.
StringAppendF(&commands, "-A %s -p tcp --tcp-flags RST RST -j RETURN\n", name);
- if (isWhitelist) {
+ if (isAllowlist) {
commands.append(makeCriticalCommands(target, name));
}
- // Blacklist chains have UIDs at the end, and new UIDs are added with '-A'.
- if (!isWhitelist) {
+ // Denylist chains have UIDs at the end, and new UIDs are added with '-A'.
+ if (!isAllowlist) {
for (auto uid : uids) {
StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j DROP\n", name, uid);
}
}
- // 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) {
+ // 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) {
StringAppendF(&commands, "-A %s -j DROP\n", name);
}
@@ -344,13 +351,13 @@ std::string FirewallController::makeUidRules(IptablesTarget target, const char *
return commands;
}
-int FirewallController::replaceUidChain(
- const std::string &name, bool isWhitelist, const std::vector<int32_t>& uids) {
+int FirewallController::replaceUidChain(const std::string& name, bool isAllowlist,
+ const std::vector<int32_t>& uids) {
if (mUseBpfOwnerMatch) {
- return gCtls->trafficCtrl.replaceUidOwnerMap(name, isWhitelist, uids);
+ return gCtls->trafficCtrl.replaceUidOwnerMap(name, isAllowlist, uids);
}
- std::string commands4 = makeUidRules(V4, name.c_str(), isWhitelist, uids);
- std::string commands6 = makeUidRules(V6, name.c_str(), isWhitelist, uids);
+ std::string commands4 = makeUidRules(V4, name.c_str(), isAllowlist, uids);
+ std::string commands6 = makeUidRules(V6, name.c_str(), isAllowlist, uids);
return execIptablesRestore(V4, commands4.c_str()) | execIptablesRestore(V6, commands6.c_str());
}
@@ -398,4 +405,4 @@ uid_t FirewallController::discoverMaximumValidUid(const std::string& fileName) {
}
} // namespace net
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 620f1969..6cabfb52 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -33,16 +33,17 @@ namespace net {
enum FirewallRule { ALLOW = INetd::FIREWALL_RULE_ALLOW, DENY = INetd::FIREWALL_RULE_DENY };
-// 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
+// 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
-enum FirewallType { WHITELIST = INetd::FIREWALL_WHITELIST, BLACKLIST = INetd::FIREWALL_BLACKLIST };
+enum FirewallType { ALLOWLIST = INetd::FIREWALL_ALLOWLIST, DENYLIST = INetd::FIREWALL_DENYLIST };
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
};
@@ -85,6 +86,7 @@ public:
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[];
@@ -92,7 +94,7 @@ public:
protected:
friend class FirewallControllerTest;
- std::string makeUidRules(IptablesTarget target, const char *name, bool isWhitelist,
+ std::string makeUidRules(IptablesTarget target, const char* name, bool isAllowlist,
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 1b53fb85..df6ca82d 100644
--- a/server/FirewallControllerTest.cpp
+++ b/server/FirewallControllerTest.cpp
@@ -56,61 +56,58 @@ protected:
}
};
-TEST_F(FirewallControllerTest, TestCreateWhitelistChain) {
+TEST_F(FirewallControllerTest, TestCreateAllowlistChain) {
std::vector<std::string> expectedRestore4 = {
- "*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"
- };
+ "*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"};
std::vector<std::string> expectedRestore6 = {
- "*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"
- };
+ "*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"};
std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
{V4, Join(expectedRestore4, '\n')},
{V6, Join(expectedRestore6, '\n')},
};
- createChain("fw_whitelist", WHITELIST);
+ createChain("fw_allowlist", ALLOWLIST);
expectIptablesRestoreCommands(expectedRestoreCommands);
}
-TEST_F(FirewallControllerTest, TestCreateBlacklistChain) {
+TEST_F(FirewallControllerTest, TestCreateDenylistChain) {
std::vector<std::string> expectedRestore = {
- "*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"
- };
+ "*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"};
std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
{V4, Join(expectedRestore, '\n')},
{V6, Join(expectedRestore, '\n')},
};
- createChain("fw_blacklist", BLACKLIST);
+ createChain("fw_denylist", DENYLIST);
expectIptablesRestoreCommands(expectedRestoreCommands);
}
@@ -162,50 +159,50 @@ TEST_F(FirewallControllerTest, TestSetFirewallRule) {
expectIptablesRestoreCommands(expected);
}
-TEST_F(FirewallControllerTest, TestReplaceWhitelistUidRule) {
+TEST_F(FirewallControllerTest, TestReplaceAllowlistUidRule) {
std::string expected =
"*filter\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"
+ ":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"
"COMMIT\n";
std::vector<int32_t> uids = { 10023, 10059, 10124, 10111, 110122, 210153, 210024 };
- EXPECT_EQ(expected, makeUidRules(V6, "FW_whitechain", true, uids));
+ EXPECT_EQ(expected, makeUidRules(V6, "FW_allowchain", true, uids));
}
-TEST_F(FirewallControllerTest, TestReplaceBlacklistUidRule) {
+TEST_F(FirewallControllerTest, TestReplaceDenylistUidRule) {
std::string expected =
"*filter\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"
+ ":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"
"COMMIT\n";
std::vector<int32_t> uids = { 10023, 10059, 10124 };
- EXPECT_EQ(expected, makeUidRules(V4 ,"FW_blackchain", false, uids));
+ EXPECT_EQ(expected, makeUidRules(V4, "FW_denychain", false, uids));
}
TEST_F(FirewallControllerTest, TestEnableChildChains) {
@@ -251,10 +248,10 @@ TEST_F(FirewallControllerTest, TestFirewall) {
EXPECT_EQ(0, mFw.resetFirewall());
expectIptablesRestoreCommands(disableCommands);
- EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(DENYLIST));
expectIptablesRestoreCommands(disableCommands);
- EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
+ EXPECT_EQ(0, mFw.setFirewallType(DENYLIST));
expectIptablesRestoreCommands(noCommands);
std::vector<std::string> disableEnableCommands;
@@ -263,7 +260,7 @@ TEST_F(FirewallControllerTest, TestFirewall) {
disableEnableCommands.insert(
disableEnableCommands.end(), enableCommands.begin(), enableCommands.end());
- EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
+ EXPECT_EQ(0, mFw.setFirewallType(ALLOWLIST));
expectIptablesRestoreCommands(disableEnableCommands);
std::vector<std::string> ifaceCommands = {
@@ -290,15 +287,15 @@ TEST_F(FirewallControllerTest, TestFirewall) {
EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", DENY));
expectIptablesRestoreCommands(noCommands);
- EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
+ EXPECT_EQ(0, mFw.setFirewallType(ALLOWLIST));
expectIptablesRestoreCommands(noCommands);
EXPECT_EQ(0, mFw.resetFirewall());
expectIptablesRestoreCommands(disableCommands);
- // TODO: calling resetFirewall and then setFirewallType(WHITELIST) does
+ // TODO: calling resetFirewall and then setFirewallType(ALLOWLIST) does
// nothing. This seems like a clear bug.
- EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
+ EXPECT_EQ(0, mFw.setFirewallType(ALLOWLIST));
expectIptablesRestoreCommands(noCommands);
}
diff --git a/server/IdletimerController.cpp b/server/IdletimerController.cpp
index 103e7cd6..cc86d1bd 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 1
- * iptables -t mangle -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
+ * 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 -nxvL -t raw
* iptables -nxvL -t mangle
@@ -147,14 +147,14 @@ int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface,
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 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",
+ "*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",
};
return (execIptablesRestore(V4V6, Join(cmds, '\n')) == 0) ? 0 : -EREMOTEIO;
diff --git a/server/IdletimerControllerTest.cpp b/server/IdletimerControllerTest.cpp
index 30c22987..68d6108c 100644
--- a/server/IdletimerControllerTest.cpp
+++ b/server/IdletimerControllerTest.cpp
@@ -43,14 +43,16 @@ TEST_F(IdletimerControllerTest, TestSetupIptablesHooks) {
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 1", op),
- "COMMIT",
- "*mangle",
- StringPrintf("%s idletimer_mangle_POSTROUTING -o wlan0 -j IDLETIMER"
- " --timeout 12345 --label hello --send_nl_msg 1", op),
- "COMMIT\n",
+ "*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",
};
return { Join(cmds, '\n') };
}
diff --git a/server/IptablesRestoreControllerTest.cpp b/server/IptablesRestoreControllerTest.cpp
index 20f61835..3881124a 100644
--- a/server/IptablesRestoreControllerTest.cpp
+++ b/server/IptablesRestoreControllerTest.cpp
@@ -40,7 +40,14 @@
#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;
@@ -75,10 +82,29 @@ public:
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 = StringPrintf("/proc/%d/stat", pid);
+ std::string statPath = getProcStatPath(pid);
int fd = open(statPath.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
// ENOENT means the process is gone (expected).
@@ -89,14 +115,28 @@ public:
// 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.
- char statBuf[1024];
- ASSERT_NE(-1, read(fd, statBuf, sizeof(statBuf)))
- << "Could not read from " << statPath << ": " << strerror(errno);
+ 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, " ");
+
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);
- std::string statString(statBuf);
- EXPECT_FALSE(statString.find("iptables-restor") || statString.find("ip6tables-resto"))
- << "Previous iptables-restore pid " << pid << " still alive: " << statString;
+ 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());
}
int createTestChain() {
@@ -217,7 +257,7 @@ TEST_F(IptablesRestoreControllerTest, TestRestartOnProcessDeath) {
TEST_F(IptablesRestoreControllerTest, TestCommandTimeout) {
// Don't wait 10 seconds for this test to fail.
- setRetryParameters(3, 50);
+ setRetryParameters(3, 100);
// Expected contents of the chain.
std::vector<std::string> expectedLines = {
@@ -299,3 +339,44 @@ TEST_F(IptablesRestoreControllerTest, TestStartup) {
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 91fda3ca..7127b3fe 100644
--- a/server/LocalNetwork.cpp
+++ b/server/LocalNetwork.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
+#define LOG_TAG "Netd"
+
#include "LocalNetwork.h"
#include "RouteController.h"
-#define LOG_TAG "Netd"
#include "log/log.h"
namespace android {
@@ -30,10 +31,6 @@ LocalNetwork::LocalNetwork(unsigned netId) : Network(netId) {
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 7a39a9d1..c774067c 100644
--- a/server/LocalNetwork.h
+++ b/server/LocalNetwork.h
@@ -26,7 +26,7 @@ public:
virtual ~LocalNetwork();
private:
- Type getType() const override;
+ std::string getTypeString() const override { return "LOCAL"; };
[[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 48f7d9f5..80ad7fb6 100644
--- a/server/NdcDispatcher.cpp
+++ b/server/NdcDispatcher.cpp
@@ -747,13 +747,13 @@ int NdcDispatcher::FirewallCmd::parseRule(const char* arg) {
}
int NdcDispatcher::FirewallCmd::parseFirewallType(const char* arg) {
- if (!strcmp(arg, "whitelist")) {
- return INetd::FIREWALL_WHITELIST;
- } else if (!strcmp(arg, "blacklist")) {
- return INetd::FIREWALL_BLACKLIST;
+ if (!strcmp(arg, "allowlist")) {
+ return INetd::FIREWALL_ALLOWLIST;
+ } else if (!strcmp(arg, "denylist")) {
+ return INetd::FIREWALL_DENYLIST;
} else {
LOG(LOGLEVEL) << "failed to parse firewall type " << arg;
- return INetd::FIREWALL_BLACKLIST;
+ return INetd::FIREWALL_DENYLIST;
}
}
@@ -764,6 +764,8 @@ int NdcDispatcher::FirewallCmd::parseChildChain(const char* arg) {
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 {
@@ -781,7 +783,7 @@ int NdcDispatcher::FirewallCmd::runCommand(NdcClient* cli, int argc, char** argv
if (!strcmp(argv[1], "enable")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: firewall enable <whitelist|blacklist>", false);
+ "Usage: firewall enable <allowlist|denylist>", false);
return 0;
}
int res = !mNetd->firewallSetFirewallType(parseFirewallType(argv[2])).isOk();
@@ -1047,9 +1049,12 @@ int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** a
return syntaxError(cli, "Missing argument");
}
unsigned netId = stringToNetId(argv[2]);
- if (argc == 6 && !strcmp(argv[3], "vpn")) {
+ if (argc == 5 && !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());
}
@@ -1063,7 +1068,10 @@ int NdcDispatcher::NetworkCommand::runCommand(NdcClient* cli, int argc, char** a
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 80282b35..f3898f59 100644
--- a/server/NetdConstants.cpp
+++ b/server/NetdConstants.cpp
@@ -66,7 +66,8 @@ bool isIfaceName(const std::string& name) {
}
for (i = 1; i < name.size(); i++) {
- if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-') && (name[i] != ':')) {
+ if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-')
+ && (name[i] != ':') && (name[i] != '.')) {
return false;
}
}
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 3bf879bf..1f5dc976 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -52,9 +52,11 @@
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;
@@ -170,8 +172,9 @@ bool contains(const Vector<String16>& words, const String16& word) {
NetdNativeService::NetdNativeService() {
// register log callback to BnNetd::logFunc
- BnNetd::logFunc = std::bind(binderCallLogFn, std::placeholders::_1,
- [](const std::string& msg) { gLog.info("%s", msg.c_str()); });
+ BnNetd::logFunc = [](const auto& log) {
+ binderCallLogFn(log, [](const std::string& msg) { gLog.info("%s", msg.c_str()); });
+ };
}
status_t NetdNativeService::start() {
@@ -268,9 +271,11 @@ binder::Status NetdNativeService::isAlive(bool *alive) {
}
binder::Status NetdNativeService::firewallReplaceUidChain(const std::string& chainName,
- bool isWhitelist, const std::vector<int32_t>& uids, bool *ret) {
+ bool isAllowlist,
+ 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, isWhitelist, uids);
+ int err = gCtls->firewallCtrl.replaceUidChain(chainName, isAllowlist, uids);
*ret = (err == 0);
return binder::Status::ok();
}
@@ -316,41 +321,60 @@ binder::Status NetdNativeService::bandwidthSetGlobalAlert(int64_t bytes) {
binder::Status NetdNativeService::bandwidthAddNaughtyApp(int32_t uid) {
NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
- int res = gCtls->bandwidthCtrl.addNaughtyApps(appStrUids);
+ std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
+ int res = gCtls->bandwidthCtrl.addNaughtyApps(appUids);
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<std::string> appStrUids = {std::to_string(abs(uid))};
- int res = gCtls->bandwidthCtrl.removeNaughtyApps(appStrUids);
+ std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
+ int res = gCtls->bandwidthCtrl.removeNaughtyApps(appUids);
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<std::string> appStrUids = {std::to_string(abs(uid))};
- int res = gCtls->bandwidthCtrl.addNiceApps(appStrUids);
+ std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
+ int res = gCtls->bandwidthCtrl.addNiceApps(appUids);
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<std::string> appStrUids = {std::to_string(abs(uid))};
- int res = gCtls->bandwidthCtrl.removeNiceApps(appStrUids);
+ std::vector<uint32_t> appUids = {static_cast<uint32_t>(abs(uid))};
+ int res = gCtls->bandwidthCtrl.removeNiceApps(appUids);
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();
- int ret = gCtls->netCtrl.createVirtualNetwork(netId, secure);
+ // 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);
+ }
return statusFromErrcode(ret);
}
@@ -377,7 +401,8 @@ binder::Status NetdNativeService::networkAddUidRanges(
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));
+ int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray),
+ UidRanges::DEFAULT_SUB_PRIORITY);
return statusFromErrcode(ret);
}
@@ -385,7 +410,22 @@ binder::Status NetdNativeService::networkRemoveUidRanges(
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));
+ 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);
return statusFromErrcode(ret);
}
@@ -1120,7 +1160,7 @@ binder::Status NetdNativeService::networkClearPermissionForUser(const std::vecto
return binder::Status::ok();
}
-binder::Status NetdNativeService::NetdNativeService::networkSetProtectAllow(int32_t uid) {
+binder::Status NetdNativeService::networkSetProtectAllow(int32_t uid) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
std::vector<uid_t> uids = {(uid_t) uid};
gCtls->netCtrl.allowProtect(uids);
@@ -1251,65 +1291,43 @@ binder::Status NetdNativeService::getFwmarkForNetwork(int32_t netId, MarkMaskPar
return binder::Status::ok();
}
-binder::Status NetdNativeService::tetherOffloadRuleAdd(const TetherOffloadRuleParcel& rule) {
+// TODO: remark @deprecated in INetd.aidl.
+binder::Status NetdNativeService::tetherOffloadRuleAdd(const TetherOffloadRuleParcel& /* rule */) {
+ // deprecated
ENFORCE_NETWORK_STACK_PERMISSIONS();
-
- return asBinderStatus(gCtls->tetherCtrl.addOffloadRule(rule));
+ return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
}
-binder::Status NetdNativeService::tetherOffloadRuleRemove(const TetherOffloadRuleParcel& rule) {
+// TODO: remark @deprecated in INetd.aidl.
+binder::Status NetdNativeService::tetherOffloadRuleRemove(
+ const TetherOffloadRuleParcel& /* rule */) {
+ // deprecated
ENFORCE_NETWORK_STACK_PERMISSIONS();
-
- return asBinderStatus(gCtls->tetherCtrl.removeOffloadRule(rule));
-}
-
-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;
+ return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
}
-} // namespace
-
+// TODO: remark @deprecated in INetd.aidl.
binder::Status NetdNativeService::tetherOffloadGetStats(
- std::vector<TetherStatsParcel>* tetherStatsParcelVec) {
+ std::vector<TetherStatsParcel>* /* tetherStatsParcelVec */) {
+ // deprecated
NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
-
- 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();
+ return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
}
-binder::Status NetdNativeService::tetherOffloadSetInterfaceQuota(int ifIndex, int64_t quotaBytes) {
+// TODO: remark @deprecated in INetd.aidl.
+binder::Status NetdNativeService::tetherOffloadSetInterfaceQuota(int /* ifIndex */,
+ int64_t /* quotaBytes */) {
+ // deprecated
NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- int res = gCtls->tetherCtrl.setTetherOffloadInterfaceQuota(ifIndex, quotaBytes);
- return statusFromErrcode(res);
+ return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
}
+// TODO: remark @deprecated in INetd.aidl.
binder::Status NetdNativeService::tetherOffloadGetAndClearStats(
- int ifIndex, android::net::TetherStatsParcel* tetherStats) {
+ int /* ifIndex */, android::net::TetherStatsParcel* /* tetherStats */) {
+ // deprecated
NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
- const auto& stats = gCtls->tetherCtrl.getAndClearTetherOffloadStats(ifIndex);
- if (!stats.ok()) {
- return asBinderStatus(stats);
- }
- *tetherStats = toTetherStatsParcel(stats.value());
- return binder::Status::ok();
+ return binder::Status::fromExceptionCode(binder::Status::EX_UNSUPPORTED_OPERATION);
}
} // namespace net
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 7b7f9b33..9779f368 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -37,9 +37,8 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
binder::Status isAlive(bool *alive) override;
// Firewall commands.
- binder::Status firewallReplaceUidChain(
- const std::string& chainName, bool isWhitelist,
- const std::vector<int32_t>& uids, bool *ret) override;
+ binder::Status firewallReplaceUidChain(const std::string& chainName, bool isAllowlist,
+ 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;
@@ -65,6 +64,7 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
// 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,6 +74,10 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
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 7fb34379..525bb2d6 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -155,7 +155,11 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
if (shouldDestroy) {
SockDiag sd;
if (sd.open()) {
- int ret = sd.destroySockets(addrstr);
+ // 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);
if (ret < 0) {
ALOGE("Error destroying sockets: %s", strerror(-ret));
}
diff --git a/server/Network.cpp b/server/Network.cpp
index eb2a233a..72a15454 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define LOG_TAG "Netd"
#include "Network.h"
-#define LOG_TAG "Netd"
+#include "RouteController.h"
+#include "SockDiag.h"
#include "log/log.h"
#include <android-base/strings.h>
@@ -59,25 +61,7 @@ std::string Network::toString() const {
const char kSeparator[] = " ";
std::stringstream repr;
- 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";
- }
+ repr << mNetId << kSeparator << getTypeString();
if (mInterfaces.size() > 0) {
repr << kSeparator << android::base::Join(mInterfaces, ",");
@@ -86,9 +70,73 @@ std::string Network::toString() const {
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();
+}
+
+// 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);
+ }
+}
-Network::Network(unsigned netId) : mNetId(netId) {
+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 8417f340..aa1b21a1 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -17,45 +17,67 @@
#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 Type getType() const = 0;
+ virtual std::string getTypeString() 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& interface) = 0;
- [[nodiscard]] virtual int removeInterface(const std::string& interface) = 0;
+ [[nodiscard]] virtual int addInterface(const std::string&) { return -EINVAL; }
+ [[nodiscard]] virtual int removeInterface(const std::string&) { return -EINVAL; }
[[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);
+ explicit Network(unsigned netId, bool mSecure = false);
+ bool canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const;
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 20ae44b2..602639cb 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -39,6 +39,7 @@
#include "OffloadUtils.h"
#include "PhysicalNetwork.h"
#include "RouteController.h"
+#include "UnreachableNetwork.h"
#include "VirtualNetwork.h"
#include "netdutils/DumpWriter.h"
#include "netid_client.h"
@@ -128,7 +129,7 @@ int NetworkController::DelegateImpl::removeFallthrough(const std::string& physic
int NetworkController::DelegateImpl::modifyFallthrough(const std::string& physicalInterface,
Permission permission, bool add) {
for (const auto& entry : mNetworkController->mNetworks) {
- if (entry.second->getType() == Network::VIRTUAL) {
+ if (entry.second->isVirtual()) {
if (int ret = modifyFallthrough(entry.first, physicalInterface, permission, add)) {
return ret;
}
@@ -140,24 +141,25 @@ int NetworkController::DelegateImpl::modifyFallthrough(const std::string& physic
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.
- 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);
- }
+ 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 {
@@ -178,7 +180,7 @@ int NetworkController::setDefaultNetwork(unsigned netId) {
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (network->getType() != Network::PHYSICAL) {
+ if (!network->isPhysical()) {
ALOGE("cannot set default to non-physical network with netId %u", netId);
return -EINVAL;
}
@@ -189,7 +191,7 @@ int NetworkController::setDefaultNetwork(unsigned netId) {
if (mDefaultNetId != NETID_UNSET) {
Network* network = getNetworkLocked(mDefaultNetId);
- if (!network || network->getType() != Network::PHYSICAL) {
+ if (!network || !network->isPhysical()) {
ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
return -ESRCH;
}
@@ -207,13 +209,16 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
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 = mDefaultNetId;
+ *netId = defaultNetId;
fwmark.netId = *netId;
fwmark.explicitlySelected = true;
return fwmark.intValue;
@@ -229,8 +234,8 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
// servers (through the default network). Otherwise, the query is guaranteed to fail.
// http://b/29498052
Network *network = getNetworkLocked(*netId);
- if (network && network->getType() == Network::VIRTUAL && !resolv_has_nameservers(*netId)) {
- *netId = mDefaultNetId;
+ if (network && network->isVirtual() && !resolv_has_nameservers(*netId)) {
+ *netId = defaultNetId;
}
} else {
// If the user is subject to a VPN and the VPN provides DNS servers, use those servers
@@ -243,7 +248,7 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
} else {
// TODO: return an error instead of silently doing the DNS lookup on the wrong network.
// http://b/27560555
- *netId = mDefaultNetId;
+ *netId = defaultNetId;
}
}
fwmark.netId = *netId;
@@ -251,17 +256,22 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
}
// 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.
+// 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.
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.
+// applies to the user if any; otherwise, the default network that applies to user if any; lastly,
+// 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
@@ -274,11 +284,21 @@ unsigned NetworkController::getNetworkForUser(uid_t uid) const {
// 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;
}
@@ -357,7 +377,7 @@ bool NetworkController::isVirtualNetwork(unsigned netId) const {
bool NetworkController::isVirtualNetworkLocked(unsigned netId) const {
Network* network = getNetworkLocked(netId);
- return network && network->getType() == Network::VIRTUAL;
+ return network && network->isVirtual();
}
int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission permission) {
@@ -417,7 +437,7 @@ int NetworkController::createPhysicalOemNetwork(Permission permission, unsigned
return ret;
}
-int NetworkController::createVirtualNetwork(unsigned netId, bool secure) {
+int NetworkController::createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType) {
ScopedWLock lock(mRWLock);
if (!(MIN_NET_ID <= netId && netId <= MAX_NET_ID)) {
@@ -430,6 +450,11 @@ int NetworkController::createVirtualNetwork(unsigned netId, bool secure) {
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;
}
@@ -440,8 +465,8 @@ int NetworkController::createVirtualNetwork(unsigned netId, bool secure) {
int NetworkController::destroyNetwork(unsigned netId) {
ScopedWLock lock(mRWLock);
- if (netId == LOCAL_NET_ID) {
- ALOGE("cannot destroy local network");
+ if (netId == LOCAL_NET_ID || netId == UNREACHABLE_NET_ID) {
+ ALOGE("cannot destroy local or unreachable network");
return -EINVAL;
}
if (!isValidNetworkLocked(netId)) {
@@ -466,7 +491,7 @@ int NetworkController::destroyNetwork(unsigned netId) {
}
}
mDefaultNetId = NETID_UNSET;
- } else if (network->getType() == Network::VIRTUAL) {
+ } else if (network->isVirtual()) {
if (int err = modifyFallthroughLocked(netId, false)) {
if (!ret) {
ret = err;
@@ -562,7 +587,7 @@ int NetworkController::setPermissionForNetworks(Permission permission,
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (network->getType() != Network::PHYSICAL) {
+ if (!network->isPhysical()) {
ALOGE("cannot set permissions on non-physical network with netId %u", netId);
return -EINVAL;
}
@@ -574,39 +599,41 @@ int NetworkController::setPermissionForNetworks(Permission permission,
return 0;
}
-int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
- ScopedWLock lock(mRWLock);
- Network* network = getNetworkLocked(netId);
+namespace {
+
+int isWrongNetworkForUidRanges(unsigned netId, Network* network) {
if (!network) {
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (network->getType() != Network::VIRTUAL) {
- ALOGE("cannot add users to non-virtual network with netId %u", netId);
+ if (!network->canAddUsers()) {
+ ALOGE("cannot add/remove users to/from %s network %u", network->getTypeString().c_str(),
+ netId);
return -EINVAL;
}
- if (int ret = static_cast<VirtualNetwork*>(network)->addUsers(uidRanges, mProtectableUsers)) {
- return ret;
- }
return 0;
}
-int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
+} // namespace
+
+int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority) {
ScopedWLock lock(mRWLock);
Network* network = getNetworkLocked(netId);
- 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 = isWrongNetworkForUidRanges(netId, network)) {
+ return ret;
}
- if (int ret = static_cast<VirtualNetwork*>(network)->removeUsers(uidRanges,
- mProtectableUsers)) {
+ 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 0;
+ return network->removeUsers(uidRanges, subPriority);
}
int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
@@ -709,12 +736,17 @@ void NetworkController::dump(DumpWriter& dw) {
for (const auto& i : mNetworks) {
Network* network = i.second;
dw.println(network->toString());
- if (network->getType() == Network::PHYSICAL) {
+ if (network->isPhysical()) {
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();
@@ -751,17 +783,34 @@ Network* NetworkController::getNetworkLocked(unsigned netId) const {
}
VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
- for (const auto& entry : mNetworks) {
- if (entry.second->getType() == Network::VIRTUAL) {
- VirtualNetwork* virtualNetwork = static_cast<VirtualNetwork*>(entry.second);
- if (virtualNetwork->appliesToUser(uid)) {
- return virtualNetwork;
- }
+ uint32_t subPriority;
+ for (const auto& [_, network] : mNetworks) {
+ if (network->isVirtual() && network->appliesToUser(uid, &subPriority)) {
+ return static_cast<VirtualNetwork*>(network);
}
}
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()) {
@@ -781,18 +830,35 @@ int NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) c
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 (network->getType() == Network::VIRTUAL) {
- return static_cast<VirtualNetwork*>(network)->appliesToUser(uid) ? 0 : -EPERM;
+ // 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 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;
}
@@ -849,7 +915,7 @@ int NetworkController::modifyFallthroughLocked(unsigned vpnNetId, bool add) {
ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
return -ESRCH;
}
- if (network->getType() != Network::PHYSICAL) {
+ if (!network->isPhysical()) {
ALOGE("inconceivable! default network must be a physical network");
return -EINVAL;
}
@@ -867,7 +933,7 @@ void NetworkController::updateTcpSocketMonitorPolling() {
bool physicalNetworkExists = false;
for (const auto& entry : mNetworks) {
const auto& network = entry.second;
- if (network->getType() == Network::PHYSICAL && network->getNetId() >= MIN_NET_ID) {
+ if (network->isPhysical() && network->getNetId() >= MIN_NET_ID) {
physicalNetworkExists = true;
break;
}
diff --git a/server/NetworkController.h b/server/NetworkController.h
index ff49c025..a61ac39f 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -22,6 +22,8 @@
#include "NetdConstants.h"
#include "Permission.h"
+#include "PhysicalNetwork.h"
+#include "UnreachableNetwork.h"
#include "android/net/INetd.h"
#include "netdutils/DumpWriter.h"
@@ -82,11 +84,12 @@ class VirtualNetwork;
*/
class NetworkController {
public:
- // NetIds 52..98 are reserved for future use.
+ // NetIds 53..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 = 51;
+ static constexpr int DUMMY_NET_ID = INetd::DUMMY_NET_ID;
+ static constexpr int UNREACHABLE_NET_ID = INetd::UNREACHABLE_NET_ID;
// Route mode for modify route
enum RouteOperation { ROUTE_ADD, ROUTE_UPDATE, ROUTE_REMOVE };
@@ -104,7 +107,7 @@ public:
[[nodiscard]] int createPhysicalNetwork(unsigned netId, Permission permission);
[[nodiscard]] int createPhysicalOemNetwork(Permission permission, unsigned* netId);
- [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure);
+ [[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType);
[[nodiscard]] int destroyNetwork(unsigned netId);
[[nodiscard]] int addInterfaceToNetwork(unsigned netId, const char* interface);
@@ -116,8 +119,10 @@ public:
[[nodiscard]] int setPermissionForNetworks(Permission permission,
const std::vector<unsigned>& netIds);
- [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges);
- [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges);
+ [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority);
+ [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority);
// |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.
@@ -151,13 +156,12 @@ public:
// 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 fb07a805..9c44cf23 100644
--- a/server/OemNetdListener.cpp
+++ b/server/OemNetdListener.cpp
@@ -24,16 +24,10 @@ namespace internal {
namespace net {
::android::sp<::android::IBinder> OemNetdListener::getListener() {
- 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;
+ // Thread-safe initialization.
+ static ::android::sp<OemNetdListener> listener = ::android::sp<OemNetdListener>::make();
+ static ::android::sp<::android::IBinder> sIBinder = ::android::IInterface::asBinder(listener);
+ return sIBinder;
}
::android::binder::Status OemNetdListener::isAlive(bool* alive) {
diff --git a/server/OemNetdListener.h b/server/OemNetdListener.h
index 4fb4fb78..b94827b3 100644
--- a/server/OemNetdListener.h
+++ b/server/OemNetdListener.h
@@ -43,14 +43,10 @@ class OemNetdListener : public BnOemNetd {
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);
@@ -64,4 +60,4 @@ class OemNetdListener : public BnOemNetd {
} // namespace android
} // namespace com
-#endif // NETD_SERVER_OEM_NETD_LISTENER_H \ No newline at end of file
+#endif // NETD_SERVER_OEM_NETD_LISTENER_H
diff --git a/server/OffloadUtils.cpp b/server/OffloadUtils.cpp
index a743458c..0d9869fa 100644
--- a/server/OffloadUtils.cpp
+++ b/server/OffloadUtils.cpp
@@ -38,7 +38,7 @@ namespace net {
using std::max;
-int hardwareAddressType(const std::string& interface) {
+static int doSIOCGIF(const std::string& interface, int opt) {
base::unique_fd ufd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (ufd < 0) {
@@ -56,9 +56,19 @@ int hardwareAddressType(const std::string& interface) {
// match a truncated interface if one were to exist.
strncpy(ifr.ifr_name, interface.c_str(), sizeof(ifr.ifr_name));
- if (ioctl(ufd, SIOCGIFHWADDR, &ifr, sizeof(ifr))) return -errno;
+ if (ioctl(ufd, opt, &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);
+}
- return ifr.ifr_hwaddr.sa_family;
+int deviceMTU(const std::string& interface) {
+ return doSIOCGIF(interface, SIOCGIFMTU);
}
base::Result<bool> isEthernet(const std::string& interface) {
@@ -194,10 +204,12 @@ int doTcQdiscClsact(int ifIndex, uint16_t nlMsgType, uint16_t nlMsgFlags) {
return sendAndProcessNetlinkResponse(&req, sizeof(req));
}
-// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
+// 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/...
// direct-action
-int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, int bpfFd,
- bool ethernet) {
+int tcFilterAddDevBpf(int ifIndex, bool ingress, 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.
//
@@ -213,40 +225,28 @@ int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
#define FSOBJ_SUFFIX ":[*fsobj]"
// This macro expands (from header files) to:
- // prog_clatd_schedcls_ingress_clat_rawip:[*fsobj]
+ // prog_clatd_schedcls_ingress6_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_INGRESS_PROG_RAWIP_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_rx_rawip[] = CLAT_INGRESS6_PROG_RAWIP_NAME FSOBJ_SUFFIX;
// This macro expands (from header files) to:
- // prog_clatd_schedcls_ingress_clat_ether:[*fsobj]
+ // prog_clatd_schedcls_ingress6_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_INGRESS_PROG_ETHER_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_rx_ether[] = CLAT_INGRESS6_PROG_ETHER_NAME FSOBJ_SUFFIX;
// This macro expands (from header files) to:
- // prog_clatd_schedcls_egress_clat_rawip:[*fsobj]
+ // prog_clatd_schedcls_egress4_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_EGRESS_PROG_RAWIP_NAME FSOBJ_SUFFIX;
+ static constexpr char name_clat_tx_rawip[] = CLAT_EGRESS4_PROG_RAWIP_NAME FSOBJ_SUFFIX;
// This macro expands (from header files) to:
- // prog_clatd_schedcls_egress_clat_ether:[*fsobj]
+ // prog_clatd_schedcls_egress4_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_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;
+ static constexpr char name_clat_tx_ether[] = CLAT_EGRESS4_PROG_ETHER_NAME FSOBJ_SUFFIX;
#undef FSOBJ_SUFFIX
@@ -259,16 +259,12 @@ int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
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_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;
+ const char* const name = ingress ? name_clat_rx : name_clat_tx;
struct {
nlmsghdr n;
@@ -306,7 +302,7 @@ int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
.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 << 16) | htons(proto)),
+ .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)),
},
.kind =
{
@@ -322,7 +318,7 @@ int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
.attr =
{
.nla_len = sizeof(req.options),
- .nla_type = TCA_OPTIONS,
+ .nla_type = NLA_F_NESTED | TCA_OPTIONS,
},
.fd =
{
@@ -362,8 +358,8 @@ int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
return sendAndProcessNetlinkResponse(&req, sizeof(req));
}
-// tc filter del dev .. in/egress prio .. protocol ..
-int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) {
+// tc filter del dev .. in/egress prio 4 protocol ..
+int tcFilterDelDev(int ifIndex, bool ingress, uint16_t proto) {
const struct {
nlmsghdr n;
tcmsg t;
@@ -381,7 +377,7 @@ int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) {
.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 << 16) | htons(proto)),
+ .tcm_info = static_cast<__u32>((PRIO_CLAT << 16) | htons(proto)),
},
};
diff --git a/server/OffloadUtils.h b/server/OffloadUtils.h
index 818fd39d..684ffb35 100644
--- a/server/OffloadUtils.h
+++ b/server/OffloadUtils.h
@@ -19,6 +19,7 @@
#include <android-base/result.h>
#include <errno.h>
#include <linux/if_ether.h>
+#include <linux/if_link.h>
#include <linux/rtnetlink.h>
#include <string>
@@ -38,55 +39,33 @@ constexpr bool ETHER = true;
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);
-base::Result<bool> isEthernet(const std::string& interface);
-
-inline int getClatEgressMapFd(void) {
- const int fd = bpf::mapRetrieveRW(CLAT_EGRESS_MAP_PATH);
- return (fd == -1) ? -errno : fd;
-}
-
-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 getClatIngressMapFd(void) {
- const int fd = bpf::mapRetrieveRW(CLAT_INGRESS_MAP_PATH);
- return (fd == -1) ? -errno : fd;
-}
+// return MTU or -errno
+int deviceMTU(const std::string& interface);
-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;
-}
+base::Result<bool> isEthernet(const std::string& interface);
-inline int getTetherIngressMapFd(void) {
- const int fd = bpf::mapRetrieveRW(TETHER_INGRESS_MAP_PATH);
+inline int getClatEgress4MapFd(void) {
+ const int fd = bpf::mapRetrieveRW(CLAT_EGRESS4_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);
+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);
return (fd == -1) ? -errno : fd;
}
-inline int getTetherStatsMapFd(void) {
- const int fd = bpf::mapRetrieveRW(TETHER_STATS_MAP_PATH);
+inline int getClatIngress6MapFd(void) {
+ const int fd = bpf::mapRetrieveRW(CLAT_INGRESS6_MAP_PATH);
return (fd == -1) ? -errno : fd;
}
-inline int getTetherLimitMapFd(void) {
- const int fd = bpf::mapRetrieveRW(TETHER_LIMIT_MAP_PATH);
+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);
return (fd == -1) ? -errno : fd;
}
@@ -104,42 +83,31 @@ inline int tcQdiscDelDevClsact(int ifIndex) {
return doTcQdiscClsact(ifIndex, RTM_DELQDISC, 0);
}
-// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
+// tc filter add dev .. in/egress prio 4 protocol ipv6/ip bpf object-pinned /sys/fs/bpf/...
// direct-action
-int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t prio, uint16_t proto, int bpfFd,
- bool ethernet);
+int tcFilterAddDevBpf(int ifIndex, bool ingress, uint16_t proto, int bpfFd, bool ethernet);
-// tc filter add dev .. ingress prio 1 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
+// tc filter add dev .. ingress prio 4 protocol ipv6 bpf object-pinned /sys/fs/bpf/... direct-action
inline int tcFilterAddDevIngressClatIpv6(int ifIndex, int bpfFd, bool ethernet) {
- return tcFilterAddDevBpf(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6, bpfFd, ethernet);
+ return tcFilterAddDevBpf(ifIndex, INGRESS, ETH_P_IPV6, bpfFd, ethernet);
}
-// tc filter add dev .. egress prio 1 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action
+// tc filter add dev .. egress prio 4 protocol ip bpf object-pinned /sys/fs/bpf/... direct-action
inline int tcFilterAddDevEgressClatIpv4(int ifIndex, int bpfFd, bool 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);
+ return tcFilterAddDevBpf(ifIndex, EGRESS, ETH_P_IP, bpfFd, ethernet);
}
// tc filter del dev .. in/egress prio .. protocol ..
-int tcFilterDelDev(int ifIndex, bool ingress, uint16_t prio, uint16_t proto);
+int tcFilterDelDev(int ifIndex, bool ingress, uint16_t proto);
-// tc filter del dev .. ingress prio 1 protocol ipv6
+// tc filter del dev .. ingress prio 4 protocol ipv6
inline int tcFilterDelDevIngressClatIpv6(int ifIndex) {
- return tcFilterDelDev(ifIndex, INGRESS, PRIO_CLAT, ETH_P_IPV6);
+ return tcFilterDelDev(ifIndex, INGRESS, ETH_P_IPV6);
}
-// tc filter del dev .. egress prio 1 protocol ip
+// tc filter del dev .. egress prio 4 protocol ip
inline int tcFilterDelDevEgressClatIpv4(int ifIndex) {
- 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);
+ return tcFilterDelDev(ifIndex, EGRESS, ETH_P_IP);
}
} // namespace net
diff --git a/server/OffloadUtilsTest.cpp b/server/OffloadUtilsTest.cpp
index 1760c1d1..16c108b4 100644
--- a/server/OffloadUtilsTest.cpp
+++ b/server/OffloadUtilsTest.cpp
@@ -98,160 +98,60 @@ TEST_F(OffloadUtilsTest, IsEthernetOfCellular) {
ASSERT_FALSE(res.value());
}
-TEST_F(OffloadUtilsTest, GetClatEgressMapFd) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
- 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, DeviceMTUOfNonExistingIf) {
+ ASSERT_EQ(-ENODEV, deviceMTU("not_existing_if"));
}
-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, DeviceMTUofLoopback) {
+ ASSERT_EQ(65536, deviceMTU("lo"));
}
-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, GetClatIngressMapFd) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
- int fd = getClatIngressMapFd();
+TEST_F(OffloadUtilsTest, GetClatEgress4MapFd) {
+ int fd = getClatEgress4MapFd();
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, GetClatIngressRawIpProgFd) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
- int fd = getClatIngressProgFd(RAWIP);
+TEST_F(OffloadUtilsTest, GetClatEgress4RawIpProgFd) {
+ int fd = getClatEgress4ProgFd(RAWIP);
ASSERT_GE(fd, 3);
EXPECT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD));
close(fd);
}
-TEST_F(OffloadUtilsTest, GetClatIngressEtherProgFd) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
- int fd = getClatIngressProgFd(ETHER);
+TEST_F(OffloadUtilsTest, GetClatEgress4EtherProgFd) {
+ int fd = getClatEgress4ProgFd(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();
+TEST_F(OffloadUtilsTest, GetClatIngress6MapFd) {
+ int fd = getClatIngress6MapFd();
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);
+TEST_F(OffloadUtilsTest, GetClatIngress6RawIpProgFd) {
+ int fd = getClatIngress6ProgFd(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);
+TEST_F(OffloadUtilsTest, GetClatIngress6EtherProgFd) {
+ int fd = getClatIngress6ProgFd(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));
@@ -261,27 +161,12 @@ TEST_F(OffloadUtilsTest, AttachReplaceDetachClsactLo) {
}
static void checkAttachDetachBpfFilterClsactLo(const bool ingress, const bool ethernet) {
- // This test requires kernel 4.9-Q or better
- SKIP_IF_BPF_NOT_SUPPORTED;
- if (!kernelSupportsNetSchIngress()) return;
- if (!kernelSupportsNetClsBpf()) return;
-
- 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;
+ const int errNOENT = android::bpf::isAtLeastKernelVersion(4, 19, 0) ? ENOENT : EINVAL;
- int clatBpfFd = ingress ? getClatIngressProgFd(ethernet) : getClatEgressProgFd(ethernet);
+ int clatBpfFd = ingress ? getClatIngress6ProgFd(ethernet) : getClatEgress4ProgFd(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.
@@ -293,10 +178,6 @@ static void checkAttachDetachBpfFilterClsactLo(const bool ingress, const bool et
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));
@@ -308,7 +189,6 @@ static void checkAttachDetachBpfFilterClsactLo(const bool ingress, const bool et
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 2808fbe7..7b9a19a1 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -158,8 +158,36 @@ int PhysicalNetwork::removeAsDefault() {
return 0;
}
-Network::Type PhysicalNetwork::getType() const {
- return PHYSICAL;
+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;
}
int PhysicalNetwork::addInterface(const std::string& interface) {
@@ -167,7 +195,7 @@ int PhysicalNetwork::addInterface(const std::string& interface) {
return 0;
}
if (int ret = RouteController::addInterfaceToPhysicalNetwork(mNetId, interface.c_str(),
- mPermission)) {
+ mPermission, mUidRangeMap)) {
ALOGE("failed to add interface %s to netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -194,7 +222,7 @@ int PhysicalNetwork::removeInterface(const std::string& interface) {
// 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)) {
+ mPermission, mUidRangeMap)) {
ALOGE("failed to remove interface %s from netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -202,4 +230,9 @@ int PhysicalNetwork::removeInterface(const std::string& interface) {
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 07208243..d9461b2e 100644
--- a/server/PhysicalNetwork.h
+++ b/server/PhysicalNetwork.h
@@ -42,13 +42,18 @@ class PhysicalNetwork : public Network {
[[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:
- Type getType() const override;
+ std::string getTypeString() const override { return "PHYSICAL"; };
[[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 134bbcae..ba305e69 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -27,14 +27,11 @@
#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>
@@ -54,23 +51,6 @@ auto RouteController::iptablesRestoreCommandFunction = execIptablesRestoreComman
// 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;
@@ -131,6 +111,9 @@ rtattr RTATTR_METRICS = { U16_RTA_LENGTH(RTATTR_METRICS_SIZE), RTA_MET
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) {
@@ -146,6 +129,8 @@ static const char* familyName(uint8_t family) {
}
}
+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.
@@ -507,7 +492,7 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
// 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,
- bool secure, bool add) {
+ uint32_t subPriority, bool secure, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -525,8 +510,8 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
mask.explicitlySelected = true;
}
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority, table, fwmark.intValue,
- mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority + subPriority, 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
@@ -560,7 +545,7 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
// modifyNetworkPermission().
[[nodiscard]] static int modifyExplicitNetworkRule(unsigned netId, uint32_t table,
Permission permission, uid_t uidStart,
- uid_t uidEnd, bool add) {
+ uid_t uidEnd, uint32_t subPriority, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -573,8 +558,9 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
fwmark.permission = permission;
mask.permission = permission;
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_EXPLICIT_NETWORK, table,
- fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ RULE_PRIORITY_EXPLICIT_NETWORK + subPriority, table, fwmark.intValue,
+ mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
// A rule to route traffic based on a chosen outgoing interface.
@@ -583,7 +569,7 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
// 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, bool add) {
+ uid_t uidEnd, uint32_t subPriority, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -601,8 +587,9 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
}
}
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_OUTPUT_INTERFACE, table,
- fwmark.intValue, mask.intValue, IIF_LOOPBACK, interface, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ RULE_PRIORITY_OUTPUT_INTERFACE + subPriority, table, fwmark.intValue,
+ mask.intValue, IIF_LOOPBACK, interface, uidStart, uidEnd);
}
// A rule to route traffic based on the chosen network.
@@ -682,7 +669,8 @@ int RouteController::modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId
// 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, ACTION_ADD)) {
+ INVALID_UID, INVALID_UID,
+ UidRanges::DEFAULT_SUB_PRIORITY, ACTION_ADD)) {
return ret;
}
@@ -713,8 +701,9 @@ int RouteController::configureDummyNetwork() {
return -errno;
}
- if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE,
- INVALID_UID, INVALID_UID, ACTION_ADD))) {
+ if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, INVALID_UID,
+ INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
+ ACTION_ADD))) {
ALOGE("Can't create oif rules for %s: %s", interface, strerror(-ret));
return ret;
}
@@ -745,27 +734,102 @@ int RouteController::configureDummyNetwork() {
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, add);
+ 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);
}
/* static */
int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission, bool add) {
+ const UidRangeMap& uidRangeMap, Permission permission,
+ 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 = 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,
- add)) {
+ UidRanges::DEFAULT_SUB_PRIORITY, add)) {
return ret;
}
if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
- add)) {
+ UidRanges::DEFAULT_SUB_PRIORITY, add)) {
return ret;
}
@@ -795,6 +859,79 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
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;
@@ -813,24 +950,27 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
}
int RouteController::modifyVirtualNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges, bool secure, bool add,
+ const UidRangeMap& uidRangeMap, bool secure, bool add,
bool modifyNonUidBasedRules) {
uint32_t table = getRouteTableForInterface(interface);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
- 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;
+ 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;
+ }
}
}
@@ -844,7 +984,8 @@ int RouteController::modifyVirtualNetwork(unsigned netId, const char* interface,
if (int ret = modifyVpnSystemPermissionRule(netId, table, secure, add)) {
return ret;
}
- return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT, add);
+ return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT,
+ UidRanges::DEFAULT_SUB_PRIORITY, add);
}
return 0;
@@ -918,9 +1059,7 @@ int RouteController::modifyRoute(uint16_t action, uint16_t flags, const char* in
return 0;
}
-void maybeModifyQdiscClsact(const char* interface, bool add) {
- if (!bpf::isBpfSupported()) return;
-
+static void maybeModifyQdiscClsact(const char* interface, bool add) {
// 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.
@@ -1047,8 +1186,10 @@ int RouteController::removeInterfaceFromLocalNetwork(unsigned netId, const char*
}
int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission) {
- if (int ret = modifyPhysicalNetwork(netId, interface, permission, ACTION_ADD)) {
+ Permission permission,
+ const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_ADD,
+ MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
maybeModifyQdiscClsact(interface, ACTION_ADD);
@@ -1057,8 +1198,10 @@ int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* i
}
int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission) {
- if (int ret = modifyPhysicalNetwork(netId, interface, permission, ACTION_DEL)) {
+ Permission permission,
+ const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_DEL,
+ MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
if (int ret = flushRoutes(interface)) {
@@ -1073,8 +1216,8 @@ int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const ch
}
int RouteController::addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges) {
- if (int ret = modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,
+ bool secure, const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1083,8 +1226,9 @@ int RouteController::addInterfaceToVirtualNetwork(unsigned netId, const char* in
}
int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges) {
- if (int ret = modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_DEL,
+ bool secure,
+ const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1098,11 +1242,16 @@ int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const cha
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, newPermission, ACTION_ADD)) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, newPermission,
+ ACTION_ADD, MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
- return modifyPhysicalNetwork(netId, interface, oldPermission, ACTION_DEL);
+ return modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, oldPermission, ACTION_DEL,
+ MODIFY_NON_UID_BASED_RULES);
}
int RouteController::addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges) {
@@ -1114,14 +1263,14 @@ int RouteController::removeUsersFromRejectNonSecureNetworkRule(const UidRanges&
}
int RouteController::addUsersToVirtualNetwork(unsigned netId, const char* interface, bool secure,
- const UidRanges& uidRanges) {
- return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,
+ const UidRangeMap& uidRangeMap) {
+ return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
!MODIFY_NON_UID_BASED_RULES);
}
int RouteController::removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges) {
- return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_DEL,
+ bool secure, const UidRangeMap& uidRangeMap) {
+ return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
!MODIFY_NON_UID_BASED_RULES);
}
@@ -1171,6 +1320,27 @@ int RouteController::removeVirtualNetworkFallthrough(unsigned vpnNetId,
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 656fc21d..38d2d621 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -17,6 +17,7 @@
#pragma once
#include "NetdConstants.h" // IptablesTarget
+#include "Network.h" // UidRangeMap
#include "Permission.h"
#include <android-base/thread_annotations.h>
@@ -28,6 +29,53 @@
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 {
@@ -59,25 +107,29 @@ public:
[[nodiscard]] static int removeInterfaceFromLocalNetwork(unsigned netId, const char* interface);
[[nodiscard]] static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
- Permission permission);
+ Permission permission,
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeInterfaceFromPhysicalNetwork(unsigned netId,
const char* interface,
- Permission permission);
+ Permission permission,
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges);
+ bool secure,
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeInterfaceFromVirtualNetwork(unsigned netId,
const char* interface, bool secure,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[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 UidRanges& uidRanges);
+ bool secure, const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges);
+ bool secure,
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges);
[[nodiscard]] static int removeUsersFromRejectNonSecureNetworkRule(const UidRanges& uidRanges);
@@ -108,6 +160,18 @@ public:
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 *);
@@ -125,8 +189,10 @@ private:
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, Permission permission,
- bool add);
+ 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 modifyRoute(uint16_t action, uint16_t flags, const char* interface,
const char* destination, const char* nexthop, TableType tableType,
int mtu);
@@ -135,7 +201,7 @@ private:
static int modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId,
const char* physicalInterface, Permission permission);
static int modifyVirtualNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges, bool secure, bool add,
+ const UidRangeMap& uidRangeMap, bool secure, bool add,
bool modifyNonUidBasedRules);
static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock);
};
diff --git a/server/RouteControllerTest.cpp b/server/RouteControllerTest.cpp
index fed15a3a..e85a83c7 100644
--- a/server/RouteControllerTest.cpp
+++ b/server/RouteControllerTest.cpp
@@ -45,10 +45,10 @@ TEST_F(RouteControllerTest, TestGetRulePriority) {
// 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,
- 15000, // RULE_PRIORITY_LEGACY_SYSTEM
- 16000, // RULE_PRIORITY_LEGACY_NETWORK
- 32000, // RULE_PRIORITY_UNREACHABLE
+ 0,
+ RULE_PRIORITY_LEGACY_SYSTEM,
+ RULE_PRIORITY_LEGACY_NETWORK,
+ RULE_PRIORITY_UNREACHABLE,
};
NetlinkDumpCallback callback = [&expectedPriorities] (const nlmsghdr *nlh) {
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index 44bda3b0..b3d9150a 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -31,6 +31,8 @@
#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>
@@ -46,12 +48,22 @@
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;
@@ -294,7 +306,7 @@ int SockDiag::sockDestroy(uint8_t proto, const inet_diag_msg *msg) {
return ret;
}
-int SockDiag::destroySockets(uint8_t proto, int family, const char *addrstr) {
+int SockDiag::destroySockets(uint8_t proto, int family, const char* addrstr, int ifindex) {
if (!hasSocks()) {
return -EBADFD;
}
@@ -303,28 +315,33 @@ int SockDiag::destroySockets(uint8_t proto, int family, const char *addrstr) {
return ret;
}
- auto destroyAll = [] (uint8_t, const inet_diag_msg*) { return true; };
+ auto destroyAll = [ifindex](uint8_t, const inet_diag_msg* msg) {
+ return ifindex == 0 || ifindex == (int)msg->id.idiag_if;
+ };
return readDiagMsg(proto, destroyAll);
}
-int SockDiag::destroySockets(const char *addrstr) {
+int SockDiag::destroySockets(const char* addrstr, int ifindex) {
Stopwatch s;
mSocketsDestroyed = 0;
- if (!strchr(addrstr, ':')) {
- if (int ret = destroySockets(IPPROTO_TCP, AF_INET, addrstr)) {
- ALOGE("Failed to destroy IPv4 sockets on %s: %s", addrstr, strerror(-ret));
+ 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));
return ret;
}
}
- if (int ret = destroySockets(IPPROTO_TCP, AF_INET6, addrstr)) {
- ALOGE("Failed to destroy IPv6 sockets on %s: %s", addrstr, strerror(-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));
return ret;
}
if (mSocketsDestroyed > 0) {
- ALOGI("Destroyed %d sockets on %s in %" PRId64 "us", mSocketsDestroyed, addrstr,
+ ALOGI("Destroyed %d sockets on %s in %" PRId64 "us", mSocketsDestroyed, where.c_str(),
s.timeTakenUs());
}
@@ -414,7 +431,8 @@ int SockDiag::destroySockets(const UidRanges& uidRanges, const std::set<uid_t>&
return msg != nullptr &&
uidRanges.hasUid(msg->idiag_uid) &&
skipUids.find(msg->idiag_uid) == skipUids.end() &&
- !(excludeLoopback && isLoopbackSocket(msg));
+ !(excludeLoopback && isLoopbackSocket(msg)) &&
+ !isAdbSocket(msg, getAdbPort());
};
iovec iov[] = {
diff --git a/server/SockDiag.h b/server/SockDiag.h
index 745c09e3..240e4e5d 100644
--- a/server/SockDiag.h
+++ b/server/SockDiag.h
@@ -70,7 +70,7 @@ class SockDiag {
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 destroySockets(const char* addrstr, int ifindex);
// 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 @@ class SockDiag {
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 destroySockets(uint8_t proto, int family, const char* addrstr, int ifindex);
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 b79471a5..49601aa4 100644
--- a/server/SockDiagTest.cpp
+++ b/server/SockDiagTest.cpp
@@ -370,7 +370,7 @@ protected:
int ret;
switch (mode) {
case ADDRESS:
- ret = mSd.destroySockets("::1");
+ ret = mSd.destroySockets("::1", 0 /* ifindex */);
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 2445fb70..325fc413 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -60,14 +60,11 @@
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;
@@ -84,10 +81,6 @@ constexpr const char kTcpBeLiberal[] = "/proc/sys/net/netfilter/nf_conntrack_tcp
// 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) {
@@ -164,12 +157,13 @@ int TetherController::DnsmasqState::sendAllState(int daemonFd) const {
}
TetherController::TetherController() {
+ gLog.info("enter TetherController ctor");
if (inBpToolsMode()) {
enableForwarding(BP_TOOLS_MODE);
} else {
setIpFwdEnabled();
}
- maybeInitMaps();
+ gLog.info("leave TetherController ctor");
}
bool TetherController::setIpFwdEnabled() {
@@ -202,27 +196,6 @@ bool TetherController::disableForwarding(const char* requester) {
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;
}
@@ -606,8 +579,7 @@ int TetherController::enableNat(const char* intIface, const char* extIface) {
}
// add this if we are the first enabled nat for this upstream
- bool firstDownstreamForThisUpstream = !isAnyForwardingEnabledOnUpstream(extIface);
- if (firstDownstreamForThisUpstream) {
+ if (!isAnyForwardingEnabledOnUpstream(extIface)) {
std::vector<std::string> v4Cmds = {
"*nat",
StringPrintf("-A %s -o %s -j MASQUERADE", LOCAL_NAT_POSTROUTING, extIface),
@@ -633,7 +605,6 @@ int TetherController::enableNat(const char* intIface, const char* extIface) {
return -ENODEV;
}
- if (firstDownstreamForThisUpstream) maybeStartBpf(extIface);
return 0;
}
@@ -817,82 +788,10 @@ int TetherController::disableNat(const char* intIface, const char* extIface) {
}
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)) {
@@ -1028,180 +927,6 @@ StatusOr<TetherController::TetherStatsList> TetherController::getTetherStats() {
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:");
@@ -1212,90 +937,6 @@ void TetherController::dumpIfaces(DumpWriter& dw) {
}
}
-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);
@@ -1313,8 +954,6 @@ void TetherController::dump(DumpWriter& dw) {
}
dumpIfaces(dw);
- dw.println("");
- dumpBpf(dw);
}
} // namespace net
diff --git a/server/TetherController.h b/server/TetherController.h
index bcd2ee67..585686a0 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -72,11 +72,6 @@ class TetherController {
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;
@@ -105,11 +100,6 @@ class TetherController {
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;
@@ -138,20 +128,9 @@ class TetherController {
}
};
- 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.
@@ -173,7 +152,6 @@ class TetherController {
void dump(netdutils::DumpWriter& dw);
void dumpIfaces(netdutils::DumpWriter& dw);
- void dumpBpf(netdutils::DumpWriter& dw);
private:
bool setIpFwdEnabled();
@@ -195,11 +173,6 @@ class TetherController {
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 db9892f9..e700f605 100644
--- a/server/TetherControllerTest.cpp
+++ b/server/TetherControllerTest.cpp
@@ -38,28 +38,13 @@
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() {
@@ -68,38 +53,6 @@ public:
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();
@@ -485,64 +438,5 @@ TEST_F(TetherControllerTest, TestGetTetherStats) {
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 3839962f..1f678cbf 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -52,13 +52,16 @@
#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;
@@ -100,6 +103,7 @@ const std::string uidMatchTypeToString(uint8_t match) {
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);
@@ -167,14 +171,11 @@ StatusOr<std::unique_ptr<NetlinkListenerInterface>> TrafficController::makeSkDes
}
TrafficController::TrafficController()
- : mBpfEnabled(isBpfSupported()),
- mPerUidStatsEntriesLimit(PER_UID_STATS_ENTRIES_LIMIT),
+ : mPerUidStatsEntriesLimit(PER_UID_STATS_ENTRIES_LIMIT),
mTotalUidStatsEntriesLimit(TOTAL_UID_STATS_ENTRIES_LIMIT) {}
TrafficController::TrafficController(uint32_t perUidLimit, uint32_t totalLimit)
- : mBpfEnabled(isBpfSupported()),
- mPerUidStatsEntriesLimit(perUidLimit),
- mTotalUidStatsEntriesLimit(totalLimit) {}
+ : mPerUidStatsEntriesLimit(perUidLimit), mTotalUidStatsEntriesLimit(totalLimit) {}
Status TrafficController::initMaps() {
std::lock_guard guard(mMutex);
@@ -247,10 +248,6 @@ static Status initPrograms() {
}
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.
@@ -314,11 +311,6 @@ int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t call
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};
@@ -382,10 +374,6 @@ int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t call
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;
@@ -403,11 +391,6 @@ int TrafficController::setCounterSet(int counterSetNum, uid_t uid, uid_t calling
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) {
@@ -436,11 +419,6 @@ int TrafficController::deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid)
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,
@@ -501,8 +479,6 @@ int TrafficController::deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid)
}
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);
@@ -521,10 +497,10 @@ int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
FirewallType type) {
std::lock_guard guard(mMutex);
- 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));
+ 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));
} else {
//Cannot happen.
return statusFromErrno(EINVAL, "");
@@ -532,29 +508,17 @@ Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid
return netdutils::status::ok;
}
-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);
+Status TrafficController::removeRule(uint32_t uid, UidOwnerMatchType match) {
+ auto oldMatch = mUidOwnerMap.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(map.deleteValue(uid));
+ RETURN_IF_NOT_OK(mUidOwnerMap.deleteValue(uid));
} else {
- RETURN_IF_NOT_OK(map.writeValue(uid, newMatch, BPF_ANY));
+ RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
}
} else {
return statusFromErrno(ENOENT, StringPrintf("uid: %u does not exist in map", uid));
@@ -562,55 +526,42 @@ Status TrafficController::removeRule(BpfMap<uint32_t, UidOwnerValue>& map, uint3
return netdutils::status::ok;
}
-Status TrafficController::addRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
- UidOwnerMatchType match, uint32_t iif) {
+Status TrafficController::addRule(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 = map.readValue(uid);
+ auto oldMatch = mUidOwnerMap.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(map.writeValue(uid, newMatch, BPF_ANY));
+ RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
} else {
UidOwnerValue newMatch = {
.iif = iif,
.rule = static_cast<uint8_t>(match),
};
- RETURN_IF_NOT_OK(map.writeValue(uid, newMatch, BPF_ANY));
+ RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
}
return netdutils::status::ok;
}
-Status TrafficController::updateUidOwnerMap(const std::vector<std::string>& appStrUids,
- BandwidthController::IptJumpOp jumpHandling,
+Status TrafficController::updateUidOwnerMap(const std::vector<uint32_t>& appUids,
+ UidOwnerMatchType matchType,
BandwidthController::IptOp op) {
std::lock_guard guard(mMutex);
- 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);
- }
-
+ for (uint32_t uid : appUids) {
if (op == BandwidthController::IptOpDelete) {
- RETURN_IF_NOT_OK(removeRule(mUidOwnerMap, uid, match));
+ RETURN_IF_NOT_OK(removeRule(uid, matchType));
} else if (op == BandwidthController::IptOpInsert) {
- RETURN_IF_NOT_OK(addRule(mUidOwnerMap, uid, match));
+ RETURN_IF_NOT_OK(addRule(uid, matchType));
} else {
// Cannot happen.
- return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, match));
+ return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, matchType));
}
}
return netdutils::status::ok;
@@ -618,10 +569,6 @@ Status TrafficController::updateUidOwnerMap(const std::vector<std::string>& appS
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:
@@ -633,6 +580,9 @@ int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallR
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;
@@ -660,28 +610,24 @@ Status TrafficController::replaceRulesInMap(const UidOwnerMatchType match,
RETURN_IF_NOT_OK(mUidOwnerMap.iterate(getUidsToDelete));
for(auto uid : uidsToDelete) {
- RETURN_IF_NOT_OK(removeRule(mUidOwnerMap, uid, match));
+ RETURN_IF_NOT_OK(removeRule(uid, match));
}
for (auto uid : uids) {
- RETURN_IF_NOT_OK(addRule(mUidOwnerMap, uid, match));
+ RETURN_IF_NOT_OK(addRule(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(mUidOwnerMap, uid, IIF_MATCH, iif);
+ netdutils::Status result = addRule(uid, IIF_MATCH, iif);
if (!isOk(result)) {
ALOGW("addRule failed(%d): uid=%d iif=%d", result.code(), uid, iif);
}
@@ -690,14 +636,10 @@ Status TrafficController::addUidInterfaceRules(const int iif,
}
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(mUidOwnerMap, uid, IIF_MATCH);
+ netdutils::Status result = removeRule(uid, IIF_MATCH);
if (!isOk(result)) {
ALOGW("removeRule failed(%d): uid=%d", result.code(), uid);
}
@@ -705,10 +647,10 @@ Status TrafficController::removeUidInterfaceRules(const std::vector<int32_t>& ui
return netdutils::status::ok;
}
-int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist __unused,
+int TrafficController::replaceUidOwnerMap(const std::string& name, bool isAllowlist __unused,
const std::vector<int32_t>& uids) {
- // FirewallRule rule = isWhitelist ? ALLOW : DENY;
- // FirewallType type = isWhitelist ? WHITELIST : BLACKLIST;
+ // FirewallRule rule = isAllowlist ? ALLOW : DENY;
+ // FirewallType type = isAllowlist ? ALLOWLIST : DENYLIST;
Status res;
if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
res = replaceRulesInMap(DOZABLE_MATCH, uids);
@@ -716,6 +658,8 @@ int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitel
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;
@@ -749,6 +693,9 @@ int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
case POWERSAVE:
match = POWERSAVE_MATCH;
break;
+ case RESTRICTED:
+ match = RESTRICTED_MATCH;
+ break;
default:
return -EINVAL;
}
@@ -761,17 +708,9 @@ int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
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()) {
@@ -814,12 +753,9 @@ void TrafficController::setPermissionForUids(int permission, const std::vector<u
// Clean up all permission information for the related uid if all the
// packages related to it are uninstalled.
mPrivilegedUser.erase(uid);
- 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()));
- }
+ 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;
@@ -834,10 +770,6 @@ void TrafficController::setPermissionForUids(int permission, const std::vector<u
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) {
@@ -893,12 +825,6 @@ void TrafficController::dump(DumpWriter& dw, bool verbose) {
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",
@@ -928,10 +854,10 @@ void TrafficController::dump(DumpWriter& dw, bool verbose) {
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 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());
+ 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());
if (!verbose) {
return;
diff --git a/server/TrafficController.h b/server/TrafficController.h
index a2539a90..2e799598 100644
--- a/server/TrafficController.h
+++ b/server/TrafficController.h
@@ -78,12 +78,6 @@ class TrafficController {
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);
@@ -97,7 +91,7 @@ class TrafficController {
int removeUidOwnerRule(const uid_t uid);
- int replaceUidOwnerMap(const std::string& name, bool isWhitelist,
+ int replaceUidOwnerMap(const std::string& name, bool isAllowlist,
const std::vector<int32_t>& uids);
netdutils::Status updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
@@ -112,9 +106,9 @@ class TrafficController {
EXCLUDES(mMutex);
netdutils::Status removeUidInterfaceRules(const std::vector<int32_t>& uids) EXCLUDES(mMutex);
- netdutils::Status updateUidOwnerMap(const std::vector<std::string>& appStrUids,
- BandwidthController::IptJumpOp jumpHandling,
- BandwidthController::IptOp op) EXCLUDES(mMutex);
+ netdutils::Status updateUidOwnerMap(const std::vector<uint32_t>& appStrUids,
+ UidOwnerMatchType matchType, BandwidthController::IptOp op)
+ EXCLUDES(mMutex);
static const String16 DUMP_KEYWORD;
int toggleUidOwnerMap(ChildChain chain, bool enable) EXCLUDES(mMutex);
@@ -183,7 +177,7 @@ class TrafficController {
* 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 mode.
+ * is in doze/powersave/standby/restricted 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
@@ -203,13 +197,10 @@ class TrafficController {
std::unique_ptr<NetlinkListenerInterface> mSkDestroyListener;
- netdutils::Status removeRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
- UidOwnerMatchType match) REQUIRES(mMutex);
-
- netdutils::Status addRule(BpfMap<uint32_t, UidOwnerValue>& map, uint32_t uid,
- UidOwnerMatchType match, uint32_t iif = 0) REQUIRES(mMutex);
+ netdutils::Status removeRule(uint32_t uid, UidOwnerMatchType match) REQUIRES(mMutex);
- bool mBpfEnabled;
+ netdutils::Status addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif = 0)
+ REQUIRES(mMutex);
// 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 3cde9be8..159fb086 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -16,6 +16,7 @@
* TrafficControllerTest.cpp - unit tests for TrafficController.cpp
*/
+#include <cstdint>
#include <string>
#include <vector>
@@ -74,7 +75,6 @@ class TrafficControllerTest : public ::testing::Test {
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 @@ class TrafficControllerTest : public ::testing::Test {
void checkUidOwnerRuleForChain(ChildChain chain, UidOwnerMatchType match) {
uint32_t uid = TEST_UID;
- EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, BLACKLIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, DENYLIST));
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, WHITELIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, ALLOWLIST));
value = mFakeUidOwnerMap.readValue(uid);
EXPECT_RESULT_OK(value);
EXPECT_TRUE(value.value().rule & match);
- EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, WHITELIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, DENY, ALLOWLIST));
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, BLACKLIST));
+ EXPECT_EQ(0, mTc.changeUidOwnerRule(chain, uid, ALLOW, DENYLIST));
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, BLACKLIST));
+ EXPECT_EQ(-ENOENT, mTc.changeUidOwnerRule(chain, uid, ALLOW, DENYLIST));
value = mFakeUidOwnerMap.readValue(uid);
EXPECT_FALSE(value.ok());
EXPECT_EQ(ENOENT, value.error().code());
@@ -211,18 +211,18 @@ class TrafficControllerTest : public ::testing::Test {
void checkUidMapReplace(const std::string& name, const std::vector<int32_t>& uids,
UidOwnerMatchType match) {
- bool isWhitelist = true;
- EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isWhitelist, uids));
+ bool isAllowlist = true;
+ EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isAllowlist, uids));
checkEachUidValue(uids, match);
- isWhitelist = false;
- EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isWhitelist, uids));
+ isAllowlist = false;
+ EXPECT_EQ(0, mTc.replaceUidOwnerMap(name, isAllowlist, uids));
checkEachUidValue(uids, match);
}
- void expectUidOwnerMapValues(const std::vector<std::string>& appStrUids, uint8_t expectedRule,
+
+ void expectUidOwnerMapValues(const std::vector<uint32_t>& appUids, uint8_t expectedRule,
uint32_t expectedIif) {
- for (const std::string& strUid : appStrUids) {
- uint32_t uid = stoi(strUid);
+ for (uint32_t uid : appUids) {
Result<UidOwnerValue> value = mFakeUidOwnerMap.readValue(uid);
EXPECT_RESULT_OK(value);
EXPECT_EQ(expectedRule, value.value().rule)
@@ -315,8 +315,6 @@ class TrafficControllerTest : public ::testing::Test {
};
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);
@@ -326,8 +324,6 @@ TEST_F(TrafficControllerTest, TestTagSocketV4) {
}
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);
@@ -336,8 +332,6 @@ TEST_F(TrafficControllerTest, TestReTagSocket) {
}
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);
@@ -351,8 +345,6 @@ TEST_F(TrafficControllerTest, TestTagTwoSockets) {
}
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);
@@ -362,16 +354,12 @@ TEST_F(TrafficControllerTest, TestTagSocketV6) {
}
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));
@@ -379,8 +367,6 @@ TEST_F(TrafficControllerTest, TestTagSocketWithoutPermission) {
}
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);
@@ -399,8 +385,6 @@ TEST_F(TrafficControllerTest, TestTagSocketWithPermission) {
}
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);
@@ -409,8 +393,6 @@ TEST_F(TrafficControllerTest, TestUntagInvalidSocket) {
}
TEST_F(TrafficControllerTest, TestTagSocketReachLimitFail) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uid_t uid = TEST_UID;
StatsKey tagStatsMapKey[4];
for (int i = 0; i < 3; i++) {
@@ -422,8 +404,6 @@ TEST_F(TrafficControllerTest, TestTagSocketReachLimitFail) {
}
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;
@@ -435,8 +415,6 @@ TEST_F(TrafficControllerTest, TestTagSocketReachTotalLimitFail) {
}
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));
@@ -450,8 +428,6 @@ TEST_F(TrafficControllerTest, TestSetCounterSet) {
}
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());
@@ -459,8 +435,6 @@ TEST_F(TrafficControllerTest, TestSetCounterSetWithoutPermission) {
}
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));
@@ -470,8 +444,6 @@ TEST_F(TrafficControllerTest, TestSetInvalidCounterSet) {
}
TEST_F(TrafficControllerTest, TestDeleteTagDataWithoutPermission) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uint64_t cookie = 1;
uid_t uid = TEST_UID;
uint32_t tag = TEST_TAG;
@@ -483,8 +455,6 @@ TEST_F(TrafficControllerTest, TestDeleteTagDataWithoutPermission) {
}
TEST_F(TrafficControllerTest, TestDeleteTagData) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie = 1;
@@ -510,8 +480,6 @@ TEST_F(TrafficControllerTest, TestDeleteTagData) {
}
TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie = 1;
@@ -529,8 +497,6 @@ TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
}
TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie1 = 1;
@@ -559,8 +525,6 @@ TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
}
TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uid_t callingUid = TEST_UID2;
addPrivilegedUid(callingUid);
uint64_t cookie1 = 1;
@@ -602,174 +566,156 @@ TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
}
TEST_F(TrafficControllerTest, TestUpdateOwnerMapEntry) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
uint32_t uid = TEST_UID;
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, BLACKLIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, DENYLIST)));
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, WHITELIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, ALLOW, ALLOWLIST)));
value = mFakeUidOwnerMap.readValue(uid);
ASSERT_RESULT_OK(value);
ASSERT_TRUE(value.value().rule & DOZABLE_MATCH);
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, DENY, WHITELIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(DOZABLE_MATCH, uid, DENY, ALLOWLIST)));
value = mFakeUidOwnerMap.readValue(uid);
ASSERT_RESULT_OK(value);
ASSERT_FALSE(value.value().rule & DOZABLE_MATCH);
- ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, BLACKLIST)));
+ ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, DENYLIST)));
ASSERT_FALSE(mFakeUidOwnerMap.readValue(uid).ok());
uid = TEST_UID2;
- ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, BLACKLIST)));
+ ASSERT_FALSE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, ALLOW, DENYLIST)));
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);
- ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(NONE, TEST_UID, ALLOW, WHITELIST));
- ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(INVALID_CHAIN, TEST_UID, ALLOW, WHITELIST));
+ 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));
}
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, 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)));
+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)));
expectMapEmpty(mFakeUidOwnerMap);
}
-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)));
+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)));
expectMapEmpty(mFakeUidOwnerMap);
}
TEST_F(TrafficControllerTest, TestReplaceMatchUid) {
- SKIP_IF_BPF_NOT_SUPPORTED;
+ 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);
- 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 |
+ // Add the same UIDs to the allowlist and expect that we get PENALTY_BOX_MATCH |
// HAPPY_BOX_MATCH.
- 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 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 blacklist and check the map is empty.
- ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReject,
- BandwidthController::IptOpDelete)));
+ ASSERT_TRUE(isOk(
+ mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
+ expectUidOwnerMapValues(appUids, 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 denylist and check the map is empty.
+ ASSERT_TRUE(isOk(
+ mTc.updateUidOwnerMap(appUids, PENALTY_BOX_MATCH, BandwidthController::IptOpDelete)));
ASSERT_FALSE(mFakeUidOwnerMap.getFirstKey().ok());
}
TEST_F(TrafficControllerTest, TestDeleteWrongMatchSilentlyFails) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
- std::vector<std::string> appStrUids = {"1000", "1001", "10012"};
+ std::vector<uint32_t> appUids = {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(appStrUids, BandwidthController::IptJumpReturn,
- BandwidthController::IptOpDelete)));
+ ASSERT_FALSE(isOk(
+ mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpDelete)));
expectMapEmpty(mFakeUidOwnerMap);
- // Add blacklist rules for appStrUids.
- ASSERT_TRUE(isOk(mTc.updateUidOwnerMap(appStrUids, BandwidthController::IptJumpReturn,
- BandwidthController::IptOpInsert)));
- expectUidOwnerMapValues(appStrUids, HAPPY_BOX_MATCH, 0);
+ // Add denylist rules for appUids.
+ ASSERT_TRUE(isOk(
+ mTc.updateUidOwnerMap(appUids, HAPPY_BOX_MATCH, BandwidthController::IptOpInsert)));
+ 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);
+ // 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);
}
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
@@ -778,72 +724,65 @@ TEST_F(TrafficControllerTest, TestRemoveUidInterfaceFilteringRules) {
}
TEST_F(TrafficControllerTest, TestUidInterfaceFilteringRulesCoexistWithExistingMatches) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
// Set up existing PENALTY_BOX_MATCH rules
- ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({"1000", "1001", "10012"},
- BandwidthController::IptJumpReject,
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({1000, 1001, 10012}, PENALTY_BOX_MATCH,
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"}, BandwidthController::IptJumpReject,
+ ASSERT_TRUE(isOk(mTc.updateUidOwnerMap({1001, 10012}, PENALTY_BOX_MATCH,
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);
@@ -852,8 +791,6 @@ TEST_F(TrafficControllerTest, TestGrantInternetPermission) {
}
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);
@@ -861,8 +798,6 @@ TEST_F(TrafficControllerTest, TestRevokeInternetPermission) {
}
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);
@@ -882,8 +817,6 @@ TEST_F(TrafficControllerTest, TestPermissionUninstalled) {
}
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);
@@ -896,8 +829,6 @@ TEST_F(TrafficControllerTest, TestGrantUpdateStatsPermission) {
}
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);
@@ -914,8 +845,6 @@ TEST_F(TrafficControllerTest, TestRevokeUpdateStatsPermission) {
}
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);
@@ -924,8 +853,6 @@ TEST_F(TrafficControllerTest, TestGrantWrongPermission) {
}
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 883a13f9..093a1e27 100644
--- a/server/UidRanges.cpp
+++ b/server/UidRanges.cpp
@@ -127,8 +127,35 @@ void UidRanges::remove(const UidRanges& other) {
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("UidRanges{ ");
+ std::string s("uids{ ");
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 28d3c6b4..99e7a99d 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -28,6 +28,9 @@ namespace net {
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);
@@ -40,7 +43,16 @@ public:
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
new file mode 100644
index 00000000..2f801f0c
--- /dev/null
+++ b/server/UnreachableNetwork.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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
new file mode 100644
index 00000000..f1547d60
--- /dev/null
+++ b/server/UnreachableNetwork.h
@@ -0,0 +1,36 @@
+/*
+ * 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 33791c68..1906e208 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -20,7 +20,6 @@
#include "VirtualNetwork.h"
-#include "SockDiag.h"
#include "RouteController.h"
#include "log/log.h"
@@ -28,78 +27,48 @@
namespace android {
namespace net {
-VirtualNetwork::VirtualNetwork(unsigned netId, bool secure) : Network(netId), mSecure(secure) {}
+VirtualNetwork::VirtualNetwork(unsigned netId, bool secure) : Network(netId, secure) {}
VirtualNetwork::~VirtualNetwork() {}
-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;
+int VirtualNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
+ return -EINVAL;
}
- 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) {
- if (int ret = RouteController::addUsersToVirtualNetwork(mNetId, interface.c_str(), mSecure,
- uidRanges)) {
+ int ret = RouteController::addUsersToVirtualNetwork(mNetId, interface.c_str(), mSecure,
+ {{subPriority, uidRanges}});
+ if (ret) {
ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- mUidRanges.add(uidRanges);
+ addToUidRangeMap(uidRanges, subPriority);
return 0;
}
-int VirtualNetwork::removeUsers(const UidRanges& uidRanges,
- const std::set<uid_t>& protectableUsers) {
- maybeCloseSockets(false, uidRanges, protectableUsers);
+int VirtualNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority)) return -EINVAL;
for (const std::string& interface : mInterfaces) {
- if (int ret = RouteController::removeUsersFromVirtualNetwork(mNetId, interface.c_str(),
- mSecure, uidRanges)) {
+ int ret = RouteController::removeUsersFromVirtualNetwork(mNetId, interface.c_str(), mSecure,
+ {{subPriority, uidRanges}});
+ if (ret) {
ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- mUidRanges.remove(uidRanges);
+ removeFromUidRangeMap(uidRanges, subPriority);
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,
- mUidRanges)) {
+ mUidRangeMap)) {
ALOGE("failed to add interface %s to VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -112,7 +81,7 @@ int VirtualNetwork::removeInterface(const std::string& interface) {
return 0;
}
if (int ret = RouteController::removeInterfaceFromVirtualNetwork(mNetId, interface.c_str(),
- mSecure, mUidRanges)) {
+ mSecure, mUidRangeMap)) {
ALOGE("failed to remove interface %s from VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -120,5 +89,10 @@ int VirtualNetwork::removeInterface(const std::string& interface) {
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 20c8dee3..20c9e2c2 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -19,7 +19,6 @@
#include <set>
#include "Network.h"
-#include "UidRanges.h"
namespace android::net {
@@ -34,23 +33,16 @@ class VirtualNetwork : public Network {
public:
VirtualNetwork(unsigned netId, bool secure);
virtual ~VirtualNetwork();
-
- 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);
+ [[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; }
private:
- Type getType() const override;
+ std::string getTypeString() const override { return "VIRTUAL"; };
[[nodiscard]] int addInterface(const std::string& interface) override;
[[nodiscard]] int removeInterface(const std::string& interface) override;
- int maybeCloseSockets(bool add, const UidRanges& uidRanges,
- const std::set<uid_t>& protectableUsers);
-
- const bool mSecure;
- UidRanges mUidRanges;
+ bool isValidSubPriority(uint32_t priority) override;
};
} // namespace android::net
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 33a2aa21..24168a20 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -646,20 +646,69 @@ netdutils::Status XfrmController::ipSecDeleteSecurityAssociation(
return ret;
}
-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) {
+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) {
// 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 ||
@@ -669,10 +718,24 @@ netdutils::Status XfrmController::fillXfrmCommonInfo(const std::string& sourceAd
return netdutils::statusFromErrno(EINVAL, "Invalid or mismatched address families");
}
- info->addrFamily = destFamily.value();
+ endpointPair->addrFamily = destFamily.value();
- info->dstAddr = destXfrmAddr;
- info->srcAddr = sourceXfrmAddr;
+ 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;
+ }
return fillXfrmCommonInfo(spi, markValue, markMask, transformId, xfrmInterfaceId, info);
}
@@ -721,6 +784,7 @@ netdutils::Status XfrmController::ipSecApplyTransportModeTransform(
}
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
@@ -737,7 +801,7 @@ netdutils::Status XfrmController::ipSecApplyTransportModeTransform(
xfrm_user_tmpl tmpl;
} policy{};
- fillUserSpInfo(spInfo, static_cast<XfrmDirection>(direction), &policy.info);
+ fillUserSpInfo(spInfo, &policy.info);
fillUserTemplate(spInfo, &policy.tmpl);
LOG_HEX("XfrmUserPolicy", reinterpret_cast<char*>(&policy), sizeof(policy));
@@ -853,18 +917,18 @@ netdutils::Status XfrmController::processSecurityPolicy(
// 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, static_cast<XfrmDirection>(direction));
+ return deleteTunnelModeSecurityPolicy(spInfo, sock);
} else {
RETURN_IF_NOT_OK(fillXfrmCommonInfo(tmplSrcAddress, tmplDstAddress, spi, markValue,
markMask, transformId, xfrmInterfaceId, &spInfo));
- return updateTunnelModeSecurityPolicy(spInfo, sock, static_cast<XfrmDirection>(direction),
- msgType);
+ return updateTunnelModeSecurityPolicy(spInfo, sock, msgType);
}
}
@@ -961,7 +1025,7 @@ netdutils::Status XfrmController::updateSecurityAssociation(const XfrmSaInfo& re
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.netId, &xfrmoutputmark);
+ len = iov[OUTPUT_MARK].iov_len = fillNlAttrXfrmOutputMark(record, &xfrmoutputmark);
iov[OUTPUT_MARK_PAD].iov_len = NLA_ALIGN(len) - len;
len = iov[ENCAP].iov_len = fillNlAttrXfrmEncapTmpl(record, &encap);
@@ -1110,6 +1174,24 @@ netdutils::Status XfrmController::deleteSecurityAssociation(const XfrmCommonInfo
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) {
@@ -1160,7 +1242,6 @@ netdutils::Status XfrmController::allocateSpi(const XfrmSaInfo& record, uint32_t
netdutils::Status XfrmController::updateTunnelModeSecurityPolicy(const XfrmSpInfo& record,
const XfrmSocket& sock,
- XfrmDirection direction,
uint16_t msgType) {
xfrm_userpolicy_info userpolicy{};
nlattr_user_tmpl usertmpl{};
@@ -1192,7 +1273,7 @@ netdutils::Status XfrmController::updateTunnelModeSecurityPolicy(const XfrmSpInf
};
int len;
- len = iov[USERPOLICY].iov_len = fillUserSpInfo(record, direction, &userpolicy);
+ len = iov[USERPOLICY].iov_len = fillUserSpInfo(record, &userpolicy);
iov[USERPOLICY_PAD].iov_len = NLMSG_ALIGN(len) - len;
len = iov[USERTMPL].iov_len = fillNlAttrUserTemplate(record, &usertmpl);
@@ -1208,8 +1289,7 @@ netdutils::Status XfrmController::updateTunnelModeSecurityPolicy(const XfrmSpInf
}
netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSpInfo& record,
- const XfrmSocket& sock,
- XfrmDirection direction) {
+ const XfrmSocket& sock) {
xfrm_userpolicy_id policyid{};
nlattr_xfrm_mark xfrmmark{};
nlattr_xfrm_interface_id xfrm_if_id{};
@@ -1234,7 +1314,7 @@ netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSpInf
{kPadBytes, 0}, // up to NLATTR_ALIGNTO pad bytes
};
- int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, direction, &policyid);
+ int len = iov[USERPOLICYID].iov_len = fillUserPolicyId(record, &policyid);
iov[USERPOLICYID_PAD].iov_len = NLMSG_ALIGN(len) - len;
len = iov[MARK].iov_len = fillNlAttrXfrmMark(record, &xfrmmark);
@@ -1246,15 +1326,14 @@ netdutils::Status XfrmController::deleteTunnelModeSecurityPolicy(const XfrmSpInf
return sock.sendMessage(XFRM_MSG_DELPOLICY, NETLINK_REQUEST_FLAGS, 0, &iov);
}
-int XfrmController::fillUserSpInfo(const XfrmSpInfo& record, XfrmDirection direction,
- xfrm_userpolicy_info* usersp) {
+int XfrmController::fillUserSpInfo(const XfrmSpInfo& record, 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>(direction);
+ usersp->dir = static_cast<uint8_t>(record.direction);
usersp->action = XFRM_POLICY_ALLOW;
usersp->flags = XFRM_POLICY_LOCALOK;
usersp->share = XFRM_SHARE_UNIQUE;
@@ -1302,24 +1381,30 @@ int XfrmController::fillNlAttrXfrmMark(const XfrmCommonInfo& record, nlattr_xfrm
// 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. 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,
+// 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,
nlattr_xfrm_output_mark* output_mark) {
- // Do not set if we were not given an output mark
- if (underlyingNetId == 0) {
+ // Only set for tunnel mode transforms
+ if (record.mode != XfrmMode::TUNNEL) {
return 0;
}
Fwmark fwmark;
- fwmark.netId = underlyingNetId;
- // TODO: Rework this to more accurately follow the underlying network
- fwmark.permission = PERMISSION_SYSTEM;
- fwmark.explicitlySelected = true;
- fwmark.protectedFromVpn = true;
+ // 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.
+
output_mark->outputMark = fwmark.intValue;
int len = NLA_HDRLEN + sizeof(__u32);
@@ -1340,11 +1425,28 @@ int XfrmController::fillNlAttrXfrmIntfId(const uint32_t intfIdValue,
return len;
}
-int XfrmController::fillUserPolicyId(const XfrmSpInfo& record, XfrmDirection direction,
- xfrm_userpolicy_id* usersp) {
+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) {
// For DELPOLICY, when index is absent, selector is needed to match the policy
fillXfrmSelector(record.selAddrFamily, &usersp->sel);
- usersp->dir = static_cast<uint8_t>(direction);
+ usersp->dir = static_cast<uint8_t>(record.direction);
return sizeof(*usersp);
}
diff --git a/server/XfrmController.h b/server/XfrmController.h
index 15eef3d7..4f167c5f 100644
--- a/server/XfrmController.h
+++ b/server/XfrmController.h
@@ -107,15 +107,19 @@ struct XfrmEncap {
uint16_t dstPort;
};
-// minimally sufficient structure to match either an SA or a Policy
-struct XfrmCommonInfo {
+struct XfrmEndpointPair {
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 {
@@ -123,14 +127,18 @@ struct XfrmSaInfo : XfrmCommonInfo {
XfrmAlgo crypt;
XfrmAlgo aead;
int netId;
- XfrmMode mode;
XfrmEncap encap;
};
-struct XfrmSpInfo : XfrmSaInfo {
+struct XfrmSpInfo : XfrmCommonInfo {
// 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;
};
/*
@@ -260,6 +268,13 @@ public:
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
@@ -329,6 +344,13 @@ public:
__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;
@@ -338,6 +360,9 @@ public:
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,
@@ -373,15 +398,15 @@ public:
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, XfrmDirection direction,
- xfrm_userpolicy_info* usersp);
+ static int fillUserSpInfo(const XfrmSpInfo& record, xfrm_userpolicy_info* usersp);
static int fillNlAttrUserTemplate(const XfrmSpInfo& record, nlattr_user_tmpl* tmpl);
- static int fillUserPolicyId(const XfrmSpInfo& record, XfrmDirection direction,
- xfrm_userpolicy_id* policy_id);
+ static int fillUserPolicyId(const XfrmSpInfo& record, xfrm_userpolicy_id* policy_id);
static int fillNlAttrXfrmMark(const XfrmCommonInfo& record, nlattr_xfrm_mark* mark);
- static int fillNlAttrXfrmOutputMark(const __u32 underlyingNetId,
+ static int fillNlAttrXfrmOutputMark(const XfrmSaInfo& record,
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);
@@ -394,11 +419,10 @@ public:
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,
- XfrmDirection direction);
+ const XfrmSocket& sock);
+ static netdutils::Status migrate(const XfrmMigrateInfo& record, const XfrmSocket& sock);
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/5/.hash b/server/aidl_api/netd_aidl_interface/5/.hash
new file mode 100644
index 00000000..a6ced453
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/.hash
@@ -0,0 +1 @@
+d97c56dd789cee9eeb5cdcec43a99df0a01873a5
diff --git a/server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl
new file mode 100644
index 00000000..b30748a3
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/android/net/INetd.aidl
@@ -0,0 +1,167 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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 isAllowlist, 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 @JavaPassthrough(annotation="@Deprecated") int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_ALLOWLIST = 0;
+ const @JavaPassthrough(annotation="@Deprecated") int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_DENYLIST = 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 int FIREWALL_CHAIN_RESTRICTED = 4;
+ 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/5/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 00000000..44593632
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 00000000..01e0f955
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/MarkMaskParcel.aidl
new file mode 100644
index 00000000..62be8384
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/RouteInfoParcel.aidl
new file mode 100644
index 00000000..5e0ee62a
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/TetherConfigParcel.aidl
new file mode 100644
index 00000000..b1364545
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 00000000..c9d84580
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/TetherStatsParcel.aidl
new file mode 100644
index 00000000..0b0960ef
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/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/5/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.aidl
new file mode 100644
index 00000000..debc6be2
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/5/android/net/UidRangeParcel.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;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/6/.hash b/server/aidl_api/netd_aidl_interface/6/.hash
new file mode 100644
index 00000000..f5acf5d1
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/.hash
@@ -0,0 +1 @@
+b08451d9673b09cba84f1fd8740e1fdac64ff7be
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl
new file mode 100644
index 00000000..a7952f28
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/INetd.aidl
@@ -0,0 +1,198 @@
+/**
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 isAllowlist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
+ void networkCreatePhysical(int netId, int permission);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
+ 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);
+ void networkCreate(in android.net.NativeNetworkConfig config);
+ 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 int DUMMY_NET_ID = 51;
+ const int UNREACHABLE_NET_ID = 52;
+ 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;
+ /**
+ * @deprecated use FIREWALL_ALLOWLIST.
+ */
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_ALLOWLIST = 0;
+ /**
+ * @deprecated use FIREWALL_DENYLIST.
+ */
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_DENYLIST = 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 int FIREWALL_CHAIN_RESTRICTED = 4;
+ 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/6/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 00000000..31775dfd
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 00000000..1869d8d4
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl
new file mode 100644
index 00000000..8ea20d11
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/NativeNetworkConfig.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl
new file mode 100644
index 00000000..76562b29
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkConfig.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeNetworkConfig {
+ int netId;
+ android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
+ int permission;
+ boolean secure;
+ android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
+}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl
new file mode 100644
index 00000000..06c8979d
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/NativeNetworkType.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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;
+@Backing(type="int")
+enum NativeNetworkType {
+ PHYSICAL = 0,
+ VIRTUAL = 1,
+}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl
new file mode 100644
index 00000000..8a8be839
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/NativeVpnType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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;
+@Backing(type="int")
+enum NativeVpnType {
+ SERVICE = 1,
+ PLATFORM = 2,
+ LEGACY = 3,
+ OEM = 4,
+}
diff --git a/server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl
new file mode 100644
index 00000000..5ef95e67
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/RouteInfoParcel.aidl
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl
new file mode 100644
index 00000000..7b39c22e
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 00000000..983e9860
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl
new file mode 100644
index 00000000..5f1b7226
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/6/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl
new file mode 100644
index 00000000..72e987a2
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/6/android/net/UidRangeParcel.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/7/.hash b/server/aidl_api/netd_aidl_interface/7/.hash
new file mode 100644
index 00000000..cad59dfd
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/.hash
@@ -0,0 +1 @@
+850353de5d19a0dd718f8fd20791f0532e6a34c7
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl
new file mode 100644
index 00000000..ec03d86b
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/INetd.aidl
@@ -0,0 +1,200 @@
+/**
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 isAllowlist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
+ void networkCreatePhysical(int netId, int permission);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
+ 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);
+ void networkCreate(in android.net.NativeNetworkConfig config);
+ void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
+ void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
+ 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 int DUMMY_NET_ID = 51;
+ const int UNREACHABLE_NET_ID = 52;
+ 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;
+ /**
+ * @deprecated use FIREWALL_ALLOWLIST.
+ */
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_ALLOWLIST = 0;
+ /**
+ * @deprecated use FIREWALL_DENYLIST.
+ */
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_DENYLIST = 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 int FIREWALL_CHAIN_RESTRICTED = 4;
+ 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/7/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 00000000..31775dfd
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 00000000..1869d8d4
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl
new file mode 100644
index 00000000..8ea20d11
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/NativeNetworkConfig.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl
new file mode 100644
index 00000000..76562b29
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkConfig.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeNetworkConfig {
+ int netId;
+ android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
+ int permission;
+ boolean secure;
+ android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
+}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl
new file mode 100644
index 00000000..06c8979d
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/NativeNetworkType.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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;
+@Backing(type="int")
+enum NativeNetworkType {
+ PHYSICAL = 0,
+ VIRTUAL = 1,
+}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl
new file mode 100644
index 00000000..8a8be839
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/NativeVpnType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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;
+@Backing(type="int")
+enum NativeVpnType {
+ SERVICE = 1,
+ PLATFORM = 2,
+ LEGACY = 3,
+ OEM = 4,
+}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl
new file mode 100644
index 00000000..5ef95e67
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/RouteInfoParcel.aidl
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl
new file mode 100644
index 00000000..7b39c22e
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 00000000..983e9860
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl
new file mode 100644
index 00000000..5f1b7226
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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/7/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl
new file mode 100644
index 00000000..72e987a2
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/UidRangeParcel.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 00000000..9bb679f1
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/7/android/net/netd/aidl/NativeUidRangeConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.netd.aidl;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeUidRangeConfig {
+ int netId;
+ android.net.UidRangeParcel[] uidRanges;
+ int subPriority;
+}
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
index 47e2931d..ec03d86b 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
@@ -1,14 +1,30 @@
+/**
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
@@ -19,9 +35,15 @@ package android.net;
/* @hide */
interface INetd {
boolean isAlive();
- boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isWhitelist, in int[] uids);
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
boolean bandwidthEnableDataSaver(boolean enable);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
void networkCreatePhysical(int netId, int permission);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
void networkCreateVpn(int netId, boolean secure);
void networkDestroy(int netId);
void networkAddInterface(int netId, in @utf8InCpp String iface);
@@ -122,6 +144,9 @@ interface INetd {
android.net.TetherStatsParcel[] tetherOffloadGetStats();
void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
+ void networkCreate(in android.net.NativeNetworkConfig config);
+ void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
+ void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
const int IPV4 = 4;
const int IPV6 = 6;
const int CONF = 1;
@@ -136,6 +161,8 @@ interface INetd {
const int PENALTY_POLICY_LOG = 2;
const int PENALTY_POLICY_REJECT = 3;
const int LOCAL_NET_ID = 99;
+ const int DUMMY_NET_ID = 51;
+ const int UNREACHABLE_NET_ID = 52;
const String NEXTHOP_NONE = "";
const String NEXTHOP_UNREACHABLE = "unreachable";
const String NEXTHOP_THROW = "throw";
@@ -146,14 +173,23 @@ interface INetd {
const int PERMISSION_INTERNET = 4;
const int PERMISSION_UPDATE_DEVICE_STATS = 8;
const int PERMISSION_UNINSTALLED = -1;
+ /**
+ * @deprecated use FIREWALL_ALLOWLIST.
+ */
const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_ALLOWLIST = 0;
+ /**
+ * @deprecated use FIREWALL_DENYLIST.
+ */
const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_DENYLIST = 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 int FIREWALL_CHAIN_RESTRICTED = 4;
const String IF_STATE_UP = "up";
const String IF_STATE_DOWN = "down";
const String IF_FLAG_BROADCAST = "broadcast";
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
index 44593632..31775dfd 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
@@ -1,14 +1,30 @@
+/**
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
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
index 01e0f955..1869d8d4 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
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
index 62be8384..8ea20d11 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl
new file mode 100644
index 00000000..76562b29
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkConfig.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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 */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeNetworkConfig {
+ int netId;
+ android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
+ int permission;
+ boolean secure;
+ android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl
new file mode 100644
index 00000000..06c8979d
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/NativeNetworkType.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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;
+@Backing(type="int")
+enum NativeNetworkType {
+ PHYSICAL = 0,
+ VIRTUAL = 1,
+}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl
new file mode 100644
index 00000000..8a8be839
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/NativeVpnType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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;
+@Backing(type="int")
+enum NativeVpnType {
+ SERVICE = 1,
+ PLATFORM = 2,
+ LEGACY = 3,
+ OEM = 4,
+}
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
index 5e0ee62a..5ef95e67 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
@@ -1,14 +1,30 @@
+/**
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
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
index b1364545..7b39c22e 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
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
index c9d84580..983e9860 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
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
index 0b0960ef..5f1b7226 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
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
index 84ff4572..72e987a2 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// 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.
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
//
-// You must not make a backward incompatible changes to the AIDL files built
+// You must not make a backward incompatible change to any AIDL file 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
@@ -17,6 +33,7 @@
package android.net;
/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
parcelable UidRangeParcel {
int start;
int stop;
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 00000000..9bb679f1
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.netd.aidl;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeUidRangeConfig {
+ int netId;
+ android.net.UidRangeParcel[] uidRanges;
+ int subPriority;
+}
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 3b221cf0..d6398c12 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -19,11 +19,13 @@ package android.net;
import android.net.INetdUnsolicitedEventListener;
import android.net.InterfaceConfigurationParcel;
import android.net.MarkMaskParcel;
+import android.net.NativeNetworkConfig;
import android.net.RouteInfoParcel;
import android.net.TetherConfigParcel;
import android.net.TetherOffloadRuleParcel;
import android.net.TetherStatsParcel;
import android.net.UidRangeParcel;
+import android.net.netd.aidl.NativeUidRangeConfig;
/** {@hide} */
interface INetd {
@@ -35,18 +37,18 @@ interface INetd {
/**
* 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
+ * The chain may be an allowlist chain or a denylist chain. A denylist chain contains DROP
+ * rules for the specified UIDs and a RETURN rule at the end. An allowlist 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 isAllowlist Whether this is an allowlist or denylist 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,
+ boolean isAllowlist,
in int[] uids);
/**
@@ -69,6 +71,7 @@ interface INetd {
/**
* Creates a physical network (i.e., one containing physical interfaces.
+ * @deprecated use networkCreate() instead.
*
* @param netId the networkId to create.
* @param permission the permission necessary to use the network. Must be one of
@@ -81,6 +84,7 @@ interface INetd {
/**
* Creates a VPN network.
+ * @deprecated use networkCreate() instead.
*
* @param netId the network to create.
* @param secure whether unprivileged apps are allowed to bypass the VPN.
@@ -125,12 +129,12 @@ interface INetd {
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.
+ * Adds the specified UID ranges to the specified network. The network can be physical or
+ * virtual. Traffic from the UID ranges will be routed to the network by default.
*
* @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.
+ * @param uidRanges a set of non-overlapping ranges of UIDs to add. These exact ranges
+ * must not overlap with existing ranges assigned to this network.
*
* @throws ServiceSpecificException in case of failure, with an error code corresponding to the
* unix errno.
@@ -138,12 +142,12 @@ interface INetd {
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.
+ * Remove the specified UID ranges from the specified network. The network can be physical or
+ * virtual. Traffic from the UID ranges will no longer be routed to the network by default.
*
* @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.
+ * @param uidRanges a set of non-overlapping ranges of UIDs to remove. These exact ranges
+ * must already be assigned to this network.
*
* @throws ServiceSpecificException in case of failure, with an error code corresponding to the
* unix errno.
@@ -771,6 +775,22 @@ interface INetd {
const int LOCAL_NET_ID = 99;
+ /**
+ * Constant net ID for the "dummy" network.
+ *
+ * The dummy network is used to blackhole or reject traffic. Any attempt to use it will
+ * either drop the packets or fail with ENETUNREACH.
+ */
+ const int DUMMY_NET_ID = 51;
+
+ /**
+ * Constant net ID for the "unreachable" network.
+ *
+ * The unreachable network is used to reject traffic. Any attempt to use it will fail
+ * with ENETUNREACH.
+ */
+ const int UNREACHABLE_NET_ID = 52;
+
// Route does not specify a next hop
const String NEXTHOP_NONE = "";
// Route next hop is unreachable
@@ -981,17 +1001,26 @@ interface INetd {
*/
boolean networkCanProtect(int uid);
- // Whitelist only allows packets from specific UID/Interface
+ /** Only allows packets from specific UID/Interface.
+ @deprecated use FIREWALL_ALLOWLIST. */
const int FIREWALL_WHITELIST = 0;
- // Blacklist blocks packets from specific UID/Interface
+
+ /** Only allows packets from specific UID/Interface. */
+ const int FIREWALL_ALLOWLIST = 0;
+
+ /** Blocks packets from specific UID/Interface.
+ @deprecated use FIREWALL_DENYLIST. */
const int FIREWALL_BLACKLIST = 1;
+ /** Blocks packets from specific UID/Interface. */
+ const int FIREWALL_DENYLIST = 1;
+
/**
* Set type of firewall
- * Type whitelist only allows packets from specific UID/Interface
- * Type blacklist blocks packets from specific UID/Interface
+ * Type allowlist only allows packets from specific UID/Interface
+ * Type denylist blocks packets from specific UID/Interface
*
- * @param firewalltype type of firewall, either FIREWALL_WHITELIST or FIREWALL_BLACKLIST
+ * @param firewalltype type of firewall, either FIREWALL_ALLOWLIST or FIREWALL_DENYLIST
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
@@ -1010,6 +1039,9 @@ interface INetd {
const int FIREWALL_CHAIN_STANDBY = 2;
// Specify POWERSAVE chain(fw_powersave) which is used in power save mode
const int FIREWALL_CHAIN_POWERSAVE = 3;
+ // Specify RESTRICTED chain(fw_restricted) which is used in restricted
+ // networking mode
+ const int FIREWALL_CHAIN_RESTRICTED = 4;
/**
* Set firewall rule for interface
@@ -1159,7 +1191,7 @@ interface INetd {
* 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.
+ * allowed 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
@@ -1309,4 +1341,40 @@ interface INetd {
* cause of the failure.
*/
TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
+
+ /**
+ * Creates a network.
+ *
+ * @param config the configuration of network.
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkCreate(in NativeNetworkConfig config);
+
+ /**
+ * Adds the specified UID ranges to the specified network. The network can be physical or
+ * virtual. Traffic from the UID ranges will be routed to the network by default. The possible
+ * value of subsidiary priority for physical and unreachable networks is 0-999. 0 is the highest
+ * priority. 0 is also the default value. Virtual network supports only the default value.
+ *
+ * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkAddUidRangesParcel(in NativeUidRangeConfig uidRangesConfig);
+
+ /**
+ * Removes the specified UID ranges from the specified network. The network can be physical or
+ * virtual. Traffic from the UID ranges will no longer be routed to the network by default. The
+ * possible value of subsidiary priority for physical and unreachable networks is 0-999. 0 is
+ * the highest priority. 0 is also the default value. Virtual network supports only the default
+ * value.
+ *
+ * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkRemoveUidRangesParcel(in NativeUidRangeConfig uidRangesConfig);
}
diff --git a/server/binder/android/net/NativeNetworkConfig.aidl b/server/binder/android/net/NativeNetworkConfig.aidl
new file mode 100644
index 00000000..2c4f83a4
--- /dev/null
+++ b/server/binder/android/net/NativeNetworkConfig.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package android.net;
+
+import android.net.NativeNetworkType;
+import android.net.NativeVpnType;
+
+/**
+ * The configuration to create a network.
+ *
+ * {@hide}
+ */
+@JavaDerive(toString=true, equals=true)
+@JavaOnlyImmutable
+parcelable NativeNetworkConfig {
+ /** The networkId to create. */
+ int netId;
+
+ /**
+ * The type of network, e.g. physical network or virtual network.
+ */
+ NativeNetworkType networkType = NativeNetworkType.PHYSICAL;
+
+ /**
+ * For physical networks. The permission necessary to use the network. Must be one of
+ * PERMISSION_NONE/PERMISSION_NETWORK/PERMISSION_SYSTEM. Ignored for all other network types.
+ */
+ int permission;
+
+ /**
+ * For virtual networks. Whether unprivileged apps are allowed to bypass the VPN. Ignored for
+ * all other network types.
+ */
+ boolean secure;
+
+ /** For virtual networks. The type of VPN to create. Ignored for all other network types. */
+ NativeVpnType vpnType = NativeVpnType.PLATFORM;
+}
diff --git a/server/binder/android/net/NativeNetworkType.aidl b/server/binder/android/net/NativeNetworkType.aidl
new file mode 100644
index 00000000..d6670294
--- /dev/null
+++ b/server/binder/android/net/NativeNetworkType.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.net;
+
+@Backing(type="int")
+enum NativeNetworkType {
+ /**
+ * Physical network type.
+ */
+ PHYSICAL = 0,
+
+ /**
+ * Virtual private network type.
+ */
+ VIRTUAL = 1,
+} \ No newline at end of file
diff --git a/server/binder/android/net/NativeVpnType.aidl b/server/binder/android/net/NativeVpnType.aidl
new file mode 100644
index 00000000..cd1b4474
--- /dev/null
+++ b/server/binder/android/net/NativeVpnType.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package android.net;
+
+@Backing(type="int")
+enum NativeVpnType {
+ /**
+ * A VPN created by an app using the VpnService API.
+ */
+ SERVICE = 1,
+
+ /**
+ * A VPN created using a VpnManager API such as startProvisionedVpnProfile.
+ */
+ PLATFORM = 2,
+
+ /**
+ * An IPsec VPN created by the built-in LegacyVpnRunner.
+ */
+ LEGACY = 3,
+
+ /**
+ * An VPN created by OEM code through other means than VpnService or VpnManager.
+ */
+ OEM = 4,
+} \ No newline at end of file
diff --git a/server/binder/android/net/UidRangeParcel.aidl b/server/binder/android/net/UidRangeParcel.aidl
index 08fd4918..8f1fef6f 100644
--- a/server/binder/android/net/UidRangeParcel.aidl
+++ b/server/binder/android/net/UidRangeParcel.aidl
@@ -21,7 +21,8 @@ package android.net;
*
* {@hide}
*/
+@JavaOnlyImmutable @JavaDerive(toString=true, equals=true)
parcelable UidRangeParcel {
int start;
int stop;
-} \ No newline at end of file
+}
diff --git a/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 00000000..99497a86
--- /dev/null
+++ b/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.net.netd.aidl;
+
+import android.net.UidRangeParcel;
+
+/**
+ * The configuration to add or remove UID ranges.
+ *
+ * {@hide}
+ */
+@JavaDerive(toString=true, equals=true)
+@JavaOnlyImmutable
+parcelable NativeUidRangeConfig {
+ /** The network ID of the network to add/remove the ranges to/from. */
+ int netId;
+
+ /** A set of non-overlapping ranges of UIDs. */
+ UidRangeParcel[] uidRanges;
+
+ /**
+ * The priority of this UID range config. 0 is the highest priority; 999 is the lowest priority.
+ * The function of this parameter is to adjust the priority when the same UID is set to
+ * different networks for different features.
+ */
+ int subPriority;
+} \ No newline at end of file
diff --git a/server/main.cpp b/server/main.cpp
index 4949ff6f..bc48ac20 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -110,7 +110,9 @@ int main() {
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
@@ -118,16 +120,19 @@ int main() {
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 3baaa184..c5d9bb53 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -13,6 +13,15 @@
// 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"],
@@ -43,7 +52,7 @@ cc_test_library {
"libnetutils",
"libsysutils",
"libutils",
- "netd_aidl_interface-cpp",
+ "netd_aidl_interface-V7-cpp",
],
}
@@ -86,6 +95,7 @@ cc_test {
"libnetutils",
"libprocessgroup",
"libssl",
+ "libsysutils",
"libutils",
],
static_libs: [
@@ -97,8 +107,8 @@ cc_test {
"libnetdbpf",
"libnetdutils",
"libqtaguid",
- "netd_aidl_interface-unstable-cpp",
- "netd_event_listener_interface-cpp",
+ "netd_aidl_interface-V7-cpp",
+ "netd_event_listener_interface-V1-cpp",
"oemnetd_aidl_interface-cpp",
],
compile_multilib: "both",
@@ -111,7 +121,7 @@ cc_test {
},
},
sanitize: {
- address: true,
+ address: false,
recover: [ "all" ],
},
}
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
index e1bf67cc..00c28eb5 100644
--- a/tests/benchmarks/Android.bp
+++ b/tests/benchmarks/Android.bp
@@ -1,5 +1,14 @@
// 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"],
@@ -13,10 +22,10 @@ cc_benchmark {
],
static_libs: [
"libnetd_test_dnsresponder_ndk",
- "dnsresolver_aidl_interface-unstable-ndk_platform",
- "netd_aidl_interface-cpp", // system/netd/server/UidRanges.h
- "netd_aidl_interface-ndk_platform",
- "netd_event_listener_interface-ndk_platform",
+ "dnsresolver_aidl_interface-lateststable-ndk_platform",
+ "netd_aidl_interface-lateststable-cpp", // system/netd/server/UidRanges.h
+ "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 12aaf958..bf4bd541 100644
--- a/tests/benchmarks/bpf_benchmark.cpp
+++ b/tests/benchmarks/bpf_benchmark.cpp
@@ -34,7 +34,7 @@ class BpfBenchMark : public ::benchmark::Fixture {
};
BENCHMARK_DEFINE_F(BpfBenchMark, MapWriteNewEntry)(benchmark::State& state) {
- for (auto _ : state) {
+ for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
// TODO(b/147676069) assert
mBpfTestMap.writeValue(state.range(0), state.range(0), BPF_NOEXIST);
}
@@ -45,7 +45,7 @@ BENCHMARK_DEFINE_F(BpfBenchMark, MapUpdateEntry)(benchmark::State& state) {
// TODO(b/147676069) assert
mBpfTestMap.writeValue(i, i, BPF_NOEXIST);
}
- for (auto _ : state) {
+ for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
// TODO(b/147676069) assert
mBpfTestMap.writeValue(state.range(0), state.range(0) + 1, BPF_EXIST);
}
@@ -56,7 +56,7 @@ BENCHMARK_DEFINE_F(BpfBenchMark, MapDeleteAddEntry)(benchmark::State& state) {
// TODO(b/147676069) assert
mBpfTestMap.writeValue(i, i, BPF_NOEXIST);
}
- for (auto _ : state) {
+ for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
// TODO(b/147676069) assert
mBpfTestMap.deleteValue(state.range(0));
// TODO(b/147676069) assert
@@ -65,7 +65,7 @@ BENCHMARK_DEFINE_F(BpfBenchMark, MapDeleteAddEntry)(benchmark::State& state) {
}
BENCHMARK_DEFINE_F(BpfBenchMark, WaitForRcu)(benchmark::State& state) {
- for (auto _ : state) {
+ for (auto _ : state) { // NOLINT(clang-analyzer-deadcode.DeadStores)
int ret = android::bpf::synchronizeKernelRCU();
if (ret) {
state.SkipWithError(
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 2a6bb7c3..22d1f226 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -24,7 +24,10 @@
#include <cstdlib>
#include <iostream>
#include <mutex>
+#include <regex>
#include <set>
+#include <string>
+#include <thread>
#include <vector>
#include <dirent.h>
@@ -57,11 +60,13 @@
#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"
@@ -90,6 +95,7 @@ using android::String16;
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;
@@ -99,11 +105,28 @@ using android::net::INetd;
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;
@@ -113,18 +136,29 @@ static const char* IP_RULE_V4 = "-4";
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() {
@@ -142,6 +176,8 @@ class NetdBinderTest : public ::testing::Test {
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);
@@ -153,14 +189,20 @@ class NetdBinderTest : public ::testing::Test {
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,
@@ -169,6 +211,22 @@ class NetdBinderTest : public ::testing::Test {
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.
@@ -176,10 +234,14 @@ class NetdBinderTest : public ::testing::Test {
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:
@@ -199,67 +261,62 @@ TEST_F(NetdBinderTest, IsAlive) {
ASSERT_TRUE(isAlive);
}
-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);
+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;
}
-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();
- }
-
- 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()));
+} // namespace
- {
- TimedOperation op(StringPrintf("Programming %d-UID blacklist chain", kNumUids));
- mNetd->firewallReplaceUidChain(chainName, false, uids, &ret);
+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;
}
- 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()));
+ 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;
+}
- // 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, 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 */));
}
TEST_F(NetdBinderTest, IpSecTunnelInterface) {
@@ -507,14 +564,22 @@ TEST_F(NetdBinderTest, BandwidthEnableDataSaver) {
}
static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
- const std::string& action, const char* ipVersion) {
+ const std::string& action, const char* ipVersion,
+ const char* oif) {
// Output looks like this:
- // "12500:\tfrom all fwmark 0x0/0x20000 iif lo uidrange 1000-2000 prohibit"
+ // "<priority>:\tfrom all iif lo oif netdc0ca6 uidrange 500000-500000 lookup netdc0ca6"
+ // "<priority>:\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 =
- StringPrintf(" iif lo uidrange %d-%d %s\n", range.start, range.stop, action.c_str());
+ 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());
+ }
for (const auto& line : rules) {
if (android::base::StartsWith(line, prefix) && android::base::EndsWith(line, suffix)) {
return true;
@@ -523,14 +588,20 @@ static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel&
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) {
- bool existsIp4 = ipRuleExistsForRange(priority, range, action, IP_RULE_V4);
- bool existsIp6 = ipRuleExistsForRange(priority, range, action, IP_RULE_V6);
+ 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);
+}
+
namespace {
UidRangeParcel makeUidRangeParcel(int start, int stop) {
@@ -541,14 +612,31 @@ UidRangeParcel makeUidRangeParcel(int start, int stop) {
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) {
- 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());
+ 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->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
EXPECT_EQ(EBUSY,
@@ -561,51 +649,49 @@ TEST_F(NetdBinderTest, NetworkInterfaces) {
}
TEST_F(NetdBinderTest, NetworkUidRules) {
- 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());
+ auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::VIRTUAL,
+ INetd::PERMISSION_NONE, true);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_EQ(EEXIST, mNetd->networkCreate(config).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 suffix = StringPrintf("lookup %s ", sTun.name().c_str());
+ std::string action = StringPrintf("lookup %s ", sTun.name().c_str());
EXPECT_TRUE(mNetd->networkAddUidRanges(TEST_NETID1, uidRanges).isOk());
- EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], suffix));
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, otherRange, suffix));
+ EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], action));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, otherRange, action));
EXPECT_TRUE(mNetd->networkRemoveUidRanges(TEST_NETID1, uidRanges).isOk());
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], suffix));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[0], action));
EXPECT_TRUE(mNetd->networkAddUidRanges(TEST_NETID1, uidRanges).isOk());
- EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], suffix));
+ EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], action));
EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], suffix));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_SECURE_VPN, uidRanges[1], action));
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, range, "prohibit"));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_PROHIBIT_NON_VPN, range, "prohibit"));
}
// Create two valid rules.
ASSERT_TRUE(mNetd->networkRejectNonSecureVpn(true, uidRanges).isOk());
for (auto const& range : uidRanges) {
- EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit"));
+ EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY_PROHIBIT_NON_VPN, range, "prohibit"));
}
// Remove the rules.
ASSERT_TRUE(mNetd->networkRejectNonSecureVpn(false, uidRanges).isOk());
for (auto const& range : uidRanges) {
- EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit"));
+ EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY_PROHIBIT_NON_VPN, range, "prohibit"));
}
// Fail to remove the rules a second time after they are already deleted.
@@ -702,6 +788,72 @@ TEST_F(NetdBinderTest, SocketDestroy) {
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) {
@@ -820,6 +972,7 @@ TEST_F(NetdBinderTest, InterfaceAddRemoveAddress) {
{"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},
@@ -875,7 +1028,7 @@ TEST_F(NetdBinderTest, InterfaceAddRemoveAddress) {
}
TEST_F(NetdBinderTest, GetProcSysNet) {
- const char LOOPBACK[] = "lo";
+ const char* LOOPBACK = "lo";
static const struct {
const int ipversion;
const int which;
@@ -1090,7 +1243,7 @@ bool iptablesIdleTimerInterfaceRuleExists(const char* binary, const char* chainN
void expectIdletimerInterfaceRuleExists(const std::string& ifname, int timeout,
const std::string& classLabel) {
std::string IdletimerRule =
- StringPrintf("timeout:%u label:%s send_nl_msg:1", timeout, classLabel.c_str());
+ StringPrintf("timeout:%u label:%s send_nl_msg", timeout, classLabel.c_str());
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
EXPECT_TRUE(iptablesIdleTimerInterfaceRuleExists(binary, IDLETIMER_RAW_PREROUTING, ifname,
IdletimerRule, RAW_TABLE));
@@ -1102,7 +1255,7 @@ void expectIdletimerInterfaceRuleExists(const std::string& ifname, int timeout,
void expectIdletimerInterfaceRuleNotExists(const std::string& ifname, int timeout,
const std::string& classLabel) {
std::string IdletimerRule =
- StringPrintf("timeout:%u label:%s send_nl_msg:1", timeout, classLabel.c_str());
+ StringPrintf("timeout:%u label:%s send_nl_msg", timeout, classLabel.c_str());
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
EXPECT_FALSE(iptablesIdleTimerInterfaceRuleExists(binary, IDLETIMER_RAW_PREROUTING, ifname,
IdletimerRule, RAW_TABLE));
@@ -1255,7 +1408,9 @@ TEST_F(NetdBinderTest, ClatdStartStop) {
EXPECT_EQ(ENODEV, status.serviceSpecificErrorCode());
// ... so create a test physical network and add our tun to it.
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Prefix must be 96 bits long.
@@ -1345,7 +1500,8 @@ bool ipRuleIpfwdExists(const char* ipVersion, const std::string& ipfwdRule) {
}
void expectIpfwdRuleExists(const char* fromIf, const char* toIf) {
- std::string ipfwdRule = StringPrintf("18000:\tfrom all iif %s lookup %s ", fromIf, toIf);
+ std::string ipfwdRule =
+ StringPrintf("%u:\tfrom all iif %s lookup %s ", RULE_PRIORITY_TETHERING, fromIf, toIf);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_TRUE(ipRuleIpfwdExists(ipVersion, ipfwdRule));
@@ -1353,7 +1509,8 @@ void expectIpfwdRuleExists(const char* fromIf, const char* toIf) {
}
void expectIpfwdRuleNotExists(const char* fromIf, const char* toIf) {
- std::string ipfwdRule = StringPrintf("18000:\tfrom all iif %s lookup %s ", fromIf, toIf);
+ std::string ipfwdRule =
+ StringPrintf("%u:\tfrom all iif %s lookup %s ", RULE_PRIORITY_TETHERING, fromIf, toIf);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_FALSE(ipRuleIpfwdExists(ipVersion, ipfwdRule));
@@ -1417,9 +1574,13 @@ TEST_F(NetdBinderTest, TestIpfwdEnableDisableStatusForwarding) {
TEST_F(NetdBinderTest, TestIpfwdAddRemoveInterfaceForward) {
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID2, INetd::PERMISSION_NONE).isOk());
+
+ config.netId = TEST_NETID2;
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID2, sTun2.name()).isOk());
binder::Status status = mNetd->ipfwdAddInterfaceForward(sTun.name(), sTun2.name());
@@ -1437,7 +1598,6 @@ constexpr char BANDWIDTH_INPUT[] = "bw_INPUT";
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.
@@ -1530,29 +1690,15 @@ void expectBandwidthGlobalAlertRuleExists(long alertBytes) {
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
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
binder::Status status = mNetd->bandwidthSetInterfaceQuota(sTun.name(), testQuotaBytes);
@@ -1570,7 +1716,9 @@ TEST_F(NetdBinderTest, BandwidthSetRemoveInterfaceQuota) {
TEST_F(NetdBinderTest, BandwidthSetRemoveInterfaceAlert) {
long testAlertBytes = 373;
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).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);
@@ -1604,34 +1752,6 @@ TEST_F(NetdBinderTest, BandwidthSetGlobalAlert) {
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,
@@ -1695,7 +1815,8 @@ bool ipRuleExists(const char* ipVersion, const std::string& ipRule) {
void expectNetworkDefaultIpRuleExists(const char* ifName) {
std::string networkDefaultRule =
- StringPrintf("22000:\tfrom all fwmark 0x0/0xffff iif lo lookup %s", ifName);
+ StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo lookup %s",
+ RULE_PRIORITY_DEFAULT_NETWORK, ifName);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_TRUE(ipRuleExists(ipVersion, networkDefaultRule));
@@ -1703,7 +1824,8 @@ void expectNetworkDefaultIpRuleExists(const char* ifName) {
}
void expectNetworkDefaultIpRuleDoesNotExist() {
- static const char networkDefaultRule[] = "22000:\tfrom all fwmark 0x0/0xffff iif lo";
+ std::string networkDefaultRule =
+ StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo", RULE_PRIORITY_DEFAULT_NETWORK);
for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
EXPECT_FALSE(ipRuleExists(ipVersion, networkDefaultRule));
@@ -1714,16 +1836,19 @@ void expectNetworkPermissionIpRuleExists(const char* ifName, int permission) {
std::string networkPermissionRule = "";
switch (permission) {
case INetd::PERMISSION_NONE:
- networkPermissionRule = StringPrintf(
- "13000:\tfrom all fwmark 0x1ffdd/0x1ffff iif lo lookup %s", ifName);
+ networkPermissionRule =
+ StringPrintf("%u:\tfrom all fwmark 0x1ffdd/0x1ffff iif lo lookup %s",
+ RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
break;
case INetd::PERMISSION_NETWORK:
- networkPermissionRule = StringPrintf(
- "13000:\tfrom all fwmark 0x5ffdd/0x5ffff iif lo lookup %s", ifName);
+ networkPermissionRule =
+ StringPrintf("%u:\tfrom all fwmark 0x5ffdd/0x5ffff iif lo lookup %s",
+ RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
break;
case INetd::PERMISSION_SYSTEM:
- networkPermissionRule = StringPrintf(
- "13000:\tfrom all fwmark 0xdffdd/0xdffff iif lo lookup %s", ifName);
+ networkPermissionRule =
+ StringPrintf("%u:\tfrom all fwmark 0xdffdd/0xdffff iif lo lookup %s",
+ RULE_PRIORITY_EXPLICIT_NETWORK, ifName);
break;
}
@@ -1804,7 +1929,9 @@ TEST_F(NetdBinderTest, NetworkAddRemoveRouteUserPermission) {
const std::vector<int32_t> testUids = {testUid};
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Setup route for testing nextHop
@@ -1958,7 +2085,9 @@ TEST_F(NetdBinderTest, NetworkAddRemoveRouteUserPermission) {
TEST_F(NetdBinderTest, NetworkPermissionDefault) {
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Get current default network NetId
@@ -2279,13 +2408,8 @@ namespace {
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 expectFirewallWhitelistMode() {
+void expectFirewallAllowlistMode() {
static const char dropRule[] = "DROP all";
static const char rejectRule[] = "REJECT all";
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
@@ -2295,7 +2419,7 @@ void expectFirewallWhitelistMode() {
}
}
-void expectFirewallBlacklistMode() {
+void expectFirewallDenylistMode() {
for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_INPUT));
EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_OUTPUT));
@@ -2357,126 +2481,45 @@ void expectFireWallInterfaceRuleAllowDoesNotExist(const std::string& ifname) {
}
}
-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_WHITELIST);
+ binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallWhitelistMode();
+ expectFirewallAllowlistMode();
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallBlacklistMode();
+ expectFirewallDenylistMode();
// set firewall type blacklist twice
- mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallBlacklistMode();
+ expectFirewallDenylistMode();
// set firewall type whitelist twice
- mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallWhitelistMode();
+ expectFirewallAllowlistMode();
// reset firewall type to default
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- expectFirewallBlacklistMode();
+ expectFirewallDenylistMode();
}
TEST_F(NetdBinderTest, FirewallSetInterfaceRule) {
// setinterfaceRule is not supported in BLACKLIST MODE
- binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
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_WHITELIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_ALLOWLIST);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
status = mNetd->firewallSetInterfaceRule(sTun.name(), INetd::FIREWALL_RULE_ALLOW);
@@ -2488,113 +2531,9 @@ TEST_F(NetdBinderTest, FirewallSetInterfaceRule) {
expectFireWallInterfaceRuleAllowDoesNotExist(sTun.name());
// reset firewall mode to default
- status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
- EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
- 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);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_DENYLIST);
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);
+ expectFirewallDenylistMode();
}
namespace {
@@ -2797,7 +2736,9 @@ TEST_F(NetdBinderTest, InterfaceGetCfg) {
InterfaceConfigurationParcel interfaceCfgResult;
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
binder::Status status = mNetd->interfaceGetCfg(sTun.name(), &interfaceCfgResult);
@@ -2816,7 +2757,9 @@ TEST_F(NetdBinderTest, InterfaceSetCfg) {
std::vector<std::string> downFlags = {"down"};
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// Set tun interface down.
@@ -2854,7 +2797,9 @@ TEST_F(NetdBinderTest, InterfaceClearAddr) {
std::vector<std::string> noFlags{};
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
auto interfaceCfg = makeInterfaceCfgParcel(sTun.name(), testAddr, testPrefixLength, noFlags);
@@ -2872,7 +2817,9 @@ TEST_F(NetdBinderTest, InterfaceClearAddr) {
TEST_F(NetdBinderTest, InterfaceSetEnableIPv6) {
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
// disable
@@ -2893,7 +2840,9 @@ TEST_F(NetdBinderTest, InterfaceSetMtu) {
const int testMtu = 1200;
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
binder::Status status = mNetd->interfaceSetMtu(sTun.name(), testMtu);
@@ -3059,8 +3008,6 @@ void checkUidsInPermissionMap(std::vector<int32_t>& uids, bool exist) {
} // 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);
@@ -3181,7 +3128,9 @@ TEST_F(NetdBinderTest, NDC) {
}
// Add test physical network
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
for (const auto& td : kTestData) {
@@ -3271,11 +3220,16 @@ void NetdBinderTest::createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetI
sTun2.init();
// Create physical network with fallthroughNetId but not set it as default network
- EXPECT_TRUE(mNetd->networkCreatePhysical(fallthroughNetId, INetd::PERMISSION_NONE).isOk());
+ auto config = makeNativeNetworkConfig(fallthroughNetId, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
EXPECT_TRUE(mNetd->networkAddInterface(fallthroughNetId, sTun.name()).isOk());
// Create VPN with vpnNetId
- EXPECT_TRUE(mNetd->networkCreateVpn(vpnNetId, secure).isOk());
+ config.netId = vpnNetId;
+ config.networkType = NativeNetworkType::VIRTUAL;
+ config.secure = secure;
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
// Add uid to VPN
EXPECT_TRUE(mNetd->networkAddUidRanges(vpnNetId, {makeUidRangeParcel(uid, uid)}).isOk());
@@ -3287,12 +3241,68 @@ void NetdBinderTest::createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetI
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 = getuid();
+ mStoredUid = geteuid();
if (mInputUid == mStoredUid) return;
EXPECT_TRUE(seteuid(uid) == 0);
}
@@ -3306,8 +3316,6 @@ class ScopedUidChange {
uid_t mStoredUid;
};
-constexpr uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 21000;
-
void clearQueue(int tunFd) {
char buf[4096];
int ret;
@@ -3316,17 +3324,18 @@ void clearQueue(int tunFd) {
} while (ret > 0);
}
-void checkDataReceived(int udpSocket, int tunFd) {
+void checkDataReceived(int udpSocket, int tunFd, sockaddr* dstAddr, int addrLen) {
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, write(udpSocket, "foo", sizeof("foo")));
+ EXPECT_EQ(4, sendto(udpSocket, "foo", sizeof("foo"), 0, dstAddr, addrLen));
// 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 sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, int tunFd,
+ bool doConnect = true) {
ScopedUidChange scopedUidChange(uid);
unique_fd testSocket(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (testSocket < 0) return false;
@@ -3336,15 +3345,51 @@ bool sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, i
.sin6_port = 42,
.sin6_addr = dstAddr,
};
- int res = connect(testSocket, (sockaddr*)&dst6, sizeof(dst6));
+ if (doConnect && connect(testSocket, (sockaddr*)&dst6, sizeof(dst6)) == -1) return false;
+
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("sendIPv6PacketFromUid, addr: %s, uid: %u", addr, uid));
- checkDataReceived(testSocket, tunFd);
+ 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;
+ }
return true;
}
@@ -3477,24 +3522,24 @@ TEST_F(NetdBinderTest, GetFwmarkForNetwork) {
// 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.
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).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
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID2, INetd::PERMISSION_NONE).isOk());
+ config.netId = TEST_NETID2;
+ EXPECT_TRUE(mNetd->networkCreate(config).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, v6Addr);
- uint32_t fwmarkUdp = createIpv6SocketAndCheckMark(SOCK_DGRAM, v6Addr);
+ uint32_t fwmarkTcp = createIpv6SocketAndCheckMark(SOCK_STREAM, V6_ADDR);
+ uint32_t fwmarkUdp = createIpv6SocketAndCheckMark(SOCK_DGRAM, V6_ADDR);
EXPECT_EQ(maskMarkNet1.mark, static_cast<int>(fwmarkTcp & maskMarkNet1.mask));
EXPECT_EQ(maskMarkNet1.mark, static_cast<int>(fwmarkUdp & maskMarkNet1.mask));
@@ -3529,9 +3574,8 @@ TetherOffloadRuleParcel makeTetherOffloadRule(int inputInterfaceIndex, int outpu
} // namespace
-TEST_F(NetdBinderTest, TetherOffloadRule) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
+// TODO: probably remove the test because TetherOffload* binder calls are deprecated.
+TEST_F(NetdBinderTest, DISABLED_TetherOffloadRule) {
// TODO: Perhaps verify invalid interface index once the netd handle the error in methods.
constexpr uint32_t kIfaceInt = 101;
constexpr uint32_t kIfaceExt = 102;
@@ -3645,7 +3689,27 @@ static bool expectPacket(int fd, uint8_t* ipPacket, ssize_t ipLen) {
return false;
}
-TEST_F(NetdBinderTest, TetherOffloadForwarding) {
+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) {
SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED;
constexpr const char* kDownstreamPrefix = "2001:db8:2::/64";
@@ -3672,9 +3736,12 @@ TEST_F(NetdBinderTest, TetherOffloadForwarding) {
// 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.
- EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
+ INetd::PERMISSION_NONE, false);
+ EXPECT_TRUE(mNetd->networkCreate(config).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;
@@ -3692,6 +3759,7 @@ TEST_F(NetdBinderTest, TetherOffloadForwarding) {
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, "");
@@ -3702,6 +3770,7 @@ TEST_F(NetdBinderTest, TetherOffloadForwarding) {
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);
@@ -3753,3 +3822,880 @@ TEST_F(NetdBinderTest, TetherOffloadForwarding) {
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 f28c5f81..7ab42904 100644
--- a/tests/bpf_base_test.cpp
+++ b/tests/bpf_base_test.cpp
@@ -56,25 +56,13 @@ class BpfBasicTest : public testing::Test {
};
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));
@@ -97,8 +85,6 @@ TEST_F(BpfBasicTest, TestSocketFilterSetUp) {
}
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);
@@ -117,8 +103,6 @@ TEST_F(BpfBasicTest, TestTagSocket) {
}
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);
@@ -144,8 +128,6 @@ TEST_F(BpfBasicTest, TestCloseSocketWithoutUntag) {
}
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));
@@ -160,8 +142,6 @@ TEST_F(BpfBasicTest, TestChangeCounterSet) {
}
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 dd25f969..fcd538e3 100644
--- a/tests/netd_test.cpp
+++ b/tests/netd_test.cpp
@@ -48,6 +48,22 @@ TEST(NetUtilsWrapperTest, TestFileCapabilities) {
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
@@ -105,195 +121,5 @@ TEST(NetdNamespaceTest, CheckFullNamespaceSupport) {
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 46394cac..249bdfbe 100644
--- a/tests/netlink_listener_test.cpp
+++ b/tests/netlink_listener_test.cpp
@@ -45,7 +45,7 @@ constexpr uid_t TEST_UID = UID_MAX - 2;
// A test tag arbitrarily selected.
constexpr uint32_t TEST_TAG = 0xFF0F0F0F;
-constexpr uint32_t SOCK_CLOSE_WAIT_US = 20 * 1000;
+constexpr uint32_t SOCK_CLOSE_WAIT_US = 30 * 1000;
constexpr uint32_t ENOBUFS_POLL_WAIT_US = 10 * 1000;
using android::base::Result;
@@ -67,15 +67,11 @@ class NetlinkListenerTest : public testing::Test {
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)) {
@@ -103,7 +99,7 @@ class NetlinkListenerTest : public testing::Test {
return mCookieTagMap.iterateWithValue(checkGarbageTags);
}
- void checkMassiveSocketDestroy(int totalNumber, bool expectError) {
+ bool checkMassiveSocketDestroy(int totalNumber, bool expectError) {
std::unique_ptr<android::net::NetlinkListenerInterface> skDestroyListener;
auto result = android::net::TrafficController::makeSkDestroyListener();
if (!isOk(result)) {
@@ -141,25 +137,36 @@ class NetlinkListenerTest : public testing::Test {
// If ENOBUFS triggered, check it only called into the handler once, ie.
// that the netlink handler is not spinning.
int currentErrorCount = rxErrorCount;
- EXPECT_LT(0, rxErrorCount);
+ // 0 error count is acceptable because the system has chances to close all sockets
+ // normally.
+ EXPECT_LE(0, rxErrorCount);
+ if (!rxErrorCount) return true;
+
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);
}
-TEST_F(NetlinkListenerTest, TestSkDestroyError) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
- checkMassiveSocketDestroy(32500, true);
+// 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);
}