add route table, needs to handle route info in VPNService and arp table
This commit is contained in:
parent
f04b16f7c4
commit
e0061c1277
47
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
47
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="ComposePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ComposePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GlancePreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewDeviceShouldUseNewSpec" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
@ -82,6 +82,9 @@ dependencies {
|
|||||||
implementation("com.google.protobuf:protobuf-java:4.29.3")
|
implementation("com.google.protobuf:protobuf-java:4.29.3")
|
||||||
implementation("com.google.protobuf:protobuf-kotlin:4.29.3")
|
implementation("com.google.protobuf:protobuf-kotlin:4.29.3")
|
||||||
|
|
||||||
|
implementation("androidx.navigation:navigation-compose:2.9.0")
|
||||||
|
implementation("io.coil-kt:coil-compose:2.6.0")
|
||||||
|
|
||||||
// implementation(libs.bcprov.jdk18on)
|
// implementation(libs.bcprov.jdk18on)
|
||||||
implementation(libs.bcpkix.jdk18on)
|
implementation(libs.bcpkix.jdk18on)
|
||||||
// implementation(files("libs/org.asxalex.sdlan/sdlan-1.0-SNAPSHOT.jar"))
|
// implementation(files("libs/org.asxalex.sdlan/sdlan-1.0-SNAPSHOT.jar"))
|
||||||
|
|||||||
@ -19,6 +19,9 @@ import com.jihe.punchnet.sdlan.network.ARPTable
|
|||||||
import com.jihe.punchnet.sdlan.network.ARPWaitList
|
import com.jihe.punchnet.sdlan.network.ARPWaitList
|
||||||
import com.jihe.punchnet.sdlan.network.DeviceConfig
|
import com.jihe.punchnet.sdlan.network.DeviceConfig
|
||||||
import com.jihe.punchnet.sdlan.network.IfaceTun
|
import com.jihe.punchnet.sdlan.network.IfaceTun
|
||||||
|
import com.jihe.punchnet.sdlan.network.RouteDetail
|
||||||
|
import com.jihe.punchnet.sdlan.network.RouteTable
|
||||||
|
import com.jihe.punchnet.sdlan.network.cidrToRouteDetail
|
||||||
import com.jihe.punchnet.sdlan.network.ipInt2ByteArray
|
import com.jihe.punchnet.sdlan.network.ipInt2ByteArray
|
||||||
import com.jihe.punchnet.sdlan.network.run_sdlan
|
import com.jihe.punchnet.sdlan.network.run_sdlan
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@ -69,7 +72,7 @@ class PunchnetService : VpnService() , IfaceTun {
|
|||||||
|
|
||||||
override suspend fun send(content: ByteArray) {
|
override suspend fun send(content: ByteArray) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
Log.d(TAG, "WROTE bytes to vpn service")
|
// Log.d(TAG, "WROTE bytes to vpn service")
|
||||||
output?.write(content)
|
output?.write(content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +107,7 @@ class PunchnetService : VpnService() , IfaceTun {
|
|||||||
output?.close()
|
output?.close()
|
||||||
vpnDescriptor?.close()
|
vpnDescriptor?.close()
|
||||||
|
|
||||||
stopForeground(true)
|
// stopForeground(true)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +120,14 @@ class PunchnetService : VpnService() , IfaceTun {
|
|||||||
Log.d("DIR", "external storage = ${Environment.getExternalStorageDirectory().name}")
|
Log.d("DIR", "external storage = ${Environment.getExternalStorageDirectory().name}")
|
||||||
Log.d("DIR", "filesdir = ${this.filesDir.path}")
|
Log.d("DIR", "filesdir = ${this.filesDir.path}")
|
||||||
|
|
||||||
|
arpTable.routeTable.clearRoute()
|
||||||
|
for (route in startArg?.routes?.toList()?:listOf()) {
|
||||||
|
val r = cidrToRouteDetail(route.targetNetCIDR, route.gateway)
|
||||||
|
if (r != null) {
|
||||||
|
arpTable.routeTable.addRoute(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val argument = Arguments(
|
val argument = Arguments(
|
||||||
baseDir = this.filesDir.path,
|
baseDir = this.filesDir.path,
|
||||||
sn = "$server:1265",
|
sn = "$server:1265",
|
||||||
@ -124,13 +135,12 @@ class PunchnetService : VpnService() , IfaceTun {
|
|||||||
|
|
||||||
nat_server1 = "$server:1265",
|
nat_server1 = "$server:1265",
|
||||||
nat_server2 = "47.98.178.3:1265",
|
nat_server2 = "47.98.178.3:1265",
|
||||||
token = "",
|
token = startArg?.token?:"",
|
||||||
name = "tau",
|
name = "tau",
|
||||||
)
|
)
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
run_sdlan(iface, argument, startArg)
|
||||||
run_sdlan(iface, argument)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val notification = createNotification()
|
val notification = createNotification()
|
||||||
@ -141,8 +151,9 @@ class PunchnetService : VpnService() , IfaceTun {
|
|||||||
super.onStartCommand(intent, flags, startId)
|
super.onStartCommand(intent, flags, startId)
|
||||||
|
|
||||||
return if (intent?.action == ACTION_DISCONNECT) {
|
return if (intent?.action == ACTION_DISCONNECT) {
|
||||||
|
scope.cancel()
|
||||||
disconnect()
|
disconnect()
|
||||||
START_NOT_STICKY
|
START_STICKY
|
||||||
} else {
|
} else {
|
||||||
val argument = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
val argument = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
intent?.getParcelableExtra("argument", PunchnetServiceArgument::class.java)
|
intent?.getParcelableExtra("argument", PunchnetServiceArgument::class.java)
|
||||||
@ -174,8 +185,8 @@ class PunchnetService : VpnService() , IfaceTun {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
scope.cancel()
|
// scope.cancel()
|
||||||
disconnect()
|
// disconnect()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
6
app/src/main/java/com/jihe/punchnet/helper/Screens.kt
Normal file
6
app/src/main/java/com/jihe/punchnet/helper/Screens.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.jihe.punchnet.helper
|
||||||
|
|
||||||
|
sealed class Screen(val route: String) {
|
||||||
|
object ScreenRoutes: Screen("routes")
|
||||||
|
object ScreenMain: Screen("main")
|
||||||
|
}
|
||||||
105
app/src/main/java/com/jihe/punchnet/screen/MainScreen.kt
Normal file
105
app/src/main/java/com/jihe/punchnet/screen/MainScreen.kt
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package com.jihe.punchnet.screen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MainApp(
|
||||||
|
navController: NavHostController,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CustomHeaderScreen(
|
||||||
|
text: String,
|
||||||
|
onBack: @Composable (() -> Unit)? = null,
|
||||||
|
onMenu: @Composable (() -> Unit)? = null,
|
||||||
|
body: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Box (
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(56.dp)
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceContainer),
|
||||||
|
//.padding(horizontal = 16.dp),
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
Row (
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.width(35.dp)
|
||||||
|
) {
|
||||||
|
if (onBack != null) {
|
||||||
|
onBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
// color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.width(35.dp)
|
||||||
|
) {
|
||||||
|
if (onMenu != null) {
|
||||||
|
onMenu()
|
||||||
|
/*
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
onMenu()
|
||||||
|
}
|
||||||
|
.fillMaxSize(),
|
||||||
|
imageVector = Icons.Filled.Menu,
|
||||||
|
contentDescription = "setting",
|
||||||
|
// tint = MaterialTheme.colorScheme.onPrimary
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,10 @@ import kotlinx.coroutines.async
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
class ARPTable() {
|
class ARPTable(
|
||||||
|
) {
|
||||||
|
val routeTable: RouteTable = RouteTable()
|
||||||
|
|
||||||
val content = ConcurrentHashMap<Int, ARPInfo>()
|
val content = ConcurrentHashMap<Int, ARPInfo>()
|
||||||
|
|
||||||
suspend fun agingARP() {
|
suspend fun agingARP() {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.jihe.punchnet.sdlan.network
|
package com.jihe.punchnet.sdlan.network
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.jihe.punchnet.PunchnetServiceArgument
|
||||||
import com.jihe.punchnet.protobuf.PunchProto.SDLDevAddr
|
import com.jihe.punchnet.protobuf.PunchProto.SDLDevAddr
|
||||||
import com.jihe.punchnet.protobuf.PunchProto.SDLRegisterSuper
|
import com.jihe.punchnet.protobuf.PunchProto.SDLRegisterSuper
|
||||||
import com.jihe.punchnet.protobuf.PunchProto.SDLRegisterSuperAck
|
import com.jihe.punchnet.protobuf.PunchProto.SDLRegisterSuperAck
|
||||||
@ -125,7 +126,7 @@ suspend fun onMessage(data: SDLanTCP) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun run_sdlan(iface: Iface, argument: Arguments) {
|
suspend fun run_sdlan(iface: Iface, argument: Arguments, routeinfo: PunchnetServiceArgument?) {
|
||||||
UniqueNodeID.setBaseDir(argument.baseDir)
|
UniqueNodeID.setBaseDir(argument.baseDir)
|
||||||
val edgeUUID = UniqueNodeID.getUUID()
|
val edgeUUID = UniqueNodeID.getUUID()
|
||||||
val config = parseConfig(edgeUUID, argument)
|
val config = parseConfig(edgeUUID, argument)
|
||||||
@ -135,6 +136,8 @@ suspend fun run_sdlan(iface: Iface, argument: Arguments) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val toSocket = Channel<ByteArray>(100)
|
val toSocket = Channel<ByteArray>(100)
|
||||||
val start_stop_channel = Channel<StartStopChanInfo>(100)
|
val start_stop_channel = Channel<StartStopChanInfo>(100)
|
||||||
initEdge(iface, argument.token, config, toSocket, start_stop_channel)
|
initEdge(iface, argument.token, config, toSocket, start_stop_channel)
|
||||||
|
|||||||
122
app/src/main/java/com/jihe/punchnet/sdlan/network/route.kt
Normal file
122
app/src/main/java/com/jihe/punchnet/sdlan/network/route.kt
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package com.jihe.punchnet.sdlan.network
|
||||||
|
|
||||||
|
import com.jihe.punchnet.sdlan.logs.TerminalLogger
|
||||||
|
import org.bouncycastle.util.Strings
|
||||||
|
import java.util.LinkedList
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||||
|
|
||||||
|
data class RouteDetail(
|
||||||
|
// Int representation of 255.255.255.0
|
||||||
|
val mask: Int,
|
||||||
|
val gw: Int,
|
||||||
|
val maskedAddr: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun cidrToRouteDetail(cidr: String, gw: String): RouteDetail? {
|
||||||
|
val ipAndMaskDigit = Strings.split(cidr, '/')
|
||||||
|
if (ipAndMaskDigit.size != 2) {
|
||||||
|
TerminalLogger.debugf { "cidr format error: ${cidr}" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val ip = ipStringToInt(ipAndMaskDigit[0])
|
||||||
|
val mask = maskDigitToInt(ipAndMaskDigit[1].toInt())
|
||||||
|
|
||||||
|
if (ip == null || mask == null) {
|
||||||
|
TerminalLogger.debugf { "cidr format error2: ${cidr}" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val gateway = ipStringToInt(gw)
|
||||||
|
if (gateway == null) {
|
||||||
|
TerminalLogger.debugf { "gateway format error: ${gateway}" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ip and mask) != ip) {
|
||||||
|
TerminalLogger.debugf { "net not masked" }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return RouteDetail(
|
||||||
|
mask = mask,
|
||||||
|
gw = gateway,
|
||||||
|
maskedAddr = ip,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun maskDigitToInt(digit: Int): Int? {
|
||||||
|
if (digit <= 0 || digit >= 32) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return ((2 shl (32-digit)) - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ipStringToInt(ip: String): Int? {
|
||||||
|
val ipFiltered = ip.trim { it.isWhitespace() }
|
||||||
|
val ipSeg = Strings.split(ipFiltered, '.')
|
||||||
|
if (ipSeg.size != 4) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return ((ipSeg[0].toInt() and 0xff) shl 24) +
|
||||||
|
((ipSeg[1].toInt() and 0xff) shl 16) +
|
||||||
|
((ipSeg[2].toInt() and 0xff) shl 8) +
|
||||||
|
(ipSeg[3].toInt() and 0xff)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class RouteTable() {
|
||||||
|
val lock = ReentrantReadWriteLock()
|
||||||
|
|
||||||
|
val routeInfo: MutableList<RouteDetail> = mutableListOf()
|
||||||
|
|
||||||
|
fun addRoute(vararg routes: RouteDetail) {
|
||||||
|
try {
|
||||||
|
lock.writeLock().lock()
|
||||||
|
for (route in routes) {
|
||||||
|
routeInfo.add(route)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearRoute() {
|
||||||
|
try {
|
||||||
|
lock.writeLock().lock()
|
||||||
|
routeInfo.clear()
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getGeteway(ip: Int): Int? {
|
||||||
|
try {
|
||||||
|
lock.readLock().lock()
|
||||||
|
for (item in routeInfo) {
|
||||||
|
if ((ip and item.mask) == item.maskedAddr) {
|
||||||
|
return item.gw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
lock.readLock().unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class RouteTable2(
|
||||||
|
val initRouteInfo: List<RouteDetail>
|
||||||
|
) {
|
||||||
|
val routeInfo: Array<RouteDetail> = initRouteInfo.toTypedArray()
|
||||||
|
|
||||||
|
fun getGeteway(ip: Int): Int? {
|
||||||
|
for (item in routeInfo) {
|
||||||
|
if ((ip and item.mask) == item.maskedAddr) {
|
||||||
|
return item.gw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user