1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.testutils 18 19 import android.content.Context 20 import android.net.ConnectivityManager 21 import android.net.LinkAddress 22 import android.net.LinkProperties 23 import android.net.Network 24 import android.net.NetworkCapabilities 25 import android.net.NetworkRequest 26 import android.net.TestNetworkInterface 27 import android.net.TestNetworkManager 28 import android.net.TestNetworkSpecifier 29 import android.os.Binder 30 import com.android.testutils.RecorderCallback.CallbackEntry.Available 31 import java.net.InetAddress 32 import libcore.io.IoUtils 33 34 private const val MIN_PORT_NUMBER = 1025 35 private const val MAX_PORT_NUMBER = 65535 36 37 /** 38 * A class that set up two {@link TestNetworkInterface} with NAT, and forward packets between them. 39 * 40 * See {@link NatPacketForwarder} for more detailed information. 41 */ 42 class PacketBridge( 43 context: Context, 44 internalAddr: LinkAddress, 45 externalAddr: LinkAddress, 46 dnsAddr: InetAddress 47 ) { 48 private val natMap = NatMap() 49 private val binder = Binder() 50 51 private val cm = context.getSystemService(ConnectivityManager::class.java) 52 private val tnm = context.getSystemService(TestNetworkManager::class.java) 53 54 // Create test networks. 55 private val internalIface = tnm.createTunInterface(listOf(internalAddr)) 56 private val externalIface = tnm.createTunInterface(listOf(externalAddr)) 57 58 // Register test networks to ConnectivityService. 59 private val internalNetworkCallback: TestableNetworkCallback 60 private val externalNetworkCallback: TestableNetworkCallback 61 val internalNetwork: Network 62 val externalNetwork: Network 63 init { 64 val (inCb, inNet) = createTestNetwork(internalIface, internalAddr, dnsAddr) 65 val (exCb, exNet) = createTestNetwork(externalIface, externalAddr, dnsAddr) 66 internalNetworkCallback = inCb 67 externalNetworkCallback = exCb 68 internalNetwork = inNet 69 externalNetwork = exNet 70 } 71 72 // Setup the packet bridge. 73 private val internalFd = internalIface.fileDescriptor.fileDescriptor 74 private val externalFd = externalIface.fileDescriptor.fileDescriptor 75 76 private val pr1 = NatInternalPacketForwarder( 77 internalFd, 78 1500, 79 externalFd, 80 externalAddr.address, 81 natMap 82 ) 83 private val pr2 = NatExternalPacketForwarder( 84 externalFd, 85 1500, 86 internalFd, 87 externalAddr.address, 88 natMap 89 ) 90 startnull91 fun start() { 92 IoUtils.setBlocking(internalFd, true /* blocking */) 93 IoUtils.setBlocking(externalFd, true /* blocking */) 94 pr1.start() 95 pr2.start() 96 } 97 stopnull98 fun stop() { 99 pr1.interrupt() 100 pr2.interrupt() 101 cm.unregisterNetworkCallback(internalNetworkCallback) 102 cm.unregisterNetworkCallback(externalNetworkCallback) 103 } 104 105 /** 106 * Creates a test network with given test TUN interface and addresses. 107 */ createTestNetworknull108 private fun createTestNetwork( 109 testIface: TestNetworkInterface, 110 addr: LinkAddress, 111 dnsAddr: InetAddress 112 ): Pair<TestableNetworkCallback, Network> { 113 // Make a network request to hold the test network 114 val nr = NetworkRequest.Builder() 115 .clearCapabilities() 116 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 117 .setNetworkSpecifier(TestNetworkSpecifier(testIface.interfaceName)) 118 .build() 119 val testCb = TestableNetworkCallback() 120 cm.requestNetwork(nr, testCb) 121 122 val lp = LinkProperties().apply { 123 addLinkAddress(addr) 124 interfaceName = testIface.interfaceName 125 addDnsServer(dnsAddr) 126 } 127 tnm.setupTestNetwork(lp, true /* isMetered */, binder) 128 129 // Wait for available before return. 130 val network = testCb.expect<Available>().network 131 return testCb to network 132 } 133 134 /** 135 * A helper class to maintain the mappings between internal addresses/ports and external 136 * ports. 137 * 138 * This class assigns an unused external port number if the mapping between 139 * srcaddress:srcport:protocol and the external port does not exist yet. 140 * 141 * Note that this class is not thread-safe. The instance of the class needs to be 142 * synchronized in the callers when being used in multiple threads. 143 */ 144 class NatMap { 145 data class AddressInfo(val address: InetAddress, val port: Int, val protocol: Int) 146 147 private val mToExternalPort = HashMap<AddressInfo, Int>() 148 private val mFromExternalPort = HashMap<Int, AddressInfo>() 149 150 // Skip well-known port 0~1024. 151 private var nextExternalPort = MIN_PORT_NUMBER 152 toExternalPortnull153 fun toExternalPort(addr: InetAddress, port: Int, protocol: Int): Int { 154 val info = AddressInfo(addr, port, protocol) 155 val extPort: Int 156 if (!mToExternalPort.containsKey(info)) { 157 extPort = nextExternalPort++ 158 if (nextExternalPort > MAX_PORT_NUMBER) { 159 throw IllegalStateException("Available ports are exhausted") 160 } 161 mToExternalPort[info] = extPort 162 mFromExternalPort[extPort] = info 163 } else { 164 extPort = mToExternalPort[info]!! 165 } 166 return extPort 167 } 168 fromExternalPortnull169 fun fromExternalPort(port: Int): AddressInfo? { 170 return mFromExternalPort[port] 171 } 172 } 173 } 174