From 37ad62b885a9408670ba60d3f6d3f8cd9fa65f71 Mon Sep 17 00:00:00 2001 From: pyamsoft Date: Thu, 2 May 2024 20:56:08 -0700 Subject: [PATCH] Guard IP connections to the host address #292 --- .../com/pyamsoft/tetherfi/server/Utils.kt | 1 - .../broadcast/BroadcastNetworkStatus.kt | 311 +++++++++--------- .../tetherfi/server/clients/TetherClient.kt | 244 +++++++------- .../server/proxy/manager/TcpProxyManager.kt | 6 +- .../server/proxy/manager/UdpProxyManager.kt | 6 +- .../factory/DefaultProxyManagerFactory.kt | 4 +- .../server/proxy/session/ProxySession.kt | 2 + .../proxy/session/tcp/TcpProxySession.kt | 17 + .../proxy/session/udp/UdpProxySession.kt | 2 + 9 files changed, 302 insertions(+), 291 deletions(-) diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/Utils.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/Utils.kt index bc24a8fa..3a59d770 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/Utils.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/Utils.kt @@ -16,7 +16,6 @@ package com.pyamsoft.tetherfi.server - /** * What the fuck is this * https://stackoverflow.com/questions/10006459/regular-expression-for-ip-address-validation diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/broadcast/BroadcastNetworkStatus.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/broadcast/BroadcastNetworkStatus.kt index 39720c28..ac5af855 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/broadcast/BroadcastNetworkStatus.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/broadcast/BroadcastNetworkStatus.kt @@ -22,180 +22,171 @@ import androidx.compose.runtime.Stable import com.pyamsoft.tetherfi.core.Timber import com.pyamsoft.tetherfi.server.IP_ADDRESS_REGEX import com.pyamsoft.tetherfi.server.Server -import com.pyamsoft.tetherfi.server.clients.TetherClient import com.pyamsoft.tetherfi.server.status.RunningStatus import kotlinx.coroutines.flow.Flow interface BroadcastNetworkStatus : Server { - @CheckResult - fun onGroupInfoChanged(): Flow + @CheckResult fun onGroupInfoChanged(): Flow - @CheckResult - fun onConnectionInfoChanged(): Flow + @CheckResult fun onConnectionInfoChanged(): Flow - @CheckResult - fun getCurrentProxyStatus(): RunningStatus + @CheckResult fun getCurrentProxyStatus(): RunningStatus + + @CheckResult fun onProxyStatusChanged(): Flow + + @Stable + @Immutable + sealed interface GroupInfo { + + data object Unchanged : GroupInfo + + data class Connected + internal constructor( + val ssid: String, + val password: String, + ) : GroupInfo + + data object Empty : GroupInfo + + data class Error + internal constructor( + val error: Throwable, + ) : GroupInfo @CheckResult - fun onProxyStatusChanged(): Flow - - @Stable - @Immutable - sealed interface GroupInfo { - - data object Unchanged : GroupInfo - - data class Connected - internal constructor( - val ssid: String, - val password: String, - ) : GroupInfo - - data object Empty : GroupInfo - - data class Error - internal constructor( - val error: Throwable, - ) : GroupInfo - - @CheckResult - fun update(onUpdate: (Connected) -> Connected): GroupInfo { - return when (this) { - is Connected -> onUpdate(this) - is Empty -> this - is Error -> this - is Unchanged -> this - } - } + fun update(onUpdate: (Connected) -> Connected): GroupInfo { + return when (this) { + is Connected -> onUpdate(this) + is Empty -> this + is Error -> this + is Unchanged -> this + } } + } + + @Stable + @Immutable + sealed interface ConnectionInfo { + data object Unchanged : ConnectionInfo + + data class Connected + internal constructor( + val hostName: String, + ) : ConnectionInfo { + + private data class NotAnIpAddressException(val hostName: String) : + IllegalStateException("Not an IP address: $hostName") + + // Is this Connection info from the server an IP address or a DNS hostname? + // It's almost always an IP address + val isIpAddress by lazy { IP_ADDRESS_REGEX.matches(hostName) } + + /** + * Split up an IP address + * + * 192.168.49.1 -> [ 192, 168, 49, 1 ] + */ + private val splitUpIp by lazy { + ensureIpAddress() + hostName.split(".") + } + + /** + * IP first block + * + * 192.168.49.1 -> 192 + */ + private val ipFirstBlock by lazy { + ensureIpAddress() + splitUpIp[0] + } + + /** + * IP second block + * + * 192.168.49.1 -> 168 + */ + private val ipSecondBlock by lazy { + ensureIpAddress() + splitUpIp[1] + } + + /** + * IP third block + * + * 192.168.49.1 -> 49 + */ + private val ipThirdBlock by lazy { + ensureIpAddress() + splitUpIp[2] + } + + /** If this is not an IP address, you've done something wrong */ + private fun ensureIpAddress() { + if (!isIpAddress) { + throw NotAnIpAddressException(hostName) + } + } + + /** + * If the server is an IP address, then we should check that this client is also IP + * addressable. + * + * If the client is a hostname client (do we have any of these ever?), then this method does + * not apply + */ + @CheckResult + fun isClientWithinAddressableIpRange(ip: String): Boolean { + val splitUpAddress = ip.split(".") + + // Needs to be 4 sections + if (splitUpAddress.size != 4) { + Timber.w { "Split up IP address was wrong format: $ip $splitUpAddress" } + return false + } - @Stable - @Immutable - sealed interface ConnectionInfo { - data object Unchanged : ConnectionInfo - - data class Connected - internal constructor( - val hostName: String, - ) : ConnectionInfo { - - private data class NotAnIpAddressException(val hostName: String) : - IllegalStateException("Not an IP address: $hostName") - - // Is this Connection info from the server an IP address or a DNS hostname? - // It's almost always an IP address - val isIpAddress by lazy { IP_ADDRESS_REGEX.matches(hostName) } - - /** - * Split up an IP address - * - * 192.168.49.1 -> [ 192, 168, 49, 1 ] - */ - private val splitUpIp by lazy { - ensureIpAddress() - hostName.split(".") - } - - /** - * IP first block - * - * 192.168.49.1 -> 192 - */ - private val ipFirstBlock by lazy { - ensureIpAddress() - splitUpIp[0] - } - - /** - * IP second block - * - * 192.168.49.1 -> 168 - */ - private val ipSecondBlock by lazy { - ensureIpAddress() - splitUpIp[1] - } - - /** - * IP third block - * - * 192.168.49.1 -> 49 - */ - private val ipThirdBlock by lazy { - ensureIpAddress() - splitUpIp[2] - } - - /** - * If this is not an IP address, you've done something wrong - */ - private fun ensureIpAddress() { - if (!isIpAddress) { - throw NotAnIpAddressException(hostName) - } - } - - /** - * If the server is an IP address, then we should check that this client is - * also IP addressable. - * - * If the client is a hostname client (do we have any of these ever?), then - * this method does not apply - */ - @CheckResult - fun isClientWithinAddressableIpRange(client: TetherClient.IpAddress): Boolean { - val ip = client.ip - val splitUpAddress = ip.split(".") - - // Needs to be 4 sections - if (splitUpAddress.size != 4) { - Timber.w { "Split up IP address was wrong format: $ip $splitUpAddress" } - return false - } - - val first = splitUpAddress[0] - val second = splitUpAddress[1] - val third = splitUpAddress[2] - - if (first != ipFirstBlock) { - Timber.w { "Mismatch IP first block: $ip $hostName" } - return false - } - - if (second != ipSecondBlock) { - Timber.w { "Mismatch IP second block: $ip $hostName" } - return false - } - - if (third != ipThirdBlock) { - Timber.w { "Mismatch IP third block: $ip $hostName" } - return false - } - - // This is a "matching" IP of - // XXX.YYY.ZZZ.??? - // which is good enough for us - return true - } + val first = splitUpAddress[0] + val second = splitUpAddress[1] + val third = splitUpAddress[2] + if (first != ipFirstBlock) { + Timber.w { "Mismatch IP first block: $ip $hostName" } + return false } - data object Empty : ConnectionInfo - - data class Error - internal constructor( - val error: Throwable, - ) : ConnectionInfo - - @CheckResult - fun update(onUpdate: (Connected) -> Connected): ConnectionInfo { - return when (this) { - is Connected -> onUpdate(this) - is Empty -> this - is Error -> this - is Unchanged -> this - } + if (second != ipSecondBlock) { + Timber.w { "Mismatch IP second block: $ip $hostName" } + return false } + + if (third != ipThirdBlock) { + Timber.w { "Mismatch IP third block: $ip $hostName" } + return false + } + + // This is a "matching" IP of + // XXX.YYY.ZZZ.??? + // which is good enough for us + return true + } + } + + data object Empty : ConnectionInfo + + data class Error + internal constructor( + val error: Throwable, + ) : ConnectionInfo + + @CheckResult + fun update(onUpdate: (Connected) -> Connected): ConnectionInfo { + return when (this) { + is Connected -> onUpdate(this) + is Empty -> this + is Error -> this + is Unchanged -> this + } } + } } diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/clients/TetherClient.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/clients/TetherClient.kt index 06465661..1448b432 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/clients/TetherClient.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/clients/TetherClient.kt @@ -26,12 +26,12 @@ import java.time.LocalDateTime private val UNIT_JUMP = 1024UL enum class BandwidthUnit(val displayName: String) { - BYTE("bytes"), - KB("KB"), - MB("MB"), - GB("DB"), - TB("TB"), - PB("PB"), + BYTE("bytes"), + KB("KB"), + MB("MB"), + GB("DB"), + TB("TB"), + PB("PB"), } @Stable @@ -41,9 +41,7 @@ data class BandwidthLimit( val unit: BandwidthUnit, ) { - val display by lazy { - "$amount ${unit.displayName}" - } + val display by lazy { "$amount ${unit.displayName}" } } @Stable @@ -54,138 +52,136 @@ sealed class TetherClient( protected open val totalBytes: ByteTransferReport, ) { - val transferToInternet by lazy { parseBandwidth(totalBytes.proxyToInternet) } - val transferFromInternet by lazy { parseBandwidth(totalBytes.internetToProxy) } + val transferToInternet by lazy { parseBandwidth(totalBytes.proxyToInternet) } + val transferFromInternet by lazy { parseBandwidth(totalBytes.internetToProxy) } - @CheckResult - private fun parseBandwidth(total: ULong): BandwidthLimit { - var amount = total - var suffix = BandwidthUnit.BYTE - while (amount > UNIT_JUMP) { - suffix = mapSuffixToNextLargest(amount, suffix) - amount /= UNIT_JUMP - } - - return BandwidthLimit( - amount = amount, - unit = suffix, - ) + @CheckResult + private fun parseBandwidth(total: ULong): BandwidthLimit { + var amount = total + var suffix = BandwidthUnit.BYTE + while (amount > UNIT_JUMP) { + suffix = mapSuffixToNextLargest(amount, suffix) + amount /= UNIT_JUMP } - @CheckResult - private fun mapSuffixToNextLargest(amount: ULong, suffix: BandwidthUnit): BandwidthUnit = - when (suffix) { - BandwidthUnit.BYTE -> BandwidthUnit.KB - BandwidthUnit.KB -> BandwidthUnit.MB - BandwidthUnit.MB -> BandwidthUnit.GB - BandwidthUnit.GB -> BandwidthUnit.TB - BandwidthUnit.TB -> BandwidthUnit.PB - else -> throw IllegalStateException("Bytes payload too big: $amount$suffix") + return BandwidthLimit( + amount = amount, + unit = suffix, + ) + } + + @CheckResult + private fun mapSuffixToNextLargest(amount: ULong, suffix: BandwidthUnit): BandwidthUnit = + when (suffix) { + BandwidthUnit.BYTE -> BandwidthUnit.KB + BandwidthUnit.KB -> BandwidthUnit.MB + BandwidthUnit.MB -> BandwidthUnit.GB + BandwidthUnit.GB -> BandwidthUnit.TB + BandwidthUnit.TB -> BandwidthUnit.PB + else -> throw IllegalStateException("Bytes payload too big: $amount$suffix") + } + + @CheckResult + fun matches(o: TetherClient): Boolean { + when (this) { + is IpAddress -> { + if (o is IpAddress) { + return ip == o.ip } - @CheckResult - fun matches(o: TetherClient): Boolean { - when (this) { - is IpAddress -> { - if (o is IpAddress) { - return ip == o.ip - } - - return false - } - - is HostName -> { - if (o is HostName) { - return hostname == o.hostname - } - - return false - } + return false + } + is HostName -> { + if (o is HostName) { + return hostname == o.hostname } + + return false + } } + } + + @CheckResult + fun matches(hostNameOrIp: String): Boolean { + when (this) { + is IpAddress -> { + if (IP_ADDRESS_REGEX.matches(hostNameOrIp)) { + return ip == hostNameOrIp + } - @CheckResult - fun matches(hostNameOrIp: String): Boolean { - when (this) { - is IpAddress -> { - if (IP_ADDRESS_REGEX.matches(hostNameOrIp)) { - return ip == hostNameOrIp - } - - return false - } - - is HostName -> { - if (!IP_ADDRESS_REGEX.matches(hostNameOrIp)) { - return hostname == hostNameOrIp - } - - return false - } + return false + } + is HostName -> { + if (!IP_ADDRESS_REGEX.matches(hostNameOrIp)) { + return hostname == hostNameOrIp } + + return false + } } + } + + @CheckResult + fun mergeReport(report: ByteTransferReport): ByteTransferReport { + return report.copy( + internetToProxy = report.internetToProxy + totalBytes.internetToProxy, + proxyToInternet = report.proxyToInternet + totalBytes.proxyToInternet, + ) + } + + data class IpAddress + internal constructor( + val ip: String, + override val nickName: String, + override val mostRecentlySeen: LocalDateTime, + override val totalBytes: ByteTransferReport, + ) : + TetherClient( + nickName = nickName, + mostRecentlySeen = mostRecentlySeen, + totalBytes = totalBytes, + ) + + data class HostName + internal constructor( + val hostname: String, + override val nickName: String, + override val mostRecentlySeen: LocalDateTime, + override val totalBytes: ByteTransferReport, + ) : + TetherClient( + nickName = nickName, + mostRecentlySeen = mostRecentlySeen, + totalBytes = totalBytes, + ) + + companion object { @CheckResult - fun mergeReport(report: ByteTransferReport): ByteTransferReport { - return report.copy( - internetToProxy = report.internetToProxy + totalBytes.internetToProxy, - proxyToInternet = report.proxyToInternet + totalBytes.proxyToInternet, + fun create(hostNameOrIp: String, clock: Clock): TetherClient { + return if (IP_ADDRESS_REGEX.matches(hostNameOrIp)) { + IpAddress( + ip = hostNameOrIp, + mostRecentlySeen = LocalDateTime.now(clock), + nickName = "", + totalBytes = ByteTransferReport.EMPTY, ) - } - - data class IpAddress - internal constructor( - val ip: String, - override val nickName: String, - override val mostRecentlySeen: LocalDateTime, - override val totalBytes: ByteTransferReport, - ) : - TetherClient( - nickName = nickName, - mostRecentlySeen = mostRecentlySeen, - totalBytes = totalBytes, + } else { + HostName( + hostname = hostNameOrIp, + mostRecentlySeen = LocalDateTime.now(clock), + nickName = "", + totalBytes = ByteTransferReport.EMPTY, ) - - data class HostName - internal constructor( - val hostname: String, - override val nickName: String, - override val mostRecentlySeen: LocalDateTime, - override val totalBytes: ByteTransferReport, - ) : - TetherClient( - nickName = nickName, - mostRecentlySeen = mostRecentlySeen, - totalBytes = totalBytes, - ) - - companion object { - - @CheckResult - fun create(hostNameOrIp: String, clock: Clock): TetherClient { - return if (IP_ADDRESS_REGEX.matches(hostNameOrIp)) { - IpAddress( - ip = hostNameOrIp, - mostRecentlySeen = LocalDateTime.now(clock), - nickName = "", - totalBytes = ByteTransferReport.EMPTY, - ) - } else { - HostName( - hostname = hostNameOrIp, - mostRecentlySeen = LocalDateTime.now(clock), - nickName = "", - totalBytes = ByteTransferReport.EMPTY, - ) - } - } + } } + } } @CheckResult fun TetherClient.key(): String { - return when (this) { - is TetherClient.HostName -> this.hostname - is TetherClient.IpAddress -> this.ip - } + return when (this) { + is TetherClient.HostName -> this.hostname + is TetherClient.IpAddress -> this.ip + } } diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/TcpProxyManager.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/TcpProxyManager.kt index d4c31e21..3e83adc6 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/TcpProxyManager.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/TcpProxyManager.kt @@ -22,6 +22,7 @@ import com.pyamsoft.pydroid.util.ifNotCancellation import com.pyamsoft.tetherfi.core.AppDevEnvironment import com.pyamsoft.tetherfi.core.Timber import com.pyamsoft.tetherfi.server.ServerPreferences +import com.pyamsoft.tetherfi.server.broadcast.BroadcastNetworkStatus import com.pyamsoft.tetherfi.server.proxy.ServerDispatcher import com.pyamsoft.tetherfi.server.proxy.session.ProxySession import com.pyamsoft.tetherfi.server.proxy.session.tagSocket @@ -48,7 +49,7 @@ internal constructor( private val preferences: ServerPreferences, private val enforcer: ThreadEnforcer, private val session: ProxySession, - private val hostName: String, + private val hostConnection: BroadcastNetworkStatus.ConnectionInfo.Connected, private val port: Int, serverDispatcher: ServerDispatcher ) : @@ -68,6 +69,7 @@ internal constructor( try { session.exchange( scope = scope, + hostConnection = hostConnection, serverDispatcher = serverDispatcher, data = TcpProxyData( @@ -86,7 +88,7 @@ internal constructor( val localAddress = getServerAddress( - hostName = hostName, + hostName = hostConnection.hostName, port = port, verifyPort = true, verifyHostName = true, diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/UdpProxyManager.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/UdpProxyManager.kt index 5ab36063..7942e9a7 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/UdpProxyManager.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/UdpProxyManager.kt @@ -19,6 +19,7 @@ package com.pyamsoft.tetherfi.server.proxy.manager import com.pyamsoft.pydroid.core.ThreadEnforcer import com.pyamsoft.pydroid.util.ifNotCancellation import com.pyamsoft.tetherfi.core.Timber +import com.pyamsoft.tetherfi.server.broadcast.BroadcastNetworkStatus import com.pyamsoft.tetherfi.server.proxy.ServerDispatcher import com.pyamsoft.tetherfi.server.proxy.session.ProxySession import com.pyamsoft.tetherfi.server.proxy.session.tagSocket @@ -35,7 +36,7 @@ internal class UdpProxyManager internal constructor( private val enforcer: ThreadEnforcer, private val session: ProxySession, - private val hostName: String, + private val hostConnection: BroadcastNetworkStatus.ConnectionInfo.Connected, private val port: Int, serverDispatcher: ServerDispatcher, ) : @@ -52,6 +53,7 @@ internal constructor( try { session.exchange( scope = scope, + hostConnection = hostConnection, serverDispatcher = serverDispatcher, data = UdpProxyData( @@ -70,7 +72,7 @@ internal constructor( val localAddress = getServerAddress( - hostName = hostName, + hostName = hostConnection.hostName, port = port, verifyPort = false, verifyHostName = true, diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/factory/DefaultProxyManagerFactory.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/factory/DefaultProxyManagerFactory.kt index 00b07832..9688544e 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/factory/DefaultProxyManagerFactory.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/manager/factory/DefaultProxyManagerFactory.kt @@ -60,7 +60,7 @@ internal constructor( preferences = serverPreferences, enforcer = enforcer, session = tcpSession, - hostName = info.hostName, + hostConnection = info, port = port, serverDispatcher = dispatcher, appEnvironment = appEnvironment, @@ -79,7 +79,7 @@ internal constructor( return UdpProxyManager( enforcer = enforcer, session = udpSession, - hostName = info.hostName, + hostConnection = info, port = port, serverDispatcher = dispatcher, ) diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/ProxySession.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/ProxySession.kt index 5d8ca688..6f4249ed 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/ProxySession.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/ProxySession.kt @@ -17,6 +17,7 @@ package com.pyamsoft.tetherfi.server.proxy.session import androidx.annotation.CheckResult +import com.pyamsoft.tetherfi.server.broadcast.BroadcastNetworkStatus import com.pyamsoft.tetherfi.server.proxy.ServerDispatcher import kotlinx.coroutines.CoroutineScope @@ -24,6 +25,7 @@ internal interface ProxySession { suspend fun exchange( scope: CoroutineScope, + hostConnection: BroadcastNetworkStatus.ConnectionInfo.Connected, serverDispatcher: ServerDispatcher, data: T, ) diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/tcp/TcpProxySession.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/tcp/TcpProxySession.kt index 2d7f836d..32e81ce9 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/tcp/TcpProxySession.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/tcp/TcpProxySession.kt @@ -20,7 +20,9 @@ import androidx.annotation.CheckResult import com.pyamsoft.pydroid.core.ThreadEnforcer import com.pyamsoft.pydroid.util.ifNotCancellation import com.pyamsoft.tetherfi.core.Timber +import com.pyamsoft.tetherfi.server.IP_ADDRESS_REGEX import com.pyamsoft.tetherfi.server.ServerInternalApi +import com.pyamsoft.tetherfi.server.broadcast.BroadcastNetworkStatus import com.pyamsoft.tetherfi.server.clients.AllowedClients import com.pyamsoft.tetherfi.server.clients.BlockedClients import com.pyamsoft.tetherfi.server.clients.ByteTransferReport @@ -193,6 +195,7 @@ internal constructor( private suspend fun handleClientRequest( scope: CoroutineScope, + hostConnection: BroadcastNetworkStatus.ConnectionInfo.Connected, serverDispatcher: ServerDispatcher, proxyInput: ByteReadChannel, proxyOutput: ByteWriteChannel, @@ -261,6 +264,7 @@ internal constructor( override suspend fun exchange( scope: CoroutineScope, + hostConnection: BroadcastNetworkStatus.ConnectionInfo.Connected, serverDispatcher: ServerDispatcher, data: TcpProxyData, ) = @@ -279,8 +283,21 @@ internal constructor( return@withContext } + // If the host is an IP address, and we are an IP address, + // check that we fall into the host + if (hostConnection.isIpAddress) { + if (IP_ADDRESS_REGEX.matches(hostNameOrIp)) { + if (!hostConnection.isClientWithinAddressableIpRange(hostNameOrIp)) { + Timber.w { "Reject IP address outside of host range: $hostNameOrIp" } + writeError(proxyOutput) + return@withContext + } + } + } + handleClientRequest( scope = this, + hostConnection = hostConnection, serverDispatcher = serverDispatcher, proxyInput = proxyInput, proxyOutput = proxyOutput, diff --git a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/udp/UdpProxySession.kt b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/udp/UdpProxySession.kt index 9a0d9308..b4000bce 100644 --- a/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/udp/UdpProxySession.kt +++ b/server/src/main/java/com/pyamsoft/tetherfi/server/proxy/session/udp/UdpProxySession.kt @@ -18,6 +18,7 @@ package com.pyamsoft.tetherfi.server.proxy.session.udp import com.pyamsoft.pydroid.core.ThreadEnforcer import com.pyamsoft.tetherfi.core.Timber +import com.pyamsoft.tetherfi.server.broadcast.BroadcastNetworkStatus import com.pyamsoft.tetherfi.server.proxy.ServerDispatcher import com.pyamsoft.tetherfi.server.proxy.session.ProxySession import javax.inject.Inject @@ -32,6 +33,7 @@ internal constructor( override suspend fun exchange( scope: CoroutineScope, + hostConnection: BroadcastNetworkStatus.ConnectionInfo.Connected, serverDispatcher: ServerDispatcher, data: UdpProxyData, ) =