blob: da24a6b760ba3e84bebb9a903591fc53b69b7f1c [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
19import android.net.apf.ApfTestUtils.DROP
Yuyang Huang2fdba242024-02-06 14:52:22 +090020import android.net.apf.ApfTestUtils.MIN_PKT_SIZE
Yuyang Huangc11962e2024-02-14 20:37:06 +090021import android.net.apf.ApfTestUtils.PASS
22import android.net.apf.ApfTestUtils.assertDrop
Yuyang Huang2fdba242024-02-06 14:52:22 +090023import android.net.apf.ApfTestUtils.assertPass
Yuyang Huangc11962e2024-02-14 20:37:06 +090024import android.net.apf.ApfTestUtils.assertVerdict
Yuyang Huang4057de52024-03-13 21:24:46 +090025import android.net.apf.BaseApfGenerator.APF_VERSION_4
Yuyang Huang2b402472024-02-13 16:31:55 +090026import android.net.apf.BaseApfGenerator.DROP_LABEL
Yuyang Huangbded8e32024-02-09 13:34:58 +090027import android.net.apf.BaseApfGenerator.IllegalInstructionException
Yuyang Huang12145c92024-02-09 07:20:15 +090028import android.net.apf.BaseApfGenerator.MIN_APF_VERSION
29import android.net.apf.BaseApfGenerator.MIN_APF_VERSION_IN_DEV
Yuyang Huang12145c92024-02-09 07:20:15 +090030import android.net.apf.BaseApfGenerator.Register.R0
31import android.net.apf.BaseApfGenerator.Register.R1
Yuyang Huangae57be02023-10-16 17:49:31 +090032import androidx.test.filters.SmallTest
33import androidx.test.runner.AndroidJUnit4
Yuyang Huangbcfa09b2024-02-20 11:20:47 +090034import com.android.net.module.util.Struct
35import com.android.net.module.util.structs.EthernetHeader
36import com.android.net.module.util.structs.Ipv4Header
37import com.android.net.module.util.structs.UdpHeader
38import java.nio.ByteBuffer
Yuyang Huangae57be02023-10-16 17:49:31 +090039import kotlin.test.assertContentEquals
Yuyang Huangc11962e2024-02-14 20:37:06 +090040import kotlin.test.assertEquals
Yuyang Huangce1493a2023-12-07 15:29:40 +090041import kotlin.test.assertFailsWith
Yuyang Huang4f849692024-03-20 00:29:58 +090042import org.junit.After
Yuyang Huangae57be02023-10-16 17:49:31 +090043import org.junit.Test
44import org.junit.runner.RunWith
45
46/**
47 * Tests for APFv6 specific instructions.
48 */
49@RunWith(AndroidJUnit4::class)
50@SmallTest
51class ApfV5Test {
52
Yuyang Huang2283be72024-02-08 04:49:08 +090053 private val testPacket = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8,
54 9, 10, 11, 12, 13, 14, 15, 16)
55
Yuyang Huang4f849692024-03-20 00:29:58 +090056 @After
57 fun tearDown() {
58 ApfJniUtils.resetTransmittedPacketMemory()
59 }
60
Yuyang Huangae57be02023-10-16 17:49:31 +090061 @Test
Yuyang Huanga112cc82023-12-13 17:55:47 +090062 fun testDataInstructionMustComeFirst() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090063 var gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +090064 gen.addAllocateR0()
65 assertFailsWith<IllegalInstructionException> { gen.addData(ByteArray(3) { 0x01 }) }
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +090066 }
67
68 @Test
Yuyang Huang3ac843c2023-12-13 16:40:15 +090069 fun testApfInstructionEncodingSizeCheck() {
Yuyang Huangd89cdbe2024-02-01 09:49:07 +090070 var gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +090071 assertFailsWith<IllegalArgumentException> { gen.addAllocate(65536) }
72 assertFailsWith<IllegalArgumentException> { gen.addAllocate(-1) }
Yuyang Huang293f7e72023-12-31 14:24:03 +090073 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(-1, 1) }
74 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(-1, 1) }
75 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, 256) }
76 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, 256) }
77 assertFailsWith<IllegalArgumentException> { gen.addDataCopy(1, -1) }
78 assertFailsWith<IllegalArgumentException> { gen.addPacketCopy(1, -1) }
Yuyang Huangd0390612024-01-01 16:21:16 +090079 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(256) }
80 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(256) }
Yuyang Huang96697842024-01-02 21:53:48 +090081 assertFailsWith<IllegalArgumentException> { gen.addPacketCopyFromR0(-1) }
82 assertFailsWith<IllegalArgumentException> { gen.addDataCopyFromR0(-1) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090083 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090084 byteArrayOf(1, 'A'.code.toByte(), 0, 0),
85 256,
86 ApfV4Generator.DROP_LABEL
87 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090088 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090089 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
90 0x0c,
91 ApfV4Generator.DROP_LABEL
92 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090093 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090094 byteArrayOf(1, '.'.code.toByte(), 0, 0),
95 0x0c,
96 ApfV4Generator.DROP_LABEL
97 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +090098 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +090099 byteArrayOf(0, 0),
100 0xc0,
101 ApfV4Generator.DROP_LABEL
102 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900103 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900104 byteArrayOf(1, 'A'.code.toByte()),
105 0xc0,
106 ApfV4Generator.DROP_LABEL
107 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900108 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
109 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900110 0xc0,
111 ApfV4Generator.DROP_LABEL
112 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900113 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
114 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900115 0xc0,
116 ApfV4Generator.DROP_LABEL
117 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900118 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsQ(
119 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900120 0xc0,
121 ApfV4Generator.DROP_LABEL
122 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900123 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900124 byteArrayOf(1, 'A'.code.toByte(), 0, 0),
125 256,
126 ApfV4Generator.DROP_LABEL
127 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900128 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900129 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
130 0x0c,
131 ApfV4Generator.DROP_LABEL
132 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900133 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900134 byteArrayOf(1, '.'.code.toByte(), 0, 0),
135 0x0c,
136 ApfV4Generator.DROP_LABEL
137 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900138 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900139 byteArrayOf(0, 0),
140 0xc0,
141 ApfV4Generator.DROP_LABEL
142 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900143 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900144 byteArrayOf(1, 'A'.code.toByte()),
145 0xc0,
146 ApfV4Generator.DROP_LABEL
147 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900148 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
149 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900150 0xc0,
151 ApfV4Generator.DROP_LABEL
152 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900153 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
154 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900155 0xc0,
156 ApfV4Generator.DROP_LABEL
157 ) }
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900158 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsQ(
159 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900160 0xc0,
161 ApfV4Generator.DROP_LABEL
162 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900163 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900164 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
165 ApfV4Generator.DROP_LABEL
166 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900167 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900168 byteArrayOf(1, '.'.code.toByte(), 0, 0),
169 ApfV4Generator.DROP_LABEL
170 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900171 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900172 byteArrayOf(0, 0),
173 ApfV4Generator.DROP_LABEL
174 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900175 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900176 byteArrayOf(1, 'A'.code.toByte()),
177 ApfV4Generator.DROP_LABEL
178 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900179 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
180 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900181 ApfV4Generator.DROP_LABEL
182 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900183 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
184 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900185 ApfV4Generator.DROP_LABEL
186 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900187 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0DoesNotContainDnsA(
188 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900189 ApfV4Generator.DROP_LABEL
190 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900191 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900192 byteArrayOf(1, 'a'.code.toByte(), 0, 0),
193 ApfV4Generator.DROP_LABEL
194 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900195 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900196 byteArrayOf(1, '.'.code.toByte(), 0, 0),
197 ApfV4Generator.DROP_LABEL
198 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900199 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900200 byteArrayOf(0, 0),
201 ApfV4Generator.DROP_LABEL
202 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900203 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900204 byteArrayOf(1, 'A'.code.toByte()),
205 ApfV4Generator.DROP_LABEL
206 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900207 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
208 byteArrayOf(64) + ByteArray(64) { 'A'.code.toByte() } + byteArrayOf(0, 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900209 ApfV4Generator.DROP_LABEL
210 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900211 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
212 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900213 ApfV4Generator.DROP_LABEL
214 ) }
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900215 assertFailsWith<IllegalArgumentException> { gen.addJumpIfPktAtR0ContainDnsA(
216 byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte()),
Yuyang Huang3f4ca9d2024-03-21 19:07:09 +0900217 ApfV4Generator.DROP_LABEL
218 ) }
Yuyang Huangce1493a2023-12-07 15:29:40 +0900219 }
220
221 @Test
Yuyang Huang2b402472024-02-13 16:31:55 +0900222 fun testValidateDnsNames() {
223 // '%' is a valid label character in mDNS subtype
Yuyang Huangb31cef22024-02-13 16:43:33 +0900224 // byte == 0xff means it is a '*' wildcard, which is a valid encoding.
Yuyang Huang2b402472024-02-13 16:31:55 +0900225 val program = ApfV6Generator().addJumpIfPktAtR0ContainDnsQ(
226 byteArrayOf(1, '%'.code.toByte(), 0, 0),
227 1,
228 DROP_LABEL)
Yuyang Huangb31cef22024-02-13 16:43:33 +0900229 .addJumpIfPktAtR0ContainDnsA(
230 byteArrayOf(0xff.toByte(), 1, 'B'.code.toByte(), 0, 0),
231 DROP_LABEL
232 )
Yuyang Huang2b402472024-02-13 16:31:55 +0900233 .generate()
234 }
235
236 @Test
Yuyang Huangae57be02023-10-16 17:49:31 +0900237 fun testApfInstructionsEncoding() {
Yuyang Huang9b6be762024-02-22 17:06:51 +0900238 val v4gen = ApfV4Generator(MIN_APF_VERSION)
Yuyang Huangafe7b652024-02-09 09:45:01 +0900239 v4gen.addPass()
240 var program = v4gen.generate()
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900241 // encoding PASS opcode: opcode=0, imm_len=0, R=0
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900242 assertContentEquals(
243 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 0)), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900244 assertContentEquals(
245 listOf("0: pass"),
246 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900247
Yuyang Huangafe7b652024-02-09 09:45:01 +0900248 var gen = ApfV6Generator()
Yuyang Huangce1493a2023-12-07 15:29:40 +0900249 gen.addDrop()
250 program = gen.generate()
251 // encoding DROP opcode: opcode=0, imm_len=0, R=1
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900252 assertContentEquals(
253 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 1)), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900254 assertContentEquals(
255 listOf("0: drop"),
256 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900257
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900258 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900259 gen.addCountAndPass(129)
260 program = gen.generate()
261 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
262 assertContentEquals(
263 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 0),
264 0x81.toByte()), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900265 assertContentEquals(
Yuyang Huang4057de52024-03-13 21:24:46 +0900266 listOf("0: pass 129"),
267 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900268
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900269 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900270 gen.addCountAndDrop(1000)
271 program = gen.generate()
272 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
273 assertContentEquals(
274 byteArrayOf(encodeInstruction(opcode = 0, immLength = 2, register = 1),
275 0x03, 0xe8.toByte()), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900276 assertContentEquals(
Yuyang Huang4057de52024-03-13 21:24:46 +0900277 listOf("0: drop 1000"),
278 ApfJniUtils.disassembleApf(program).map { it.trim() } )
279
280 gen = ApfV6Generator()
281 gen.addCountAndPass(Counter.TOTAL_PACKETS)
282 program = gen.generate()
283 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
284 assertContentEquals(
285 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 0),
286 0x02), program)
287 assertContentEquals(
288 listOf("0: pass 2"),
289 ApfJniUtils.disassembleApf(program).map { it.trim() } )
290
291 gen = ApfV6Generator()
292 gen.addCountAndDrop(Counter.PASSED_ALLOCATE_FAILURE)
293 program = gen.generate()
294 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
295 assertContentEquals(
296 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 1),
297 0x03), program)
298 assertContentEquals(
299 listOf("0: drop 3"),
Yuyang Huang98b99f22024-01-29 06:35:27 +0900300 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huangce1493a2023-12-07 15:29:40 +0900301
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900302 gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900303 gen.addAllocateR0()
304 gen.addAllocate(1500)
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900305 program = gen.generate()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900306 // encoding ALLOC opcode: opcode=21(EXT opcode number), imm=36(TRANS opcode number).
307 // R=0 means length stored in R0. R=1 means the length stored in imm1.
308 assertContentEquals(byteArrayOf(
309 encodeInstruction(opcode = 21, immLength = 1, register = 0), 36,
310 encodeInstruction(opcode = 21, immLength = 1, register = 1), 36, 0x05,
311 0xDC.toByte()),
312 program)
Yuyang Huang626414e2024-01-29 06:52:57 +0900313 assertContentEquals(listOf("0: allocate r0", "2: allocate 1500"),
314 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900315
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900316 gen = ApfV6Generator()
Yuyang Huangfb803682024-02-20 17:52:27 +0900317 gen.addTransmitWithoutChecksum()
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900318 gen.addTransmitL4(30, 40, 50, 256, true)
Yuyang Huangae57be02023-10-16 17:49:31 +0900319 program = gen.generate()
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800320 // encoding TRANSMIT opcode: opcode=21(EXT opcode number),
321 // imm=37(TRANSMIT opcode number),
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900322 assertContentEquals(byteArrayOf(
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800323 encodeInstruction(opcode = 21, immLength = 1, register = 0),
324 37, 255.toByte(), 255.toByte(),
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900325 encodeInstruction(opcode = 21, immLength = 1, register = 1), 37, 30, 40, 50, 1, 0
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900326 ), program)
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900327 assertContentEquals(listOf(
328 "0: transmit ip_ofs=255",
329 "4: transmitudp ip_ofs=30, csum_ofs=40, csum_start=50, partial_csum=0x0100",
330 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900331
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900332 gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +0900333 val largeByteArray = ByteArray(256) { 0x01 }
334 gen.addData(largeByteArray)
335 program = gen.generate()
336 // encoding DATA opcode: opcode=14(JMP), R=1
337 assertContentEquals(byteArrayOf(
338 encodeInstruction(opcode = 14, immLength = 2, register = 1), 0x01, 0x00) +
339 largeByteArray, program)
Yuyang Huang937ba492024-02-04 07:20:32 +0900340 assertContentEquals(listOf("0: data 256, " + "01".repeat(256) ),
Yuyang Huangf97b28a2024-01-29 09:36:25 +0900341 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huanga112cc82023-12-13 17:55:47 +0900342
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900343 gen = ApfV6Generator()
Yuyang Huangadf69672024-01-02 10:18:11 +0900344 gen.addWriteU8(0x01)
345 gen.addWriteU16(0x0102)
346 gen.addWriteU32(0x01020304)
347 gen.addWriteU8(0x00)
348 gen.addWriteU8(0x80)
349 gen.addWriteU16(0x0000)
350 gen.addWriteU16(0x8000)
351 gen.addWriteU32(0x00000000)
352 gen.addWriteU32(0x80000000)
Yuyang Huang4ac891f2023-12-20 11:49:11 +0900353 program = gen.generate()
354 assertContentEquals(byteArrayOf(
355 encodeInstruction(24, 1, 0), 0x01,
356 encodeInstruction(24, 2, 0), 0x01, 0x02,
357 encodeInstruction(24, 4, 0), 0x01, 0x02, 0x03, 0x04,
358 encodeInstruction(24, 1, 0), 0x00,
359 encodeInstruction(24, 1, 0), 0x80.toByte(),
360 encodeInstruction(24, 2, 0), 0x00, 0x00,
361 encodeInstruction(24, 2, 0), 0x80.toByte(), 0x00,
362 encodeInstruction(24, 4, 0), 0x00, 0x00, 0x00, 0x00,
363 encodeInstruction(24, 4, 0), 0x80.toByte(), 0x00, 0x00,
364 0x00), program)
Yuyang Huang7affd672024-01-29 13:04:43 +0900365 assertContentEquals(listOf(
366 "0: write 0x01",
367 "2: write 0x0102",
368 "5: write 0x01020304",
369 "10: write 0x00",
370 "12: write 0x80",
371 "14: write 0x0000",
372 "17: write 0x8000",
373 "20: write 0x00000000",
374 "25: write 0x80000000"
Yuyang Huang15b45782024-01-18 07:19:11 +0900375 ),
Yuyang Huang7affd672024-01-29 13:04:43 +0900376 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huange84a9692024-01-01 11:49:49 +0900377
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900378 gen = ApfV6Generator()
Yuyang Huange84a9692024-01-01 11:49:49 +0900379 gen.addWriteU8(R0)
380 gen.addWriteU16(R0)
381 gen.addWriteU32(R0)
382 gen.addWriteU8(R1)
383 gen.addWriteU16(R1)
384 gen.addWriteU32(R1)
385 program = gen.generate()
386 assertContentEquals(byteArrayOf(
387 encodeInstruction(21, 1, 0), 38,
388 encodeInstruction(21, 1, 0), 39,
389 encodeInstruction(21, 1, 0), 40,
390 encodeInstruction(21, 1, 1), 38,
391 encodeInstruction(21, 1, 1), 39,
392 encodeInstruction(21, 1, 1), 40
393 ), program)
Yuyang Huangf0b46cb2024-01-30 03:37:17 +0900394 assertContentEquals(listOf(
395 "0: ewrite1 r0",
396 "2: ewrite2 r0",
397 "4: ewrite4 r0",
398 "6: ewrite1 r1",
399 "8: ewrite2 r1",
400 "10: ewrite4 r1"), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900401
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900402 gen = ApfV6Generator()
Yuyang Huang293f7e72023-12-31 14:24:03 +0900403 gen.addDataCopy(0, 10)
404 gen.addDataCopy(1, 5)
405 gen.addPacketCopy(1000, 255)
406 program = gen.generate()
407 assertContentEquals(byteArrayOf(
408 encodeInstruction(25, 0, 1), 10,
409 encodeInstruction(25, 1, 1), 1, 5,
410 encodeInstruction(25, 2, 0),
411 0x03.toByte(), 0xe8.toByte(), 0xff.toByte(),
412 ), program)
Yuyang Huange8003982024-01-30 04:06:18 +0900413 assertContentEquals(listOf(
Yuyang Huangb2a93342024-02-07 06:32:00 +0900414 "0: datacopy src=0, len=10",
415 "2: datacopy src=1, len=5",
416 "5: pktcopy src=1000, len=255"
Yuyang Huanga699e542024-02-06 12:50:03 +0900417 ),
418 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang293f7e72023-12-31 14:24:03 +0900419
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900420 gen = ApfV6Generator()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900421 gen.addDataCopyFromR0(5)
Yuyang Huangd0390612024-01-01 16:21:16 +0900422 gen.addPacketCopyFromR0(5)
423 gen.addDataCopyFromR0LenR1()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900424 gen.addPacketCopyFromR0LenR1()
Yuyang Huangd0390612024-01-01 16:21:16 +0900425 program = gen.generate()
426 assertContentEquals(byteArrayOf(
Yuyang Huangbed904a2024-01-30 11:22:49 +0900427 encodeInstruction(21, 1, 1), 41, 5,
Yuyang Huangd0390612024-01-01 16:21:16 +0900428 encodeInstruction(21, 1, 0), 41, 5,
429 encodeInstruction(21, 1, 1), 42,
Yuyang Huangbed904a2024-01-30 11:22:49 +0900430 encodeInstruction(21, 1, 0), 42,
Yuyang Huangd0390612024-01-01 16:21:16 +0900431 ), program)
Yuyang Huangbed904a2024-01-30 11:22:49 +0900432 assertContentEquals(listOf(
Yuyang Huanga699e542024-02-06 12:50:03 +0900433 "0: edatacopy src=r0, len=5",
434 "3: epktcopy src=r0, len=5",
435 "6: edatacopy src=r0, len=r1",
436 "8: epktcopy src=r0, len=r1"), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900437
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900438 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900439 gen.addJumpIfBytesAtR0Equal(byteArrayOf('a'.code.toByte()), ApfV4Generator.DROP_LABEL)
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900440 program = gen.generate()
441 assertContentEquals(
442 byteArrayOf(encodeInstruction(opcode = 20, immLength = 1, register = 1),
443 1, 1, 'a'.code.toByte()), program)
Yuyang Huangbffcf262024-02-04 07:52:48 +0900444 assertContentEquals(listOf(
Yuyang Huangb61b7342024-02-06 05:44:24 +0900445 "0: jbseq r0, 0x1, DROP, 61"),
Yuyang Huangbffcf262024-02-04 07:52:48 +0900446 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900447
448 val qnames = byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0, 0)
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900449 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900450 gen.addJumpIfPktAtR0DoesNotContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
451 gen.addJumpIfPktAtR0ContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900452 program = gen.generate()
453 assertContentEquals(byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900454 encodeInstruction(21, 1, 0), 43, 11, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900455 ) + qnames + byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900456 encodeInstruction(21, 1, 1), 43, 1, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900457 ) + qnames, program)
Yuyang Huang49ab8822024-02-04 09:39:00 +0900458 assertContentEquals(listOf(
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900459 "0: jdnsqne r0, DROP, 12, (1)A(1)B(0)(0)",
460 "10: jdnsqeq r0, DROP, 12, (1)A(1)B(0)(0)"),
Yuyang Huang49ab8822024-02-04 09:39:00 +0900461 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900462
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900463 gen = ApfV6Generator()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900464 gen.addJumpIfPktAtR0DoesNotContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
465 gen.addJumpIfPktAtR0ContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
466 program = gen.generate()
467 assertContentEquals(byteArrayOf(
468 encodeInstruction(21, 1, 0), 45, 11, 0x0c.toByte(),
469 ) + qnames + byteArrayOf(
470 encodeInstruction(21, 1, 1), 45, 1, 0x0c.toByte(),
471 ) + qnames, program)
472 assertContentEquals(listOf(
473 "0: jdnsqnesafe r0, DROP, 12, (1)A(1)B(0)(0)",
474 "10: jdnsqeqsafe r0, DROP, 12, (1)A(1)B(0)(0)"),
475 ApfJniUtils.disassembleApf(program).map{ it.trim() })
476
477 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900478 gen.addJumpIfPktAtR0DoesNotContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
479 gen.addJumpIfPktAtR0ContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900480 program = gen.generate()
481 assertContentEquals(byteArrayOf(
482 encodeInstruction(21, 1, 0), 44, 10,
483 ) + qnames + byteArrayOf(
484 encodeInstruction(21, 1, 1), 44, 1,
485 ) + qnames, program)
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900486 assertContentEquals(listOf(
487 "0: jdnsane r0, DROP, (1)A(1)B(0)(0)",
488 "9: jdnsaeq r0, DROP, (1)A(1)B(0)(0)"),
489 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900490
491 gen = ApfV6Generator()
492 gen.addJumpIfPktAtR0DoesNotContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
493 gen.addJumpIfPktAtR0ContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
494 program = gen.generate()
495 assertContentEquals(byteArrayOf(
496 encodeInstruction(21, 1, 0), 46, 10,
497 ) + qnames + byteArrayOf(
498 encodeInstruction(21, 1, 1), 46, 1,
499 ) + qnames, program)
500 assertContentEquals(listOf(
501 "0: jdnsanesafe r0, DROP, (1)A(1)B(0)(0)",
502 "9: jdnsaeqsafe r0, DROP, (1)A(1)B(0)(0)"),
503 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900504 }
505
Yuyang Huang2fdba242024-02-06 14:52:22 +0900506 @Test
507 fun testWriteToTxBuffer() {
Yuyang Huangbded8e32024-02-09 13:34:58 +0900508 var program = ApfV6Generator()
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900509 .addAllocate(14)
Yuyang Huangb97aa962024-02-08 08:13:56 +0900510 .addWriteU8(0x01)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900511 .addWriteU16(0x0203)
512 .addWriteU32(0x04050607)
Yuyang Huangbded8e32024-02-09 13:34:58 +0900513 .addLoadImmediate(R0, 1)
514 .addWriteU8(R0)
515 .addLoadImmediate(R0, 0x0203)
516 .addWriteU16(R0)
517 .addLoadImmediate(R1, 0x04050607)
518 .addWriteU32(R1)
Yuyang Huangfb803682024-02-20 17:52:27 +0900519 .addTransmitWithoutChecksum()
Yuyang Huangbded8e32024-02-09 13:34:58 +0900520 .generate()
521 assertPass(MIN_APF_VERSION_IN_DEV, program, ByteArray(MIN_PKT_SIZE))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900522 assertContentEquals(byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03,
523 0x04, 0x05, 0x06, 0x07), ApfJniUtils.getTransmittedPacket())
Yuyang Huang2fdba242024-02-06 14:52:22 +0900524 }
525
Yuyang Huang2283be72024-02-08 04:49:08 +0900526 @Test
527 fun testCopyToTxBuffer() {
Yuyang Huang10598932024-02-14 10:00:59 +0900528 var program = ApfV6Generator()
Yuyang Huang2283be72024-02-08 04:49:08 +0900529 .addData(byteArrayOf(33, 34, 35))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900530 .addAllocate(14)
531 .addDataCopy(2 /* src */, 2 /* len */)
532 .addDataCopy(4 /* src */, 1 /* len */)
533 .addPacketCopy(0 /* src */, 1 /* len */)
534 .addPacketCopy(1 /* src */, 3 /* len */)
535 .addLoadImmediate(R0, 2) // data copy offset
536 .addDataCopyFromR0(2 /* len */)
537 .addLoadImmediate(R0, 4) // data copy offset
538 .addLoadImmediate(R1, 1) // len
539 .addDataCopyFromR0LenR1()
540 .addLoadImmediate(R0, 0) // packet copy offset
541 .addPacketCopyFromR0(1 /* len */)
542 .addLoadImmediate(R0, 1) // packet copy offset
543 .addLoadImmediate(R1, 3) // len
544 .addPacketCopyFromR0LenR1()
Yuyang Huangfb803682024-02-20 17:52:27 +0900545 .addTransmitWithoutChecksum()
Yuyang Huang2283be72024-02-08 04:49:08 +0900546 .generate()
547 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900548 assertContentEquals(byteArrayOf(33, 34, 35, 1, 2, 3, 4, 33, 34, 35, 1, 2, 3, 4),
549 ApfJniUtils.getTransmittedPacket())
Yuyang Huang2283be72024-02-08 04:49:08 +0900550 }
551
Yuyang Huangc11962e2024-02-14 20:37:06 +0900552 @Test
553 fun testPassDrop() {
554 var program = ApfV6Generator()
555 .addDrop()
556 .addPass()
557 .generate()
558 assertDrop(MIN_APF_VERSION_IN_DEV, program, testPacket)
559
560 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
561 program = ApfV6Generator()
562 .addData(byteArrayOf())
Yuyang Huang4057de52024-03-13 21:24:46 +0900563 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900564 .generate()
565 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
566 var counterMap = decodeCountersIntoMap(dataRegion)
567 assertEquals(mapOf<Counter, Long>(
568 Counter.TOTAL_PACKETS to 1,
569 Counter.DROPPED_ETH_BROADCAST to 1), counterMap)
570
571 dataRegion = ByteArray(Counter.totalSize()) { 0 }
572 program = ApfV6Generator()
573 .addData(byteArrayOf())
Yuyang Huang4057de52024-03-13 21:24:46 +0900574 .addCountAndPass(Counter.PASSED_ARP)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900575 .generate()
576 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
577 counterMap = decodeCountersIntoMap(dataRegion)
578 assertEquals(mapOf<Counter, Long>(
579 Counter.TOTAL_PACKETS to 1,
580 Counter.PASSED_ARP to 1), counterMap)
581 }
582
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900583 @Test
Yuyang Huang4057de52024-03-13 21:24:46 +0900584 fun testV4CountAndPassDrop() {
585 var program = ApfV4Generator(APF_VERSION_4)
586 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
587 .addCountTrampoline()
588 .generate()
589 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
590 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
591 var counterMap = decodeCountersIntoMap(dataRegion)
592 assertEquals(mapOf<Counter, Long>(
593 Counter.DROPPED_ETH_BROADCAST to 1), counterMap)
594
595 program = ApfV4Generator(APF_VERSION_4)
596 .addCountAndPass(Counter.PASSED_ARP)
597 .addCountTrampoline()
598 .generate()
599 dataRegion = ByteArray(Counter.totalSize()) { 0 }
600 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
601 counterMap = decodeCountersIntoMap(dataRegion)
602 assertEquals(mapOf<Counter, Long>(
603 Counter.PASSED_ARP to 1), counterMap)
604 }
605
606 @Test
607 fun testV2CountAndPssDrop() {
608 var program = ApfV4Generator(MIN_APF_VERSION)
609 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
610 .addCountTrampoline()
611 .generate()
612 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
613 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
614 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
615
616 program = ApfV4Generator(MIN_APF_VERSION)
617 .addCountAndPass(Counter.DROPPED_ETH_BROADCAST)
618 .addCountTrampoline()
619 .generate()
620 dataRegion = ByteArray(Counter.totalSize()) { 0 }
621 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
622 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
623 }
624
625 @Test
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900626 fun testAllocateFailure() {
627 val program = ApfV6Generator()
628 .addData(byteArrayOf())
629 // allocate size: 65535 > sizeof(apf_test_buffer): 1514, trigger allocate failure.
630 .addAllocate(65535)
631 .addDrop()
632 .generate()
633 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
634 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
635 val counterMap = decodeCountersIntoMap(dataRegion)
636 assertEquals(mapOf<Counter, Long>(
637 Counter.TOTAL_PACKETS to 1,
638 Counter.PASSED_ALLOCATE_FAILURE to 1), counterMap)
639 }
640
Yuyang Huang19df0482024-02-19 16:38:45 +0900641 @Test
642 fun testTransmitFailure() {
643 val program = ApfV6Generator()
644 .addData(byteArrayOf())
645 .addAllocate(14)
646 // len: 13 is less than ETH_HLEN, trigger transmit failure.
647 .addLoadImmediate(R0, 13)
648 .addStoreToMemory(R0, 10)
649 .addTransmitWithoutChecksum()
650 .addDrop()
651 .generate()
652 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
653 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
654 val counterMap = decodeCountersIntoMap(dataRegion)
655 assertEquals(mapOf<Counter, Long>(
656 Counter.TOTAL_PACKETS to 1,
657 Counter.PASSED_TRANSMIT_FAILURE to 1), counterMap)
658 }
659
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900660 @Test
661 fun testTransmitL4() {
662 val etherIpv4UdpPacket = intArrayOf(
663 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb,
664 0x38, 0xca, 0x84, 0xb7, 0x7f, 0x16,
665 0x08, 0x00, // end of ethernet header
666 0x45,
667 0x04,
668 0x00, 0x3f,
669 0x43, 0xcd,
670 0x40, 0x00,
671 0xff,
672 0x11,
673 0x00, 0x00, // ipv4 checksum set to 0
674 0xc0, 0xa8, 0x01, 0x03,
675 0xe0, 0x00, 0x00, 0xfb, // end of ipv4 header
676 0x14, 0xe9,
677 0x14, 0xe9,
678 0x00, 0x2b,
679 0x00, 0x2b, // end of udp header. udp checksum set to udp (header + payload) size
680 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
681 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
682 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01,
683 0x09,
684 ).map { it.toByte() }.toByteArray()
685 val program = ApfV6Generator()
686 .addData(etherIpv4UdpPacket)
687 .addAllocate(etherIpv4UdpPacket.size)
688 .addDataCopy(2 /* src */, etherIpv4UdpPacket.size /* len */)
689 .addTransmitL4(ETH_HLEN /* ipOfs */,
690 ETH_HLEN + IPV4_HLEN + 6 /* csumOfs */,
691 ETH_HLEN + IPV4_HLEN - 8 /* csumStart */,
692 IPPROTO_UDP /* partialCsum */,
693 true /* isUdp */)
694 .generate()
695 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
696 val txBuf = ByteBuffer.wrap(ApfJniUtils.getTransmittedPacket())
697 Struct.parse(EthernetHeader::class.java, txBuf)
698 val ipv4Hdr = Struct.parse(Ipv4Header::class.java, txBuf)
699 val udpHdr = Struct.parse(UdpHeader::class.java, txBuf)
700 assertEquals(0x9535.toShort(), ipv4Hdr.checksum)
701 assertEquals(0xa73d.toShort(), udpHdr.checksum)
702 }
703
Yuyang Huangebd52752024-02-20 17:08:55 +0900704 @Test
705 fun testDnsQuestionMatch() {
706 // needles = { A, B.LOCAL }
707 val needlesMatch = intArrayOf(
708 0x01, 'A'.code,
709 0x00,
710 0x01, 'B'.code,
711 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
712 0x00,
713 0x00
714 ).map { it.toByte() }.toByteArray()
715 val udpPayload = intArrayOf(
716 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
717 0x00, 0x02, // qdcount = 2
718 0x00, 0x00, // ancount = 0
719 0x00, 0x00, // nscount = 0
720 0x00, 0x00, // arcount = 0
721 0x01, 'a'.code,
722 0x01, 'b'.code,
723 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
724 0x00, // qname1 = a.b.local
725 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
726 0xc0, 0x0e, // qname2 = b.local (name compression)
727 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
728 ).map { it.toByte() }.toByteArray()
729
730 var program = ApfV6Generator()
731 .addData(byteArrayOf())
732 .addLoadImmediate(R0, 0)
733 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
734 .addPass()
735 .generate()
736 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
737
738 program = ApfV6Generator()
739 .addData(byteArrayOf())
740 .addLoadImmediate(R0, 0)
741 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
742 .addPass()
743 .generate()
744 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
745
746 program = ApfV6Generator()
747 .addData(byteArrayOf())
748 .addLoadImmediate(R0, 0)
749 .addJumpIfPktAtR0DoesNotContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
750 .addPass()
751 .generate()
752 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
753
754 program = ApfV6Generator()
755 .addData(byteArrayOf())
756 .addLoadImmediate(R0, 0)
757 .addJumpIfPktAtR0DoesNotContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
758 .addPass()
759 .generate()
760 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
761
762 val badUdpPayload = intArrayOf(
763 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
764 0x00, 0x02, // qdcount = 2
765 0x00, 0x00, // ancount = 0
766 0x00, 0x00, // nscount = 0
767 0x00, 0x00, // arcount = 0
768 0x01, 'a'.code,
769 0x01, 'b'.code,
770 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
771 0x00, // qname1 = a.b.local
772 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
773 0xc0, 0x1b, // corrupted pointer cause infinite loop
774 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
775 ).map { it.toByte() }.toByteArray()
776
777 program = ApfV6Generator()
778 .addData(byteArrayOf())
779 .addLoadImmediate(R0, 0)
780 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
781 .addPass()
782 .generate()
783 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
784 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
785 var counterMap = decodeCountersIntoMap(dataRegion)
786 assertEquals(mapOf<Counter, Long>(
787 Counter.TOTAL_PACKETS to 1,
788 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
789
790 program = ApfV6Generator()
791 .addData(byteArrayOf())
792 .addLoadImmediate(R0, 0)
793 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
794 .addPass()
795 .generate()
796 dataRegion = ByteArray(Counter.totalSize()) { 0 }
797 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
798 counterMap = decodeCountersIntoMap(dataRegion)
799 assertEquals(mapOf<Counter, Long>(
800 Counter.TOTAL_PACKETS to 1,
801 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
802 }
803
804 @Test
805 fun testDnsAnswerMatch() {
806 // needles = { A, B.LOCAL }
807 val needlesMatch = intArrayOf(
808 0x01, 'A'.code,
809 0x00,
810 0x01, 'B'.code,
811 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
812 0x00,
813 0x00
814 ).map { it.toByte() }.toByteArray()
815
816 val udpPayload = intArrayOf(
817 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
818 0x00, 0x00, // qdcount = 0
819 0x00, 0x02, // ancount = 2
820 0x00, 0x00, // nscount = 0
821 0x00, 0x00, // arcount = 0
822 0x01, 'a'.code,
823 0x01, 'b'.code,
824 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
825 0x00, // name1 = a.b.local
826 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
827 0x00, 0x00, 0x00, 0x78, // ttl = 120
828 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
829 0xc0, 0x0e, // name2 = b.local (name compression)
830 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
831 0x00, 0x00, 0x00, 0x78, // ttl = 120
832 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
833 ).map { it.toByte() }.toByteArray()
834
835 var program = ApfV6Generator()
836 .addData(byteArrayOf())
837 .addLoadImmediate(R0, 0)
838 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
839 .addPass()
840 .generate()
841 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
842
843 program = ApfV6Generator()
844 .addData(byteArrayOf())
845 .addLoadImmediate(R0, 0)
846 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
847 .addPass()
848 .generate()
849 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
850
851 program = ApfV6Generator()
852 .addData(byteArrayOf())
853 .addLoadImmediate(R0, 0)
854 .addJumpIfPktAtR0DoesNotContainDnsA(needlesMatch, DROP_LABEL)
855 .addPass()
856 .generate()
857 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
858
859 program = ApfV6Generator()
860 .addData(byteArrayOf())
861 .addLoadImmediate(R0, 0)
862 .addJumpIfPktAtR0DoesNotContainDnsASafe(needlesMatch, DROP_LABEL)
863 .addPass()
864 .generate()
865 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
866
867 val badUdpPayload = intArrayOf(
868 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
869 0x00, 0x00, // qdcount = 0
870 0x00, 0x02, // ancount = 2
871 0x00, 0x00, // nscount = 0
872 0x00, 0x00, // arcount = 0
873 0x01, 'a'.code,
874 0x01, 'b'.code,
875 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
876 0x00, // name1 = a.b.local
877 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
878 0x00, 0x00, 0x00, 0x78, // ttl = 120
879 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
880 0xc0, 0x25, // corrupted pointer cause infinite loop
881 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
882 0x00, 0x00, 0x00, 0x78, // ttl = 120
883 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
884 ).map { it.toByte() }.toByteArray()
885
886 program = ApfV6Generator()
887 .addData(byteArrayOf())
888 .addLoadImmediate(R0, 0)
889 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
890 .addPass()
891 .generate()
892 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
893 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
894 var counterMap = decodeCountersIntoMap(dataRegion)
895 assertEquals(mapOf<Counter, Long>(
896 Counter.TOTAL_PACKETS to 1,
897 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
898
899 program = ApfV6Generator()
900 .addData(byteArrayOf())
901 .addLoadImmediate(R0, 0)
902 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
903 .addPass()
904 .generate()
905 dataRegion = ByteArray(Counter.totalSize()) { 0 }
906 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
907 counterMap = decodeCountersIntoMap(dataRegion)
908 assertEquals(mapOf<Counter, Long>(
909 Counter.TOTAL_PACKETS to 1,
910 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
911 }
912
Yuyang Huang2f3f4492024-02-22 16:52:17 +0900913 @Test
914 fun testGetCounterValue() {
915 val counterBytes = intArrayOf(0xff, 0, 0, 0, 0x78, 0x56, 0x34, 0x12)
916 .map { it.toByte() }.toByteArray()
917 assertEquals(0xff, ApfCounterTracker.getCounterValue(counterBytes, Counter.TOTAL_PACKETS))
918 }
919
Yuyang Huangc11962e2024-02-14 20:37:06 +0900920 private fun decodeCountersIntoMap(counterBytes: ByteArray): Map<Counter, Long> {
921 val counters = Counter::class.java.enumConstants
922 val ret = HashMap<Counter, Long>()
923 // starting from index 2 to skip the endianness mark
924 for (c in listOf(*counters).subList(2, counters.size)) {
925 val value = ApfCounterTracker.getCounterValue(counterBytes, c)
926 if (value != 0L) {
927 ret[c] = value
928 }
929 }
930 return ret
931 }
932
Yuyang Huangae57be02023-10-16 17:49:31 +0900933 private fun encodeInstruction(opcode: Int, immLength: Int, register: Int): Byte {
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900934 val immLengthEncoding = if (immLength == 4) 3 else immLength
935 return opcode.shl(3).or(immLengthEncoding.shl(1)).or(register).toByte()
Yuyang Huangae57be02023-10-16 17:49:31 +0900936 }
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900937
938 companion object {
939 const val ETH_HLEN = 14
940 const val IPV4_HLEN = 20
941 const val IPPROTO_UDP = 17
942 }
Yuyang Huangae57be02023-10-16 17:49:31 +0900943}