package firewall import ( "net/netip" "testing" "github.com/stretchr/testify/assert" ) func Test_parseIptablesInstruction(t *testing.T) { t.Parallel() testCases := map[string]struct { s string instruction iptablesInstruction errWrapped error errMessage string }{ "no_instruction": { errWrapped: ErrIptablesCommandMalformed, errMessage: "iptables command is malformed: empty instruction", }, "uneven_fields": { s: "-A", errWrapped: ErrIptablesCommandMalformed, errMessage: "iptables command is malformed: fields count 1 is not even: \"-A\"", }, "unknown_key": { s: "-x something", errWrapped: ErrIptablesCommandMalformed, errMessage: "parsing \"-x something\": iptables command is malformed: unknown key \"-x\"", }, "one_pair": { s: "-A INPUT", instruction: iptablesInstruction{ table: "filter", chain: "INPUT", append: true, }, }, "instruction_A": { s: "-A INPUT -i tun0 -p tcp -m tcp -s 1.2.3.4/32 -d 5.6.7.8 --dport 10000 -j ACCEPT", instruction: iptablesInstruction{ table: "filter", chain: "INPUT", append: true, inputInterface: "tun0", protocol: "tcp", source: netip.MustParsePrefix("1.2.3.4/32"), destination: netip.MustParsePrefix("5.6.7.8/32"), destinationPort: 10000, target: "ACCEPT", }, }, "nat_redirection": { s: "-t nat --delete PREROUTING -i tun0 -p tcp --dport 43716 -j REDIRECT --to-ports 5678", instruction: iptablesInstruction{ table: "nat", chain: "PREROUTING", append: false, inputInterface: "tun0", protocol: "tcp", destinationPort: 43716, target: "REDIRECT", toPorts: []uint16{5678}, }, }, } for name, testCase := range testCases { testCase := testCase t.Run(name, func(t *testing.T) { t.Parallel() rule, err := parseIptablesInstruction(testCase.s) assert.Equal(t, testCase.instruction, rule) assert.ErrorIs(t, err, testCase.errWrapped) if testCase.errWrapped != nil { assert.EqualError(t, err, testCase.errMessage) } }) } } func Test_parseIPPrefix(t *testing.T) { t.Parallel() testCases := map[string]struct { value string prefix netip.Prefix errMessage string }{ "empty": { errMessage: `parsing IP address: ParseAddr(""): unable to parse IP`, }, "invalid": { value: "invalid", errMessage: `parsing IP address: ParseAddr("invalid"): unable to parse IP`, }, "valid_ipv4_with_bits": { value: "10.0.0.0/16", prefix: netip.PrefixFrom(netip.AddrFrom4([4]byte{10, 0, 0, 0}), 16), }, "valid_ipv4_without_bits": { value: "10.0.0.4", prefix: netip.PrefixFrom(netip.AddrFrom4([4]byte{10, 0, 0, 4}), 32), }, "valid_ipv6_with_bits": { value: "2001:db8::/32", prefix: netip.PrefixFrom( netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8}), 32), }, "valid_ipv6_without_bits": { value: "2001:db8::", prefix: netip.PrefixFrom( netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8}), 128), }, } for name, testCase := range testCases { testCase := testCase t.Run(name, func(t *testing.T) { t.Parallel() prefix, err := parseIPPrefix(testCase.value) assert.Equal(t, testCase.prefix, prefix) if testCase.errMessage != "" { assert.EqualError(t, err, testCase.errMessage) } else { assert.NoError(t, err) } }) } }