bpfasm 1.0.0

Berkley Packet Filter (BPF) assembler
// Copyright © Alex Forster <alex@alexforster.com>
// SPDX-License-Identifier: MIT OR Apache-2.0

#[test]
fn test() {
    let programs = [
        [
            r#"
            ldh [12]
            jne #0x806, drop
            ret #-1
            drop: ret #0
            "#,
            "4,40 0 0 12,21 0 1 2054,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            ldh [12]
            jne #0x800, drop
            ldb [23]
            jneq #6, drop
            ret #-1
            drop: ret #0
            "#,
            "6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 6,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            start:
            ldh [12]
            jne #0x800, drop
            ldb [23]
            jneq #6, drop
            ldh [20]
            jset #0x1fff, drop
            ldxb 4 * ([14] & 0xf)
            ldh [x + 14]
            jeq #0x16, pass
            ldh [x + 16]
            jne #0x16, drop
            pass: ret #-1
            drop: ret #0
            "#,
            "13,40 0 0 12,21 0 10 2048,48 0 0 23,21 0 8 6,40 0 0 20,69 6 0 8191,177 0 0 14,72 0 0 14,21 2 0 22,72 0 0 16,21 0 1 22,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            ld [4]                  /* offsetof(struct seccomp_data, arch) */
            jne #0xc000003e, bad    /* AUDIT_ARCH_X86_64 */
            ld [0]                  /* offsetof(struct seccomp_data, nr) */
            jeq #15, good           /* __NR_rt_sigreturn */
            jeq #231, good          /* __NR_exit_group */
            jeq #60, good           /* __NR_exit */
            jeq #0, good            /* __NR_read */
            jeq #1, good            /* __NR_write */
            jeq #5, good            /* __NR_fstat */
            jeq #9, good            /* __NR_mmap */
            jeq #14, good           /* __NR_rt_sigprocmask */
            jeq #13, good           /* __NR_rt_sigaction */
            jeq #35, good           /* __NR_nanosleep */
            bad: ret #0             /* SECCOMP_RET_KILL */
            good: ret #0x7fff0000   /* SECCOMP_RET_ALLOW */
            "#,
            "15,32 0 0 4,21 0 11 3221225534,32 0 0 0,21 10 0 15,21 9 0 231,21 8 0 60,21 7 0 0,21 6 0 1,21 5 0 5,21 4 0 9,21 3 0 14,21 2 0 13,21 1 0 35,6 0 0 0,6 0 0 2147418112",
        ],
        [
            r#"
            ld poff
            ret a
            "#,
            "2,32 0 0 4294963252,22 0 0 0",
        ],
        [
            r#"
            ld vlanp
            jeq #0, drop
            ret #-1
            drop: ret #0
            "#,
            "4,32 0 0 4294963248,21 1 0 0,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            ld #vlanp
            jeq #0, drop
            ld vlant
            jneq #10, drop
            ret #-1
            drop: ret #0
            "#,
            "6,32 0 0 4294963248,21 3 0 0,32 0 0 4294963244,21 0 1 10,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            ldh #proto       /* A = skb->protocol */
            
            jneq #0, skip    /* check for NETLINK_ROUTE */
            ldb [4]          /* A = nlmsg_type */
            
            jneq #0x10, skip /* check type == RTNL_NEWLINK */
            ldx #16          /* X = offset(ifinfomsg) */
            
            ldb [x + 4]      /* offset(ifi_index) */
            jneq #0x3, skip  /* check ifindex == 3 */
            
            ld #32           /* A = len(nlmsghdr) + len(ifinfomsg), payload offset */
            ldx #16          /* X = IFLA_OPERSTATE */
            ld #nla          /* A = offset(IFLA_OPERSTATE) */
            jeq #0, skip
            tax
            ld M[1]
            and x
            ldb [x + 4]      /* A = value(IFLA_OPERSTATE) */
            jneq #0x6, skip  /* check oper state is UP */
            
            ret #-1
            skip: ret #0
            "#,
            "18,40 0 0 4294963200,21 0 15 0,48 0 0 4,21 0 13 16,1 0 0 16,80 0 0 4,21 0 10 3,0 0 0 32,1 0 0 16,32 0 0 4294963212,21 6 0 0,7 0 0 0,96 0 0 1,92 0 0 0,80 0 0 4,21 0 1 6,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            ; icmp random packet sampling, 1 in 4
            ldh 	[12]
            jne 	#0x800, drop
            ldb 	[23]
            jneq 	#1, drop
            ; get a random uint32 number
            ld 		rand
            mod 	#4
            jneq 	#1, drop
            ret 	#-1
            drop: 	ret 	#0
            "#,
            "9,40 0 0 12,21 0 6 2048,48 0 0 23,21 0 4 1,32 0 0 4294963256,148 0 0 4,21 0 1 1,6 0 0 4294967295,6 0 0 0",
        ],
        [
            r#"
            ld [4]
            ld [x + 4]
            ld M[4]
            ld #4
            ld len
            ld proto
            ldi #4
            ldh [4]
            ldh [x + 4]
            ldh proto
            ldb [4]
            ldb [x + 4]
            ldb proto
            ldx M[4]
            ldx 4 * ([4] & 0xF)
            ldx #4
            ldx len
            ldxi #4
            ldxb 4 * ([4] & 0xF)
            st M[4]
            stx M[4]
            jmp jump_target_1
            ja jump_target_2
            jeq x, jump_target_3, jump_target_1
            jeq x, jump_target_2
            jeq #4, jump_target_3, jump_target_1
            jeq #4, jump_target_2
            jneq x, jump_target_3
            jne x, jump_target_1
            jneq #4, jump_target_2
            jne #4, jump_target_3
            jlt x, jump_target_1
            jlt #4, jump_target_2
            jle x, jump_target_3
            jle #4, jump_target_1
            jgt x, jump_target_2
            jgt #4, jump_target_3
            jge x, jump_target_1
            jge x, jump_target_2
            jset x, jump_target_3, jump_target_1
            jset x, jump_target_2
            jset #4, jump_target_3, jump_target_1
            jset #4, jump_target_2
            add x
            add #4
            sub x
            sub #4
            mul x
            mul #4
            div x
            div #4
            mod x
            mod #4
            neg
            and x
            and #4
            or x
            or #4
            xor x
            xor #4
            lsh x
            lsh #4
            rsh x
            rsh #4
            tax
            txa
            jump_target_1: ret a
            jump_target_2: ret x
            jump_target_3: ret #4
            "#,
            "69,32 0 0 4,64 0 0 4,96 0 0 4,0 0 0 4,128 0 0 0,32 0 0 4294963200,0 0 0 4,40 0 0 4,72 0 0 4,40 0 0 4294963200,48 0 0 4,80 0 0 4,48 0 0 4294963200,97 0 0 4,177 0 0 4,1 0 0 4,129 0 0 0,1 0 0 4,177 0 0 4,2 0 0 4,3 0 0 4,5 0 0 44,5 0 0 44,29 44 42 0,29 42 0 0,21 42 40 4,21 40 0 4,29 0 40 0,29 0 37 0,21 0 37 4,21 0 37 4,61 0 34 0,53 0 34 4,45 0 34 0,37 0 31 4,45 31 0 0,37 31 0 4,61 28 0 0,61 28 0 0,77 28 26 0,77 26 0 0,69 26 24 4,69 24 0 4,12 0 0 0,4 0 0 4,28 0 0 0,20 0 0 4,44 0 0 0,36 0 0 4,60 0 0 0,52 0 0 4,156 0 0 0,148 0 0 4,132 0 0 0,92 0 0 0,84 0 0 4,76 0 0 0,68 0 0 4,172 0 0 0,164 0 0 4,108 0 0 0,100 0 0 4,124 0 0 0,116 0 0 4,7 0 0 0,135 0 0 0,22 0 0 0,14 0 0 0,6 0 0 4",
        ]
    ];

    let extensions = bpfasm::extensions::linux();

    for [source, expected] in programs {
        let instructions = bpfasm::assemble(source, &extensions).expect("compiler error");
        let actual = format!(
            "{},{}",
            instructions.len(),
            instructions.iter().map(|s| s.to_string()).collect::<Vec<_>>().join(",")
        );
        assert_eq!(actual, expected);
    }
}