@@ -5,10 +5,33 @@ import (
55 "fmt"
66
77 "github.com/mdlayher/netlink"
8- "github.com/pkg/errors"
9- "golang.org/x/sys/unix"
108)
119
10+ // NewAttributeDecoder instantiates a new netlink.AttributeDecoder
11+ // configured with a Big Endian byte order.
12+ func NewAttributeDecoder (b []byte ) (* netlink.AttributeDecoder , error ) {
13+ ad , err := netlink .NewAttributeDecoder (b )
14+ if err != nil {
15+ return nil , err
16+ }
17+
18+ // All Netfilter attribute payloads are big-endian. (network byte order)
19+ ad .ByteOrder = binary .BigEndian
20+
21+ return ad , nil
22+ }
23+
24+ // NewAttributeDecoder instantiates a new netlink.AttributeEncoder
25+ // configured with a Big Endian byte order.
26+ func NewAttributeEncoder () * netlink.AttributeEncoder {
27+ ae := netlink .NewAttributeEncoder ()
28+
29+ // All Netfilter attribute payloads are big-endian. (network byte order)
30+ ae .ByteOrder = binary .BigEndian
31+
32+ return ae
33+ }
34+
1235// An Attribute is a copy of a netlink.Attribute that can be nested.
1336type Attribute struct {
1437
@@ -138,99 +161,127 @@ func Uint64Bytes(u uint64) []byte {
138161 return d
139162}
140163
141- // unmarshalAttributes returns an array of netfilter.Attributes decoded from
142- // a byte array. This byte array should be taken from the netlink.Message's
143- // Data payload after the nfHeaderLen offset.
144- func unmarshalAttributes (b []byte ) ([]Attribute , error ) {
145-
146- // Obtain a list of parsed netlink attributes possibly holding
147- // nested Netfilter attributes in their binary Data field.
148- attrs , err := netlink .UnmarshalAttributes (b )
149- if err != nil {
150- return nil , errors .Wrap (err , errWrapNetlinkUnmarshalAttrs )
151- }
164+ // decode fills the Attribute's Children field with Attributes
165+ // obtained by exhausting ad.
166+ func (a * Attribute ) decode (ad * netlink.AttributeDecoder ) error {
152167
153- var ra []Attribute
154-
155- // Only allocate backing array when there are netlink attributes to decode.
156- if len (attrs ) != 0 {
157- ra = make ([]Attribute , 0 , len (attrs ))
158- }
159-
160- // Wrap all netlink.Attributes into netfilter.Attributes to support nesting
161- for _ , nla := range attrs {
168+ for ad .Next () {
162169
163170 // Copy the netlink attribute's fields into the netfilter attribute.
164171 nfa := Attribute {
165- // Only consider the rightmost 14 bits for Type
166- Type : nla .Type & ^ (uint16 (unix .NLA_F_NESTED ) | uint16 (unix .NLA_F_NET_BYTEORDER )),
167- Data : nla .Data ,
172+ // Only consider the rightmost 14 bits for Type.
173+ // ad.Type implicitly masks the Nested and NetByteOrder bits.
174+ Type : ad .Type (),
175+ Data : ad .Bytes (),
168176 }
169177
170- // Boolean flags extracted from the two leftmost bits of Type
171- nfa .Nested = ( nla . Type & uint16 ( unix . NLA_F_NESTED )) != 0
172- nfa .NetByteOrder = ( nla . Type & uint16 ( unix . NLA_F_NET_BYTEORDER )) != 0
178+ // Boolean flags extracted from the two leftmost bits of Type.
179+ nfa .Nested = ad . TypeFlags () & netlink . Nested != 0
180+ nfa .NetByteOrder = ad . TypeFlags () & netlink . NetByteOrder != 0
173181
174182 if nfa .NetByteOrder && nfa .Nested {
175- return nil , errInvalidAttributeFlags
183+ return errInvalidAttributeFlags
176184 }
177185
178- // Unmarshal recursively if the netlink Nested flag is set
186+ // Unmarshal recursively if the netlink Nested flag is set.
179187 if nfa .Nested {
180- if nfa .Children , err = unmarshalAttributes (nla .Data ); err != nil {
181- return nil , err
182- }
188+ ad .Nested (nfa .decode )
183189 }
184190
185- ra = append (ra , nfa )
191+ a . Children = append (a . Children , nfa )
186192 }
187193
188- return ra , nil
194+ return ad . Err ()
189195}
190196
191- // marshalAttributes marshals a nested attribute structure into a byte slice.
192- // This byte slice can then be copied into a netlink.Message's Data field after
193- // the nfHeaderLen offset.
194- func marshalAttributes (attrs []Attribute ) ([]byte , error ) {
197+ // encode returns a function that takes an AttributeEncoder and returns error.
198+ // This function can be passed to AttributeEncoder.Nested for recursively
199+ // encoding Attributes.
200+ func (a * Attribute ) encode (attrs []Attribute ) func (* netlink.AttributeEncoder ) error {
201+
202+ return func (ae * netlink.AttributeEncoder ) error {
195203
196- // netlink.Attribute to use as scratch buffer, requires a single allocation
197- nla := netlink.Attribute {}
204+ for _ , nfa := range attrs {
198205
199- // Output array, initialized to the length of the input array
200- ra := make ([]netlink.Attribute , 0 , len (attrs ))
206+ if nfa .NetByteOrder && nfa .Nested {
207+ return errInvalidAttributeFlags
208+ }
201209
202- for _ , nfa := range attrs {
210+ if nfa .Nested {
211+ ae .Nested (nfa .Type , nfa .encode (nfa .Children ))
212+ continue
213+ }
203214
204- if nfa .NetByteOrder && nfa .Nested {
205- return nil , errInvalidAttributeFlags
215+ // Manually set the NetByteOrder flag, since ae.Bytes() can't.
216+ if nfa .NetByteOrder {
217+ nfa .Type |= netlink .NetByteOrder
218+ }
219+ ae .Bytes (nfa .Type , nfa .Data )
206220 }
207221
208- // Save nested or byte order flags back to the netlink.Attribute's
209- // Type field to include it in the marshaling operation
210- nla . Type = nfa . Type
222+ return nil
223+ }
224+ }
211225
212- switch {
213- case nfa .Nested :
214- nla .Type = nla .Type | unix .NLA_F_NESTED
215- case nfa .NetByteOrder :
216- nla .Type = nla .Type | unix .NLA_F_NET_BYTEORDER
217- }
226+ // decodeAttributes returns an array of netfilter.Attributes decoded from
227+ // a byte array. This byte array should be taken from the netlink.Message's
228+ // Data payload after the nfHeaderLen offset.
229+ func decodeAttributes (ad * netlink.AttributeDecoder ) ([]Attribute , error ) {
218230
219- // Recursively marshal the attribute's children
220- if nfa .Nested {
221- nfnab , err := marshalAttributes (nfa .Children )
222- if err != nil {
223- return nil , err
224- }
231+ // Use the Children element of the Attribute to decode into.
232+ // Attribute already has nested decoding implemented on the type.
233+ var a Attribute
225234
226- nla .Data = nfnab
227- } else {
228- nla .Data = nfa .Data
229- }
235+ // Pre-allocate backing array when there are netlink attributes to decode.
236+ if ad .Len () != 0 {
237+ a .Children = make ([]Attribute , 0 , ad .Len ())
238+ }
239+
240+ // Catch any errors encountered parsing netfilter structures.
241+ if err := a .decode (ad ); err != nil {
242+ return nil , err
243+ }
244+
245+ return a .Children , nil
246+ }
247+
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+
259+ // MarshalAttributes marshals a nested attribute structure into a byte slice.
260+ // This byte slice can then be copied into a netlink.Message's Data field after
261+ // the nfHeaderLen offset.
262+ func MarshalAttributes (attrs []Attribute ) ([]byte , error ) {
263+
264+ ae := NewAttributeEncoder ()
265+
266+ if err := encodeAttributes (ae , attrs ); err != nil {
267+ return nil , err
268+ }
230269
231- ra = append (ra , nla )
270+ b , err := ae .Encode ()
271+ if err != nil {
272+ return nil , err
273+ }
274+
275+ return b , nil
276+ }
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
232284 }
233285
234- // Marshal all Netfilter attributes into binary representation of Netlink attributes
235- return netlink .MarshalAttributes (ra )
286+ return decodeAttributes (ad )
236287}
0 commit comments