blob: 123fc0ac2e485ab5403fc89de9e55300bd6f56f2 [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,
Yuyang Huang22c76a82024-03-21 19:11:43 +0900228 DROP_LABEL
229 ).addJumpIfPktAtR0ContainDnsA(
230 byteArrayOf(0xff.toByte(), 1, 'B'.code.toByte(), 0, 0),
231 DROP_LABEL
232 ).generate()
Yuyang Huang2b402472024-02-13 16:31:55 +0900233 }
234
235 @Test
Yuyang Huangae57be02023-10-16 17:49:31 +0900236 fun testApfInstructionsEncoding() {
Yuyang Huang9b6be762024-02-22 17:06:51 +0900237 val v4gen = ApfV4Generator(MIN_APF_VERSION)
Yuyang Huangafe7b652024-02-09 09:45:01 +0900238 v4gen.addPass()
239 var program = v4gen.generate()
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900240 // encoding PASS opcode: opcode=0, imm_len=0, R=0
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900241 assertContentEquals(
242 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 0)), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900243 assertContentEquals(
244 listOf("0: pass"),
245 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900246
Yuyang Huangafe7b652024-02-09 09:45:01 +0900247 var gen = ApfV6Generator()
Yuyang Huangce1493a2023-12-07 15:29:40 +0900248 gen.addDrop()
249 program = gen.generate()
250 // encoding DROP opcode: opcode=0, imm_len=0, R=1
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900251 assertContentEquals(
252 byteArrayOf(encodeInstruction(opcode = 0, immLength = 0, register = 1)), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900253 assertContentEquals(
254 listOf("0: drop"),
255 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900256
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900257 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900258 gen.addCountAndPass(129)
259 program = gen.generate()
260 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
261 assertContentEquals(
262 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 0),
263 0x81.toByte()), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900264 assertContentEquals(
Yuyang Huang4057de52024-03-13 21:24:46 +0900265 listOf("0: pass 129"),
266 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900267
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900268 gen = ApfV6Generator()
Yuyang Huang1e5bfaf2023-12-11 00:21:54 +0900269 gen.addCountAndDrop(1000)
270 program = gen.generate()
271 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
272 assertContentEquals(
273 byteArrayOf(encodeInstruction(opcode = 0, immLength = 2, register = 1),
274 0x03, 0xe8.toByte()), program)
Yuyang Huang98b99f22024-01-29 06:35:27 +0900275 assertContentEquals(
Yuyang Huang4057de52024-03-13 21:24:46 +0900276 listOf("0: drop 1000"),
277 ApfJniUtils.disassembleApf(program).map { it.trim() } )
278
279 gen = ApfV6Generator()
280 gen.addCountAndPass(Counter.TOTAL_PACKETS)
281 program = gen.generate()
282 // encoding COUNT(PASS) opcode: opcode=0, imm_len=size_of(imm), R=0, imm=counterNumber
283 assertContentEquals(
284 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 0),
285 0x02), program)
286 assertContentEquals(
287 listOf("0: pass 2"),
288 ApfJniUtils.disassembleApf(program).map { it.trim() } )
289
290 gen = ApfV6Generator()
291 gen.addCountAndDrop(Counter.PASSED_ALLOCATE_FAILURE)
292 program = gen.generate()
293 // encoding COUNT(DROP) opcode: opcode=0, imm_len=size_of(imm), R=1, imm=counterNumber
294 assertContentEquals(
295 byteArrayOf(encodeInstruction(opcode = 0, immLength = 1, register = 1),
296 0x03), program)
297 assertContentEquals(
298 listOf("0: drop 3"),
Yuyang Huang98b99f22024-01-29 06:35:27 +0900299 ApfJniUtils.disassembleApf(program).map { it.trim() } )
Yuyang Huangce1493a2023-12-07 15:29:40 +0900300
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900301 gen = ApfV6Generator()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900302 gen.addAllocateR0()
303 gen.addAllocate(1500)
Yuyang Huangdcdb4442023-12-07 14:56:21 +0900304 program = gen.generate()
Yuyang Huang3ac843c2023-12-13 16:40:15 +0900305 // encoding ALLOC opcode: opcode=21(EXT opcode number), imm=36(TRANS opcode number).
306 // R=0 means length stored in R0. R=1 means the length stored in imm1.
307 assertContentEquals(byteArrayOf(
308 encodeInstruction(opcode = 21, immLength = 1, register = 0), 36,
309 encodeInstruction(opcode = 21, immLength = 1, register = 1), 36, 0x05,
310 0xDC.toByte()),
311 program)
Yuyang Huang626414e2024-01-29 06:52:57 +0900312 assertContentEquals(listOf("0: allocate r0", "2: allocate 1500"),
313 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900314
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900315 gen = ApfV6Generator()
Yuyang Huangfb803682024-02-20 17:52:27 +0900316 gen.addTransmitWithoutChecksum()
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900317 gen.addTransmitL4(30, 40, 50, 256, true)
Yuyang Huangae57be02023-10-16 17:49:31 +0900318 program = gen.generate()
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800319 // encoding TRANSMIT opcode: opcode=21(EXT opcode number),
320 // imm=37(TRANSMIT opcode number),
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900321 assertContentEquals(byteArrayOf(
Maciej Żenczykowskidbf2f972024-02-09 23:01:04 -0800322 encodeInstruction(opcode = 21, immLength = 1, register = 0),
323 37, 255.toByte(), 255.toByte(),
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900324 encodeInstruction(opcode = 21, immLength = 1, register = 1), 37, 30, 40, 50, 1, 0
Yuyang Huangfd74ce42023-12-12 20:10:45 +0900325 ), program)
Yuyang Huang738fa6d2024-02-13 22:03:42 +0900326 assertContentEquals(listOf(
327 "0: transmit ip_ofs=255",
328 "4: transmitudp ip_ofs=30, csum_ofs=40, csum_start=50, partial_csum=0x0100",
329 ), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900330
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900331 gen = ApfV6Generator()
Yuyang Huanga112cc82023-12-13 17:55:47 +0900332 val largeByteArray = ByteArray(256) { 0x01 }
333 gen.addData(largeByteArray)
334 program = gen.generate()
335 // encoding DATA opcode: opcode=14(JMP), R=1
336 assertContentEquals(byteArrayOf(
337 encodeInstruction(opcode = 14, immLength = 2, register = 1), 0x01, 0x00) +
338 largeByteArray, program)
Yuyang Huang937ba492024-02-04 07:20:32 +0900339 assertContentEquals(listOf("0: data 256, " + "01".repeat(256) ),
Yuyang Huangf97b28a2024-01-29 09:36:25 +0900340 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huanga112cc82023-12-13 17:55:47 +0900341
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900342 gen = ApfV6Generator()
Yuyang Huangadf69672024-01-02 10:18:11 +0900343 gen.addWriteU8(0x01)
344 gen.addWriteU16(0x0102)
345 gen.addWriteU32(0x01020304)
346 gen.addWriteU8(0x00)
347 gen.addWriteU8(0x80)
348 gen.addWriteU16(0x0000)
349 gen.addWriteU16(0x8000)
350 gen.addWriteU32(0x00000000)
351 gen.addWriteU32(0x80000000)
Yuyang Huang4ac891f2023-12-20 11:49:11 +0900352 program = gen.generate()
353 assertContentEquals(byteArrayOf(
354 encodeInstruction(24, 1, 0), 0x01,
355 encodeInstruction(24, 2, 0), 0x01, 0x02,
356 encodeInstruction(24, 4, 0), 0x01, 0x02, 0x03, 0x04,
357 encodeInstruction(24, 1, 0), 0x00,
358 encodeInstruction(24, 1, 0), 0x80.toByte(),
359 encodeInstruction(24, 2, 0), 0x00, 0x00,
360 encodeInstruction(24, 2, 0), 0x80.toByte(), 0x00,
361 encodeInstruction(24, 4, 0), 0x00, 0x00, 0x00, 0x00,
362 encodeInstruction(24, 4, 0), 0x80.toByte(), 0x00, 0x00,
363 0x00), program)
Yuyang Huang7affd672024-01-29 13:04:43 +0900364 assertContentEquals(listOf(
365 "0: write 0x01",
366 "2: write 0x0102",
367 "5: write 0x01020304",
368 "10: write 0x00",
369 "12: write 0x80",
370 "14: write 0x0000",
371 "17: write 0x8000",
372 "20: write 0x00000000",
373 "25: write 0x80000000"
Yuyang Huang15b45782024-01-18 07:19:11 +0900374 ),
Yuyang Huang7affd672024-01-29 13:04:43 +0900375 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huange84a9692024-01-01 11:49:49 +0900376
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900377 gen = ApfV6Generator()
Yuyang Huange84a9692024-01-01 11:49:49 +0900378 gen.addWriteU8(R0)
379 gen.addWriteU16(R0)
380 gen.addWriteU32(R0)
381 gen.addWriteU8(R1)
382 gen.addWriteU16(R1)
383 gen.addWriteU32(R1)
384 program = gen.generate()
385 assertContentEquals(byteArrayOf(
386 encodeInstruction(21, 1, 0), 38,
387 encodeInstruction(21, 1, 0), 39,
388 encodeInstruction(21, 1, 0), 40,
389 encodeInstruction(21, 1, 1), 38,
390 encodeInstruction(21, 1, 1), 39,
391 encodeInstruction(21, 1, 1), 40
392 ), program)
Yuyang Huangf0b46cb2024-01-30 03:37:17 +0900393 assertContentEquals(listOf(
394 "0: ewrite1 r0",
395 "2: ewrite2 r0",
396 "4: ewrite4 r0",
397 "6: ewrite1 r1",
398 "8: ewrite2 r1",
399 "10: ewrite4 r1"), ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900400
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900401 gen = ApfV6Generator()
Yuyang Huang293f7e72023-12-31 14:24:03 +0900402 gen.addDataCopy(0, 10)
403 gen.addDataCopy(1, 5)
404 gen.addPacketCopy(1000, 255)
405 program = gen.generate()
406 assertContentEquals(byteArrayOf(
407 encodeInstruction(25, 0, 1), 10,
408 encodeInstruction(25, 1, 1), 1, 5,
409 encodeInstruction(25, 2, 0),
410 0x03.toByte(), 0xe8.toByte(), 0xff.toByte(),
411 ), program)
Yuyang Huange8003982024-01-30 04:06:18 +0900412 assertContentEquals(listOf(
Yuyang Huangb2a93342024-02-07 06:32:00 +0900413 "0: datacopy src=0, len=10",
414 "2: datacopy src=1, len=5",
415 "5: pktcopy src=1000, len=255"
Yuyang Huanga699e542024-02-06 12:50:03 +0900416 ),
417 ApfJniUtils.disassembleApf(program).map { it.trim() })
Yuyang Huang293f7e72023-12-31 14:24:03 +0900418
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900419 gen = ApfV6Generator()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900420 gen.addDataCopyFromR0(5)
Yuyang Huangd0390612024-01-01 16:21:16 +0900421 gen.addPacketCopyFromR0(5)
422 gen.addDataCopyFromR0LenR1()
Yuyang Huangbed904a2024-01-30 11:22:49 +0900423 gen.addPacketCopyFromR0LenR1()
Yuyang Huangd0390612024-01-01 16:21:16 +0900424 program = gen.generate()
425 assertContentEquals(byteArrayOf(
Yuyang Huangbed904a2024-01-30 11:22:49 +0900426 encodeInstruction(21, 1, 1), 41, 5,
Yuyang Huangd0390612024-01-01 16:21:16 +0900427 encodeInstruction(21, 1, 0), 41, 5,
428 encodeInstruction(21, 1, 1), 42,
Yuyang Huangbed904a2024-01-30 11:22:49 +0900429 encodeInstruction(21, 1, 0), 42,
Yuyang Huangd0390612024-01-01 16:21:16 +0900430 ), program)
Yuyang Huangbed904a2024-01-30 11:22:49 +0900431 assertContentEquals(listOf(
Yuyang Huanga699e542024-02-06 12:50:03 +0900432 "0: edatacopy src=r0, len=5",
433 "3: epktcopy src=r0, len=5",
434 "6: edatacopy src=r0, len=r1",
435 "8: epktcopy src=r0, len=r1"), ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900436
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900437 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900438 gen.addJumpIfBytesAtR0Equal(byteArrayOf('a'.code.toByte()), ApfV4Generator.DROP_LABEL)
Yuyang Huang0f49d0a2024-01-04 19:14:22 +0900439 program = gen.generate()
440 assertContentEquals(
441 byteArrayOf(encodeInstruction(opcode = 20, immLength = 1, register = 1),
442 1, 1, 'a'.code.toByte()), program)
Yuyang Huangbffcf262024-02-04 07:52:48 +0900443 assertContentEquals(listOf(
Yuyang Huangb61b7342024-02-06 05:44:24 +0900444 "0: jbseq r0, 0x1, DROP, 61"),
Yuyang Huangbffcf262024-02-04 07:52:48 +0900445 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900446
447 val qnames = byteArrayOf(1, 'A'.code.toByte(), 1, 'B'.code.toByte(), 0, 0)
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900448 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900449 gen.addJumpIfPktAtR0DoesNotContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
450 gen.addJumpIfPktAtR0ContainDnsQ(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900451 program = gen.generate()
452 assertContentEquals(byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900453 encodeInstruction(21, 1, 0), 43, 11, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900454 ) + qnames + byteArrayOf(
Yuyang Huang823351f2024-01-08 14:28:42 +0900455 encodeInstruction(21, 1, 1), 43, 1, 0x0c.toByte(),
Yuyang Huanga01e0d72024-01-03 17:14:47 +0900456 ) + qnames, program)
Yuyang Huang49ab8822024-02-04 09:39:00 +0900457 assertContentEquals(listOf(
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900458 "0: jdnsqne r0, DROP, 12, (1)A(1)B(0)(0)",
459 "10: jdnsqeq r0, DROP, 12, (1)A(1)B(0)(0)"),
Yuyang Huang49ab8822024-02-04 09:39:00 +0900460 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900461
Yuyang Huangd89cdbe2024-02-01 09:49:07 +0900462 gen = ApfV6Generator()
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900463 gen.addJumpIfPktAtR0DoesNotContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
464 gen.addJumpIfPktAtR0ContainDnsQSafe(qnames, 0x0c, ApfV4Generator.DROP_LABEL)
465 program = gen.generate()
466 assertContentEquals(byteArrayOf(
467 encodeInstruction(21, 1, 0), 45, 11, 0x0c.toByte(),
468 ) + qnames + byteArrayOf(
469 encodeInstruction(21, 1, 1), 45, 1, 0x0c.toByte(),
470 ) + qnames, program)
471 assertContentEquals(listOf(
472 "0: jdnsqnesafe r0, DROP, 12, (1)A(1)B(0)(0)",
473 "10: jdnsqeqsafe r0, DROP, 12, (1)A(1)B(0)(0)"),
474 ApfJniUtils.disassembleApf(program).map{ it.trim() })
475
476 gen = ApfV6Generator()
Yuyang Huangaf0d3722024-01-12 13:38:44 +0900477 gen.addJumpIfPktAtR0DoesNotContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
478 gen.addJumpIfPktAtR0ContainDnsA(qnames, ApfV4Generator.DROP_LABEL)
Yuyang Huangdd2d0d92024-01-06 12:01:31 +0900479 program = gen.generate()
480 assertContentEquals(byteArrayOf(
481 encodeInstruction(21, 1, 0), 44, 10,
482 ) + qnames + byteArrayOf(
483 encodeInstruction(21, 1, 1), 44, 1,
484 ) + qnames, program)
Yuyang Huang1efe2fc2024-02-07 04:02:07 +0900485 assertContentEquals(listOf(
486 "0: jdnsane r0, DROP, (1)A(1)B(0)(0)",
487 "9: jdnsaeq r0, DROP, (1)A(1)B(0)(0)"),
488 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huang365fc3a2024-02-14 21:47:37 +0900489
490 gen = ApfV6Generator()
491 gen.addJumpIfPktAtR0DoesNotContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
492 gen.addJumpIfPktAtR0ContainDnsASafe(qnames, ApfV4Generator.DROP_LABEL)
493 program = gen.generate()
494 assertContentEquals(byteArrayOf(
495 encodeInstruction(21, 1, 0), 46, 10,
496 ) + qnames + byteArrayOf(
497 encodeInstruction(21, 1, 1), 46, 1,
498 ) + qnames, program)
499 assertContentEquals(listOf(
500 "0: jdnsanesafe r0, DROP, (1)A(1)B(0)(0)",
501 "9: jdnsaeqsafe r0, DROP, (1)A(1)B(0)(0)"),
502 ApfJniUtils.disassembleApf(program).map{ it.trim() })
Yuyang Huangae57be02023-10-16 17:49:31 +0900503 }
504
Yuyang Huang2fdba242024-02-06 14:52:22 +0900505 @Test
506 fun testWriteToTxBuffer() {
Yuyang Huangbded8e32024-02-09 13:34:58 +0900507 var program = ApfV6Generator()
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900508 .addAllocate(14)
Yuyang Huangb97aa962024-02-08 08:13:56 +0900509 .addWriteU8(0x01)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900510 .addWriteU16(0x0203)
511 .addWriteU32(0x04050607)
Yuyang Huangbded8e32024-02-09 13:34:58 +0900512 .addLoadImmediate(R0, 1)
513 .addWriteU8(R0)
514 .addLoadImmediate(R0, 0x0203)
515 .addWriteU16(R0)
516 .addLoadImmediate(R1, 0x04050607)
517 .addWriteU32(R1)
Yuyang Huangfb803682024-02-20 17:52:27 +0900518 .addTransmitWithoutChecksum()
Yuyang Huangbded8e32024-02-09 13:34:58 +0900519 .generate()
520 assertPass(MIN_APF_VERSION_IN_DEV, program, ByteArray(MIN_PKT_SIZE))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900521 assertContentEquals(byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x02, 0x03,
522 0x04, 0x05, 0x06, 0x07), ApfJniUtils.getTransmittedPacket())
Yuyang Huang2fdba242024-02-06 14:52:22 +0900523 }
524
Yuyang Huang2283be72024-02-08 04:49:08 +0900525 @Test
526 fun testCopyToTxBuffer() {
Yuyang Huang10598932024-02-14 10:00:59 +0900527 var program = ApfV6Generator()
Yuyang Huang2283be72024-02-08 04:49:08 +0900528 .addData(byteArrayOf(33, 34, 35))
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900529 .addAllocate(14)
530 .addDataCopy(2 /* src */, 2 /* len */)
531 .addDataCopy(4 /* src */, 1 /* len */)
532 .addPacketCopy(0 /* src */, 1 /* len */)
533 .addPacketCopy(1 /* src */, 3 /* len */)
534 .addLoadImmediate(R0, 2) // data copy offset
535 .addDataCopyFromR0(2 /* len */)
536 .addLoadImmediate(R0, 4) // data copy offset
537 .addLoadImmediate(R1, 1) // len
538 .addDataCopyFromR0LenR1()
539 .addLoadImmediate(R0, 0) // packet copy offset
540 .addPacketCopyFromR0(1 /* len */)
541 .addLoadImmediate(R0, 1) // packet copy offset
542 .addLoadImmediate(R1, 3) // len
543 .addPacketCopyFromR0LenR1()
Yuyang Huangfb803682024-02-20 17:52:27 +0900544 .addTransmitWithoutChecksum()
Yuyang Huang2283be72024-02-08 04:49:08 +0900545 .generate()
546 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
Yuyang Huang3fa07a72024-02-20 19:13:33 +0900547 assertContentEquals(byteArrayOf(33, 34, 35, 1, 2, 3, 4, 33, 34, 35, 1, 2, 3, 4),
548 ApfJniUtils.getTransmittedPacket())
Yuyang Huang2283be72024-02-08 04:49:08 +0900549 }
550
Yuyang Huangc11962e2024-02-14 20:37:06 +0900551 @Test
552 fun testPassDrop() {
553 var program = ApfV6Generator()
554 .addDrop()
555 .addPass()
556 .generate()
557 assertDrop(MIN_APF_VERSION_IN_DEV, program, testPacket)
558
559 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
560 program = ApfV6Generator()
561 .addData(byteArrayOf())
Yuyang Huang4057de52024-03-13 21:24:46 +0900562 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900563 .generate()
564 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
565 var counterMap = decodeCountersIntoMap(dataRegion)
566 assertEquals(mapOf<Counter, Long>(
567 Counter.TOTAL_PACKETS to 1,
568 Counter.DROPPED_ETH_BROADCAST to 1), counterMap)
569
570 dataRegion = ByteArray(Counter.totalSize()) { 0 }
571 program = ApfV6Generator()
572 .addData(byteArrayOf())
Yuyang Huang4057de52024-03-13 21:24:46 +0900573 .addCountAndPass(Counter.PASSED_ARP)
Yuyang Huangc11962e2024-02-14 20:37:06 +0900574 .generate()
575 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
576 counterMap = decodeCountersIntoMap(dataRegion)
577 assertEquals(mapOf<Counter, Long>(
578 Counter.TOTAL_PACKETS to 1,
579 Counter.PASSED_ARP to 1), counterMap)
580 }
581
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900582 @Test
Yuyang Huang4057de52024-03-13 21:24:46 +0900583 fun testV4CountAndPassDrop() {
584 var program = ApfV4Generator(APF_VERSION_4)
585 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
586 .addCountTrampoline()
587 .generate()
588 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
589 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
590 var counterMap = decodeCountersIntoMap(dataRegion)
591 assertEquals(mapOf<Counter, Long>(
592 Counter.DROPPED_ETH_BROADCAST to 1), counterMap)
593
594 program = ApfV4Generator(APF_VERSION_4)
595 .addCountAndPass(Counter.PASSED_ARP)
596 .addCountTrampoline()
597 .generate()
598 dataRegion = ByteArray(Counter.totalSize()) { 0 }
599 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
600 counterMap = decodeCountersIntoMap(dataRegion)
601 assertEquals(mapOf<Counter, Long>(
602 Counter.PASSED_ARP to 1), counterMap)
603 }
604
605 @Test
606 fun testV2CountAndPssDrop() {
607 var program = ApfV4Generator(MIN_APF_VERSION)
608 .addCountAndDrop(Counter.DROPPED_ETH_BROADCAST)
609 .addCountTrampoline()
610 .generate()
611 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
612 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, testPacket, dataRegion)
613 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
614
615 program = ApfV4Generator(MIN_APF_VERSION)
616 .addCountAndPass(Counter.DROPPED_ETH_BROADCAST)
617 .addCountTrampoline()
618 .generate()
619 dataRegion = ByteArray(Counter.totalSize()) { 0 }
620 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
621 assertContentEquals(ByteArray(Counter.totalSize()) { 0 }, dataRegion)
622 }
623
624 @Test
Yuyang Huang0e3b4cb2024-02-19 16:20:26 +0900625 fun testAllocateFailure() {
626 val program = ApfV6Generator()
627 .addData(byteArrayOf())
628 // allocate size: 65535 > sizeof(apf_test_buffer): 1514, trigger allocate failure.
629 .addAllocate(65535)
630 .addDrop()
631 .generate()
632 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
633 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
634 val counterMap = decodeCountersIntoMap(dataRegion)
635 assertEquals(mapOf<Counter, Long>(
636 Counter.TOTAL_PACKETS to 1,
637 Counter.PASSED_ALLOCATE_FAILURE to 1), counterMap)
638 }
639
Yuyang Huang19df0482024-02-19 16:38:45 +0900640 @Test
641 fun testTransmitFailure() {
642 val program = ApfV6Generator()
643 .addData(byteArrayOf())
644 .addAllocate(14)
645 // len: 13 is less than ETH_HLEN, trigger transmit failure.
646 .addLoadImmediate(R0, 13)
647 .addStoreToMemory(R0, 10)
648 .addTransmitWithoutChecksum()
649 .addDrop()
650 .generate()
651 val dataRegion = ByteArray(Counter.totalSize()) { 0 }
652 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, testPacket, dataRegion)
653 val counterMap = decodeCountersIntoMap(dataRegion)
654 assertEquals(mapOf<Counter, Long>(
655 Counter.TOTAL_PACKETS to 1,
656 Counter.PASSED_TRANSMIT_FAILURE to 1), counterMap)
657 }
658
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900659 @Test
660 fun testTransmitL4() {
661 val etherIpv4UdpPacket = intArrayOf(
662 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb,
663 0x38, 0xca, 0x84, 0xb7, 0x7f, 0x16,
664 0x08, 0x00, // end of ethernet header
665 0x45,
666 0x04,
667 0x00, 0x3f,
668 0x43, 0xcd,
669 0x40, 0x00,
670 0xff,
671 0x11,
672 0x00, 0x00, // ipv4 checksum set to 0
673 0xc0, 0xa8, 0x01, 0x03,
674 0xe0, 0x00, 0x00, 0xfb, // end of ipv4 header
675 0x14, 0xe9,
676 0x14, 0xe9,
677 0x00, 0x2b,
678 0x00, 0x2b, // end of udp header. udp checksum set to udp (header + payload) size
679 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
680 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
681 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01,
682 0x09,
683 ).map { it.toByte() }.toByteArray()
684 val program = ApfV6Generator()
685 .addData(etherIpv4UdpPacket)
686 .addAllocate(etherIpv4UdpPacket.size)
687 .addDataCopy(2 /* src */, etherIpv4UdpPacket.size /* len */)
688 .addTransmitL4(ETH_HLEN /* ipOfs */,
689 ETH_HLEN + IPV4_HLEN + 6 /* csumOfs */,
690 ETH_HLEN + IPV4_HLEN - 8 /* csumStart */,
691 IPPROTO_UDP /* partialCsum */,
692 true /* isUdp */)
693 .generate()
694 assertPass(MIN_APF_VERSION_IN_DEV, program, testPacket)
695 val txBuf = ByteBuffer.wrap(ApfJniUtils.getTransmittedPacket())
696 Struct.parse(EthernetHeader::class.java, txBuf)
697 val ipv4Hdr = Struct.parse(Ipv4Header::class.java, txBuf)
698 val udpHdr = Struct.parse(UdpHeader::class.java, txBuf)
699 assertEquals(0x9535.toShort(), ipv4Hdr.checksum)
700 assertEquals(0xa73d.toShort(), udpHdr.checksum)
701 }
702
Yuyang Huangebd52752024-02-20 17:08:55 +0900703 @Test
704 fun testDnsQuestionMatch() {
705 // needles = { A, B.LOCAL }
706 val needlesMatch = intArrayOf(
707 0x01, 'A'.code,
708 0x00,
709 0x01, 'B'.code,
710 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
711 0x00,
712 0x00
713 ).map { it.toByte() }.toByteArray()
714 val udpPayload = intArrayOf(
715 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
716 0x00, 0x02, // qdcount = 2
717 0x00, 0x00, // ancount = 0
718 0x00, 0x00, // nscount = 0
719 0x00, 0x00, // arcount = 0
720 0x01, 'a'.code,
721 0x01, 'b'.code,
722 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
723 0x00, // qname1 = a.b.local
724 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
725 0xc0, 0x0e, // qname2 = b.local (name compression)
726 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
727 ).map { it.toByte() }.toByteArray()
728
729 var program = ApfV6Generator()
730 .addData(byteArrayOf())
731 .addLoadImmediate(R0, 0)
732 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
733 .addPass()
734 .generate()
735 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
736
737 program = ApfV6Generator()
738 .addData(byteArrayOf())
739 .addLoadImmediate(R0, 0)
740 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
741 .addPass()
742 .generate()
743 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
744
745 program = ApfV6Generator()
746 .addData(byteArrayOf())
747 .addLoadImmediate(R0, 0)
748 .addJumpIfPktAtR0DoesNotContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
749 .addPass()
750 .generate()
751 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
752
753 program = ApfV6Generator()
754 .addData(byteArrayOf())
755 .addLoadImmediate(R0, 0)
756 .addJumpIfPktAtR0DoesNotContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
757 .addPass()
758 .generate()
759 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
760
761 val badUdpPayload = intArrayOf(
762 0x00, 0x00, 0x00, 0x00, // tid = 0x00, flags = 0x00,
763 0x00, 0x02, // qdcount = 2
764 0x00, 0x00, // ancount = 0
765 0x00, 0x00, // nscount = 0
766 0x00, 0x00, // arcount = 0
767 0x01, 'a'.code,
768 0x01, 'b'.code,
769 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
770 0x00, // qname1 = a.b.local
771 0x00, 0x01, 0x00, 0x01, // type = A, class = 0x0001
772 0xc0, 0x1b, // corrupted pointer cause infinite loop
773 0x00, 0x01, 0x00, 0x01 // type = A, class = 0x0001
774 ).map { it.toByte() }.toByteArray()
775
776 program = ApfV6Generator()
777 .addData(byteArrayOf())
778 .addLoadImmediate(R0, 0)
779 .addJumpIfPktAtR0ContainDnsQ(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
780 .addPass()
781 .generate()
782 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
783 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
784 var counterMap = decodeCountersIntoMap(dataRegion)
785 assertEquals(mapOf<Counter, Long>(
786 Counter.TOTAL_PACKETS to 1,
787 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
788
789 program = ApfV6Generator()
790 .addData(byteArrayOf())
791 .addLoadImmediate(R0, 0)
792 .addJumpIfPktAtR0ContainDnsQSafe(needlesMatch, 0x01 /* qtype */, DROP_LABEL)
793 .addPass()
794 .generate()
795 dataRegion = ByteArray(Counter.totalSize()) { 0 }
796 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
797 counterMap = decodeCountersIntoMap(dataRegion)
798 assertEquals(mapOf<Counter, Long>(
799 Counter.TOTAL_PACKETS to 1,
800 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
801 }
802
803 @Test
804 fun testDnsAnswerMatch() {
805 // needles = { A, B.LOCAL }
806 val needlesMatch = intArrayOf(
807 0x01, 'A'.code,
808 0x00,
809 0x01, 'B'.code,
810 0x05, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code,
811 0x00,
812 0x00
813 ).map { it.toByte() }.toByteArray()
814
815 val udpPayload = intArrayOf(
816 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
817 0x00, 0x00, // qdcount = 0
818 0x00, 0x02, // ancount = 2
819 0x00, 0x00, // nscount = 0
820 0x00, 0x00, // arcount = 0
821 0x01, 'a'.code,
822 0x01, 'b'.code,
823 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
824 0x00, // name1 = a.b.local
825 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
826 0x00, 0x00, 0x00, 0x78, // ttl = 120
827 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
828 0xc0, 0x0e, // name2 = b.local (name compression)
829 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
830 0x00, 0x00, 0x00, 0x78, // ttl = 120
831 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
832 ).map { it.toByte() }.toByteArray()
833
834 var program = ApfV6Generator()
835 .addData(byteArrayOf())
836 .addLoadImmediate(R0, 0)
837 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
838 .addPass()
839 .generate()
840 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
841
842 program = ApfV6Generator()
843 .addData(byteArrayOf())
844 .addLoadImmediate(R0, 0)
845 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
846 .addPass()
847 .generate()
848 assertDrop(MIN_APF_VERSION_IN_DEV, program, udpPayload)
849
850 program = ApfV6Generator()
851 .addData(byteArrayOf())
852 .addLoadImmediate(R0, 0)
853 .addJumpIfPktAtR0DoesNotContainDnsA(needlesMatch, DROP_LABEL)
854 .addPass()
855 .generate()
856 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
857
858 program = ApfV6Generator()
859 .addData(byteArrayOf())
860 .addLoadImmediate(R0, 0)
861 .addJumpIfPktAtR0DoesNotContainDnsASafe(needlesMatch, DROP_LABEL)
862 .addPass()
863 .generate()
864 assertPass(MIN_APF_VERSION_IN_DEV, program, udpPayload)
865
866 val badUdpPayload = intArrayOf(
867 0x00, 0x00, 0x84, 0x00, // tid = 0x00, flags = 0x8400,
868 0x00, 0x00, // qdcount = 0
869 0x00, 0x02, // ancount = 2
870 0x00, 0x00, // nscount = 0
871 0x00, 0x00, // arcount = 0
872 0x01, 'a'.code,
873 0x01, 'b'.code,
874 0x05, 'l'.code, 'o'.code, 'c'.code, 'a'.code, 'l'.code,
875 0x00, // name1 = a.b.local
876 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
877 0x00, 0x00, 0x00, 0x78, // ttl = 120
878 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09, // rdlengh = 4, rdata = 192.168.1.9
879 0xc0, 0x25, // corrupted pointer cause infinite loop
880 0x00, 0x01, 0x80, 0x01, // type = A, class = 0x8001
881 0x00, 0x00, 0x00, 0x78, // ttl = 120
882 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x09 // rdlengh = 4, rdata = 192.168.1.9
883 ).map { it.toByte() }.toByteArray()
884
885 program = ApfV6Generator()
886 .addData(byteArrayOf())
887 .addLoadImmediate(R0, 0)
888 .addJumpIfPktAtR0ContainDnsA(needlesMatch, DROP_LABEL)
889 .addPass()
890 .generate()
891 var dataRegion = ByteArray(Counter.totalSize()) { 0 }
892 assertVerdict(MIN_APF_VERSION_IN_DEV, DROP, program, badUdpPayload, dataRegion)
893 var counterMap = decodeCountersIntoMap(dataRegion)
894 assertEquals(mapOf<Counter, Long>(
895 Counter.TOTAL_PACKETS to 1,
896 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
897
898 program = ApfV6Generator()
899 .addData(byteArrayOf())
900 .addLoadImmediate(R0, 0)
901 .addJumpIfPktAtR0ContainDnsASafe(needlesMatch, DROP_LABEL)
902 .addPass()
903 .generate()
904 dataRegion = ByteArray(Counter.totalSize()) { 0 }
905 assertVerdict(MIN_APF_VERSION_IN_DEV, PASS, program, badUdpPayload, dataRegion)
906 counterMap = decodeCountersIntoMap(dataRegion)
907 assertEquals(mapOf<Counter, Long>(
908 Counter.TOTAL_PACKETS to 1,
909 Counter.CORRUPT_DNS_PACKET to 1), counterMap)
910 }
911
Yuyang Huang2f3f4492024-02-22 16:52:17 +0900912 @Test
913 fun testGetCounterValue() {
914 val counterBytes = intArrayOf(0xff, 0, 0, 0, 0x78, 0x56, 0x34, 0x12)
915 .map { it.toByte() }.toByteArray()
916 assertEquals(0xff, ApfCounterTracker.getCounterValue(counterBytes, Counter.TOTAL_PACKETS))
917 }
918
Yuyang Huangc11962e2024-02-14 20:37:06 +0900919 private fun decodeCountersIntoMap(counterBytes: ByteArray): Map<Counter, Long> {
920 val counters = Counter::class.java.enumConstants
921 val ret = HashMap<Counter, Long>()
922 // starting from index 2 to skip the endianness mark
923 for (c in listOf(*counters).subList(2, counters.size)) {
924 val value = ApfCounterTracker.getCounterValue(counterBytes, c)
925 if (value != 0L) {
926 ret[c] = value
927 }
928 }
929 return ret
930 }
931
Yuyang Huangae57be02023-10-16 17:49:31 +0900932 private fun encodeInstruction(opcode: Int, immLength: Int, register: Int): Byte {
Yuyang Huang73c6d2d2023-10-19 13:32:37 +0900933 val immLengthEncoding = if (immLength == 4) 3 else immLength
934 return opcode.shl(3).or(immLengthEncoding.shl(1)).or(register).toByte()
Yuyang Huangae57be02023-10-16 17:49:31 +0900935 }
Yuyang Huangbcfa09b2024-02-20 11:20:47 +0900936
937 companion object {
938 const val ETH_HLEN = 14
939 const val IPV4_HLEN = 20
940 const val IPPROTO_UDP = 17
941 }
Yuyang Huangae57be02023-10-16 17:49:31 +0900942}