Skip to content

Commit a018296

Browse files
chanfung032aboch
authored andcommitted
Fix FouList attribute body truncated error with kernel 5.2+
fou module added a bunch of new attributes in commit torvalds/linux@1713cb3 which caused the old parsing logic failed, fix and add support for these attrributes.
1 parent b1ce50c commit a018296

File tree

4 files changed

+74
-50
lines changed

4 files changed

+74
-50
lines changed

fou.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
package netlink
22

33
import (
4-
"errors"
5-
)
6-
7-
var (
8-
// ErrAttrHeaderTruncated is returned when a netlink attribute's header is
9-
// truncated.
10-
ErrAttrHeaderTruncated = errors.New("attribute header truncated")
11-
// ErrAttrBodyTruncated is returned when a netlink attribute's body is
12-
// truncated.
13-
ErrAttrBodyTruncated = errors.New("attribute body truncated")
4+
"net"
145
)
156

167
type Fou struct {
178
Family int
189
Port int
1910
Protocol int
2011
EncapType int
12+
Local net.IP
13+
Peer net.IP
14+
PeerPort int
15+
IfIndex int
2116
}

fou_linux.go

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
//go:build linux
12
// +build linux
23

34
package netlink
45

56
import (
67
"encoding/binary"
78
"errors"
9+
"log"
10+
"net"
811

912
"github.com/vishvananda/netlink/nl"
1013
"golang.org/x/sys/unix"
@@ -29,6 +32,12 @@ const (
2932
FOU_ATTR_IPPROTO
3033
FOU_ATTR_TYPE
3134
FOU_ATTR_REMCSUM_NOPARTIAL
35+
FOU_ATTR_LOCAL_V4
36+
FOU_ATTR_LOCAL_V6
37+
FOU_ATTR_PEER_V4
38+
FOU_ATTR_PEER_V6
39+
FOU_ATTR_PEER_PORT
40+
FOU_ATTR_IFINDEX
3241
FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
3342
)
3443

@@ -169,41 +178,28 @@ func (h *Handle) FouList(fam int) ([]Fou, error) {
169178
}
170179

171180
func deserializeFouMsg(msg []byte) (Fou, error) {
172-
// we'll skip to byte 4 to first attribute
173-
msg = msg[3:]
174-
var shift int
175181
fou := Fou{}
176182

177-
for {
178-
// attribute header is at least 16 bits
179-
if len(msg) < 4 {
180-
return fou, ErrAttrHeaderTruncated
181-
}
182-
183-
lgt := int(binary.BigEndian.Uint16(msg[0:2]))
184-
if len(msg) < lgt+4 {
185-
return fou, ErrAttrBodyTruncated
186-
}
187-
attr := binary.BigEndian.Uint16(msg[2:4])
188-
189-
shift = lgt + 3
190-
switch attr {
183+
for attr := range nl.ParseAttributes(msg[4:]) {
184+
switch attr.Type {
191185
case FOU_ATTR_AF:
192-
fou.Family = int(msg[5])
186+
fou.Family = int(attr.Value[0])
193187
case FOU_ATTR_PORT:
194-
fou.Port = int(binary.BigEndian.Uint16(msg[5:7]))
195-
// port is 2 bytes
196-
shift = lgt + 2
188+
fou.Port = int(networkOrder.Uint16(attr.Value))
197189
case FOU_ATTR_IPPROTO:
198-
fou.Protocol = int(msg[5])
190+
fou.Protocol = int(attr.Value[0])
199191
case FOU_ATTR_TYPE:
200-
fou.EncapType = int(msg[5])
201-
}
202-
203-
msg = msg[shift:]
204-
205-
if len(msg) < 4 {
206-
break
192+
fou.EncapType = int(attr.Value[0])
193+
case FOU_ATTR_LOCAL_V4, FOU_ATTR_LOCAL_V6:
194+
fou.Local = net.IP(attr.Value)
195+
case FOU_ATTR_PEER_V4, FOU_ATTR_PEER_V6:
196+
fou.Peer = net.IP(attr.Value)
197+
case FOU_ATTR_PEER_PORT:
198+
fou.PeerPort = int(networkOrder.Uint16(attr.Value))
199+
case FOU_ATTR_IFINDEX:
200+
fou.IfIndex = int(native.Uint16(attr.Value))
201+
default:
202+
log.Printf("unknown fou attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
207203
}
208204
}
209205

fou_test.go

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
//go:build linux
12
// +build linux
23

34
package netlink
45

56
import (
7+
"net"
68
"testing"
79
)
810

@@ -33,20 +35,50 @@ func TestFouDeserializeMsg(t *testing.T) {
3335
}
3436
}
3537

36-
// deserialize truncated attribute header
37-
msg = []byte{3, 1, 0, 0, 5, 0}
38-
if _, err := deserializeFouMsg(msg); err == nil {
39-
t.Error("expected attribute header truncated error")
40-
} else if err != ErrAttrHeaderTruncated {
41-
t.Errorf("unexpected error: %s", err.Error())
38+
// deserialize a valid message(kernel >= 5.2)
39+
msg = []byte{3, 1, 0, 0, 5, 0, 2, 0, 2, 0, 0, 0, 6, 0, 1, 0, 43, 103, 0, 0, 6, 0, 10, 0, 86, 206, 0, 0, 5, 0, 3, 0, 0, 0, 0, 0, 5, 0, 4, 0, 2, 0, 0, 0, 8, 0, 11, 0, 0, 0, 0, 0, 8, 0, 6, 0, 1, 2, 3, 4, 8, 0, 8, 0, 5, 6, 7, 8}
40+
if fou, err := deserializeFouMsg(msg); err != nil {
41+
t.Error(err.Error())
42+
} else {
43+
if fou.Family != FAMILY_V4 {
44+
t.Errorf("expected family %d, got %d", FAMILY_V4, fou.Family)
45+
}
46+
47+
if fou.Port != 11111 {
48+
t.Errorf("expected port 5555, got %d", fou.Port)
49+
}
50+
51+
if fou.Protocol != 0 { // gue
52+
t.Errorf("expected protocol 0, got %d", fou.Protocol)
53+
}
54+
55+
if fou.IfIndex != 0 {
56+
t.Errorf("expected ifindex 0, got %d", fou.Protocol)
57+
}
58+
59+
if fou.EncapType != FOU_ENCAP_GUE {
60+
t.Errorf("expected encap type %d, got %d", FOU_ENCAP_GUE, fou.EncapType)
61+
}
62+
63+
if expected := net.IPv4(1, 2, 3, 4); !fou.Local.Equal(expected) {
64+
t.Errorf("expected local %v, got %v", expected, fou.Local)
65+
}
66+
67+
if expected := net.IPv4(5, 6, 7, 8); !fou.Peer.Equal(expected) {
68+
t.Errorf("expected peer %v, got %v", expected, fou.Peer)
69+
}
70+
71+
if fou.PeerPort != 22222 {
72+
t.Errorf("expected peer port 0, got %d", fou.PeerPort)
73+
}
4274
}
4375

44-
// deserialize truncated attribute header
45-
msg = []byte{3, 1, 0, 0, 5, 0, 2, 0, 2, 0, 0}
46-
if _, err := deserializeFouMsg(msg); err == nil {
47-
t.Error("expected attribute body truncated error")
48-
} else if err != ErrAttrBodyTruncated {
76+
// unknown attribute should be skipped
77+
msg = []byte{3, 1, 0, 0, 5, 0, 112, 0, 2, 0, 0, 0, 5, 0, 2, 0, 2, 0, 0}
78+
if fou, err := deserializeFouMsg(msg); err != nil {
4979
t.Errorf("unexpected error: %s", err.Error())
80+
} else if fou.Family != 2 {
81+
t.Errorf("expected family 2, got %d", fou.Family)
5082
}
5183
}
5284

fou_unspecified.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build !linux
12
// +build !linux
23

34
package netlink

0 commit comments

Comments
 (0)