Add methods for updating ingressDiscardRule bpf map to BpfNetMaps
Bug 295800201
Test: NetworkStaticLibsTests
Change-Id: I42bc0adc22c3018480029d624053f758d815e526
diff --git a/common/src/com/android/net/module/util/bpf/IngressDiscardKey.java b/common/src/com/android/net/module/util/bpf/IngressDiscardKey.java
index eabcf3c..9fefb52 100644
--- a/common/src/com/android/net/module/util/bpf/IngressDiscardKey.java
+++ b/common/src/com/android/net/module/util/bpf/IngressDiscardKey.java
@@ -16,9 +16,12 @@
package com.android.net.module.util.bpf;
+import com.android.net.module.util.InetAddressUtils;
import com.android.net.module.util.Struct;
+import java.net.Inet4Address;
import java.net.Inet6Address;
+import java.net.InetAddress;
/** Key type for ingress discard map */
public class IngressDiscardKey extends Struct {
@@ -29,4 +32,14 @@
public IngressDiscardKey(final Inet6Address dstAddr) {
this.dstAddr = dstAddr;
}
+
+ private static Inet6Address getInet6Address(final InetAddress addr) {
+ return (addr instanceof Inet4Address)
+ ? InetAddressUtils.v4MappedV6Address((Inet4Address) addr)
+ : (Inet6Address) addr;
+ }
+
+ public IngressDiscardKey(final InetAddress dstAddr) {
+ this(getInet6Address(dstAddr));
+ }
}
diff --git a/framework/src/android/net/BpfNetMapsConstants.java b/framework/src/android/net/BpfNetMapsConstants.java
index 36848e7..f888298 100644
--- a/framework/src/android/net/BpfNetMapsConstants.java
+++ b/framework/src/android/net/BpfNetMapsConstants.java
@@ -45,6 +45,8 @@
"/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
public static final String DATA_SAVER_ENABLED_MAP_PATH =
"/sys/fs/bpf/netd_shared/map_netd_data_saver_enabled_map";
+ public static final String INGRESS_DISCARD_MAP_PATH =
+ "/sys/fs/bpf/netd_shared/map_netd_ingress_discard_map";
public static final Struct.S32 UID_RULES_CONFIGURATION_KEY = new Struct.S32(0);
public static final Struct.S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new Struct.S32(1);
public static final Struct.S32 DATA_SAVER_ENABLED_KEY = new Struct.S32(0);
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 6ade124..ccff9c9 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -25,6 +25,7 @@
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_MAP_PATH;
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.IIF_MATCH;
+import static android.net.BpfNetMapsConstants.INGRESS_DISCARD_MAP_PATH;
import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH;
@@ -85,9 +86,12 @@
import com.android.net.module.util.Struct.U8;
import com.android.net.module.util.bpf.CookieTagMapKey;
import com.android.net.module.util.bpf.CookieTagMapValue;
+import com.android.net.module.util.bpf.IngressDiscardKey;
+import com.android.net.module.util.bpf.IngressDiscardValue;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -136,6 +140,7 @@
private static IBpfMap<CookieTagMapKey, CookieTagMapValue> sCookieTagMap = null;
// TODO: Add BOOL class and replace U8?
private static IBpfMap<S32, U8> sDataSaverEnabledMap = null;
+ private static IBpfMap<IngressDiscardKey, IngressDiscardValue> sIngressDiscardMap = null;
private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList(
Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"),
@@ -191,6 +196,15 @@
sDataSaverEnabledMap = dataSaverEnabledMap;
}
+ /**
+ * Set ingressDiscardMap for test.
+ */
+ @VisibleForTesting
+ public static void setIngressDiscardMapForTest(
+ IBpfMap<IngressDiscardKey, IngressDiscardValue> ingressDiscardMap) {
+ sIngressDiscardMap = ingressDiscardMap;
+ }
+
private static IBpfMap<S32, U32> getConfigurationMap() {
try {
return new BpfMap<>(
@@ -236,6 +250,15 @@
}
}
+ private static IBpfMap<IngressDiscardKey, IngressDiscardValue> getIngressDiscardMap() {
+ try {
+ return new BpfMap<>(INGRESS_DISCARD_MAP_PATH, BpfMap.BPF_F_RDWR,
+ IngressDiscardKey.class, IngressDiscardValue.class);
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Cannot open ingress discard map", e);
+ }
+ }
+
private static void initBpfMaps() {
if (sConfigurationMap == null) {
sConfigurationMap = getConfigurationMap();
@@ -278,6 +301,15 @@
} catch (ErrnoException e) {
throw new IllegalStateException("Failed to initialize data saver configuration", e);
}
+
+ if (sIngressDiscardMap == null) {
+ sIngressDiscardMap = getIngressDiscardMap();
+ }
+ try {
+ sIngressDiscardMap.clear();
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to initialize ingress discard map", e);
+ }
}
/**
@@ -315,6 +347,13 @@
}
/**
+ * Get interface name
+ */
+ public String getIfName(final int ifIndex) {
+ return Os.if_indextoname(ifIndex);
+ }
+
+ /**
* Call synchronize_rcu()
*/
public int synchronizeKernelRCU() {
@@ -575,7 +614,7 @@
private Set<Integer> asSet(final int[] uids) {
final Set<Integer> uidSet = new ArraySet<>();
- for (final int uid: uids) {
+ for (final int uid : uids) {
uidSet.add(uid);
}
return uidSet;
@@ -979,6 +1018,45 @@
}
}
+ /**
+ * Set ingress discard rule
+ *
+ * @param address target address to set the ingress discard rule
+ * @param iface allowed interface
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public void setIngressDiscardRule(final InetAddress address, final String iface) {
+ throwIfPreT("setIngressDiscardRule is not available on pre-T devices");
+ final int ifIndex = mDeps.getIfIndex(iface);
+ if (ifIndex == 0) {
+ Log.e(TAG, "Failed to get if index, skip setting ingress discard rule for " + address
+ + "(" + iface + ")");
+ return;
+ }
+ try {
+ sIngressDiscardMap.updateEntry(new IngressDiscardKey(address),
+ new IngressDiscardValue(ifIndex, ifIndex));
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to set ingress discard rule for " + address + "("
+ + iface + "), " + e);
+ }
+ }
+
+ /**
+ * Remove ingress discard rule
+ *
+ * @param address target address to remove the ingress discard rule
+ */
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ public void removeIngressDiscardRule(final InetAddress address) {
+ throwIfPreT("removeIngressDiscardRule is not available on pre-T devices");
+ try {
+ sIngressDiscardMap.deleteEntry(new IngressDiscardKey(address));
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to remove ingress discard rule for " + address + ", " + e);
+ }
+ }
+
/** Register callback for statsd to pull atom. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void setPullAtomCallback(final Context context) {
@@ -1120,7 +1198,10 @@
});
BpfDump.dumpMap(sUidPermissionMap, pw, "sUidPermissionMap",
(uid, permission) -> uid.val + " " + permissionToString(permission.val));
-
+ BpfDump.dumpMap(sIngressDiscardMap, pw, "sIngressDiscardMap",
+ (key, value) -> "[" + key.dstAddr + "]: "
+ + value.iif1 + "(" + mDeps.getIfName(value.iif1) + "), "
+ + value.iif2 + "(" + mDeps.getIfName(value.iif2) + ")");
dumpDataSaverConfig(pw);
pw.decreaseIndent();
}
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index ea2b261..cc33a3a 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -69,6 +69,7 @@
import android.content.Context;
import android.net.BpfNetMapsUtils;
import android.net.INetd;
+import android.net.InetAddresses;
import android.net.UidOwnerValue;
import android.os.Build;
import android.os.ServiceSpecificException;
@@ -85,6 +86,8 @@
import com.android.net.module.util.Struct.U8;
import com.android.net.module.util.bpf.CookieTagMapKey;
import com.android.net.module.util.bpf.CookieTagMapValue;
+import com.android.net.module.util.bpf.IngressDiscardKey;
+import com.android.net.module.util.bpf.IngressDiscardValue;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -100,6 +103,8 @@
import java.io.FileDescriptor;
import java.io.StringWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.List;
@@ -118,6 +123,10 @@
private static final int TEST_IF_INDEX = 7;
private static final int NO_IIF = 0;
private static final int NULL_IIF = 0;
+ private static final Inet4Address TEST_V4_ADDRESS =
+ (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.1");
+ private static final Inet6Address TEST_V6_ADDRESS =
+ (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
private static final String CHAINNAME = "fw_dozable";
private static final List<Integer> FIREWALL_CHAINS = List.of(
FIREWALL_CHAIN_DOZABLE,
@@ -145,11 +154,14 @@
private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap =
spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class));
private final IBpfMap<S32, U8> mDataSaverEnabledMap = new TestBpfMap<>(S32.class, U8.class);
+ private final IBpfMap<IngressDiscardKey, IngressDiscardValue> mIngressDiscardMap =
+ new TestBpfMap<>(IngressDiscardKey.class, IngressDiscardValue.class);
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME);
+ doReturn(TEST_IF_NAME).when(mDeps).getIfName(TEST_IF_INDEX);
doReturn(0).when(mDeps).synchronizeKernelRCU();
BpfNetMaps.setEnableJavaBpfMapForTest(true /* enable */);
BpfNetMaps.setConfigurationMapForTest(mConfigurationMap);
@@ -161,6 +173,7 @@
BpfNetMaps.setCookieTagMapForTest(mCookieTagMap);
BpfNetMaps.setDataSaverEnabledMapForTest(mDataSaverEnabledMap);
mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(DATA_SAVER_DISABLED));
+ BpfNetMaps.setIngressDiscardMapForTest(mIngressDiscardMap);
mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps);
}
@@ -1208,7 +1221,7 @@
@Test
@IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testSetDataSaverEnabledBeforeT() {
- for (boolean enable : new boolean[] {true, false}) {
+ for (boolean enable : new boolean[]{true, false}) {
assertThrows(UnsupportedOperationException.class,
() -> mBpfNetMaps.setDataSaverEnabled(enable));
}
@@ -1217,10 +1230,60 @@
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testSetDataSaverEnabled() throws Exception {
- for (boolean enable : new boolean[] {true, false}) {
+ for (boolean enable : new boolean[]{true, false}) {
mBpfNetMaps.setDataSaverEnabled(enable);
assertEquals(enable ? DATA_SAVER_ENABLED : DATA_SAVER_DISABLED,
- mDataSaverEnabledMap.getValue(DATA_SAVER_ENABLED_KEY).val);
+ mDataSaverEnabledMap.getValue(DATA_SAVER_ENABLED_KEY).val);
}
}
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetIngressDiscardRule_V4address() throws Exception {
+ mBpfNetMaps.setIngressDiscardRule(TEST_V4_ADDRESS, TEST_IF_NAME);
+ final IngressDiscardValue val = mIngressDiscardMap.getValue(new IngressDiscardKey(
+ TEST_V4_ADDRESS));
+ assertEquals(TEST_IF_INDEX, val.iif1);
+ assertEquals(TEST_IF_INDEX, val.iif2);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetIngressDiscardRule_V6address() throws Exception {
+ mBpfNetMaps.setIngressDiscardRule(TEST_V6_ADDRESS, TEST_IF_NAME);
+ final IngressDiscardValue val =
+ mIngressDiscardMap.getValue(new IngressDiscardKey(TEST_V6_ADDRESS));
+ assertEquals(TEST_IF_INDEX, val.iif1);
+ assertEquals(TEST_IF_INDEX, val.iif2);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testRemoveIngressDiscardRule() throws Exception {
+ mBpfNetMaps.setIngressDiscardRule(TEST_V4_ADDRESS, TEST_IF_NAME);
+ mBpfNetMaps.setIngressDiscardRule(TEST_V6_ADDRESS, TEST_IF_NAME);
+ final IngressDiscardKey v4Key = new IngressDiscardKey(TEST_V4_ADDRESS);
+ final IngressDiscardKey v6Key = new IngressDiscardKey(TEST_V6_ADDRESS);
+ assertTrue(mIngressDiscardMap.containsKey(v4Key));
+ assertTrue(mIngressDiscardMap.containsKey(v6Key));
+
+ mBpfNetMaps.removeIngressDiscardRule(TEST_V4_ADDRESS);
+ assertFalse(mIngressDiscardMap.containsKey(v4Key));
+ assertTrue(mIngressDiscardMap.containsKey(v6Key));
+
+ mBpfNetMaps.removeIngressDiscardRule(TEST_V6_ADDRESS);
+ assertFalse(mIngressDiscardMap.containsKey(v4Key));
+ assertFalse(mIngressDiscardMap.containsKey(v6Key));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testDumpIngressDiscardRule() throws Exception {
+ mBpfNetMaps.setIngressDiscardRule(TEST_V4_ADDRESS, TEST_IF_NAME);
+ mBpfNetMaps.setIngressDiscardRule(TEST_V6_ADDRESS, TEST_IF_NAME);
+ final String dump = getDump();
+ assertDumpContains(dump, TEST_V4_ADDRESS.getHostAddress());
+ assertDumpContains(dump, TEST_V6_ADDRESS.getHostAddress());
+ assertDumpContains(dump, TEST_IF_INDEX + "(" + TEST_IF_NAME + ")");
+ }
}