Merge "TestNetworkService: do not set IFF_MULTICAST when bringUp is false"
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 7e0a589..ac0bbd4 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -998,9 +998,9 @@
pw.println("Forwarding rules:");
pw.increaseIndent();
- dumpIpv6UpstreamRules(pw);
- dumpIpv6ForwardingRules(pw);
- dumpIpv4ForwardingRules(pw);
+ dumpIpv6ForwardingRulesByDownstream(pw);
+ dumpBpfForwardingRulesIpv6(pw);
+ dumpBpfForwardingRulesIpv4(pw);
pw.decreaseIndent();
pw.println();
@@ -1059,9 +1059,12 @@
}
}
- private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) {
+ private void dumpIpv6ForwardingRulesByDownstream(@NonNull IndentingPrintWriter pw) {
+ pw.println("IPv6 Forwarding rules by downstream interface:");
+ pw.increaseIndent();
if (mIpv6ForwardingRules.size() == 0) {
pw.println("No IPv6 rules");
+ pw.decreaseIndent();
return;
}
@@ -1071,22 +1074,24 @@
// The rule downstream interface index is paired with the interface name from
// IpServer#interfaceName. See #startIPv6, #updateIpv6ForwardingRules in IpServer.
final String downstreamIface = ipServer.interfaceName();
- pw.println("[" + downstreamIface + "]: iif(iface) oif(iface) v6addr srcmac dstmac");
+ pw.println("[" + downstreamIface + "]: iif(iface) oif(iface) v6addr "
+ + "[srcmac] [dstmac]");
pw.increaseIndent();
LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = entry.getValue();
for (Ipv6ForwardingRule rule : rules.values()) {
final int upstreamIfindex = rule.upstreamIfindex;
- pw.println(String.format("%d(%s) %d(%s) %s %s %s", upstreamIfindex,
+ pw.println(String.format("%d(%s) %d(%s) %s [%s] [%s]", upstreamIfindex,
mInterfaceNames.get(upstreamIfindex), rule.downstreamIfindex,
downstreamIface, rule.address.getHostAddress(), rule.srcMac, rule.dstMac));
}
pw.decreaseIndent();
}
+ pw.decreaseIndent();
}
- private String ipv6UpstreamRuletoString(TetherUpstream6Key key, Tether6Value value) {
- return String.format("%d(%s) %s -> %d(%s) %04x %s %s",
+ private String ipv6UpstreamRuleToString(TetherUpstream6Key key, Tether6Value value) {
+ return String.format("%d(%s) [%s] -> %d(%s) %04x [%s] [%s]",
key.iif, getIfName(key.iif), key.dstMac, value.oif, getIfName(value.oif),
value.ethProto, value.ethSrcMac, value.ethDstMac);
}
@@ -1101,12 +1106,56 @@
pw.println("No IPv6 upstream rules");
return;
}
- map.forEach((k, v) -> pw.println(ipv6UpstreamRuletoString(k, v)));
+ map.forEach((k, v) -> pw.println(ipv6UpstreamRuleToString(k, v)));
} catch (ErrnoException | IOException e) {
pw.println("Error dumping IPv6 upstream map: " + e);
}
}
+ private String ipv6DownstreamRuleToString(TetherDownstream6Key key, Tether6Value value) {
+ final String neigh6;
+ try {
+ neigh6 = InetAddress.getByAddress(key.neigh6).getHostAddress();
+ } catch (UnknownHostException impossible) {
+ throw new AssertionError("IP address array not valid IPv6 address!");
+ }
+ return String.format("%d(%s) [%s] %s -> %d(%s) %04x [%s] [%s]",
+ key.iif, getIfName(key.iif), key.dstMac, neigh6, value.oif, getIfName(value.oif),
+ value.ethProto, value.ethSrcMac, value.ethDstMac);
+ }
+
+ private void dumpIpv6DownstreamRules(IndentingPrintWriter pw) {
+ try (BpfMap<TetherDownstream6Key, Tether6Value> map = mDeps.getBpfDownstream6Map()) {
+ if (map == null) {
+ pw.println("No IPv6 downstream");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("No IPv6 downstream rules");
+ return;
+ }
+ map.forEach((k, v) -> pw.println(ipv6DownstreamRuleToString(k, v)));
+ } catch (ErrnoException | IOException e) {
+ pw.println("Error dumping IPv6 downstream map: " + e);
+ }
+ }
+
+ // TODO: use dump utils with headerline and lambda which prints key and value to reduce
+ // duplicate bpf map dump code.
+ private void dumpBpfForwardingRulesIpv6(IndentingPrintWriter pw) {
+ pw.println("IPv6 Upstream: iif(iface) [inDstMac] -> oif(iface) etherType [outSrcMac] "
+ + "[outDstMac]");
+ pw.increaseIndent();
+ dumpIpv6UpstreamRules(pw);
+ pw.decreaseIndent();
+
+ pw.println("IPv6 Downstream: iif(iface) [inDstMac] neigh6 -> oif(iface) etherType "
+ + "[outSrcMac] [outDstMac]");
+ pw.increaseIndent();
+ dumpIpv6DownstreamRules(pw);
+ pw.decreaseIndent();
+ }
+
private <K extends Struct, V extends Struct> void dumpRawMap(BpfMap<K, V> map,
IndentingPrintWriter pw) throws ErrnoException {
if (map == null) {
@@ -1203,7 +1252,7 @@
map.forEach((k, v) -> pw.println(ipv4RuleToString(now, downstream, k, v)));
}
- private void dumpIpv4ForwardingRules(IndentingPrintWriter pw) {
+ private void dumpBpfForwardingRulesIpv4(IndentingPrintWriter pw) {
final long now = SystemClock.elapsedRealtimeNanos();
try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map();
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 2810d80..994db1d 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -134,18 +134,16 @@
int BpfHandler::tagSocket(int sockFd, uint32_t tag, uid_t chargeUid, uid_t realUid) {
std::lock_guard guard(mMutex);
- if (chargeUid != realUid && !hasUpdateDeviceStatsPermission(realUid)) {
- return -EPERM;
- }
+ if (!mCookieTagMap.isValid()) return -EPERM;
+
+ if (chargeUid != realUid && !hasUpdateDeviceStatsPermission(realUid)) return -EPERM;
// Note that tagging the socket to AID_CLAT is only implemented in JNI ClatCoordinator.
// The process is not allowed to tag socket to AID_CLAT via tagSocket() which would cause
// process data usage accounting to be bypassed. Tagging AID_CLAT is used for avoiding counting
// CLAT traffic data usage twice. See packages/modules/Connectivity/service/jni/
// com_android_server_connectivity_ClatCoordinator.cpp
- if (chargeUid == AID_CLAT) {
- return -EPERM;
- }
+ if (chargeUid == AID_CLAT) return -EPERM;
// The socket destroy listener only monitors on the group {INET_TCP, INET_UDP, INET6_TCP,
// INET6_UDP}. Tagging listener unsupported socket causes that the tag can't be removed from
@@ -180,6 +178,7 @@
uint64_t sock_cookie = getSocketCookie(sockFd);
if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
+
UidTagValue newKey = {.uid = (uint32_t)chargeUid, .tag = tag};
uint32_t totalEntryCount = 0;
@@ -242,9 +241,11 @@
int BpfHandler::untagSocket(int sockFd) {
std::lock_guard guard(mMutex);
- uint64_t sock_cookie = getSocketCookie(sockFd);
+ uint64_t sock_cookie = getSocketCookie(sockFd);
if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
+
+ if (!mCookieTagMap.isValid()) return -EPERM;
base::Result<void> res = mCookieTagMap.deleteValue(sock_cookie);
if (!res.ok()) {
ALOGE("Failed to untag socket: %s", strerror(res.error().code()));
diff --git a/netd/NetdUpdatable.cpp b/netd/NetdUpdatable.cpp
index f0997fc..41b1fdb 100644
--- a/netd/NetdUpdatable.cpp
+++ b/netd/NetdUpdatable.cpp
@@ -16,19 +16,20 @@
#define LOG_TAG "NetdUpdatable"
-#include "NetdUpdatable.h"
+#include "BpfHandler.h"
#include <android-base/logging.h>
#include <netdutils/Status.h>
#include "NetdUpdatablePublic.h"
+static android::net::BpfHandler sBpfHandler;
+
int libnetd_updatable_init(const char* cg2_path) {
android::base::InitLogging(/*argv=*/nullptr);
LOG(INFO) << __func__ << ": Initializing";
- android::net::gNetdUpdatable = android::net::NetdUpdatable::getInstance();
- android::netdutils::Status ret = android::net::gNetdUpdatable->mBpfHandler.init(cg2_path);
+ android::netdutils::Status ret = sBpfHandler.init(cg2_path);
if (!android::netdutils::isOk(ret)) {
LOG(ERROR) << __func__ << ": BPF handler init failed";
return -ret.code();
@@ -37,25 +38,9 @@
}
int libnetd_updatable_tagSocket(int sockFd, uint32_t tag, uid_t chargeUid, uid_t realUid) {
- if (android::net::gNetdUpdatable == nullptr) return -EPERM;
- return android::net::gNetdUpdatable->mBpfHandler.tagSocket(sockFd, tag, chargeUid, realUid);
+ return sBpfHandler.tagSocket(sockFd, tag, chargeUid, realUid);
}
int libnetd_updatable_untagSocket(int sockFd) {
- if (android::net::gNetdUpdatable == nullptr) return -EPERM;
- return android::net::gNetdUpdatable->mBpfHandler.untagSocket(sockFd);
+ return sBpfHandler.untagSocket(sockFd);
}
-
-namespace android {
-namespace net {
-
-NetdUpdatable* gNetdUpdatable = nullptr;
-
-NetdUpdatable* NetdUpdatable::getInstance() {
- // Instantiated on first use.
- static NetdUpdatable instance;
- return &instance;
-}
-
-} // namespace net
-} // namespace android
diff --git a/netd/NetdUpdatable.h b/netd/NetdUpdatable.h
deleted file mode 100644
index 333037f..0000000
--- a/netd/NetdUpdatable.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2022, 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 "BpfHandler.h"
-
-namespace android {
-namespace net {
-
-class NetdUpdatable {
- public:
- NetdUpdatable() = default;
- NetdUpdatable(const NetdUpdatable&) = delete;
- NetdUpdatable& operator=(const NetdUpdatable&) = delete;
- static NetdUpdatable* getInstance();
-
- BpfHandler mBpfHandler;
-};
-
-extern NetdUpdatable* gNetdUpdatable;
-
-} // namespace net
-} // namespace android
\ No newline at end of file
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index 6c4a021..e1c7b64 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.INetd.IF_STATE_UP;
+import static android.net.INetd.PERMISSION_NETWORK;
import static android.net.INetd.PERMISSION_SYSTEM;
import static android.system.OsConstants.ETH_P_IP;
import static android.system.OsConstants.ETH_P_IPV6;
@@ -386,9 +387,9 @@
static int getFwmark(int netId) {
// See union Fwmark in system/netd/include/Fwmark.h
return (netId & 0xffff)
- | 0x1 << 16 // protectedFromVpn: true
- | 0x1 << 17 // explicitlySelected: true
- | (PERMISSION_SYSTEM & 0x3) << 18;
+ | 0x1 << 16 // explicitlySelected: true
+ | 0x1 << 17 // protectedFromVpn: true
+ | ((PERMISSION_NETWORK | PERMISSION_SYSTEM) & 0x3) << 18; // 2 permission bits = 3
}
@VisibleForTesting
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 1f76773..043a0ad 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -163,8 +163,7 @@
// Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
// address.
- iface = tnm.createTapInterface(true /* disableIpv6ProvisioningDelay */,
- arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
+ iface = tnm.createTapInterface(arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
assertNotNull(iface)
}
@@ -224,7 +223,7 @@
val onLinkPrefix = raResponder.prefix
val startTime = SystemClock.elapsedRealtime()
while (SystemClock.elapsedRealtime() - startTime < PACKET_TIMEOUT_MS) {
- SystemClock.sleep(1 /* ms */)
+ SystemClock.sleep(50 /* ms */)
val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
try {
network.bindSocket(sock)
@@ -273,7 +272,6 @@
val lp = LinkProperties().apply {
addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
- addRoute(RouteInfo(IpPrefix("::/0"), TEST_ROUTER_IPV6_ADDR))
setInterfaceName(specifier)
}
val config = NetworkAgentConfig.Builder().build()
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index bbb61cd..7646c19 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -94,10 +94,10 @@
private static final int GOOGLE_DNS_4 = 0x08080808; // 8.8.8.8
private static final int NETID = 42;
- // The test fwmark means: PERMISSION_SYSTEM (0x2), protectedFromVpn: true,
+ // The test fwmark means: PERMISSION_NETWORK | PERMISSION_SYSTEM (0x3), protectedFromVpn: true,
// explicitlySelected: true, netid: 42. For bit field structure definition, see union Fwmark in
// system/netd/include/Fwmark.h
- private static final int MARK = 0xb002a;
+ private static final int MARK = 0xf002a;
private static final String XLAT_LOCAL_IPV4ADDR_STRING = "192.0.0.46";
private static final String XLAT_LOCAL_IPV6ADDR_STRING = "2001:db8:0:b11::464";
@@ -493,10 +493,10 @@
@Test
public void testGetFwmark() throws Exception {
- assertEquals(0xb0064, ClatCoordinator.getFwmark(100));
- assertEquals(0xb03e8, ClatCoordinator.getFwmark(1000));
- assertEquals(0xb2710, ClatCoordinator.getFwmark(10000));
- assertEquals(0xbffff, ClatCoordinator.getFwmark(65535));
+ assertEquals(0xf0064, ClatCoordinator.getFwmark(100));
+ assertEquals(0xf03e8, ClatCoordinator.getFwmark(1000));
+ assertEquals(0xf2710, ClatCoordinator.getFwmark(10000));
+ assertEquals(0xfffff, ClatCoordinator.getFwmark(65535));
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index 041e4ea..f159859 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -92,6 +92,7 @@
import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.Network;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
@@ -264,6 +265,7 @@
final Ikev2VpnProfile.Builder builder =
new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
builder.setAuthPsk(TEST_VPN_PSK);
+ builder.setBypassable(true /* isBypassable */);
mVpnProfile = builder.build().toVpnProfile();
}
@@ -1787,9 +1789,11 @@
ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
+ ArgumentCaptor<NetworkAgentConfig> nacCaptor =
+ ArgumentCaptor.forClass(NetworkAgentConfig.class);
verify(mTestDeps).newNetworkAgent(
any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
- any(), any(), any());
+ any(), nacCaptor.capture(), any());
// Check LinkProperties
final LinkProperties lp = lpCaptor.getValue();
@@ -1811,6 +1815,9 @@
// Check NetworkCapabilities
assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
+ // Check if allowBypass is set or not.
+ assertTrue(nacCaptor.getValue().isBypassableVpn());
+
return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb);
}