Merge "Add methods for updating ingressDiscardRule bpf map to BpfNetMaps" into main
This commit is contained in:
@@ -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 class IngressDiscardKey extends Struct {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ public class BpfNetMapsConstants {
|
||||
"/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);
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
|
||||
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;
|
||||
@@ -86,9 +87,12 @@ import com.android.net.module.util.Struct.U32;
|
||||
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;
|
||||
@@ -137,6 +141,7 @@ public class BpfNetMaps {
|
||||
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"),
|
||||
@@ -192,6 +197,15 @@ public class BpfNetMaps {
|
||||
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<>(
|
||||
@@ -237,6 +251,15 @@ public class BpfNetMaps {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -279,6 +302,15 @@ public class BpfNetMaps {
|
||||
} 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 @@ public class BpfNetMaps {
|
||||
return Os.if_nametoindex(ifName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interface name
|
||||
*/
|
||||
public String getIfName(final int ifIndex) {
|
||||
return Os.if_indextoname(ifIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call synchronize_rcu()
|
||||
*/
|
||||
@@ -553,7 +592,7 @@ public class BpfNetMaps {
|
||||
|
||||
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;
|
||||
@@ -957,6 +996,45 @@ public class BpfNetMaps {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
@@ -1098,7 +1176,10 @@ public class BpfNetMaps {
|
||||
});
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import android.app.StatsManager;
|
||||
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;
|
||||
@@ -87,6 +88,8 @@ import com.android.net.module.util.Struct.U32;
|
||||
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;
|
||||
@@ -102,6 +105,8 @@ import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.StringWriter;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -120,6 +125,10 @@ public final class BpfNetMapsTest {
|
||||
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 long STATS_SELECT_MAP_A = 0;
|
||||
@@ -143,11 +152,14 @@ public final class BpfNetMapsTest {
|
||||
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);
|
||||
@@ -159,6 +171,7 @@ public final class BpfNetMapsTest {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1206,7 +1219,7 @@ public final class BpfNetMapsTest {
|
||||
@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));
|
||||
}
|
||||
@@ -1215,10 +1228,60 @@ public final class BpfNetMapsTest {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@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 + ")");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user