Destroy sockets with nlmsg RTM_DELADDR

Destroy sockets that matched to netId less than MIN_NET_ID for the non
link local address in RTM_DELADDR.
Destroy sockets on link local address with the corresponding interface
ID.

Bug: 373280981
Bug: 331139818
Flag: android.net.platform.flags.connectivity_service_destroy_socket
Test: atest ConnectivityCoverageTests
Test: device test
Change-Id: I4d8127fc693f8b32f815c5cddbae0b64deeb23e5
This commit is contained in:
Sewook Seo 2024-11-21 01:11:04 +00:00
commit fe1f5cbf32
2 changed files with 208 additions and 21 deletions

View file

@ -43,6 +43,10 @@ import android.net.VpnTransportInfo
import android.os.Build
import android.util.Range
import com.android.net.module.util.BaseNetdUnsolicitedEventListener
import com.android.net.module.util.netlink.NetlinkConstants
import com.android.net.module.util.netlink.RtNetlinkAddressMessage
import com.android.net.module.util.netlink.StructIfaddrMsg
import com.android.net.module.util.netlink.StructNlMsgHdr
import com.android.server.NetIdManager.MAX_NET_ID
import com.android.server.NetIdManager.MIN_NET_ID
import com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS
@ -61,9 +65,12 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.timeout
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
private const val TIMESTAMP = 1234L
@ -505,7 +512,6 @@ class CSDestroySocketTest : CSTest() {
@Test
fun testDestroySocketForRemovedIpAddressFromSingleNetwork() {
val inOrder = inOrder(destroySocketsWrapper)
val addressV6_1 = InetAddress.getByName("2100::1234")
val addressV6_2 = InetAddress.getByName("2100:0207::4321:1234")
// add a test network.
@ -523,7 +529,7 @@ class CSDestroySocketTest : CSTest() {
it.network == agent1.network && !it.lp.addresses.contains(addressV6_1)
}
// verify destroy sockets on the removed IP address
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
@ -533,17 +539,16 @@ class CSDestroySocketTest : CSTest() {
agent1.disconnect()
agent1.eventuallyExpect<OnNetworkDestroyed>()
// verify destroy sockets on the removed IP address
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_2,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
)
inOrder.verifyNoMoreInteractions()
verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(any(), anyInt())
}
@Test
fun testDestroySocketForRemovedIpAddressFromMultipleNonVpnNetworks() {
val inOrder = inOrder(destroySocketsWrapper)
val addressV6_1 = InetAddress.getByName("2100::1234")
val addressV6_2 = InetAddress.getByName("2100:0207::4321:1234")
val addressV6LinkLocal = InetAddress.getByName("FE80::1234")
@ -588,7 +593,7 @@ class CSDestroySocketTest : CSTest() {
}
// verify destroy sockets on the removed IP address and exempt netId lists.
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_1,
setOf(
Range.create(MIN_NET_ID, wlanAgent.network.netId - 1),
@ -598,7 +603,7 @@ class CSDestroySocketTest : CSTest() {
null
)
// verify destroy sockets on the removed IP address
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV4_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
@ -611,7 +616,7 @@ class CSDestroySocketTest : CSTest() {
it.network == wlanAgent.network && it.lp.interfaceName == "wlan3"
}
// verify destroy sockets on the removed IP address and exempt netId lists.
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_1,
setOf(
Range.create(MIN_NET_ID, ethAgent.network.netId - 1),
@ -620,7 +625,7 @@ class CSDestroySocketTest : CSTest() {
null
)
// verify not to destroy sockets on the link local address at NetworkAgent update.
inOrder.verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(
addressV6LinkLocal,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
@ -634,21 +639,21 @@ class CSDestroySocketTest : CSTest() {
ethAgent.eventuallyExpect<OnNetworkDestroyed>()
// verify destroy sockets on the removed IP address
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_2,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
)
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
)
verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(any(), anyInt())
}
@Test
fun testDestroySocketForRemovedIpAddressFromMultipleVpnNetworks() {
val inOrder = inOrder(destroySocketsWrapper)
val addressV6_1 = InetAddress.getByName("2100::1234")
val addressV6_2 = InetAddress.getByName("2100:0207::4321:1234")
val addressV6_3 = InetAddress.getByName("2234:0207::1234:4321")
@ -684,7 +689,7 @@ class CSDestroySocketTest : CSTest() {
it.network == vpnAgent1.network && it.lp.interfaceName == "ipsec21"
}
// verify destroy sockets on the removed IP address(TEST_IPV6_ADDRESS1) and VPN's uid range.
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
vpnAgent1.nc.uids
@ -692,7 +697,7 @@ class CSDestroySocketTest : CSTest() {
// verify destroy sockets on the removed IP address(TEST_IPV4_ADDRESS1). network#1 and
// network#4 use TEST_IPV4_ADDRESS1, however network#4 is not VPN network, so we destroy
// sockets only based on the removed IP address.
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV4_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
@ -706,13 +711,13 @@ class CSDestroySocketTest : CSTest() {
it.lp.interfaceName == "ipsec2" && it.lp.addresses.contains(addressV6_3)
}
// verify destroy sockets on the removed IP address(TEST_IPV6_ADDRESS1) and VPN's uid range.
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
vpnAgent2.nc.uids
)
// verify not to destroy sockets on the link local address at NetworkAgent update.
inOrder.verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(
addressV6LinkLocal,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
@ -726,20 +731,83 @@ class CSDestroySocketTest : CSTest() {
testAgent.eventuallyExpect<OnNetworkDestroyed>()
// verify destroy sockets on the removed IP address.
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_3,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
)
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
addressV6_2,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
)
inOrder.verify(destroySocketsWrapper).destroyLiveTcpSocketsByLocalAddress(
verify(destroySocketsWrapper, times(2)).destroyLiveTcpSocketsByLocalAddress(
addressV4_1,
setOf(Range.create(MIN_NET_ID, MAX_NET_ID)),
null
)
verify(destroySocketsWrapper, never()).destroyLiveTcpSocketsByLocalAddress(any(), anyInt())
}
@Test
fun testDestroySocketWithNetlinkMessageForLinkLocalAddress() {
val addressV6LinkLocal = InetAddress.getByName("FE80::1234")
val testInterfaceId = 10
val nlMsgLinkLocalAddressRemoved = RtNetlinkAddressMessage(
StructNlMsgHdr(
30 /* payload length */,
NetlinkConstants.RTM_DELADDR,
0 /* flages */,
0 /* seq */
),
StructIfaddrMsg(
10 /* family */,
64 /* prefix length */,
0 /* flags */,
0 /* scope */,
testInterfaceId /* interfaceId */
),
addressV6LinkLocal,
null,
0 /* flags */
)
csHandler.post{deps.netlinkMessageUpdate?.accept(nlMsgLinkLocalAddressRemoved)}
// verify destroy a socket on link local address with corresponding interface ID.
verify(destroySocketsWrapper, timeout(100)).destroyLiveTcpSocketsByLocalAddress(
addressV6LinkLocal,
testInterfaceId
)
}
@Test
fun testDestroySocketWithNetlinkMessageForOemNetwork() {
val addressV4 = InetAddress.getByName("203.0.113.10")
val nlMsgAddressRemoved = RtNetlinkAddressMessage(
StructNlMsgHdr(
30 /* payload length */,
NetlinkConstants.RTM_DELADDR,
0 /* flags */,
0 /* seq */
),
StructIfaddrMsg(
10 /* family */,
64 /* prefix length */,
0 /* flags */,
0 /* scope */,
5 /* interfaceId */
),
addressV4,
null,
0 /* flags */
)
csHandler.post{deps.netlinkMessageUpdate?.accept(nlMsgAddressRemoved)}
// verify destroy non platform socket(netId < MIN_NET_ID) with the RTM_DELADDR message
verify(destroySocketsWrapper, timeout(100)).destroyLiveTcpSocketsByLocalAddress(
addressV4,
setOf(Range.create(0, MIN_NET_ID - 1)),
null /* uidRanges */
)
}
}

View file

@ -68,6 +68,8 @@ import com.android.internal.app.IBatteryStats
import com.android.internal.util.test.BroadcastInterceptingContext
import com.android.modules.utils.build.SdkLevel
import com.android.net.module.util.ArrayTrackRecord
import com.android.net.module.util.SharedLog
import com.android.net.module.util.netlink.NetlinkMessage
import com.android.networkstack.apishim.common.UnsupportedApiLevelException
import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker
import com.android.server.connectivity.CarrierPrivilegeAuthenticator
@ -90,6 +92,7 @@ import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import java.util.function.BiConsumer
import java.util.function.Consumer
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.test.assertNotNull
@ -297,6 +300,10 @@ open class CSTest {
netIdRange: Set<Range<Int>>?,
uidRanges: Set<Range<Int>>?
) {}
open fun destroyLiveTcpSocketsByLocalAddress(
address: InetAddress?,
interfaceId: Int
) {}
}
inner class CSDeps : ConnectivityService.Dependencies() {
@ -323,7 +330,6 @@ open class CSTest {
listener: BiConsumer<Int, Int>,
handler: Handler
) = if (SdkLevel.isAtLeastT()) mock<CarrierPrivilegeAuthenticator>() else null
var satelliteNetworkFallbackUidUpdate = BiConsumer<Set<Int>, Set<Int>> {_, _ -> }
override fun makeSatelliteAccessController(
context: Context,
@ -451,6 +457,28 @@ open class CSTest {
uidRanges
)
}
override fun destroyLiveTcpSocketsByLocalAddress(
address: InetAddress,
interfaceId: Int
) {
// Call mocked destroyLiveTcpSocketsByLocalAddress so that test can verify this method
// call
destroySocketsWrapper.destroyLiveTcpSocketsByLocalAddress(
address,
interfaceId
)
}
var netlinkMessageUpdate = Consumer<NetlinkMessage> {_ -> }
override fun makeAddressUpdateMonitor(
h: Handler,
log: SharedLog,
tag: String,
consumer: Consumer<NetlinkMessage>
): ConnectivityService.AddressUpdateMonitor {
netlinkMessageUpdate = consumer
return ConnectivityService.AddressUpdateMonitor(h, log, tag, consumer)
}
}
inner class PermDeps : PermissionMonitor.Dependencies() {