diff --git a/pkg/tcpip/nftables/nftables.go b/pkg/tcpip/nftables/nftables.go index 0063102af..54cea7a4d 100644 --- a/pkg/tcpip/nftables/nftables.go +++ b/pkg/tcpip/nftables/nftables.go @@ -42,8 +42,6 @@ import ( "fmt" "slices" - "encoding/binary" - "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -658,22 +656,17 @@ func (op comparison) evaluate(regs *registerSet, pkt *stack.PacketBuffer) { // Gets the data from the source register. regBuf := bytesData.getRegisterBuffer(regs, op.sreg) - // Compares from left to right in 4-byte chunks starting with the rightmost - // byte of every 4-byte chunk since the data is little endian. - // For example, 16-byte IPv6 address 2001:000a:130f:0000:0000:09c0:876a:130b - // is represented as 0x0a000120 0x00000f13 0xc0090000 0x0b136a87 in operations - // and as [0a|00|01|20|00|00|0f|13|c0|09|00|00|0b|13|6a|87] in the byte slice, - // so we compare right to left in the first 4 bytes and then go to the next 4. + // Compares bytes from left to right for all bytes in the comparison data. dif := 0 - for i := 0; i < len(bytesData.data) && dif == 0; i += 4 { - regVal := binary.LittleEndian.Uint32(regBuf[i : i+4]) - opVal := binary.LittleEndian.Uint32(bytesData.data[i : i+4]) - if regVal < opVal { + for i := 0; i < len(bytesData.data) && dif == 0; i++ { + if regBuf[i] < bytesData.data[i] { dif = -1 - } else if regVal > opVal { + } else if regBuf[i] > bytesData.data[i] { dif = 1 } } + + // Determines the comparison result depending on the operator. var result bool switch op.cop { case linux.NFT_CMP_EQ: @@ -777,22 +770,25 @@ func (rd verdictData) storeData(regs *registerSet, reg uint8) { regs.verdict = rd.data } -// bytesData represents data in 4-byte chunks to be stored in a register. +// bytesData represents <= 16 bytes of data to be stored in a register. type bytesData struct { data []byte } -// newBytesData creates a RegisterData for 4, 8, 12, or 16 bytes of data. +// newBytesData creates a RegisterData for <= 16 bytes of data. func newBytesData(bytes []byte) registerData { - if len(bytes)%4 != 0 || len(bytes) > 16 { - panic(fmt.Errorf("invalid byte data length: %d", len(bytes))) + if len(bytes) == 0 { + panic("bytes data cannot be empty") + } + if len(bytes) > 16 { + panic(fmt.Errorf("bytes data cannot be more than 16 bytes: %d", len(bytes))) } return bytesData{data: bytes} } -// String returns a string representation of the bytes data. +// String returns a string representation of the big endian bytes data. func (rd bytesData) String() string { - return fmt.Sprintf("%x", rd.data) + return fmt.Sprintf("be %x", rd.data) } // equal compares the bytes data to another RegisterData object. @@ -812,7 +808,7 @@ func (rd bytesData) validateRegister(reg uint8) error { if isVerdictRegister(reg) { return fmt.Errorf("data cannot be stored in verdict register") } - if is4ByteRegister(reg) && len(rd.data) != 4 { + if is4ByteRegister(reg) && len(rd.data) > 4 { return fmt.Errorf("%d-byte data cannot be stored in 4-byte register", len(rd.data)) } // 16-byte register can be used for any data (guaranteed to be <= 16 bytes) @@ -824,15 +820,14 @@ func (rd bytesData) validateRegister(reg uint8) error { // Note: does not support verdict data and assumes the register is valid for the // given data type. func (rd bytesData) getRegisterBuffer(regs *registerSet, reg uint8) []byte { - // The entire 4-byte register (data must be exactly 4 bytes) + // Returns the entire 4-byte register if is4ByteRegister(reg) { start := (reg - linux.NFT_REG32_00) * linux.NFT_REG32_SIZE return regs.data[start : start+linux.NFT_REG32_SIZE] } - // The appropriate (mod 4)-byte data in a 16-byte register - // Leaves excess space on the left (bc the data is little endian). - end := (int(reg)-linux.NFT_REG_1)*linux.NFT_REG_SIZE + linux.NFT_REG_SIZE - return regs.data[end-len(rd.data) : end] + // Returns the entire 16-byte register + start := (reg - linux.NFT_REG_1) * linux.NFT_REG_SIZE + return regs.data[start : start+linux.NFT_REG_SIZE] } // storeData sets the data in the destination register to the bytes data. diff --git a/pkg/tcpip/nftables/nftables_test.go b/pkg/tcpip/nftables/nftables_test.go index 6977792c2..890b80805 100644 --- a/pkg/tcpip/nftables/nftables_test.go +++ b/pkg/tcpip/nftables/nftables_test.go @@ -106,9 +106,9 @@ func TestAcceptAllForSupportedHooks(t *testing.T) { } } -// TestEvaluateImmediate tests that the Immediate operation correctly sets the +// TestEvaluateImmediateVerdict tests that the Immediate operation correctly sets the // register value and behaves as expected during evaluation. -func TestEvaluateImmediate(t *testing.T) { +func TestEvaluateImmediateVerdict(t *testing.T) { for _, test := range []struct { tname string baseOp1 operation // will be nil if unused @@ -234,6 +234,12 @@ func TestEvaluateImmediate(t *testing.T) { baseOp2: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NF_ACCEPT)})), verdict: Verdict{Code: VC(linux.NF_DROP)}, }, + { + tname: "immediate load register", + baseOp1: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NF_DROP)})), + baseOp2: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NF_ACCEPT)})), + verdict: Verdict{Code: VC(linux.NF_DROP)}, + }, } { t.Run(test.tname, func(t *testing.T) { // Sets up an NFTables object with a base chain (for 2 rules) and another @@ -290,6 +296,62 @@ func TestEvaluateImmediate(t *testing.T) { } } +// TestEvaluateImmediateVerdict tests that the Immediate operation correctly +// loads bytes data of all lengths into all supported registers. +func TestEvaluateImmediateBytesData(t *testing.T) { + bytes := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10} + for blen := 1; blen <= len(bytes); blen++ { + for _, registerSize := range []int{linux.NFT_REG32_SIZE, linux.NFT_REG_SIZE} { + if blen > registerSize { + continue + } + tname := fmt.Sprintf("immediately load %d bytes into %d-byte registers", blen, registerSize) + t.Run(tname, func(t *testing.T) { + // Sets up an NFTables object with a base chain with policy accept. + nf := NewNFTables() + tab, err := nf.AddTable(arbitraryFamily, "test", "test table", false) + if err != nil { + t.Fatalf("unexpected error for AddTable: %v", err) + } + bc, err := tab.AddChain("base_chain", nil, "test chain", false) + if err != nil { + t.Fatalf("unexpected error for AddChain: %v", err) + } + bc.SetBaseChainInfo(arbitraryInfoPolicyAccept) + + // Adds a rule and immediate operation per register of registerSize. + switch registerSize { + case linux.NFT_REG32_SIZE: + for reg := linux.NFT_REG32_00; reg <= linux.NFT_REG32_15; reg++ { + rule := &Rule{} + rule.addOperation(mustCreateImmediate(t, uint8(reg), newBytesData(bytes[:blen]))) + if err := bc.RegisterRule(rule, -1); err != nil { + t.Fatalf("unexpected error for RegisterRule for rule %d: %v", reg-linux.NFT_REG32_00, err) + } + } + case linux.NFT_REG_SIZE: + for reg := linux.NFT_REG_1; reg <= linux.NFT_REG_4; reg++ { + rule := &Rule{} + rule.addOperation(mustCreateImmediate(t, uint8(reg), newBytesData(bytes[:blen]))) + if err := bc.RegisterRule(rule, -1); err != nil { + t.Fatalf("unexpected error for RegisterRule for rule %d: %v", reg-linux.NFT_REG_1, err) + } + } + } + // Runs evaluation and checks for default policy verdict accept + pkt := makeTestingPacket() + v, err := nf.EvaluateHook(arbitraryFamily, arbitraryHook, pkt) + if err != nil { + t.Fatalf("unexpected error for EvaluateHook: %v", err) + } + if v.Code != linux.NF_ACCEPT { + t.Fatalf("expected default policy verdict accept, got %v", v) + } + }) + } + } +} + // TestEvaluateComparison tests that the Comparison operation correctly compares // the data in the source register to the given data. // Note: Relies on expected behavior of the Immediate operation. @@ -345,8 +407,8 @@ func TestEvaluateComparison(t *testing.T) { }, { tname: "compare register > 4-byte data, true", - op1: mustCreateImmediate(t, linux.NFT_REG32_15, newBytesData([]byte{0, 0, 0, 1})), - op2: mustCreateComparison(t, linux.NFT_REG32_15, linux.NFT_CMP_GT, newBytesData([]byte{29, 76, 230, 0})), + op1: mustCreateImmediate(t, linux.NFT_REG32_15, newBytesData([]byte{29, 76, 230, 0})), + op2: mustCreateComparison(t, linux.NFT_REG32_15, linux.NFT_CMP_GT, newBytesData([]byte{0, 0, 0, 1})), res: true, }, { @@ -381,8 +443,8 @@ func TestEvaluateComparison(t *testing.T) { }, { tname: "compare register >= 4-byte data, true gt", - op1: mustCreateImmediate(t, linux.NFT_REG32_12, newBytesData([]byte{0, 0, 0, 1})), - op2: mustCreateComparison(t, linux.NFT_REG32_12, linux.NFT_CMP_GTE, newBytesData([]byte{29, 76, 230, 0})), + op1: mustCreateImmediate(t, linux.NFT_REG32_12, newBytesData([]byte{29, 76, 230, 0})), + op2: mustCreateComparison(t, linux.NFT_REG32_12, linux.NFT_CMP_GTE, newBytesData([]byte{0, 0, 0, 1})), res: true, }, { @@ -442,8 +504,8 @@ func TestEvaluateComparison(t *testing.T) { }, { tname: "compare register > 8-byte data, true", - op1: mustCreateImmediate(t, linux.NFT_REG_4, newBytesData([]byte{0, 0, 0, 1, 0, 0, 0, 0})), - op2: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_GT, newBytesData([]byte{29, 76, 230, 0, 0, 0, 0, 0})), + op1: mustCreateImmediate(t, linux.NFT_REG_4, newBytesData([]byte{29, 76, 230, 0, 0, 0, 0, 0})), + op2: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_GT, newBytesData([]byte{0, 0, 0, 1, 0, 0, 0, 0})), res: true, }, { @@ -478,7 +540,7 @@ func TestEvaluateComparison(t *testing.T) { }, { tname: "compare register >= 8-byte data, true gt", - op1: mustCreateImmediate(t, linux.NFT_REG_2, newBytesData([]byte{0, 0, 0, 1, 0, 0, 0, 0})), + op1: mustCreateImmediate(t, linux.NFT_REG_2, newBytesData([]byte{30, 0, 0, 1, 0, 0, 0, 0})), op2: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GTE, newBytesData([]byte{29, 76, 230, 0, 0, 0, 0, 0})), res: true, }, diff --git a/pkg/tcpip/nftables/nftinterp.go b/pkg/tcpip/nftables/nftinterp.go index 383c05e38..9abeee06a 100644 --- a/pkg/tcpip/nftables/nftinterp.go +++ b/pkg/tcpip/nftables/nftinterp.go @@ -365,17 +365,18 @@ func parseVerdict(tokens []string, lnIdx int, tkIdx int) (int, Verdict, error) { return tkIdx, v, nil } -// parseHexData parses little endian hexadecimal data from the given token and -// returns the index of the next token to process (can consume multiple tokens). +// parseHexData parses little endian hexadecimal data from the given token, +// converts to big endian, and returns the index of the next token to process. func parseHexData(tokens []string, lnIdx int, tkIdx int) (int, registerData, error) { var bytes []byte for ; tkIdx < len(tokens); tkIdx++ { - if len(tokens[tkIdx]) < 2 || tokens[tkIdx][:2] != "0x" { + if len(tokens[tkIdx]) <= 2 || tokens[tkIdx][:2] != "0x" { break } - if len(tokens[tkIdx]) != 10 { - return 0, nil, &SyntaxError{lnIdx, tkIdx, fmt.Sprintf("hexadecimal data must be exactly 8 digits long (excluding 0x): '%s'", tokens[tkIdx])} + // Hexadecimal data must have 2 digits per byte (even number of characters). + if len(tokens[tkIdx])%2 != 0 { + return 0, nil, &SyntaxError{lnIdx, tkIdx, fmt.Sprintf("invalid hexadecimal data: '%s'", tokens[tkIdx])} } // Decodes the little endian hex string into bytes @@ -383,6 +384,8 @@ func parseHexData(tokens []string, lnIdx int, tkIdx int) (int, registerData, err if err != nil { return 0, nil, &SyntaxError{lnIdx, tkIdx, fmt.Sprintf("could not decode hexadecimal data: '%s'", tokens[tkIdx])} } + // Converts the bytes to big endian and appends to the bytes slice. + slices.Reverse(bytes4) bytes = append(bytes, bytes4...) } if len(bytes) > 16 { diff --git a/pkg/tcpip/nftables/nftinterp_test.go b/pkg/tcpip/nftables/nftinterp_test.go index dbde4d23a..cfaa6048a 100644 --- a/pkg/tcpip/nftables/nftinterp_test.go +++ b/pkg/tcpip/nftables/nftinterp_test.go @@ -105,40 +105,25 @@ func TestInterpretImmediateOps(t *testing.T) { opStr: "[ immediate reg 2 jump -> next_chain ]", expected: nil, }, - { - tname: "16-byte register with 2-byte data", - opStr: "[ immediate reg 2 0xb80d ]", - expected: nil, // can handle 2-byte data but must be padded to 4-bytes - }, { tname: "16-byte register with 4-byte data", opStr: "[ immediate reg 1 0x0201a8c0 ]", - expected: mustCreateImmediate(t, linux.NFT_REG_1, newBytesData([]byte{0x02, 0x01, 0xa8, 0xc0})), - }, - { - tname: "16-byte register with 6-byte data", - opStr: "[ immediate reg 2 0xb80d0120 0x0050 ]", - expected: nil, // can handle 6-byte data but must be padded to 8-bytes + expected: mustCreateImmediate(t, linux.NFT_REG_1, newBytesData([]byte{0xc0, 0xa8, 0x01, 0x02})), }, { tname: "16-byte register with 8-byte data", opStr: "[ immediate reg 2 0xb80d0120 0x00000050 ]", - expected: mustCreateImmediate(t, linux.NFT_REG_2, newBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x50})), + expected: mustCreateImmediate(t, linux.NFT_REG_2, newBytesData([]byte{0x20, 0x01, 0x0d, 0xb8, 0x50, 0x00, 0x00, 0x00})), }, { tname: "16-byte register with 12-byte data", opStr: "[ immediate reg 3 0xb80d0120 0x00000050 0xb80d0120 ]", - expected: mustCreateImmediate(t, linux.NFT_REG_3, newBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x50, 0xb8, 0x0d, 0x01, 0x20})), + expected: mustCreateImmediate(t, linux.NFT_REG_3, newBytesData([]byte{0x20, 0x01, 0x0d, 0xb8, 0x50, 0x00, 0x00, 0x00, 0x20, 0x01, 0x0d, 0xb8})), }, { tname: "16-byte register with 16-byte data", opStr: "[ immediate reg 4 0xb80d0120 0x00000000 0x00000000 0x02000000 ]", - expected: mustCreateImmediate(t, linux.NFT_REG_4, newBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00})), - }, - { - tname: "16-byte register with uneven bytes data", - opStr: "[ immediate reg 2 0xb80d0120 0x0f60a0 ]", - expected: nil, // can handle uneven but must be padded to 4-byte multiple + expected: mustCreateImmediate(t, linux.NFT_REG_4, newBytesData([]byte{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})), }, { tname: "4-byte register with verdict data", @@ -150,16 +135,6 @@ func TestInterpretImmediateOps(t *testing.T) { opStr: "[ immediate reg 9 goto -> next_chain ]", expected: nil, }, - { - tname: "4-byte register with 2-byte data", - opStr: "[ immediate reg 8 0xb80d ]", - expected: nil, // can handle 2-byte data but must be padded to 4-bytes - }, - { - tname: "4-byte register with 4-byte data", - opStr: "[ immediate reg 10 0x0201a8c0 ]", - expected: mustCreateImmediate(t, linux.NFT_REG32_02, newBytesData([]byte{0x02, 0x01, 0xa8, 0xc0})), - }, { tname: "4-byte register with 16-byte data", opStr: "[ immediate reg 9 0xb80d0120 0x00000000 0x00000000 0x02000000 ]", @@ -213,12 +188,12 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "4-byte register == 4-byte data", opStr: "[ cmp eq reg 8 0x0302010a ]", - expected: mustCreateComparison(t, linux.NFT_REG32_00, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a})), + expected: mustCreateComparison(t, linux.NFT_REG32_00, linux.NFT_CMP_EQ, newBytesData([]byte{0x0a, 0x01, 0x02, 0x03})), }, { tname: "4-byte register != 4-byte data", opStr: "[ cmp neq reg 9 0x00000064 ]", - expected: mustCreateComparison(t, linux.NFT_REG32_01, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG32_01, linux.NFT_CMP_NEQ, newBytesData([]byte{0x64, 0x00, 0x00, 0x00})), }, { tname: "4-byte register < 4-byte data", @@ -228,17 +203,17 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "4-byte register <= 4-byte data", opStr: "[ cmp lte reg 11 0x00000164 ]", - expected: mustCreateComparison(t, linux.NFT_REG32_03, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG32_03, linux.NFT_CMP_LTE, newBytesData([]byte{0x64, 0x01, 0x00, 0x00})), }, { tname: "4-byte register > 4-byte data", opStr: "[ cmp gt reg 12 0xe8030000 ]", - expected: mustCreateComparison(t, linux.NFT_REG32_04, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG32_04, linux.NFT_CMP_GT, newBytesData([]byte{0x00, 0x00, 0x03, 0xe8})), }, { tname: "4-byte register >= 4-byte data", opStr: "[ cmp gte reg 13 0xc02b0000 ]", - expected: mustCreateComparison(t, linux.NFT_REG32_05, linux.NFT_CMP_GTE, newBytesData([]byte{0xc0, 0x2b, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG32_05, linux.NFT_CMP_GTE, newBytesData([]byte{0x00, 0x00, 0x2b, 0xc0})), }, { tname: "4-byte register with 8-byte data comparison", @@ -258,12 +233,12 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "16-byte register == 4-byte data", opStr: "[ cmp eq reg 1 0x0302010a ]", - expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a})), + expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x0a, 0x01, 0x02, 0x03})), }, { tname: "16-byte register != 4-byte data", opStr: "[ cmp neq reg 2 0x00000064 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x64, 0x00, 0x00, 0x00})), }, { tname: "16-byte register < 4-byte data", @@ -273,27 +248,27 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "16-byte register <= 4-byte data", opStr: "[ cmp lte reg 4 0x00000164 ]", - expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x64, 0x01, 0x00, 0x00})), }, { tname: "16-byte register > 4-byte data", opStr: "[ cmp gt reg 1 0xe8030000 ]", - expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_GT, newBytesData([]byte{0x00, 0x00, 0x03, 0xe8})), }, { tname: "16-byte register >= 4-byte data", opStr: "[ cmp gte reg 2 0xc02b0000 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GTE, newBytesData([]byte{0xc0, 0x2b, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GTE, newBytesData([]byte{0x00, 0x00, 0x2b, 0xc0})), }, { tname: "16-byte register == 8-byte data", opStr: "[ cmp eq reg 1 0x0302010a 0x12345678 ]", - expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x12, 0x34, 0x56, 0x78})), + expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x0a, 0x01, 0x02, 0x03, 0x78, 0x56, 0x34, 0x12})), }, { tname: "16-byte register != 8-byte data", opStr: "[ cmp neq reg 2 0x00000064 0x00000020 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x20})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x64, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00})), }, { tname: "16-byte register < 8-byte data", @@ -303,27 +278,27 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "16-byte register <= 8-byte data", opStr: "[ cmp lte reg 4 0x00000164 0x00000164 ]", - expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00})), }, { tname: "16-byte register > 8-byte data", opStr: "[ cmp gt reg 2 0xe8030000 0x00000f13 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0x00, 0x00, 0x03, 0xe8, 0x13, 0x0f, 0x00, 0x00})), }, { tname: "16-byte register >= 8-byte data", opStr: "[ cmp gte reg 3 0x0a000120 0xc0090000 ]", - expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0xc0, 0x09, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x20, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x09, 0xc0})), }, { tname: "16-byte register == 12-byte data", opStr: "[ cmp eq reg 1 0x0302010a 0x00000000 0x12345678 ]", - expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78})), + expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x0a, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12})), }, { tname: "16-byte register != 12-byte data", opStr: "[ cmp neq reg 2 0x00000064 0x00000000 0x00000020 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00})), }, { tname: "16-byte register < 12-byte data", @@ -333,27 +308,27 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "16-byte register <= 12-byte data", opStr: "[ cmp lte reg 4 0x00000164 0x00000164 0x00000164 ]", - expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00})), }, { tname: "16-byte register > 12-byte data", opStr: "[ cmp gt reg 2 0xe8030000 0x00000f13 0xc0090000 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0x00, 0x00, 0x03, 0xe8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0})), }, { tname: "16-byte register >= 12-byte data", opStr: "[ cmp gte reg 3 0x0a000120 0x00000f13 0xc0090000 ]", - expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x20, 0x01, 0x00, 0x0a, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0})), }, { tname: "16-byte register == 16-byte data", opStr: "[ cmp eq reg 1 0x0302010a 0x00000000 0x00000000 0x02000002 ]", - expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02})), + expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x0a, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02})), }, { tname: "16-byte register != 16-byte data", opStr: "[ cmp neq reg 2 0x00000064 0x00000000 0x00000000 0x02000000 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})), }, { tname: "16-byte register < 16-byte data", @@ -363,17 +338,17 @@ func TestInterpretComparisonOps(t *testing.T) { { tname: "16-byte register <= 16-byte data", opStr: "[ cmp lte reg 4 0x00000164 0x00000164 0x00000164 0x00000164 ]", - expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})), + expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00})), }, { tname: "16-byte register > 16-byte data", opStr: "[ cmp gt reg 2 0xe8030000 0x00000f13 0xc0090000 0x0b136a87 ]", - expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00, 0x0b, 0x13, 0x6a, 0x87})), + expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0x00, 0x00, 0x03, 0xe8, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b})), }, { tname: "16-byte register >= 16-byte data", opStr: "[ cmp gte reg 3 0x0a000120 0x00000f13 0xc0090000 0x0b136a87 ]", - expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00, 0x0b, 0x13, 0x6a, 0x87})), + expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x20, 0x01, 0x00, 0x0a, 0x13, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x87, 0x6a, 0x13, 0x0b})), }, } { t.Run(test.tname, func(t *testing.T) { checkOp(t, test, checkComparisonOp) })