Skip to content

Commit 5ebce80

Browse files
committed
Introduce UnmarshalAttributes
1 parent f805464 commit 5ebce80

5 files changed

Lines changed: 77 additions & 34 deletions

File tree

attribute.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ func (a *Attribute) encode(attrs []Attribute) func(*netlink.AttributeEncoder) er
223223
}
224224
}
225225

226-
// unmarshalAttributes returns an array of netfilter.Attributes decoded from
226+
// decodeAttributes returns an array of netfilter.Attributes decoded from
227227
// a byte array. This byte array should be taken from the netlink.Message's
228228
// Data payload after the nfHeaderLen offset.
229-
func unmarshalAttributes(ad *netlink.AttributeDecoder) ([]Attribute, error) {
229+
func decodeAttributes(ad *netlink.AttributeDecoder) ([]Attribute, error) {
230230

231231
// Use the Children element of the Attribute to decode into.
232232
// Attribute already has nested decoding implemented on the type.
@@ -245,15 +245,25 @@ func unmarshalAttributes(ad *netlink.AttributeDecoder) ([]Attribute, error) {
245245
return a.Children, nil
246246
}
247247

248+
// encodeAttributes encodes a list of Attributes into the given netlink.AttributeEncoder.
249+
func encodeAttributes(ae *netlink.AttributeEncoder, attrs []Attribute) error {
250+
251+
if ae == nil {
252+
return errNilAttributeEncoder
253+
}
254+
255+
attr := Attribute{}
256+
return attr.encode(attrs)(ae)
257+
}
258+
248259
// MarshalAttributes marshals a nested attribute structure into a byte slice.
249260
// This byte slice can then be copied into a netlink.Message's Data field after
250261
// the nfHeaderLen offset.
251262
func MarshalAttributes(attrs []Attribute) ([]byte, error) {
252263

253264
ae := NewAttributeEncoder()
254265

255-
attr := Attribute{}
256-
if err := attr.encode(attrs)(ae); err != nil {
266+
if err := encodeAttributes(ae, attrs); err != nil {
257267
return nil, err
258268
}
259269

@@ -264,3 +274,14 @@ func MarshalAttributes(attrs []Attribute) ([]byte, error) {
264274

265275
return b, nil
266276
}
277+
278+
// UnmarshalAttributes unmarshals a byte slice into a list of Attributes.
279+
func UnmarshalAttributes(b []byte) ([]Attribute, error) {
280+
281+
ad, err := NewAttributeDecoder(b)
282+
if err != nil {
283+
return nil, err
284+
}
285+
286+
return decodeAttributes(ad)
287+
}

attribute_test.go

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package netfilter
22

33
import (
4+
"errors"
45
"strings"
56
"testing"
67

@@ -209,7 +210,7 @@ func TestAttributeMarshalErrors(t *testing.T) {
209210
}
210211
}
211212

212-
func TestAttributeUnmarshalErrors(t *testing.T) {
213+
func TestAttributeDecoderErrors(t *testing.T) {
213214
tests := []struct {
214215
name string
215216
b []byte
@@ -233,31 +234,19 @@ func TestAttributeUnmarshalErrors(t *testing.T) {
233234
},
234235
err: errInvalidAttributeFlags,
235236
},
237+
{
238+
name: "decoding invalid attribute",
239+
b: []byte{4, 0, 0},
240+
err: errors.New("invalid attribute; length too short or too large"),
241+
},
236242
}
237243

238244
for _, tt := range tests {
239245
t.Run(tt.name, func(t *testing.T) {
240-
ad, err := NewAttributeDecoder(tt.b)
241-
if err != nil {
242-
t.Fatal("unexpected error creating AttributeDecoder:", err)
243-
}
244-
245-
_, err = unmarshalAttributes(ad)
246-
if err == nil {
247-
t.Fatal("unmarshal did not error")
248-
}
249-
250-
if tt.err != nil {
251-
if want, got := tt.err, err; want != got {
252-
t.Fatalf("unexpected error:\n- want: %v\n- got: %v",
253-
want, got.Error())
254-
}
255-
} else if tt.errWrap != "" {
256-
if !strings.HasPrefix(err.Error(), tt.errWrap+":") {
257-
t.Fatalf("unexpected wrapped error:\n- expected prefix: %v\n- error string: %v",
258-
tt.errWrap, err)
259-
}
260-
}
246+
_, err := UnmarshalAttributes(tt.b)
247+
require.Error(t, err)
248+
require.Error(t, tt.err)
249+
require.EqualError(t, err, tt.err.Error())
261250
})
262251
}
263252
}
@@ -402,7 +391,7 @@ func TestAttributeMarshalTwoWay(t *testing.T) {
402391
}
403392

404393
// Unmarshal binary content into nested structures
405-
attrs, err := unmarshalAttributes(ad)
394+
attrs, err := decodeAttributes(ad)
406395
require.NoError(t, err)
407396

408397
assert.Empty(t, cmp.Diff(tt.attrs, attrs))
@@ -417,3 +406,7 @@ func TestAttributeMarshalTwoWay(t *testing.T) {
417406
})
418407
}
419408
}
409+
410+
func TestErrors(t *testing.T) {
411+
assert.EqualError(t, encodeAttributes(nil, nil), errNilAttributeEncoder.Error())
412+
}

errors.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ var (
1414
errConnIsMulticast = errors.New("Conn is attached to one or more multicast groups and can no longer be used for bidirectional traffic")
1515

1616
errNoMulticastGroups = errors.New("need one or more multicast groups to join")
17+
18+
errNilAttributeEncoder = errors.New("given AttributeEncoder is nil")
1719
)

message.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func UnmarshalNetlink(msg netlink.Message) (Header, []Attribute, error) {
1414
return Header{}, nil, err
1515
}
1616

17-
attrs, err := unmarshalAttributes(ad)
17+
attrs, err := decodeAttributes(ad)
1818
if err != nil {
1919
return Header{}, nil, err
2020
}
@@ -44,18 +44,33 @@ func DecodeNetlink(msg netlink.Message) (Header, *netlink.AttributeDecoder, erro
4444
// MarshalNetlink takes a Netfilter Header and Attributes and returns a netlink.Message.
4545
func MarshalNetlink(h Header, attrs []Attribute) (netlink.Message, error) {
4646

47-
ba, err := MarshalAttributes(attrs)
47+
ae := NewAttributeEncoder()
48+
if err := encodeAttributes(ae, attrs); err != nil {
49+
return netlink.Message{}, err
50+
}
51+
52+
return EncodeNetlink(h, ae)
53+
}
54+
55+
// EncodeNetlink generates a netlink.Message based on a given netfilter header h
56+
// and a pre-filled netlink.AttributeEncoder ae.
57+
func EncodeNetlink(h Header, ae *netlink.AttributeEncoder) (netlink.Message, error) {
58+
59+
if ae == nil {
60+
return netlink.Message{}, errNilAttributeEncoder
61+
}
62+
63+
// Encode the AE into a byte slice.
64+
b, err := ae.Encode()
4865
if err != nil {
4966
return netlink.Message{}, err
5067
}
5168

52-
// initialize with 4 bytes of Data before unmarshal
53-
nlm := netlink.Message{Data: make([]byte, 4)}
69+
// Allocate space for the marshaled netfilter header.
70+
nlm := netlink.Message{Data: append(make([]byte, nfHeaderLen), b...)}
5471

55-
// marshal error ignored, safe to do if msg Data is initialized
72+
// marshal error ignored, safe to do if msg Data is initialized.
5673
_ = h.marshal(&nlm)
5774

58-
nlm.Data = append(nlm.Data, ba...)
59-
6075
return nlm, nil
6176
}

message_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,15 @@ func TestAttributeMarshalNetlink(t *testing.T) {
155155
})
156156
}
157157
}
158+
159+
func TestEncodeNetlink(t *testing.T) {
160+
161+
_, err := EncodeNetlink(Header{}, nil)
162+
assert.EqualError(t, err, errNilAttributeEncoder.Error())
163+
164+
// Make ae.Encode() throw an error inside EncodeNetlink.
165+
ae := NewAttributeEncoder()
166+
ae.Do(0, func() ([]byte, error) { return []byte{}, errors.New("test error") })
167+
_, err = EncodeNetlink(Header{}, ae)
168+
assert.EqualError(t, err, "test error")
169+
}

0 commit comments

Comments
 (0)