Skip to content

Commit aa97cf4

Browse files
committed
selectors: support ipv4-mapped ipv6 addresses
IPv4 addresses can be represented in IPv6 form as `::ffff:X.X.X.X` and may be used during connections with address family AF_INET6. This patch supports ipv4-mapped ipv6 by parsing ipv4 address only in case of absence of colon in the original address string. Fixes: #3712 Signed-off-by: Kobrin Ilay <[email protected]>
1 parent 0921cdf commit aa97cf4

File tree

2 files changed

+130
-40
lines changed

2 files changed

+130
-40
lines changed

pkg/selectors/kernel.go

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import (
1414
"strings"
1515

1616
"github.com/cilium/tetragon/api/v1/tetragon"
17+
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
18+
1719
"github.com/cilium/tetragon/pkg/api/processapi"
1820
"github.com/cilium/tetragon/pkg/config"
1921
gt "github.com/cilium/tetragon/pkg/generictypes"
2022
"github.com/cilium/tetragon/pkg/idtable"
21-
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
2223
"github.com/cilium/tetragon/pkg/kernels"
2324
"github.com/cilium/tetragon/pkg/mbset"
2425
"github.com/cilium/tetragon/pkg/reader/namespace"
@@ -536,17 +537,16 @@ func writeMatchAddrsInMap(k *KernelSelectorState, values []string) error {
536537
for _, v := range values {
537538
addr, maskLen, err := parseAddr(v)
538539
if err != nil {
539-
return fmt.Errorf("MatchArgs value %s invalid: %w", v, err)
540+
return fmt.Errorf("MatchArgs value %s invalid: parse IP: %w", v, err)
540541
}
541-
if len(addr) == 4 {
542+
543+
if len(addr) == net.IPv4len {
542544
val := KernelLPMTrie4{prefixLen: maskLen, addr: binary.LittleEndian.Uint32(addr)}
543545
m4[val] = struct{}{}
544-
} else if len(addr) == 16 {
546+
} else {
545547
val := KernelLPMTrie6{prefixLen: maskLen}
546548
copy(val.addr[:], addr)
547549
m6[val] = struct{}{}
548-
} else {
549-
return fmt.Errorf("MatchArgs value %s invalid: should be either 4 or 16 bytes long", v)
550550
}
551551
}
552552
// write the map ids into the selector
@@ -576,45 +576,55 @@ func getBase(v string) int {
576576
}
577577

578578
func parseAddr(v string) ([]byte, uint32, error) {
579-
ipaddr := net.ParseIP(v)
580-
if ipaddr != nil {
581-
ipaddr4 := ipaddr.To4()
582-
if ipaddr4 != nil {
583-
return ipaddr4, 32, nil
584-
}
585-
ipaddr6 := ipaddr.To16()
586-
if ipaddr6 != nil {
587-
return ipaddr6, 128, nil
588-
}
589-
return nil, 0, errors.New("IP address is not valid: does not parse as IPv4 or IPv6")
590-
}
579+
var maskLen uint32
580+
591581
vParts := strings.Split(v, "/")
592-
if len(vParts) != 2 {
593-
return nil, 0, errors.New("IP address is not valid: should be in format ADDR or ADDR/MASKLEN")
594-
}
595-
ipaddr = net.ParseIP(vParts[0])
596-
if ipaddr == nil {
597-
return nil, 0, errors.New("IP CIDR is not valid: address part does not parse as IPv4 or IPv6")
582+
switch len(vParts) {
583+
case 1:
584+
case 2:
585+
x, err := strconv.ParseUint(vParts[1], 10, 32)
586+
if err != nil {
587+
return nil, 0, errors.New("CIDR mask is invalid")
588+
}
589+
maskLen = uint32(x)
590+
default:
591+
return nil, 0, errors.New("IP address is invalid: invalid format")
598592
}
599-
maskLen, err := strconv.ParseUint(vParts[1], 10, 32)
600-
if err != nil {
601-
return nil, 0, errors.New("IP CIDR is not valid: mask part does not parse")
593+
594+
ipAddr := net.ParseIP(vParts[0])
595+
if ipAddr == nil {
596+
return nil, 0, errors.New("IP address is invalid: failed to parse")
602597
}
603-
ipaddr4 := ipaddr.To4()
604-
if ipaddr4 != nil {
605-
if maskLen <= 32 {
606-
return ipaddr4, uint32(maskLen), nil
598+
599+
// IPv4-mapped IPv6 form of address (::ffff:x.x.x.x) will
600+
// be successfully parsed as IPv4 address, but we want to consider
601+
// such form only as IPv6 address to add it to corresponding map,
602+
// so parse IPv4 address only in case of absence of colon.
603+
if !strings.Contains(v, ":") {
604+
ip4 := ipAddr.To4()
605+
if ip4 == nil {
606+
return nil, 0, errors.New("IPv4 address is invalid")
607607
}
608-
return nil, 0, errors.New("IP CIDR is not valid: IPv4 mask len must be <= 32")
609-
}
610-
ipaddr6 := ipaddr.To16()
611-
if ipaddr6 != nil {
612-
if maskLen <= 128 {
613-
return ipaddr6, uint32(maskLen), nil
608+
if maskLen == 0 {
609+
maskLen = 32
610+
} else if maskLen > 32 {
611+
return nil, 0, errors.New("IPv4 mask len must be <= 32")
614612
}
615-
return nil, 0, errors.New("IP CIDR is not valid: IPv6 mask len must be <= 128")
613+
614+
return ip4, maskLen, nil
615+
}
616+
617+
ip6 := ipAddr.To16()
618+
if ip6 == nil {
619+
return nil, 0, errors.New("IPv6 address is invalid")
620+
}
621+
if maskLen == 0 {
622+
maskLen = 128
623+
} else if maskLen > 128 {
624+
return nil, 0, errors.New("IPv6 mask len must be <= 128")
616625
}
617-
return nil, 0, errors.New("IP CIDR is not valid: address part does not parse")
626+
627+
return ip6, maskLen, nil
618628
}
619629

620630
func writeMatchValues(k *KernelSelectorState, values []string, ty, op uint32) error {

pkg/selectors/kernel_test.go

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ package selectors
1111
import (
1212
"bytes"
1313
"encoding/binary"
14+
"errors"
1415
"strings"
1516
"testing"
1617

18+
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
19+
"github.com/stretchr/testify/require"
20+
1721
"github.com/cilium/tetragon/pkg/config"
1822
gt "github.com/cilium/tetragon/pkg/generictypes"
1923
"github.com/cilium/tetragon/pkg/idtable"
20-
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
2124
)
2225

2326
func TestWriteSelectorUint32(t *testing.T) {
@@ -1007,3 +1010,80 @@ func TestReturnSelectorArgIntActionFollowfd(t *testing.T) {
10071010
t.Errorf("\ngot: %v\nexp: %v\n", b[:expectedLen], expected[:expectedLen])
10081011
}
10091012
}
1013+
1014+
func TestParseAddr(t *testing.T) {
1015+
tests := map[string]struct {
1016+
addrStr string
1017+
expectedAddr []byte
1018+
expectedMaskLen uint32
1019+
expectedErr error
1020+
}{
1021+
"invalid address format": {
1022+
addrStr: "1.2.3.4/16/16",
1023+
expectedErr: errors.New("IP address is invalid: invalid format"),
1024+
},
1025+
"invalid mask value": {
1026+
addrStr: "1.2.3.4/invalid",
1027+
expectedErr: errors.New("CIDR mask is invalid"),
1028+
},
1029+
"invalid ipv4": {
1030+
addrStr: "a.b.c.d/16",
1031+
expectedErr: errors.New("IP address is invalid: failed to parse"),
1032+
},
1033+
"invalid ipv6": {
1034+
addrStr: "::gg/16",
1035+
expectedErr: errors.New("IP address is invalid: failed to parse"),
1036+
},
1037+
"invalid ipv4 mask len": {
1038+
addrStr: "1.2.3.4/33",
1039+
expectedErr: errors.New("IPv4 mask len must be <= 32"),
1040+
},
1041+
"invalid ipv6 mask len": {
1042+
addrStr: "::1/256",
1043+
expectedErr: errors.New("IPv6 mask len must be <= 128"),
1044+
},
1045+
"valid ipv4": {
1046+
addrStr: "1.2.3.4",
1047+
expectedAddr: []byte{1, 2, 3, 4},
1048+
expectedMaskLen: 32,
1049+
},
1050+
"valid ipv4 cidr": {
1051+
addrStr: "1.2.3.4/16",
1052+
expectedAddr: []byte{1, 2, 3, 4},
1053+
expectedMaskLen: 16,
1054+
},
1055+
"valid ipv6": {
1056+
addrStr: "0102::0304",
1057+
expectedAddr: []byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4},
1058+
expectedMaskLen: 128,
1059+
},
1060+
"valid ipv6 cidr": {
1061+
addrStr: "0102::0304/64",
1062+
expectedAddr: []byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4},
1063+
expectedMaskLen: 64,
1064+
},
1065+
"valid ipv4-mapped ipv6": {
1066+
addrStr: "::ffff:1.2.3.4",
1067+
expectedAddr: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 1, 2, 3, 4},
1068+
expectedMaskLen: 128,
1069+
},
1070+
"valid ipv4-mapped ipv6 cidr": {
1071+
addrStr: "::ffff:1.2.3.4/96",
1072+
expectedAddr: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 1, 2, 3, 4},
1073+
expectedMaskLen: 96,
1074+
},
1075+
}
1076+
1077+
for name, test := range tests {
1078+
t.Run(name, func(t *testing.T) {
1079+
addr, maskLen, err := parseAddr(test.addrStr)
1080+
if test.expectedErr != nil {
1081+
require.Error(t, err)
1082+
require.Equal(t, test.expectedErr, err)
1083+
} else {
1084+
require.Equal(t, test.expectedAddr, addr)
1085+
require.Equal(t, test.expectedMaskLen, maskLen)
1086+
}
1087+
})
1088+
}
1089+
}

0 commit comments

Comments
 (0)