|
| 1 | +package io.nekohasekai.sagernet.fmt.wireguard |
| 2 | + |
| 3 | +import com.esotericsoftware.kryo.io.ByteBufferOutput |
| 4 | +import io.nekohasekai.sagernet.fmt.KryoConverters |
| 5 | +import moe.matsuri.nb4a.utils.JavaUtil |
| 6 | +import org.junit.Assert.assertEquals |
| 7 | +import org.junit.Assert.assertFalse |
| 8 | +import org.junit.Assert.assertTrue |
| 9 | +import org.junit.Test |
| 10 | +import java.io.ByteArrayOutputStream |
| 11 | + |
| 12 | +class WireGuardFmtTest { |
| 13 | + |
| 14 | + @Test |
| 15 | + fun buildEndpointMapsCompleteFieldsAndDualStackAllowedIps() { |
| 16 | + val endpoint = buildSingBoxEndpointWireGuardBean(completeBean("[0, 1, 2]")) |
| 17 | + |
| 18 | + assertEquals("wireguard", endpoint.type) |
| 19 | + assertEquals(listOf("10.0.0.2/32", "fd00::2/128"), endpoint.address) |
| 20 | + assertTrue(TEST_PRIVATE_KEY == endpoint.private_key) |
| 21 | + assertEquals(1380, endpoint.mtu) |
| 22 | + assertEquals(51821, endpoint.listen_port) |
| 23 | + |
| 24 | + assertEquals(1, endpoint.peers.size) |
| 25 | + val peer = endpoint.peers.single() |
| 26 | + assertEquals("198.51.100.10", peer.address) |
| 27 | + assertEquals(51820, peer.port) |
| 28 | + assertEquals(TEST_PUBLIC_KEY, peer.public_key) |
| 29 | + assertTrue(TEST_PRE_SHARED_KEY == peer.pre_shared_key) |
| 30 | + assertEquals(listOf("0.0.0.0/0", "::/0"), peer.allowed_ips) |
| 31 | + assertEquals(25, peer.persistent_keepalive_interval) |
| 32 | + assertEquals("AAEC", peer.reserved) |
| 33 | + } |
| 34 | + |
| 35 | + @Test |
| 36 | + fun buildEndpointOmitsOptionalZeroAndBlankFieldsFromJson() { |
| 37 | + val bean = completeBean("").apply { |
| 38 | + serverAddress = "" |
| 39 | + serverPort = 0 |
| 40 | + peerPreSharedKey = "" |
| 41 | + mtu = 0 |
| 42 | + listenPort = 0 |
| 43 | + persistentKeepaliveInterval = 0 |
| 44 | + } |
| 45 | + |
| 46 | + val endpointJson = JavaUtil.gson.toJsonTree(buildSingBoxEndpointWireGuardBean(bean)).asJsonObject |
| 47 | + assertFalse(endpointJson.has("mtu")) |
| 48 | + assertFalse(endpointJson.has("listen_port")) |
| 49 | + |
| 50 | + val peerJson = endpointJson.getAsJsonArray("peers").single().asJsonObject |
| 51 | + assertFalse(peerJson.has("address")) |
| 52 | + assertFalse(peerJson.has("port")) |
| 53 | + assertFalse(peerJson.has("pre_shared_key")) |
| 54 | + assertFalse(peerJson.has("persistent_keepalive_interval")) |
| 55 | + assertFalse(peerJson.has("reserved")) |
| 56 | + } |
| 57 | + |
| 58 | + @Test |
| 59 | + fun genReservedConvertsThreeByteListFormsToBase64() { |
| 60 | + assertEquals("AAEC", genReserved("[0, 1, 2]")) |
| 61 | + assertEquals("AAEC", genReserved("0,\n1 2")) |
| 62 | + } |
| 63 | + |
| 64 | + @Test |
| 65 | + fun genReservedPreservesExistingBase64() { |
| 66 | + assertEquals("AAEC", genReserved("AAEC")) |
| 67 | + } |
| 68 | + |
| 69 | + @Test |
| 70 | + fun wireGuardBeanDeserializesVersionTwoWithNewFieldsDefaulted() { |
| 71 | + val bean = KryoConverters.deserialize(WireGuardBean(), versionTwoFixture()) |
| 72 | + |
| 73 | + assertEquals("198.51.100.10", bean.serverAddress) |
| 74 | + assertEquals(51820, bean.serverPort) |
| 75 | + assertEquals("10.0.0.2/32", bean.localAddress) |
| 76 | + assertTrue(TEST_PRIVATE_KEY == bean.privateKey) |
| 77 | + assertEquals(TEST_PUBLIC_KEY, bean.peerPublicKey) |
| 78 | + assertTrue(TEST_PRE_SHARED_KEY == bean.peerPreSharedKey) |
| 79 | + assertEquals(1380, bean.mtu) |
| 80 | + assertEquals("AAEC", bean.reserved) |
| 81 | + assertEquals(0, bean.listenPort) |
| 82 | + assertEquals(0, bean.persistentKeepaliveInterval) |
| 83 | + } |
| 84 | + |
| 85 | + private fun completeBean(reservedValue: String) = WireGuardBean().apply { |
| 86 | + serverAddress = "198.51.100.10" |
| 87 | + serverPort = 51820 |
| 88 | + localAddress = "10.0.0.2/32, fd00::2/128" |
| 89 | + privateKey = TEST_PRIVATE_KEY |
| 90 | + peerPublicKey = TEST_PUBLIC_KEY |
| 91 | + peerPreSharedKey = TEST_PRE_SHARED_KEY |
| 92 | + mtu = 1380 |
| 93 | + reserved = reservedValue |
| 94 | + listenPort = 51821 |
| 95 | + persistentKeepaliveInterval = 25 |
| 96 | + } |
| 97 | + |
| 98 | + private fun versionTwoFixture(): ByteArray { |
| 99 | + val bytes = ByteArrayOutputStream() |
| 100 | + val output = ByteBufferOutput(bytes) |
| 101 | + |
| 102 | + // WireGuardBean v2 payload. This deliberately does not call the current serializer. |
| 103 | + output.writeInt(2) |
| 104 | + output.writeString("198.51.100.10") |
| 105 | + output.writeInt(51820) |
| 106 | + output.writeString("10.0.0.2/32") |
| 107 | + output.writeString(TEST_PRIVATE_KEY) |
| 108 | + output.writeString(TEST_PUBLIC_KEY) |
| 109 | + output.writeString(TEST_PRE_SHARED_KEY) |
| 110 | + output.writeInt(1380) |
| 111 | + output.writeString("AAEC") |
| 112 | + |
| 113 | + // AbstractBean extra payload. |
| 114 | + output.writeInt(1) |
| 115 | + output.writeString("legacy-wireguard-test") |
| 116 | + output.writeString("") |
| 117 | + output.writeString("") |
| 118 | + output.flush() |
| 119 | + output.close() |
| 120 | + return bytes.toByteArray() |
| 121 | + } |
| 122 | + |
| 123 | + private companion object { |
| 124 | + // Deliberately invalid-for-production, deterministic fixture material. |
| 125 | + const val TEST_PRIVATE_KEY = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" |
| 126 | + const val TEST_PUBLIC_KEY = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" |
| 127 | + const val TEST_PRE_SHARED_KEY = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=" |
| 128 | + } |
| 129 | +} |
0 commit comments