Skip to content

Commit

Permalink
Fix private network address byte ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanLongstaff committed Dec 13, 2024
1 parent 6d4b12d commit 0ac3f83
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 51 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.walkertribe.ian.protocol.udp

internal sealed interface IntConstraint {
@JvmInline
value class Equals(val value: Int) : IntConstraint {
override fun check(int: Int): Boolean = int == value
}

class Range(val range: IntRange) : IntConstraint {
override fun check(int: Int): Boolean = int in range
}

fun check(int: Int): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,43 @@ enum class PrivateNetworkType {
TWENTY_FOUR_BIT_BLOCK {
// 10.x.x.x
override val broadcastAddress: String get() = TWENTY_FOUR_BIT_BROADCAST
override val constraints: Array<ByteConstraint> get() = TWENTY_FOUR_BIT_CONSTRAINTS
override val constraints: Array<IntConstraint> get() = TWENTY_FOUR_BIT_CONSTRAINTS
},
TWENTY_BIT_BLOCK {
// 172.16.x.x - 172.31.x.x
override val broadcastAddress: String get() = TWENTY_BIT_BROADCAST
override val constraints: Array<ByteConstraint> get() = TWENTY_BIT_CONSTRAINTS
override val constraints: Array<IntConstraint> get() = TWENTY_BIT_CONSTRAINTS
},
SIXTEEN_BIT_BLOCK {
// 192.168.x.x
override val broadcastAddress: String get() = SIXTEEN_BIT_BROADCAST
override val constraints: Array<ByteConstraint> get() = SIXTEEN_BIT_CONSTRAINTS
override val constraints: Array<IntConstraint> get() = SIXTEEN_BIT_CONSTRAINTS
};

abstract val broadcastAddress: String
internal abstract val constraints: Array<ByteConstraint>
internal abstract val constraints: Array<IntConstraint>

internal fun match(address: String): Boolean = address.split('.').run {
size == Int.SIZE_BYTES && zip(constraints).all { (byte, cons) -> cons.check(byte.toByte()) }
size == Int.SIZE_BYTES && zip(constraints).all { (byte, cons) -> cons.check(byte.toInt()) }
}

companion object {
private const val TWENTY_FOUR_BIT_BROADCAST = "10.255.255.255"
private const val TWENTY_BIT_BROADCAST = "172.31.255.255"
private const val SIXTEEN_BIT_BROADCAST = "192.168.255.255"

private val TWENTY_FOUR_BIT_CONSTRAINTS = arrayOf<ByteConstraint>(
ByteConstraint.Equals(10),
private val TWENTY_FOUR_BIT_CONSTRAINTS = arrayOf<IntConstraint>(
IntConstraint.Equals(10),
)

private val TWENTY_BIT_CONSTRAINTS = arrayOf(
ByteConstraint.Equals(-44),
ByteConstraint.Range(16 ..31),
IntConstraint.Equals(172),
IntConstraint.Range(16 ..31),
)

private val SIXTEEN_BIT_CONSTRAINTS = arrayOf<ByteConstraint>(
ByteConstraint.Equals(-64),
ByteConstraint.Equals(-88),
private val SIXTEEN_BIT_CONSTRAINTS = arrayOf<IntConstraint>(
IntConstraint.Equals(192),
IntConstraint.Equals(168),
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.property.Arb
import io.kotest.property.arbitrary.bind
import io.kotest.property.arbitrary.byte
import io.kotest.property.arbitrary.byteArray
import io.kotest.property.arbitrary.filter
import io.kotest.property.arbitrary.int
import io.kotest.property.arbitrary.intArray
import io.kotest.property.arbitrary.nonNegativeInt
import io.kotest.property.arbitrary.of
import io.kotest.property.arbitrary.pair
Expand All @@ -21,38 +20,36 @@ import io.kotest.property.checkAll

class PrivateNetworkTypeTest : DescribeSpec({
describe("PrivateNetworkType") {
val arbByte = Arb.nonNegativeInt(max = 0xFF)

data class TestSuite(
val testName: String,
val firstByte: Byte,
val arbBytes: Arb<Triple<Byte, Byte, Byte>>,
val firstByte: Int,
val arbBytes: Arb<Triple<Int, Int, Int>>,
val expectedType: PrivateNetworkType,
val expectedMatches: Triple<Boolean, Boolean, Boolean>,
val expectedBroadcastAddress: String,
)

val allTestSuites = arrayOf(
TestSuite(
"24-bit block",
10,
Arb.triple(Arb.byte(), Arb.byte(), Arb.byte()),
Arb.triple(arbByte, arbByte, arbByte),
PrivateNetworkType.TWENTY_FOUR_BIT_BLOCK,
Triple(true, false, false),
"10.255.255.255",
),
TestSuite(
"20-bit block",
-44,
Arb.triple(Arb.byte(min = 16, max = 31), Arb.byte(), Arb.byte()),
172,
Arb.triple(Arb.int(16..31), arbByte, arbByte),
PrivateNetworkType.TWENTY_BIT_BLOCK,
Triple(false, true, false),
"172.31.255.255",
),
TestSuite(
"16-bit block",
-64,
Arb.triple(Arb.of(-88), Arb.byte(), Arb.byte()),
192,
Arb.triple(Arb.of(168), arbByte, arbByte),
PrivateNetworkType.SIXTEEN_BIT_BLOCK,
Triple(false, false, true),
"192.168.255.255",
),
)
Expand All @@ -61,36 +58,36 @@ class PrivateNetworkTypeTest : DescribeSpec({
} shouldContainExactlyInAnyOrder PrivateNetworkType.entries

val invalidTestSuites = listOf(
"Too few bytes" to Arb.byteArray(Arb.nonNegativeInt(3), Arb.byte()),
"Too many bytes" to Arb.byteArray(Arb.int(5..UShort.MAX_VALUE.toInt()), Arb.byte()),
"Too few bytes" to Arb.intArray(Arb.nonNegativeInt(3), arbByte),
"Too many bytes" to Arb.intArray(Arb.int(5..UShort.MAX_VALUE.toInt()), arbByte),
"Not a private address" to Arb.bind(
Arb.pair(Arb.byte(), Arb.byte()).filter { (a, b) ->
a.toInt() != 10 &&
(a.toInt() != -44 || b !in 16..31) &&
(a.toInt() != -64 || b.toInt() != -88)
Arb.pair(arbByte, arbByte).filter { (a, b) ->
a != 10 && (a != 172 || b !in 16..31) && (a != 192 || b != 168)
},
Arb.pair(Arb.byte(), Arb.byte()),
) { (a, b), (c, d) -> byteArrayOf(a, b, c, d) },
Arb.pair(arbByte, arbByte),
) { (a, b), (c, d) -> intArrayOf(a, b, c, d) },
)

allTestSuites.forEach { suite ->
allTestSuites.forEachIndexed { suiteIndex, suite ->
val first = suite.firstByte
describe(suite.testName) {
withData(
nameFn = {
"${if (it.second) "Matches" else "Does not match"} ${it.first.testName}"
},
allTestSuites.zip(suite.expectedMatches.toList()),
allTestSuites.mapIndexed { index, otherSuite ->
otherSuite to (index == suiteIndex)
},
) { (testSuite, shouldMatch) ->
suite.arbBytes.checkAll { (second, third, fourth) ->
val address = byteArrayOf(first, second, third, fourth).joinToString(".")
val address = intArrayOf(first, second, third, fourth).joinToString(".")
testSuite.expectedType.match(address) shouldBeEqual shouldMatch
}
}

it("Defines correct network type") {
suite.arbBytes.checkAll { (second, third, fourth) ->
val address = byteArrayOf(first, second, third, fourth).joinToString(".")
val address = intArrayOf(first, second, third, fourth).joinToString(".")
PrivateNetworkType.of(address).shouldNotBeNull() shouldBeEqual
suite.expectedType
}
Expand Down

0 comments on commit 0ac3f83

Please sign in to comment.