@@ -5,8 +5,10 @@ import (
55 "errors"
66 "fmt"
77 "net"
8+ "syscall"
89
910 "github.com/vishvananda/netlink/nl"
11+ "github.com/vishvananda/netns"
1012 "golang.org/x/sys/unix"
1113)
1214
@@ -119,8 +121,8 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
119121 req .AddData (nl .NewRtAttr (nl .FRA_FLOW , b ))
120122 }
121123 if rule .TunID > 0 {
122- b := make ([]byte , 4 )
123- native . PutUint32 (b , uint32 (rule .TunID ))
124+ b := make ([]byte , 8 )
125+ networkOrder . PutUint64 (b , uint64 (rule .TunID ))
124126 req .AddData (nl .NewRtAttr (nl .FRA_TUN_ID , b ))
125127 }
126128 if rule .Table >= 256 {
@@ -154,9 +156,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
154156 }
155157
156158 if rule .IPProto > 0 {
157- b := make ([]byte , 4 )
158- native .PutUint32 (b , uint32 (rule .IPProto ))
159- req .AddData (nl .NewRtAttr (nl .FRA_IP_PROTO , b ))
159+ req .AddData (nl .NewRtAttr (nl .FRA_IP_PROTO , nl .Uint8Attr (uint8 (rule .IPProto ))))
160160 }
161161
162162 if rule .Dport != nil {
@@ -227,73 +227,11 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
227227
228228 var res = make ([]Rule , 0 )
229229 for i := range msgs {
230- msg := nl .DeserializeRtMsg (msgs [i ])
231- attrs , err := nl .ParseRouteAttr (msgs [i ][msg .Len ():])
230+ rule , err := deserializeRule (msgs [i ])
232231 if err != nil {
233232 return nil , err
234233 }
235234
236- rule := NewRule ()
237- rule .Priority = 0 // The default priority from kernel
238-
239- rule .Invert = msg .Flags & FibRuleInvert > 0
240- rule .Family = int (msg .Family )
241- rule .Tos = uint (msg .Tos )
242-
243- for j := range attrs {
244- switch attrs [j ].Attr .Type {
245- case unix .RTA_TABLE :
246- rule .Table = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
247- case nl .FRA_SRC :
248- rule .Src = & net.IPNet {
249- IP : attrs [j ].Value ,
250- Mask : net .CIDRMask (int (msg .Src_len ), 8 * len (attrs [j ].Value )),
251- }
252- case nl .FRA_DST :
253- rule .Dst = & net.IPNet {
254- IP : attrs [j ].Value ,
255- Mask : net .CIDRMask (int (msg .Dst_len ), 8 * len (attrs [j ].Value )),
256- }
257- case nl .FRA_FWMARK :
258- rule .Mark = native .Uint32 (attrs [j ].Value [0 :4 ])
259- case nl .FRA_FWMASK :
260- mask := native .Uint32 (attrs [j ].Value [0 :4 ])
261- rule .Mask = & mask
262- case nl .FRA_TUN_ID :
263- rule .TunID = uint (native .Uint64 (attrs [j ].Value [0 :8 ]))
264- case nl .FRA_IIFNAME :
265- rule .IifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
266- case nl .FRA_OIFNAME :
267- rule .OifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
268- case nl .FRA_SUPPRESS_PREFIXLEN :
269- i := native .Uint32 (attrs [j ].Value [0 :4 ])
270- if i != 0xffffffff {
271- rule .SuppressPrefixlen = int (i )
272- }
273- case nl .FRA_SUPPRESS_IFGROUP :
274- i := native .Uint32 (attrs [j ].Value [0 :4 ])
275- if i != 0xffffffff {
276- rule .SuppressIfgroup = int (i )
277- }
278- case nl .FRA_FLOW :
279- rule .Flow = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
280- case nl .FRA_GOTO :
281- rule .Goto = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
282- case nl .FRA_PRIORITY :
283- rule .Priority = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
284- case nl .FRA_IP_PROTO :
285- rule .IPProto = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
286- case nl .FRA_DPORT_RANGE :
287- rule .Dport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
288- case nl .FRA_SPORT_RANGE :
289- rule .Sport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
290- case nl .FRA_UID_RANGE :
291- rule .UIDRange = NewRuleUIDRange (native .Uint32 (attrs [j ].Value [0 :4 ]), native .Uint32 (attrs [j ].Value [4 :8 ]))
292- case nl .FRA_PROTOCOL :
293- rule .Protocol = uint8 (attrs [j ].Value [0 ])
294- }
295- }
296-
297235 if filter != nil {
298236 switch {
299237 case filterMask & RT_FILTER_SRC != 0 &&
@@ -316,12 +254,210 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
316254 }
317255 }
318256
319- res = append (res , * rule )
257+ res = append (res , rule )
320258 }
321259
322260 return res , executeErr
323261}
324262
263+ func deserializeRule (m []byte ) (Rule , error ) {
264+ msg := nl .DeserializeRtMsg (m )
265+ attrs , err := nl .ParseRouteAttr (m [msg .Len ():])
266+ if err != nil {
267+ return Rule {}, err
268+ }
269+
270+ rule := NewRule ()
271+
272+ rule .Invert = msg .Flags & FibRuleInvert > 0
273+ rule .Tos = uint (msg .Tos )
274+ // The kernel returns the table id in rtmsg.table for values < 256 and as
275+ // the RTA_TABLE attribute for larger values. Start with the header value.
276+ rule .Table = int (msg .Table )
277+
278+ for j := range attrs {
279+ switch attrs [j ].Attr .Type {
280+ case unix .RTA_TABLE :
281+ rule .Table = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
282+ case nl .FRA_SRC :
283+ rule .Src = & net.IPNet {
284+ IP : attrs [j ].Value ,
285+ Mask : net .CIDRMask (int (msg .Src_len ), 8 * len (attrs [j ].Value )),
286+ }
287+ case nl .FRA_DST :
288+ rule .Dst = & net.IPNet {
289+ IP : attrs [j ].Value ,
290+ Mask : net .CIDRMask (int (msg .Dst_len ), 8 * len (attrs [j ].Value )),
291+ }
292+ case nl .FRA_FWMARK :
293+ rule .Mark = native .Uint32 (attrs [j ].Value [0 :4 ])
294+ case nl .FRA_FWMASK :
295+ mask := native .Uint32 (attrs [j ].Value [0 :4 ])
296+ rule .Mask = & mask
297+ case nl .FRA_TUN_ID :
298+ rule .TunID = uint (networkOrder .Uint64 (attrs [j ].Value [0 :8 ]))
299+ case nl .FRA_IIFNAME :
300+ rule .IifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
301+ case nl .FRA_OIFNAME :
302+ rule .OifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
303+ case nl .FRA_SUPPRESS_PREFIXLEN :
304+ i := native .Uint32 (attrs [j ].Value [0 :4 ])
305+ if i != 0xffffffff {
306+ rule .SuppressPrefixlen = int (i )
307+ }
308+ case nl .FRA_SUPPRESS_IFGROUP :
309+ i := native .Uint32 (attrs [j ].Value [0 :4 ])
310+ if i != 0xffffffff {
311+ rule .SuppressIfgroup = int (i )
312+ }
313+ case nl .FRA_FLOW :
314+ rule .Flow = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
315+ case nl .FRA_GOTO :
316+ rule .Goto = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
317+ case nl .FRA_PRIORITY :
318+ rule .Priority = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
319+ case nl .FRA_IP_PROTO :
320+ rule .IPProto = int (attrs [j ].Value [0 ])
321+ case nl .FRA_DPORT_RANGE :
322+ rule .Dport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
323+ case nl .FRA_SPORT_RANGE :
324+ rule .Sport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
325+ case nl .FRA_UID_RANGE :
326+ rule .UIDRange = NewRuleUIDRange (native .Uint32 (attrs [j ].Value [0 :4 ]), native .Uint32 (attrs [j ].Value [4 :8 ]))
327+ case nl .FRA_PROTOCOL :
328+ rule .Protocol = uint8 (attrs [j ].Value [0 ])
329+ }
330+ }
331+
332+ // Some kernels omit FRA_PRIORITY when the rule priority is 0. Since 0 is a
333+ // valid priority (e.g. the local-table rule), default to 0 if no attribute
334+ // was present.
335+ if rule .Priority < 0 {
336+ rule .Priority = 0
337+ }
338+
339+ rule .Family = int (msg .Family )
340+ rule .Type = msg .Type
341+
342+ return * rule , nil
343+ }
344+
345+ // RuleSubscribe takes a chan down which notifications will be sent
346+ // when rules are added or deleted. The 'done' chan must be closed to stop the
347+ // subscription and release the underlying socket/goroutine.
348+ func RuleSubscribe (ch chan <- RuleUpdate , done <- chan struct {}) error {
349+ return ruleSubscribeAt (netns .None (), netns .None (), ch , done , nil , false , 0 , nil , false )
350+ }
351+
352+ // RuleSubscribeAt works like RuleSubscribe plus it allows the caller
353+ // to choose the network namespace in which to subscribe (ns).
354+ // The 'done' chan must be closed to stop the subscription and release resources.
355+ func RuleSubscribeAt (ns netns.NsHandle , ch chan <- RuleUpdate , done <- chan struct {}) error {
356+ return ruleSubscribeAt (ns , netns .None (), ch , done , nil , false , 0 , nil , false )
357+ }
358+
359+ // RuleSubscribeOptions contains a set of options to use with
360+ // RuleSubscribeWithOptions.
361+ type RuleSubscribeOptions struct {
362+ Namespace * netns.NsHandle
363+ ErrorCallback func (error )
364+ ListExisting bool
365+ ReceiveBufferSize int
366+ ReceiveBufferForceSize bool
367+ ReceiveTimeout * unix.Timeval
368+ }
369+
370+ // RuleSubscribeWithOptions works like RuleSubscribe but enables
371+ // additional options to modify the behavior.
372+ func RuleSubscribeWithOptions (ch chan <- RuleUpdate , done <- chan struct {}, options RuleSubscribeOptions ) error {
373+ if options .Namespace == nil {
374+ none := netns .None ()
375+ options .Namespace = & none
376+ }
377+ return ruleSubscribeAt (* options .Namespace , netns .None (), ch , done , options .ErrorCallback , options .ListExisting ,
378+ options .ReceiveBufferSize , options .ReceiveTimeout , options .ReceiveBufferForceSize )
379+ }
380+
381+ func ruleSubscribeAt (newNs , curNs netns.NsHandle , ch chan <- RuleUpdate , done <- chan struct {}, cberr func (error ), listExisting bool ,
382+ rcvbuf int , rcvTimeout * unix.Timeval , rcvBufForce bool ) error {
383+ s , err := nl .SubscribeAt (newNs , curNs , unix .NETLINK_ROUTE , unix .RTNLGRP_IPV4_RULE , unix .RTNLGRP_IPV6_RULE )
384+ if err != nil {
385+ return err
386+ }
387+ if rcvTimeout != nil {
388+ if err := s .SetReceiveTimeout (rcvTimeout ); err != nil {
389+ return err
390+ }
391+ }
392+ if rcvbuf != 0 {
393+ err = s .SetReceiveBufferSize (rcvbuf , rcvBufForce )
394+ if err != nil {
395+ return err
396+ }
397+ }
398+ if done != nil {
399+ go func () {
400+ <- done
401+ s .Close ()
402+ }()
403+ }
404+ if listExisting {
405+ req := pkgHandle ().newNetlinkRequest (unix .RTM_GETRULE , unix .NLM_F_DUMP )
406+ infmsg := nl .NewIfInfomsg (unix .AF_UNSPEC )
407+ req .AddData (infmsg )
408+ if err := s .Send (req ); err != nil {
409+ s .Close ()
410+ return err
411+ }
412+ }
413+ go func () {
414+ defer close (ch )
415+ for {
416+ msgs , from , err := s .Receive ()
417+ if err != nil {
418+ if cberr != nil {
419+ cberr (fmt .Errorf ("Receive failed: %v" , err ))
420+ }
421+ return
422+ }
423+ if from .Pid != nl .PidKernel {
424+ if cberr != nil {
425+ cberr (fmt .Errorf ("Wrong sender portid %d, expected %d" , from .Pid , nl .PidKernel ))
426+ }
427+ continue
428+ }
429+ for _ , m := range msgs {
430+ if m .Header .Flags & unix .NLM_F_DUMP_INTR != 0 && cberr != nil {
431+ cberr (ErrDumpInterrupted )
432+ }
433+ if m .Header .Type == unix .NLMSG_DONE {
434+ continue
435+ }
436+ if m .Header .Type == unix .NLMSG_ERROR {
437+ error := int32 (native .Uint32 (m .Data [0 :4 ]))
438+ if error == 0 {
439+ continue
440+ }
441+ if cberr != nil {
442+ cberr (fmt .Errorf ("error message: %v" , syscall .Errno (- error )))
443+ }
444+ continue
445+ }
446+ rule , err := deserializeRule (m .Data )
447+ if err != nil {
448+ if cberr != nil {
449+ cberr (err )
450+ }
451+ continue
452+ }
453+ ch <- RuleUpdate {Type : m .Header .Type , Rule : rule }
454+ }
455+ }
456+ }()
457+
458+ return nil
459+ }
460+
325461func (pr * RulePortRange ) toRtAttrData () []byte {
326462 b := [][]byte {make ([]byte , 2 ), make ([]byte , 2 )}
327463 native .PutUint16 (b [0 ], pr .Start )
0 commit comments