Match temporary IPv6 flags using canonical address bytes

This commit is contained in:
evgeny committed 2026-10-29 13:35:19 +01:00
1 parent 268e8794ab
commit de907c697b
2 files changed
+36

No files matched your search

@@ -0,0 +1,13 @@
package com.utun.chat.data
/** /proc/net/if_inet6 использует 32 hex-цифры без сжатия нулей; IFA_F_TEMPORARY=0x20.
* Сопоставляется пара «интерфейс + 16 байтов адреса», прочие адреса/интерфейсы не меняют результат. */
internal fun temporaryIpv6Address(ifName: String, address: ByteArray, rows: Sequence<String>): Boolean {
require(address.size == 16) { "IPv6 address must contain 16 bytes" }
val hex = address.joinToString("") { (it.toInt() and 255).toString(16).padStart(2, '0') }
return rows.any { line ->
val fields = line.trim().split(Regex("\\s+"), limit = 6)
fields.size == 6 && fields[0].equals(hex, ignoreCase = true) && fields[5] == ifName &&
fields[4].toIntOrNull(16)?.let { it and 0x20 != 0 } == true
}
}
@@ -0,0 +1,23 @@
package com.utun.chat.data
import java.net.InetAddress
import org.junit.Assert.*
import org.junit.Test
class InterfaceAddressFlagsTest {
@Test fun compressedIpv6MustMatchKernelBytesRatherThanPaddingConcatenatedGroups() {
val address = InetAddress.getByName("2001:db8::1234").address
assertTrue(temporaryIpv6Address("wlan0", address, sequenceOf("20010db8000000000000000000001234 02 40 00 20 wlan0")))
}
@Test fun anotherInterfaceCannotMarkTheCurrentAddressTemporary() {
val address = InetAddress.getByName("2001:db8::1234").address
val rows = listOf("20010db8000000000000000000001234 02 40 00 20 mobile0",
"20010db8000000000000000000001234 03 40 00 80 wlan0")
assertFalse(temporaryIpv6Address("wlan0", address, rows.asSequence()))
}
@Test fun stableAddressDoesNotInheritFlagsFromAnotherAddressOnTheSameInterface() {
val rows = listOf("20010db8000000000000000000001234 02 40 00 20 wlan0",
"20010DB8000000000000000000005678 02 40 00 80 wlan0")
assertFalse(temporaryIpv6Address("wlan0", InetAddress.getByName("2001:db8::5678").address, rows.asSequence()))
}
}