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-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.bcpkix.jdk18on)
|
||||
// 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.DeviceConfig
|
||||
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.run_sdlan
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -69,7 +72,7 @@ class PunchnetService : VpnService() , IfaceTun {
|
||||
|
||||
override suspend fun send(content: ByteArray) {
|
||||
withContext(Dispatchers.IO) {
|
||||
Log.d(TAG, "WROTE bytes to vpn service")
|
||||
// Log.d(TAG, "WROTE bytes to vpn service")
|
||||
output?.write(content)
|
||||
}
|
||||
}
|
||||
@ -104,7 +107,7 @@ class PunchnetService : VpnService() , IfaceTun {
|
||||
output?.close()
|
||||
vpnDescriptor?.close()
|
||||
|
||||
stopForeground(true)
|
||||
// stopForeground(true)
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
@ -117,6 +120,14 @@ class PunchnetService : VpnService() , IfaceTun {
|
||||
Log.d("DIR", "external storage = ${Environment.getExternalStorageDirectory().name}")
|
||||
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(
|
||||
baseDir = this.filesDir.path,
|
||||
sn = "$server:1265",
|
||||
@ -124,13 +135,12 @@ class PunchnetService : VpnService() , IfaceTun {
|
||||
|
||||
nat_server1 = "$server:1265",
|
||||
nat_server2 = "47.98.178.3:1265",
|
||||
token = "",
|
||||
token = startArg?.token?:"",
|
||||
name = "tau",
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
|
||||
run_sdlan(iface, argument)
|
||||
run_sdlan(iface, argument, startArg)
|
||||
}
|
||||
|
||||
val notification = createNotification()
|
||||
@ -141,8 +151,9 @@ class PunchnetService : VpnService() , IfaceTun {
|
||||
super.onStartCommand(intent, flags, startId)
|
||||
|
||||
return if (intent?.action == ACTION_DISCONNECT) {
|
||||
scope.cancel()
|
||||
disconnect()
|
||||
START_NOT_STICKY
|
||||
START_STICKY
|
||||
} else {
|
||||
val argument = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent?.getParcelableExtra("argument", PunchnetServiceArgument::class.java)
|
||||
@ -174,8 +185,8 @@ class PunchnetService : VpnService() , IfaceTun {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
scope.cancel()
|
||||
disconnect()
|
||||
// scope.cancel()
|
||||
// disconnect()
|
||||
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 java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class ARPTable() {
|
||||
class ARPTable(
|
||||
) {
|
||||
val routeTable: RouteTable = RouteTable()
|
||||
|
||||
val content = ConcurrentHashMap<Int, ARPInfo>()
|
||||
|
||||
suspend fun agingARP() {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.jihe.punchnet.sdlan.network
|
||||
|
||||
import android.util.Log
|
||||
import com.jihe.punchnet.PunchnetServiceArgument
|
||||
import com.jihe.punchnet.protobuf.PunchProto.SDLDevAddr
|
||||
import com.jihe.punchnet.protobuf.PunchProto.SDLRegisterSuper
|
||||
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)
|
||||
val edgeUUID = UniqueNodeID.getUUID()
|
||||
val config = parseConfig(edgeUUID, argument)
|
||||
@ -135,6 +136,8 @@ suspend fun run_sdlan(iface: Iface, argument: Arguments) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
val toSocket = Channel<ByteArray>(100)
|
||||
val start_stop_channel = Channel<StartStopChanInfo>(100)
|
||||
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