blob: f830eb0f6b40c5f6c80304184f1b07afb7ecdc2b [file] [log] [blame]
Yuyang Huangae57be02023-10-16 17:49:31 +09001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.net.apf
17
Yuyang Huangc11962e2024-02-14 20:37:06 +090018import android.net.apf.ApfCounterTracker.Counter
Yuyang Huang5b7b05a2024-03-29 16:00:02 +090019import android.net.apf.ApfCounterTracker.Counter.DROPPED_ETHERTYPE_DENYLISTED
20import android.net.apf.ApfCounterTracker.Counter.DROPPED_ETH_BROADCAST
21import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP
Yuyang Huangc9a7a0e2024-04-08 21:22:53 +090022import android.net.apf.ApfCounterTracker.Counter.TOTAL_PACKETS
Yuyang Huangc11962e2024-02-14 20:37:06 +090023import android.net.apf.ApfTestUtils.DROP
Yuyang Huang2fdba242024-02-06 14:52:22 +090024import android.net.apf.ApfTestUtils.MIN_PKT_SIZE
Yuyang Huangc11962e2024-02-14 20:37:06 +090025import android.net.apf.ApfTestUtils.PASS
26import android.net.apf.ApfTestUtils.assertDrop
Yuyang Huang2fdba242024-02-06 14:52:22 +090027import android.net.apf.ApfTestUtils.assertPass
Yuyang Huangc11962e2024-02-14 20:37:06 +090028import android.net.apf.ApfTestUtils.assertVerdict
Yuyang Huang4057de52024-03-13 21:24:46 +090029import android.net.apf.BaseApfGenerator.APF_VERSION_4
Yuyang Huang2b402472024-02-13 16:31:55 +090030import android.net.apf.BaseApfGenerator.DROP_LABEL
Yuyang Huangbded8e32024-02-09 13:34:58 +090031import android.net.apf.BaseApfGenerator.IllegalInstructionException
Yuyang Huang12145c92024-02-09 07:20:15 +090032import android.net.apf.BaseApfGenerator.MIN_APF_VERSION
33import android.net.apf.BaseApfGenerator.MIN_APF_VERSION_IN_DEV
Yuyang Huang12145c92024-02-09 07:20:15 +090034import android.net.apf.BaseApfGenerator.Register.R0
35import android.net.apf.BaseApfGenerator.Register.R1
Yuyang Huangae57be02023-10-16 17:49:31 +090036import androidx.test.filters.SmallTest
37import androidx.test.runner.AndroidJUnit4
Yuyang Huang1a76ed72024-03-23 19:37:52 +090038import com.android.net.module.util.HexDump
Yuyang Huangbcfa09b2024-02-20 11:20:47 +090039import com.android.net.module.util.Struct
40import com.android.net.module.util.structs.EthernetHeader
41import com.android.net.module.util.structs.Ipv4Header
42import com.android.net.module.util.structs.UdpHeader
43import java.nio.ByteBuffer
Yuyang Huangae57be02023-10-16 17:49:31 +090044import kotlin.test.assertContentEquals
Yuyang Huangc11962e2024-02-14 20:37:06 +090045import kotlin.test.assertEquals
Yuyang Huangce1493a2023-12-07 15:29:40 +090046import kotlin.test.assertFailsWith
Yuyang Huang4f849692024-03-20 00:29:58 +090047import org.junit.After
Yuyang Huangae57be02023-10-16 17:49:31 +090048import org.junit.Test
49import org.junit.runner.RunWith
50
51/**
52 * Tests for APFv6 specific instructions.
53 */
54@RunWith(AndroidJUnit4::class)
55@SmallTest
56class ApfV5Test {
57
Yuyang Huang2283be72024-02-08 04:49:08 +090058 private val testPacket = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8,
59 9, 10, 11, 12, 13, 14, 15, 16)
60
Yuyang Huang4f849692024-03-20 00:29:58 +090061 @After
62 fun tearDown() {
63 ApfJniUtils.resetTransmittedPacketMemory()
64 }
65
Yuyang Huangae57be02023-10-16 17:49:31 +090066 @Test
Yuyang Huanga112cc82023-12-13 17:55:47 +090067 fun testDataInstructionMustComeFirst() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090068 var gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +090069 gen.addAllocateR0()
70 assertFailsWith<IllegalInstructionException> { gen.addData(ByteArray(3) { 0x01 }) }
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +090071 }
72
73 @Test
Yuyang Huang3ac843c2023-12-13 16:40:15 +090074 fun testApfInstructionEncodingSizeCheck() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090075 var gen = ApfV6Generator()
Yuyang Huang3def5232024-04-09 19:00:20 +090076 assertFailsWith<IllegalArgumentException> { ApfV6Generator(ByteArray(65536) { 0x01 }) }
Yuyang Huang3ac843c2023-12-13 16:40:15 +090077 assertFailsWith<IllegalArgumentException> { gen.addAllocate(65536) }
78 assertFailsWith<IllegalArgumentException> { gen.addAllocate(-1) }
Yuyang Huang293f7e72023-12-31 14:24:03 +090079 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(-1, 1) }
80 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(-1, 1) }
81 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, 256) }
82 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, 256) }
83 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, -1) }
84 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, -1) }
Yuyang Huangd0390612024-01-01 16:21:16 +090085 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(256) }
86 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(256) }
Yuyang Huang96697842024-01-02 21:53:48 +090087 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(-1) }
88 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(-1) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090089 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090090 byteArrayOf(1, 'A'.code.toByte(), 0, 0),
91 256,
92 ApfV4Generator.DROP_LABEL
93 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090094 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090095 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
96 0x0c,
97 ApfV4Generator.DROP_LABEL
98 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090099 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900100 byteArrayOf(1, '.'.code.toByte(), 0, 0),
101 0x0c,
102 ApfV4Generator.DROP_LABEL
103 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900104 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900105 byteArrayOf(0, 0),
106 0xc0,
107 ApfV4Generator.DROP_LABEL
108 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900109 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900110 byteArrayOf(1, 'A'.code.toByte()),
111 0xc0,
112 ApfV4Generator.DROP_LABEL
113 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900114 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
115 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900116 0xc0,
117 ApfV4Generator.DROP_LABEL
118 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900119 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
120 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900121 0xc0,
122 ApfV4Generator.DROP_LABEL
123 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900124 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
125 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900126 0xc0,
127 ApfV4Generator.DROP_LABEL
128 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900129 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900130 byteArrayOf(1, 'A'.code.toByte(), 0, 0),
131 256,
132 ApfV4Generator.DROP_LABEL
133 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900134 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900135 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
136 0x0c,
137 ApfV4Generator.DROP_LABEL
138 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900139 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900140 byteArrayOf(1, '.'.code.toByte(), 0, 0),
141 0x0c,
142 ApfV4Generator.DROP_LABEL
143 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900144 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900145 byteArrayOf(0, 0),
146 0xc0,
147 ApfV4Generator.DROP_LABEL
148 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900149 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900150 byteArrayOf(1, 'A'.code.toByte()),
151 0xc0,
152 ApfV4Generator.DROP_LABEL
153 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900154 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
155 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900156 0xc0,
157 ApfV4Generator.DROP_LABEL
158 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900159 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
160 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900161 0xc0,
162 ApfV4Generator.DROP_LABEL
163 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900164 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
165 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900166 0xc0,
167 ApfV4Generator.DROP_LABEL
168 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900169 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900170 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
171 ApfV4Generator.DROP_LABEL
172 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900173 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900174 byteArrayOf(1, '.'.code.toByte(), 0, 0),
175 ApfV4Generator.DROP_LABEL
176 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900177 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900178 byteArrayOf(0, 0),
179 ApfV4Generator.DROP_LABEL
180 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900181 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900182 byteArrayOf(1, 'A'.code.toByte()),
183 ApfV4Generator.DROP_LABEL
184 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900185 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
186 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900187 ApfV4Generator.DROP_LABEL
188 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900189 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
190 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900191 ApfV4Generator.DROP_LABEL
192 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900193 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
194 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900195 ApfV4Generator.DROP_LABEL
196 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900197 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900198 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
199 ApfV4Generator.DROP_LABEL
200 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900201 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900202 byteArrayOf(1, '.'.code.toByte(), 0, 0),
203 ApfV4Generator.DROP_LABEL
204 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900205 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900206 byteArrayOf(0, 0),
207 ApfV4Generator.DROP_LABEL
208 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900209 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900210 byteArrayOf(1, 'A'.code.toByte()),
211 ApfV4Generator.DROP_LABEL
212 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900213 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
214 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900215 ApfV4Generator.DROP_LABEL
216 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900217 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
218 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900219 ApfV4Generator.DROP_LABEL
220 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900221 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
222 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900223 ApfV4Generator.DROP_LABEL
224 ) }
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900225 assertFailsWith<IllegalArgumentException> { gen.addCountAndDrop(PASSED_ARP) }
226 assertFailsWith<IllegalArgumentException> { gen.addCountAndPass(DROPPED_ETH_BROADCAST) }
Yuyang Huangd4f5fa82024-03-30 09:17:34 +0900227 assertFailsWith<IllegalArgumentException> {
228 gen.addCountAndDropIfR0Equals(3, PASSED_ARP)
229 }
230 assertFailsWith<IllegalArgumentException> {
231 gen.addCountAndPassIfR0Equals(3, DROPPED_ETH_BROADCAST)
232 }
233 assertFailsWith<IllegalArgumentException> {
234 gen.addCountAndDropIfR0NotEquals(3, PASSED_ARP)
235 }
236 assertFailsWith<IllegalArgumentException> {
237 gen.addCountAndPassIfR0NotEquals(3, DROPPED_ETH_BROADCAST)
238 }
239 assertFailsWith<IllegalArgumentException> {
240 gen.addCountAndDropIfR0LessThan(3, PASSED_ARP)
241 }
242 assertFailsWith<IllegalArgumentException> {
243 gen.addCountAndPassIfR0LessThan(3, DROPPED_ETH_BROADCAST)
244 }
Yuyang Huang6f159d22024-03-31 17:35:23 +0900245 assertFailsWith<IllegalArgumentException> {
Yuyang Huang26758952024-04-03 23:58:29 +0900246 gen.addCountAndDropIfBytesAtR0NotEqual(byteArrayOf(1), PASSED_ARP)
247 }
248 assertFailsWith<IllegalArgumentException> {
Yuyang Huang6f159d22024-03-31 17:35:23 +0900249 gen.addWrite32(byteArrayOf())
250 }
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900251
252 val v4gen = ApfV4Generator(APF_VERSION_4)
253 assertFailsWith<IllegalArgumentException> { v4gen.addCountAndDrop(PASSED_ARP) }
254 assertFailsWith<IllegalArgumentException> { v4gen.addCountAndPass(DROPPED_ETH_BROADCAST) }
Yuyang Huangd4f5fa82024-03-30 09:17:34 +0900255 assertFailsWith<IllegalArgumentException> {
256 v4gen.addCountAndDropIfR0Equals(3, PASSED_ARP)
257 }
258 assertFailsWith<IllegalArgumentException> {
259 v4gen.addCountAndPassIfR0Equals(3, DROPPED_ETH_BROADCAST)
260 }
261 assertFailsWith<IllegalArgumentException> {
262 v4gen.addCountAndDropIfR0NotEquals(3, PASSED_ARP)
263 }
264 assertFailsWith<IllegalArgumentException> {
265 v4gen.addCountAndPassIfR0NotEquals(3, DROPPED_ETH_BROADCAST)
266 }
267 assertFailsWith<IllegalArgumentException> {
268 v4gen.addCountAndDropIfR0LessThan(3, PASSED_ARP)
269 }
270 assertFailsWith<IllegalArgumentException> {
271 v4gen.addCountAndPassIfR0LessThan(3, DROPPED_ETH_BROADCAST)
272 }
Yuyang Huang26758952024-04-03 23:58:29 +0900273 assertFailsWith<IllegalArgumentException> {
274 v4gen.addCountAndDropIfBytesAtR0NotEqual(byteArrayOf(1), PASSED_ARP)
275 }
Yuyang Huangce1493a2023-12-07 15:29:40 +0900276 }
277
278 @Test
Yuyang Huang2b402472024-02-13 16:31:55 +0900279 fun testValidateDnsNames() {
280 // '%' is a valid label character in mDNS subtype
Yuyang Huangb31cef22024-02-13 16:43:33 +0900281 // byte == 0xff means it is a '*' wildcard, which is a valid encoding.
Yuyang Huang2b402472024-02-13 16:31:55 +0900282 val program = ApfV6Generator().addJumpIfPktAtR0ContainDnsQ(
283 byteArrayOf(1, '%'.code.toByte(), 0, 0),
284 1,
Yuyang Huang22c76a82024-03-21 19:11:43 +0900285 DROP_LABEL
286 ).addJumpIfPktAtR0ContainDnsA(
287 byteArrayOf(0xff.toByte(), 1, 'B'.code.toByte(), 0, 0),
288 DROP_LABEL
289 ).generate()
Yuyang Huang2b402472024-02-13 16:31:55 +0900290 }
291
292 @Test
Yuyang Huangae57be02023-10-16 17:49:31 +0900293 fun testApfInstructionsEncoding() {
Yuyang Huang9b6be762024-02-22 17:06:51 +0900294 val v4gen = ApfV4Generator(MIN_APF_VERSION)
Yuyang Huangafe7b652024-02-09 09:45:01 +0900295 v4gen.addPass()
296 var program = v4gen.generate()
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900297 // encoding PASS opcode: opcode=0, imm_len=0, R=0
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900298 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900299 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 0)),
300 program
301 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900302 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900303 listOf("0: pass"),
304 ApfJniUtils.disassembleApf(program).map { it.trim() }
305 )
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900306
Yuyang Huangafe7b652024-02-09 09:45:01 +0900307 var gen = ApfV6Generator()
Yuyang Huangce1493a2023-12-07 15:29:40 +0900308 gen.addDrop()
Yuyang Huang3def5232024-04-09 19:00:20 +0900309 program = gen.generate().skipEmptyData()
Yuyang Huangce1493a2023-12-07 15:29:40 +0900310 // encoding DROP opcode: opcode=0, imm_len=0, R=1
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900311 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900312 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 1)),
313 program
314 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900315 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900316 listOf("0: drop"),
317 ApfJniUtils.disassembleApf(program).map { it.trim() }
318 )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900319
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900320 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900321 gen.addCountAndPass(129)
Yuyang Huang3def5232024-04-09 19:00:20 +0900322 program = gen.generate().skipEmptyData()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900323 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
324 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900325 byteArrayOf(
326 encodeInstruction(opcode = 0, immLength = 1, register = 0),
327 0x81.toByte()
328 ),
329 program
330 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900331 assertContentEquals(
Yuyang Huangf785c922024-04-09 01:26:41 +0900332 listOf("0: pass counter=129"),
Yuyang Huanged30e492024-03-21 19:17:40 +0900333 ApfJniUtils.disassembleApf(program).map { it.trim() }
334 )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900335
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900336 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900337 gen.addCountAndDrop(1000)
Yuyang Huang3def5232024-04-09 19:00:20 +0900338 program = gen.generate().skipEmptyData()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900339 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
340 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900341 byteArrayOf(
342 encodeInstruction(opcode = 0, immLength = 2, register = 1),
343 0x03,
344 0xe8.toByte()
345 ),
346 program
347 )
Yuyang Huang98b99f22024-01-29 06:35:27 +0900348 assertContentEquals(
Yuyang Huangf785c922024-04-09 01:26:41 +0900349 listOf("0: drop counter=1000"),
Yuyang Huanged30e492024-03-21 19:17:40 +0900350 ApfJniUtils.disassembleApf(program).map { it.trim() }
351 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900352
353 gen = ApfV6Generator()
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900354 gen.addCountAndPass(PASSED_ARP)
Yuyang Huang3def5232024-04-09 19:00:20 +0900355 program = gen.generate().skipEmptyData()
Yuyang Huang4057de52024-03-13 21:24:46 +0900356 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
357 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900358 byteArrayOf(
359 encodeInstruction(opcode = 0, immLength = 1, register = 0),
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900360 PASSED_ARP.value().toByte()
Yuyang Huanged30e492024-03-21 19:17:40 +0900361 ),
362 program
363 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900364 assertContentEquals(
Yuyang Huangf785c922024-04-09 01:26:41 +0900365 listOf("0: pass counter=10"),
Yuyang Huanged30e492024-03-21 19:17:40 +0900366 ApfJniUtils.disassembleApf(program).map { it.trim() }
367 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900368
369 gen = ApfV6Generator()
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900370 gen.addCountAndDrop(DROPPED_ETHERTYPE_DENYLISTED)
Yuyang Huang3def5232024-04-09 19:00:20 +0900371 program = gen.generate().skipEmptyData()
Yuyang Huang4057de52024-03-13 21:24:46 +0900372 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
373 assertContentEquals(
Yuyang Huanged30e492024-03-21 19:17:40 +0900374 byteArrayOf(
375 encodeInstruction(opcode = 0, immLength = 1, register = 1),
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900376 DROPPED_ETHERTYPE_DENYLISTED.value().toByte()
Yuyang Huanged30e492024-03-21 19:17:40 +0900377 ),
378 program
379 )
Yuyang Huang4057de52024-03-13 21:24:46 +0900380 assertContentEquals(
Yuyang Huangf785c922024-04-09 01:26:41 +0900381 listOf("0: drop counter=37"),
Yuyang Huanged30e492024-03-21 19:17:40 +0900382 ApfJniUtils.disassembleApf(program).map { it.trim() }
383 )
Yuyang Huangce1493a2023-12-07 15:29:40 +0900384
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900385 gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900386 gen.addAllocateR0()
387 gen.addAllocate(1500)
Yuyang Huang3def5232024-04-09 19:00:20 +0900388 program = gen.generate().skipEmptyData()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900389 // encoding ALLOC opcode: opcode=21(EXT opcode number), imm=36(TRANS opcode number).
390 // R=0 means length stored in R0. R=1 means the length stored in imm1.
Yuyang Huanged30e492024-03-21 19:17:40 +0900391 assertContentEquals(
392 byteArrayOf(
393 encodeInstruction(opcode = 21, immLength = 1, register = 0),
394 36,
395 encodeInstruction(opcode = 21, immLength = 1, register = 1),
396 36,
397 0x05,
398 0xDC.toByte()
399 ),
400 program
401 )
402 assertContentEquals(listOf(
403 "0: allocate r0",
404 "2: allocate 1500"
405 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900406
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900407 gen = ApfV6Generator()
Yuyang Huangfb803682024-02-20 17:52:27 +0900408 gen.addTransmitWithoutChecksum()
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900409 gen.addTransmitL4(30, 40, 50, 256, true)
Yuyang Huang3def5232024-04-09 19:00:20 +0900410 program = gen.generate().skipEmptyData()
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800411 // encoding TRANSMIT opcode: opcode=21(EXT opcode number),
412 // imm=37(TRANSMIT opcode number),
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900413 assertContentEquals(byteArrayOf(
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800414 encodeInstruction(opcode = 21, immLength = 1, register = 0),
415 37, 255.toByte(), 255.toByte(),
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900416 encodeInstruction(opcode = 21, immLength = 1, register = 1), 37, 30, 40, 50, 1, 0
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900417 ), program)
Yuyang Huanged30e492024-03-21 19:17:40 +0900418 assertContentEquals(listOf(
419 "0: transmit ip_ofs=255",
420 "4: transmitudp ip_ofs=30, csum_ofs=40, csum_start=50, partial_csum=0x0100",
421 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900422
Yuyang Huanga112cc82023-12-13 17:55:47 +0900423 val largeByteArray = ByteArray(256) { 0x01 }
Yuyang Huang3def5232024-04-09 19:00:20 +0900424 gen = ApfV6Generator(largeByteArray)
Yuyang Huanga112cc82023-12-13 17:55:47 +0900425 program = gen.generate()
426 // encoding DATA opcode: opcode=14(JMP), R=1
Yuyang Huanged30e492024-03-21 19:17:40 +0900427 assertContentEquals(
428 byteArrayOf(
429 encodeInstruction(opcode = 14, immLength = 2, register = 1),
430 0x01,
431 0x00
432 ) + largeByteArray,
433 program
434 )
435 assertContentEquals(
436 listOf("0: data 256, " + "01".repeat(256) ),
437 ApfJniUtils.disassembleApf(program).map { it.trim() }
438 )
Yuyang Huanga112cc82023-12-13 17:55:47 +0900439
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900440 gen = ApfV6Generator()
Yuyang Huangadf69672024-01-02 10:18:11 +0900441 gen.addWriteU8(0x01)
442 gen.addWriteU16(0x0102)
443 gen.addWriteU32(0x01020304)
444 gen.addWriteU8(0x00)
445 gen.addWriteU8(0x80)
446 gen.addWriteU16(0x0000)
447 gen.addWriteU16(0x8000)
448 gen.addWriteU32(0x00000000)
449 gen.addWriteU32(0x80000000)
Yuyang Huang403f1ce2024-03-31 17:35:23 +0900450 gen.addWrite32(-2)
Yuyang Huang6f159d22024-03-31 17:35:23 +0900451 gen.addWrite32(byteArrayOf(0xff.toByte(), 0xfe.toByte(), 0xfd.toByte(), 0xfc.toByte()))
Yuyang Huang3def5232024-04-09 19:00:20 +0900452 program = gen.generate().skipEmptyData()
Yuyang Huang4ac891f2023-12-20 11:49:11 +0900453 assertContentEquals(byteArrayOf(
454 encodeInstruction(24, 1, 0), 0x01,
455 encodeInstruction(24, 2, 0), 0x01, 0x02,
456 encodeInstruction(24, 4, 0), 0x01, 0x02, 0x03, 0x04,
457 encodeInstruction(24, 1, 0), 0x00,
458 encodeInstruction(24, 1, 0), 0x80.toByte(),
459 encodeInstruction(24, 2, 0), 0x00, 0x00,
460 encodeInstruction(24, 2, 0), 0x80.toByte(), 0x00,
461 encodeInstruction(24, 4, 0), 0x00, 0x00, 0x00, 0x00,
Yuyang Huang403f1ce2024-03-31 17:35:23 +0900462 encodeInstruction(24, 4, 0), 0x80.toByte(), 0x00, 0x00, 0x00,
463 encodeInstruction(24, 4, 0), 0xff.toByte(), 0xff.toByte(),
Yuyang Huang6f159d22024-03-31 17:35:23 +0900464 0xff.toByte(), 0xfe.toByte(),
465 encodeInstruction(24, 4, 0), 0xff.toByte(), 0xfe.toByte(),
466 0xfd.toByte(), 0xfc.toByte()), program)
Yuyang Huang7affd672024-01-29 13:04:43 +0900467 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900468 "0: write 0x01",
469 "2: write 0x0102",
470 "5: write 0x01020304",
471 "10: write 0x00",
472 "12: write 0x80",
473 "14: write 0x0000",
474 "17: write 0x8000",
475 "20: write 0x00000000",
Yuyang Huang403f1ce2024-03-31 17:35:23 +0900476 "25: write 0x80000000",
Yuyang Huang6f159d22024-03-31 17:35:23 +0900477 "30: write 0xfffffffe",
478 "35: write 0xfffefdfc"
Yuyang Huanged30e492024-03-21 19:17:40 +0900479 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huange84a9692024-01-01 11:49:49 +0900480
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900481 gen = ApfV6Generator()
Yuyang Huange84a9692024-01-01 11:49:49 +0900482 gen.addWriteU8(R0)
483 gen.addWriteU16(R0)
484 gen.addWriteU32(R0)
485 gen.addWriteU8(R1)
486 gen.addWriteU16(R1)
487 gen.addWriteU32(R1)
Yuyang Huang3def5232024-04-09 19:00:20 +0900488 program = gen.generate().skipEmptyData()
Yuyang Huange84a9692024-01-01 11:49:49 +0900489 assertContentEquals(byteArrayOf(
490 encodeInstruction(21, 1, 0), 38,
491 encodeInstruction(21, 1, 0), 39,
492 encodeInstruction(21, 1, 0), 40,
493 encodeInstruction(21, 1, 1), 38,
494 encodeInstruction(21, 1, 1), 39,
495 encodeInstruction(21, 1, 1), 40
496 ), program)
Yuyang Huangf0b46cb2024-01-30 03:37:17 +0900497 assertContentEquals(listOf(
498 "0: ewrite1 r0",
499 "2: ewrite2 r0",
500 "4: ewrite4 r0",
501 "6: ewrite1 r1",
502 "8: ewrite2 r1",
Yuyang Huanged30e492024-03-21 19:17:40 +0900503 "10: ewrite4 r1"
504 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900505
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900506 gen = ApfV6Generator()
Yuyang Huang293f7e72023-12-31 14:24:03 +0900507 gen.addDataCopy(0, 10)
508 gen.addDataCopy(1, 5)
509 gen.addPacketCopy(1000, 255)
Yuyang Huang3def5232024-04-09 19:00:20 +0900510 program = gen.generate().skipEmptyData()
Yuyang Huang293f7e72023-12-31 14:24:03 +0900511 assertContentEquals(byteArrayOf(
512 encodeInstruction(25, 0, 1), 10,
513 encodeInstruction(25, 1, 1), 1, 5,
514 encodeInstruction(25, 2, 0),
515 0x03.toByte(), 0xe8.toByte(), 0xff.toByte(),
516 ), program)
Yuyang Huange8003982024-01-30 04:06:18 +0900517 assertContentEquals(listOf(
Yuyang Huangb2a93342024-02-07 06:32:00 +0900518 "0: datacopy src=0, len=10",
519 "2: datacopy src=1, len=5",
520 "5: pktcopy src=1000, len=255"
Yuyang Huanged30e492024-03-21 19:17:40 +0900521 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang293f7e72023-12-31 14:24:03 +0900522
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900523 gen = ApfV6Generator()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900524 gen.addDataCopyFromR0(5)
Yuyang Huangd0390612024-01-01 16:21:16 +0900525 gen.addPacketCopyFromR0(5)
526 gen.addDataCopyFromR0LenR1()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900527 gen.addPacketCopyFromR0LenR1()
Yuyang Huang3def5232024-04-09 19:00:20 +0900528 program = gen.generate().skipEmptyData()
Yuyang Huangd0390612024-01-01 16:21:16 +0900529 assertContentEquals(byteArrayOf(
Yuyang Huangbed904a2024-01-30 11:22:49 +0900530 encodeInstruction(21, 1, 1), 41, 5,
Yuyang Huangd0390612024-01-01 16:21:16 +0900531 encodeInstruction(21, 1, 0), 41, 5,
532 encodeInstruction(21, 1, 1), 42,
Yuyang Huangbed904a2024-01-30 11:22:49 +0900533 encodeInstruction(21, 1, 0), 42,
Yuyang Huangd0390612024-01-01 16:21:16 +0900534 ), program)
Yuyang Huangbed904a2024-01-30 11:22:49 +0900535 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900536 "0: edatacopy src=r0, len=5",
537 "3: epktcopy src=r0, len=5",
538 "6: edatacopy src=r0, len=r1",
539 "8: epktcopy src=r0, len=r1"
540 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900541
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900542 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900543 gen.addJumpIfBytesAtR0Equal(byteArrayOf('a'.code.toByte()), ApfV4Generator.DROP_LABEL)
Yuyang Huang3def5232024-04-09 19:00:20 +0900544 program = gen.generate().skipEmptyData()
Yuyang Huanged30e492024-03-21 19:17:40 +0900545 assertContentEquals(byteArrayOf(
546 encodeInstruction(opcode = 20, immLength = 1, register = 1),
547 1,
548 1,
549 'a'.code.toByte()
550 ), program)
Yuyang Huangbffcf262024-02-04 07:52:48 +0900551 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900552 "0: jbseq r0, 0x1, DROP, 61"
553 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900554
555 val qnames = byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0, 0)
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900556 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900557 gen.addJumpIfPktAtR0DoesNotContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
558 gen.addJumpIfPktAtR0ContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
Yuyang Huang3def5232024-04-09 19:00:20 +0900559 program = gen.generate().skipEmptyData()
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900560 assertContentEquals(byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900561 encodeInstruction(21, 1, 0), 43, 11, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900562 ) + qnames + byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900563 encodeInstruction(21, 1, 1), 43, 1, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900564 ) + qnames, program)
Yuyang Huang49ab8822024-02-04 09:39:00 +0900565 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900566 "0: jdnsqne r0, DROP, 12, (1)A(1)B(0)(0)",
567 "10: jdnsqeq r0, DROP, 12, (1)A(1)B(0)(0)"
568 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900569
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900570 gen = ApfV6Generator()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900571 gen.addJumpIfPktAtR0DoesNotContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
572 gen.addJumpIfPktAtR0ContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
Yuyang Huang3def5232024-04-09 19:00:20 +0900573 program = gen.generate().skipEmptyData()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900574 assertContentEquals(byteArrayOf(
575 encodeInstruction(21, 1, 0), 45, 11, 0x0c.toByte(),
576 ) + qnames + byteArrayOf(
577 encodeInstruction(21, 1, 1), 45, 1, 0x0c.toByte(),
578 ) + qnames, program)
579 assertContentEquals(listOf(
580 "0: jdnsqnesafe r0, DROP, 12, (1)A(1)B(0)(0)",
Yuyang Huanged30e492024-03-21 19:17:40 +0900581 "10: jdnsqeqsafe r0, DROP, 12, (1)A(1)B(0)(0)"
582 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900583
584 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900585 gen.addJumpIfPktAtR0DoesNotContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
586 gen.addJumpIfPktAtR0ContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
Yuyang Huang3def5232024-04-09 19:00:20 +0900587 program = gen.generate().skipEmptyData()
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900588 assertContentEquals(byteArrayOf(
589 encodeInstruction(21, 1, 0), 44, 10,
590 ) + qnames + byteArrayOf(
591 encodeInstruction(21, 1, 1), 44, 1,
592 ) + qnames, program)
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900593 assertContentEquals(listOf(
Yuyang Huanged30e492024-03-21 19:17:40 +0900594 "0: jdnsane r0, DROP, (1)A(1)B(0)(0)",
595 "9: jdnsaeq r0, DROP, (1)A(1)B(0)(0)"
596 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900597
598 gen = ApfV6Generator()
599 gen.addJumpIfPktAtR0DoesNotContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
600 gen.addJumpIfPktAtR0ContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
Yuyang Huang3def5232024-04-09 19:00:20 +0900601 program = gen.generate().skipEmptyData()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900602 assertContentEquals(byteArrayOf(
603 encodeInstruction(21, 1, 0), 46, 10,
604 ) + qnames + byteArrayOf(
605 encodeInstruction(21, 1, 1), 46, 1,
606 ) + qnames, program)
607 assertContentEquals(listOf(
608 "0: jdnsanesafe r0, DROP, (1)A(1)B(0)(0)",
Yuyang Huanged30e492024-03-21 19:17:40 +0900609 "9: jdnsaeqsafe r0, DROP, (1)A(1)B(0)(0)"
610 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900611 }
612
Yuyang Huang2fdba242024-02-06 14:52:22 +0900613 @Test
614 fun testWriteToTxBuffer() {
Yuyang Huangbded8e32024-02-09 13:34:58 +0900615 var program = ApfV6Generator()
Yuyang Huang4be28bb2024-04-05 16:33:43 +0900616 .addAllocate(14)
617 .addWriteU8(0x01)
618 .addWriteU16(0x0203)
619 .addWriteU32(0x04050607)
620 .addWrite32(-2)
621 .addWrite32(byteArrayOf(0xff.toByte(), 0xfe.toByte(), 0xfd.toByte(), 0xfc.toByte()))
622 .addLoadImmediate(R0, 1)
623 .addWriteU8(R0)
624 .addLoadImmediate(R0, 0x0203)
625 .addWriteU16(R0)
626 .addLoadImmediate(R1, 0x04050607)
627 .addWriteU32(R1)
628 .addTransmitWithoutChecksum()
629 .generate()
Yuyang Huangbded8e32024-02-09 13:34:58 +0900630 assertPass(MIN_APF_VERSION_IN_DEV, program, ByteArray(MIN_PKT_SIZE))
Yuyang Huang6f159d22024-03-31 17:35:23 +0900631 assertContentEquals(
632 byteArrayOf(
633 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff.toByte(),
634 0xff.toByte(), 0xff.toByte(), 0xfe.toByte(), 0xff.toByte(), 0xfe.toByte(),
635 0xfd.toByte(), 0xfc.toByte(), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07),
636 ApfJniUtils.getTransmittedPacket()
637 )
Yuyang Huang2fdba242024-02-06 14:52:22 +0900638 }
639
Yuyang Huang2283be72024-02-08 04:49:08 +0900640 @Test
641 fun testCopyToTxBuffer() {
Yuyang Huang3def5232024-04-09 19:00:20 +0900642 var program = ApfV6Generator(byteArrayOf(33, 34, 35))
Yuyang Huang87750392024-03-22 10:40:06 +0900643 .addAllocate(14)
644 .addDataCopy(3, 2) // arg1=src, arg2=len
645 .addDataCopy(5, 1) // arg1=src, arg2=len
646 .addPacketCopy(0, 1) // arg1=src, arg2=len
647 .addPacketCopy(1, 3) // arg1=src, arg2=len
648 .addLoadImmediate(R0, 3) // data copy offset
649 .addDataCopyFromR0(2) // len
650 .addLoadImmediate(R0, 5) // data copy offset
651 .addLoadImmediate(R1, 1) // len
652 .addDataCopyFromR0LenR1()
653 .addLoadImmediate(R0, 0) // packet copy offset
654 .addPacketCopyFromR0(1) // len
655 .addLoadImmediate(R0, 1) // packet copy offset
656 .addLoadImmediate(R1, 3) // len
657 .addPacketCopyFromR0LenR1()
658 .addTransmitWithoutChecksum()
659 .generate()
Yuyang Huang2283be72024-02-08 04:49:08 +0900660 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
Yuyang Huang87750392024-03-22 10:40:06 +0900661 assertContentEquals(
662 byteArrayOf(33, 34, 35, 1, 2, 3, 4, 33, 34, 35, 1, 2, 3, 4),
663 ApfJniUtils.getTransmittedPacket()
664 )
Yuyang Huang2283be72024-02-08 04:49:08 +0900665 }
666
Yuyang Huangc11962e2024-02-14 20:37:06 +0900667 @Test
Yuyang Huang1a76ed72024-03-23 19:37:52 +0900668 fun testCopyContentToTxBuffer() {
669 val program = ApfV6Generator()
Yuyang Huang1a76ed72024-03-23 19:37:52 +0900670 .addAllocate(18)
671 .addDataCopy(HexDump.hexStringToByteArray("112233445566"))
672 .addDataCopy(HexDump.hexStringToByteArray("223344"))
673 .addDataCopy(HexDump.hexStringToByteArray("778899"))
674 .addDataCopy(HexDump.hexStringToByteArray("112233445566"))
675 .addTransmitWithoutChecksum()
676 .generate()
677 assertContentEquals(listOf(
678 "0: data 9, 112233445566778899",
679 "12: allocate 18",
680 "16: datacopy src=3, len=6",
681 "19: datacopy src=4, len=3",
682 "22: datacopy src=9, len=3",
683 "25: datacopy src=3, len=6",
684 "28: transmit ip_ofs=255"
685 ), ApfJniUtils.disassembleApf(program).map{ it.trim() })
686 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
687 val transmitPkt = HexDump.toHexString(ApfJniUtils.getTransmittedPacket())
688 assertEquals("112233445566223344778899112233445566", transmitPkt)
689 }
690
691 @Test
Yuyang Huangc11962e2024-02-14 20:37:06 +0900692 fun testPassDrop() {
693 var program = ApfV6Generator()
694 .addDrop()
695 .addPass()
696 .generate()
697 assertDrop(MIN_APF_VERSION_IN_DEV, program, testPacket)
698
699 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
700 program = ApfV6Generator()
Yuyang Huang4057de52024-03-13 21:24:46 +0900701 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900702 .generate()
703 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
704 var counterMap = decodeCountersIntoMap(dataRegion)
705 assertEquals(mapOf<Counter, Long>(
706 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900707 Counter.DROPPED_ETH_BROADCAST to 1
708 ), counterMap)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900709
710 dataRegion = ByteArray(Counter.totalSize()) { 0 }
711 program = ApfV6Generator()
Yuyang Huang4057de52024-03-13 21:24:46 +0900712 .addCountAndPass(Counter.PASSED_ARP)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900713 .generate()
714 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
715 counterMap = decodeCountersIntoMap(dataRegion)
716 assertEquals(mapOf<Counter, Long>(
717 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900718 Counter.PASSED_ARP to 1
719 ), counterMap)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900720 }
721
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900722 @Test
Yuyang Huangc9a7a0e2024-04-08 21:22:53 +0900723 fun testLoadStoreCounter() {
724 doTestLoadStoreCounter (
725 { mutableMapOf() },
726 { ApfV4Generator(APF_VERSION_4) }
727 )
728 doTestLoadStoreCounter (
729 { mutableMapOf(TOTAL_PACKETS to 1) },
730 { ApfV6Generator() }
731 )
732 }
733
734 private fun doTestLoadStoreCounter(
735 getInitialMap: () -> MutableMap<Counter, Long>,
736 getGenerator: () -> ApfV4GeneratorBase<*>
737 ) {
738 val program = getGenerator()
739 .addIncrementCounter(PASSED_ARP, 2)
740 .addPass()
741 .generate()
742 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
743 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
744 var counterMap = decodeCountersIntoMap(dataRegion)
745 var expectedMap = getInitialMap()
746 expectedMap[PASSED_ARP] = 2
747 assertEquals(expectedMap, counterMap)
748 }
749
750 @Test
Yuyang Huangd9cbb652024-03-20 21:00:13 +0900751 fun testCountAndPassDropCompareR0() {
752 doTestCountAndPassDropCompareR0(
753 { mutableMapOf() },
754 { ApfV4Generator(APF_VERSION_4) }
755 )
756 doTestCountAndPassDropCompareR0(
757 { mutableMapOf(Counter.TOTAL_PACKETS to 1) },
Yuyang Huang3def5232024-04-09 19:00:20 +0900758 { ApfV6Generator() }
Yuyang Huangd9cbb652024-03-20 21:00:13 +0900759 )
760 }
761
762 private fun doTestCountAndPassDropCompareR0(
763 getInitialMap: () -> MutableMap<Counter, Long>,
764 getGenerator: () -> ApfV4GeneratorBase<*>
765 ) {
766 var program = getGenerator()
767 .addLoadImmediate(R0, 123)
768 .addCountAndDropIfR0Equals(123, Counter.DROPPED_ETH_BROADCAST)
769 .addPass()
770 .addCountTrampoline()
771 .generate()
772 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
773 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
774 var counterMap = decodeCountersIntoMap(dataRegion)
775 var expectedMap = getInitialMap()
776 expectedMap[Counter.DROPPED_ETH_BROADCAST] = 1
777 assertEquals(expectedMap, counterMap)
778
779 program = getGenerator()
780 .addLoadImmediate(R0, 123)
781 .addCountAndPassIfR0Equals(123, Counter.PASSED_ARP)
782 .addPass()
783 .addCountTrampoline()
784 .generate()
785 dataRegion = ByteArray(Counter.totalSize()) { 0 }
786 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
787 counterMap = decodeCountersIntoMap(dataRegion)
788 expectedMap = getInitialMap()
789 expectedMap[Counter.PASSED_ARP] = 1
790 assertEquals(expectedMap, counterMap)
791
792 program = getGenerator()
793 .addLoadImmediate(R0, 123)
794 .addCountAndDropIfR0NotEquals(124, Counter.DROPPED_ETH_BROADCAST)
795 .addPass()
796 .addCountTrampoline()
797 .generate()
798 dataRegion = ByteArray(Counter.totalSize()) { 0 }
799 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
800 counterMap = decodeCountersIntoMap(dataRegion)
801 expectedMap = getInitialMap()
802 expectedMap[Counter.DROPPED_ETH_BROADCAST] = 1
803 assertEquals(expectedMap, counterMap)
804
805 program = getGenerator()
806 .addLoadImmediate(R0, 123)
807 .addCountAndPassIfR0NotEquals(124, Counter.PASSED_ARP)
808 .addPass()
809 .addCountTrampoline()
810 .generate()
811 dataRegion = ByteArray(Counter.totalSize()) { 0 }
812 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
813 counterMap = decodeCountersIntoMap(dataRegion)
814 expectedMap = getInitialMap()
815 expectedMap[Counter.PASSED_ARP] = 1
816 assertEquals(expectedMap, counterMap)
817
818 program = getGenerator()
819 .addLoadImmediate(R0, 123)
820 .addCountAndDropIfR0LessThan(124, Counter.DROPPED_ETH_BROADCAST)
821 .addPass()
822 .addCountTrampoline()
823 .generate()
824 dataRegion = ByteArray(Counter.totalSize()) { 0 }
825 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
826 counterMap = decodeCountersIntoMap(dataRegion)
827 expectedMap = getInitialMap()
828 expectedMap[Counter.DROPPED_ETH_BROADCAST] = 1
829 assertEquals(expectedMap, counterMap)
830
831 program = getGenerator()
832 .addLoadImmediate(R0, 123)
833 .addCountAndPassIfR0LessThan(124, Counter.PASSED_ARP)
834 .addPass()
835 .addCountTrampoline()
836 .generate()
837 dataRegion = ByteArray(Counter.totalSize()) { 0 }
838 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
839 counterMap = decodeCountersIntoMap(dataRegion)
840 expectedMap = getInitialMap()
841 expectedMap[Counter.PASSED_ARP] = 1
842 assertEquals(expectedMap, counterMap)
Yuyang Huang26758952024-04-03 23:58:29 +0900843
844 program = getGenerator()
845 .addLoadImmediate(R0, 1)
846 .addCountAndDropIfBytesAtR0NotEqual(
847 byteArrayOf(5, 5), DROPPED_ETH_BROADCAST)
848 .addPass()
849 .addCountTrampoline()
850 .generate()
851 dataRegion = ByteArray(Counter.totalSize()) { 0 }
852 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
853 counterMap = decodeCountersIntoMap(dataRegion)
854 expectedMap = getInitialMap()
855 expectedMap[DROPPED_ETH_BROADCAST] = 1
856 assertEquals(expectedMap, counterMap)
Yuyang Huang5b2ab592024-04-05 22:12:07 +0900857
858 program = getGenerator()
859 .addLoadImmediate(R0, 1)
860 .addCountAndPassIfBytesAtR0NotEqual(
861 byteArrayOf(5, 5), PASSED_ARP)
862 .addPass()
863 .addCountTrampoline()
864 .generate()
865 dataRegion = ByteArray(Counter.totalSize()) { 0 }
866 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
867 counterMap = decodeCountersIntoMap(dataRegion)
868 expectedMap = getInitialMap()
869 expectedMap[PASSED_ARP] = 1
870 assertEquals(expectedMap, counterMap)
Yuyang Huangd9cbb652024-03-20 21:00:13 +0900871 }
872
873 @Test
Yuyang Huang4057de52024-03-13 21:24:46 +0900874 fun testV4CountAndPassDrop() {
875 var program = ApfV4Generator(APF_VERSION_4)
876 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
877 .addCountTrampoline()
878 .generate()
879 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
880 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
881 var counterMap = decodeCountersIntoMap(dataRegion)
882 assertEquals(mapOf<Counter, Long>(
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900883 Counter.DROPPED_ETH_BROADCAST to 1
884 ), counterMap)
Yuyang Huang4057de52024-03-13 21:24:46 +0900885
886 program = ApfV4Generator(APF_VERSION_4)
887 .addCountAndPass(Counter.PASSED_ARP)
888 .addCountTrampoline()
889 .generate()
890 dataRegion = ByteArray(Counter.totalSize()) { 0 }
891 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
892 counterMap = decodeCountersIntoMap(dataRegion)
893 assertEquals(mapOf<Counter, Long>(
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900894 Counter.PASSED_ARP to 1
895 ), counterMap)
Yuyang Huang4057de52024-03-13 21:24:46 +0900896 }
897
898 @Test
Yuyang Huang6ff913f2024-03-20 13:31:58 +0900899 fun testV2CountAndPassDrop() {
Yuyang Huang4057de52024-03-13 21:24:46 +0900900 var program = ApfV4Generator(MIN_APF_VERSION)
901 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
902 .addCountTrampoline()
903 .generate()
904 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
905 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
906 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
907
908 program = ApfV4Generator(MIN_APF_VERSION)
Yuyang Huang5b7b05a2024-03-29 16:00:02 +0900909 .addCountAndPass(PASSED_ARP)
Yuyang Huang4057de52024-03-13 21:24:46 +0900910 .addCountTrampoline()
911 .generate()
912 dataRegion = ByteArray(Counter.totalSize()) { 0 }
913 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
914 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
915 }
916
917 @Test
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900918 fun testAllocateFailure() {
919 val program = ApfV6Generator()
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900920 // allocate size: 65535 > sizeof(apf_test_buffer): 1514, trigger allocate failure.
921 .addAllocate(65535)
922 .addDrop()
923 .generate()
924 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
925 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
926 val counterMap = decodeCountersIntoMap(dataRegion)
927 assertEquals(mapOf<Counter, Long>(
928 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900929 Counter.PASSED_ALLOCATE_FAILURE to 1
930 ), counterMap)
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900931 }
932
Yuyang Huang19df0482024-02-19 16:38:45 +0900933 @Test
934 fun testTransmitFailure() {
935 val program = ApfV6Generator()
Yuyang Huang19df0482024-02-19 16:38:45 +0900936 .addAllocate(14)
937 // len: 13 is less than ETH_HLEN, trigger transmit failure.
938 .addLoadImmediate(R0, 13)
939 .addStoreToMemory(R0, 10)
940 .addTransmitWithoutChecksum()
941 .addDrop()
942 .generate()
943 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
944 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
945 val counterMap = decodeCountersIntoMap(dataRegion)
946 assertEquals(mapOf<Counter, Long>(
947 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +0900948 Counter.PASSED_TRANSMIT_FAILURE to 1
949 ), counterMap)
Yuyang Huang19df0482024-02-19 16:38:45 +0900950 }
951
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900952 @Test
953 fun testTransmitL4() {
954 val etherIpv4UdpPacket = intArrayOf(
Yuyang Huanga6f38f32024-03-22 11:00:43 +0900955 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb,
956 0x38, 0xca, 0x84, 0xb7, 0x7f, 0x16,
957 0x08, 0x00, // end of ethernet header
958 0x45,
959 0x04,
960 0x00, 0x3f,
961 0x43, 0xcd,
962 0x40, 0x00,
963 0xff,
964 0x11,
965 0x00, 0x00, // ipv4 checksum set to 0
966 0xc0, 0xa8, 0x01, 0x03,
967 0xe0, 0x00, 0x00, 0xfb, // end of ipv4 header
968 0x14, 0xe9,
969 0x14, 0xe9,
970 0x00, 0x2b,
971 0x00, 0x2b, // end of udp header. udp checksum set to udp (header + payload) size
972 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
973 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
974 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01,
975 0x09,
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900976 ).map { it.toByte() }.toByteArray()
Yuyang Huang3def5232024-04-09 19:00:20 +0900977 val program = ApfV6Generator(etherIpv4UdpPacket)
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900978 .addAllocate(etherIpv4UdpPacket.size)
Yuyang Huanga6f38f32024-03-22 11:00:43 +0900979 .addDataCopy(3, etherIpv4UdpPacket.size) // arg1=src, arg2=len
980 .addTransmitL4(
981 ETH_HLEN, // ipOfs,
982 ETH_HLEN + IPV4_HLEN + 6, // csumOfs
983 ETH_HLEN + IPV4_HLEN - 8, // csumStart
984 IPPROTO_UDP, // partialCsum
985 true // isUdp
986 )
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900987 .generate()
988 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
989 val txBuf = ByteBuffer.wrap(ApfJniUtils.getTransmittedPacket())
990 Struct.parse(EthernetHeader::class.java, txBuf)
991 val ipv4Hdr = Struct.parse(Ipv4Header::class.java, txBuf)
992 val udpHdr = Struct.parse(UdpHeader::class.java, txBuf)
993 assertEquals(0x9535.toShort(), ipv4Hdr.checksum)
994 assertEquals(0xa73d.toShort(), udpHdr.checksum)
995 }
996
Yuyang Huangebd52752024-02-20 17:08:55 +0900997 @Test
998 fun testDnsQuestionMatch() {
999 // needles = { A, B.LOCAL }
1000 val needlesMatch = intArrayOf(
Yuyang Huang73cb5242024-03-22 11:07:31 +09001001 0x01, 'A'.code,
1002 0x00,
1003 0x01, 'B'.code,
1004 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
1005 0x00,
1006 0x00
Yuyang Huangebd52752024-02-20 17:08:55 +09001007 ).map { it.toByte() }.toByteArray()
1008 val udpPayload = intArrayOf(
Yuyang Huang73cb5242024-03-22 11:07:31 +09001009 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
1010 0x00, 0x02, // qdcount = 2
1011 0x00, 0x00, // ancount = 0
1012 0x00, 0x00, // nscount = 0
1013 0x00, 0x00, // arcount = 0
1014 0x01, 'a'.code,
1015 0x01, 'b'.code,
1016 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
1017 0x00, // qname1 = a.b.local
1018 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
1019 0xc0, 0x0e, // qname2 = b.local (name compression)
1020 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
Yuyang Huangebd52752024-02-20 17:08:55 +09001021 ).map { it.toByte() }.toByteArray()
1022
1023 var program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001024 .addLoadImmediate(R0, 0)
Yuyang Huang73cb5242024-03-22 11:07:31 +09001025 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01, DROP_LABEL) // arg2=qtype
Yuyang Huangebd52752024-02-20 17:08:55 +09001026 .addPass()
1027 .generate()
1028 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1029
1030 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001031 .addLoadImmediate(R0, 0)
Yuyang Huang73cb5242024-03-22 11:07:31 +09001032 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01, DROP_LABEL)
Yuyang Huangebd52752024-02-20 17:08:55 +09001033 .addPass()
1034 .generate()
1035 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1036
1037 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001038 .addLoadImmediate(R0, 0)
Yuyang Huang73cb5242024-03-22 11:07:31 +09001039 .addJumpIfPktAtR0DoesNotContainDnsQ(needlesMatch, 0x01, DROP_LABEL) // arg2=qtype
Yuyang Huangebd52752024-02-20 17:08:55 +09001040 .addPass()
1041 .generate()
1042 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1043
1044 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001045 .addLoadImmediate(R0, 0)
Yuyang Huang73cb5242024-03-22 11:07:31 +09001046 .addJumpIfPktAtR0DoesNotContainDnsQSafe(needlesMatch, 0x01, DROP_LABEL) // arg2=qtype
Yuyang Huangebd52752024-02-20 17:08:55 +09001047 .addPass()
1048 .generate()
1049 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1050
1051 val badUdpPayload = intArrayOf(
1052 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
1053 0x00, 0x02, // qdcount = 2
1054 0x00, 0x00, // ancount = 0
1055 0x00, 0x00, // nscount = 0
1056 0x00, 0x00, // arcount = 0
1057 0x01, 'a'.code,
1058 0x01, 'b'.code,
1059 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
1060 0x00, // qname1 = a.b.local
1061 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
1062 0xc0, 0x1b, // corrupted pointer cause infinite loop
1063 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
1064 ).map { it.toByte() }.toByteArray()
1065
1066 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001067 .addLoadImmediate(R0, 0)
Yuyang Huang73cb5242024-03-22 11:07:31 +09001068 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01, DROP_LABEL) // arg2=qtype
Yuyang Huangebd52752024-02-20 17:08:55 +09001069 .addPass()
1070 .generate()
1071 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
1072 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
1073 var counterMap = decodeCountersIntoMap(dataRegion)
1074 assertEquals(mapOf<Counter, Long>(
1075 Counter.TOTAL_PACKETS to 1,
Yuyang Huang73cb5242024-03-22 11:07:31 +09001076 Counter.CORRUPT_DNS_PACKET to 1
1077 ), counterMap)
Yuyang Huangebd52752024-02-20 17:08:55 +09001078
1079 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001080 .addLoadImmediate(R0, 0)
Yuyang Huang73cb5242024-03-22 11:07:31 +09001081 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01, DROP_LABEL) // arg2=qtype
Yuyang Huangebd52752024-02-20 17:08:55 +09001082 .addPass()
1083 .generate()
1084 dataRegion = ByteArray(Counter.totalSize()) { 0 }
1085 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
1086 counterMap = decodeCountersIntoMap(dataRegion)
1087 assertEquals(mapOf<Counter, Long>(
1088 Counter.TOTAL_PACKETS to 1,
Yuyang Huang73cb5242024-03-22 11:07:31 +09001089 Counter.CORRUPT_DNS_PACKET to 1
1090 ), counterMap)
Yuyang Huangebd52752024-02-20 17:08:55 +09001091 }
1092
1093 @Test
1094 fun testDnsAnswerMatch() {
1095 // needles = { A, B.LOCAL }
1096 val needlesMatch = intArrayOf(
1097 0x01, 'A'.code,
1098 0x00,
1099 0x01, 'B'.code,
1100 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
1101 0x00,
1102 0x00
1103 ).map { it.toByte() }.toByteArray()
1104
1105 val udpPayload = intArrayOf(
1106 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
1107 0x00, 0x00, // qdcount = 0
1108 0x00, 0x02, // ancount = 2
1109 0x00, 0x00, // nscount = 0
1110 0x00, 0x00, // arcount = 0
1111 0x01, 'a'.code,
1112 0x01, 'b'.code,
1113 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
1114 0x00, // name1 = a.b.local
1115 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
1116 0x00, 0x00, 0x00, 0x78, // ttl = 120
1117 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
1118 0xc0, 0x0e, // name2 = b.local (name compression)
1119 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
1120 0x00, 0x00, 0x00, 0x78, // ttl = 120
1121 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
1122 ).map { it.toByte() }.toByteArray()
1123
1124 var program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001125 .addLoadImmediate(R0, 0)
1126 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
1127 .addPass()
1128 .generate()
1129 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1130
1131 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001132 .addLoadImmediate(R0, 0)
1133 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
1134 .addPass()
1135 .generate()
1136 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1137
1138 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001139 .addLoadImmediate(R0, 0)
1140 .addJumpIfPktAtR0DoesNotContainDnsA(needlesMatch, DROP_LABEL)
1141 .addPass()
1142 .generate()
1143 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1144
1145 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001146 .addLoadImmediate(R0, 0)
1147 .addJumpIfPktAtR0DoesNotContainDnsASafe(needlesMatch, DROP_LABEL)
1148 .addPass()
1149 .generate()
1150 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
1151
1152 val badUdpPayload = intArrayOf(
1153 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
1154 0x00, 0x00, // qdcount = 0
1155 0x00, 0x02, // ancount = 2
1156 0x00, 0x00, // nscount = 0
1157 0x00, 0x00, // arcount = 0
1158 0x01, 'a'.code,
1159 0x01, 'b'.code,
1160 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
1161 0x00, // name1 = a.b.local
1162 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
1163 0x00, 0x00, 0x00, 0x78, // ttl = 120
1164 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
1165 0xc0, 0x25, // corrupted pointer cause infinite loop
1166 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
1167 0x00, 0x00, 0x00, 0x78, // ttl = 120
1168 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
1169 ).map { it.toByte() }.toByteArray()
1170
1171 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001172 .addLoadImmediate(R0, 0)
1173 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
1174 .addPass()
1175 .generate()
1176 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
1177 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
1178 var counterMap = decodeCountersIntoMap(dataRegion)
1179 assertEquals(mapOf<Counter, Long>(
1180 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +09001181 Counter.CORRUPT_DNS_PACKET to 1
1182 ), counterMap)
Yuyang Huangebd52752024-02-20 17:08:55 +09001183
1184 program = ApfV6Generator()
Yuyang Huangebd52752024-02-20 17:08:55 +09001185 .addLoadImmediate(R0, 0)
1186 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
1187 .addPass()
1188 .generate()
1189 dataRegion = ByteArray(Counter.totalSize()) { 0 }
1190 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
1191 counterMap = decodeCountersIntoMap(dataRegion)
1192 assertEquals(mapOf<Counter, Long>(
1193 Counter.TOTAL_PACKETS to 1,
Yuyang Huangd6eb4fc2024-03-22 10:50:25 +09001194 Counter.CORRUPT_DNS_PACKET to 1
1195 ), counterMap)
Yuyang Huangebd52752024-02-20 17:08:55 +09001196 }
1197
Yuyang Huang2f3f4492024-02-22 16:52:17 +09001198 @Test
1199 fun testGetCounterValue() {
1200 val counterBytes = intArrayOf(0xff, 0, 0, 0, 0x78, 0x56, 0x34, 0x12)
1201 .map { it.toByte() }.toByteArray()
1202 assertEquals(0xff, ApfCounterTracker.getCounterValue(counterBytes, Counter.TOTAL_PACKETS))
1203 }
1204
Yuyang Huangc11962e2024-02-14 20:37:06 +09001205 private fun decodeCountersIntoMap(counterBytes: ByteArray): Map<Counter, Long> {
1206 val counters = Counter::class.java.enumConstants
1207 val ret = HashMap<Counter, Long>()
1208 // starting from index 2 to skip the endianness mark
1209 for (c in listOf(*counters).subList(2, counters.size)) {
1210 val value = ApfCounterTracker.getCounterValue(counterBytes, c)
1211 if (value != 0L) {
1212 ret[c] = value
1213 }
1214 }
1215 return ret
1216 }
1217
Yuyang Huangae57be02023-10-16 17:49:31 +09001218 private fun encodeInstruction(opcode: Int, immLength: Int, register: Int): Byte {
Yuyang Huang73c6d2d2023-10-19 13:32:37 +09001219 val immLengthEncoding = if (immLength == 4) 3 else immLength
1220 return opcode.shl(3).or(immLengthEncoding.shl(1)).or(register).toByte()
Yuyang Huangae57be02023-10-16 17:49:31 +09001221 }
Yuyang Huangbcfa09b2024-02-20 11:20:47 +09001222
Yuyang Huang3def5232024-04-09 19:00:20 +09001223 private fun ByteArray.skipEmptyData(): ByteArray {
1224 return this.drop(3).toByteArray()
1225 }
1226
Yuyang Huangbcfa09b2024-02-20 11:20:47 +09001227 companion object {
1228 const val ETH_HLEN = 14
1229 const val IPV4_HLEN = 20
1230 const val IPPROTO_UDP = 17
1231 }
Yuyang Huangae57be02023-10-16 17:49:31 +09001232}