@@ -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
@@ -227,73 +229,11 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
227229
228230 var res = make ([]Rule , 0 )
229231 for i := range msgs {
230- msg := nl .DeserializeRtMsg (msgs [i ])
231- attrs , err := nl .ParseRouteAttr (msgs [i ][msg .Len ():])
232+ rule , err := deserializeRule (msgs [i ])
232233 if err != nil {
233234 return nil , err
234235 }
235236
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-
297237 if filter != nil {
298238 switch {
299239 case filterMask & RT_FILTER_SRC != 0 &&
@@ -316,12 +256,169 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
316256 }
317257 }
318258
319- res = append (res , * rule )
259+ res = append (res , rule )
320260 }
321261
322262 return res , executeErr
323263}
324264
265+ func deserializeRule (m []byte ) (Rule , error ) {
266+ msg := nl .DeserializeRtMsg (m )
267+ attrs , err := nl .ParseRouteAttr (m [msg .Len ():])
268+ if err != nil {
269+ return Rule {}, err
270+ }
271+
272+ rule := NewRule ()
273+
274+ rule .Invert = msg .Flags & FibRuleInvert > 0
275+ rule .Tos = uint (msg .Tos )
276+
277+ for j := range attrs {
278+ switch attrs [j ].Attr .Type {
279+ case unix .RTA_TABLE :
280+ rule .Table = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
281+ case nl .FRA_SRC :
282+ rule .Src = & net.IPNet {
283+ IP : attrs [j ].Value ,
284+ Mask : net .CIDRMask (int (msg .Src_len ), 8 * len (attrs [j ].Value )),
285+ }
286+ case nl .FRA_DST :
287+ rule .Dst = & net.IPNet {
288+ IP : attrs [j ].Value ,
289+ Mask : net .CIDRMask (int (msg .Dst_len ), 8 * len (attrs [j ].Value )),
290+ }
291+ case nl .FRA_FWMARK :
292+ rule .Mark = native .Uint32 (attrs [j ].Value [0 :4 ])
293+ case nl .FRA_FWMASK :
294+ mask := native .Uint32 (attrs [j ].Value [0 :4 ])
295+ rule .Mask = & mask
296+ case nl .FRA_TUN_ID :
297+ rule .TunID = uint (native .Uint64 (attrs [j ].Value [0 :8 ]))
298+ case nl .FRA_IIFNAME :
299+ rule .IifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
300+ case nl .FRA_OIFNAME :
301+ rule .OifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
302+ case nl .FRA_SUPPRESS_PREFIXLEN :
303+ i := native .Uint32 (attrs [j ].Value [0 :4 ])
304+ if i != 0xffffffff {
305+ rule .SuppressPrefixlen = int (i )
306+ }
307+ case nl .FRA_SUPPRESS_IFGROUP :
308+ i := native .Uint32 (attrs [j ].Value [0 :4 ])
309+ if i != 0xffffffff {
310+ rule .SuppressIfgroup = int (i )
311+ }
312+ case nl .FRA_FLOW :
313+ rule .Flow = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
314+ case nl .FRA_GOTO :
315+ rule .Goto = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
316+ case nl .FRA_PRIORITY :
317+ rule .Priority = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
318+ case nl .FRA_DPORT_RANGE :
319+ rule .Dport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
320+ case nl .FRA_SPORT_RANGE :
321+ rule .Sport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
322+ }
323+ }
324+
325+ return * rule , nil
326+ }
327+
328+ // RuleSubscribe takes a chan down which notifications will be sent
329+ // when rules are added or deleted. Close the 'done' chan to stop subscription.
330+ func RuleSubscribe (ch chan <- RuleUpdate , done <- chan struct {}) error {
331+ return ruleSubscribeAt (netns .None (), netns .None (), ch , done , nil , false )
332+ }
333+
334+ // RuleSubscribeAt works like RuleSubscribe plus it allows the caller
335+ // to choose the network namespace in which to subscribe (ns).
336+ func RuleSubscribeAt (ns netns.NsHandle , ch chan <- RuleUpdate , done <- chan struct {}) error {
337+ return ruleSubscribeAt (ns , netns .None (), ch , done , nil , false )
338+ }
339+
340+ // RuleSubscribeOptions contains a set of options to use with
341+ // RuleSubscribeWithOptions.
342+ type RuleSubscribeOptions struct {
343+ Namespace * netns.NsHandle
344+ ErrorCallback func (error )
345+ ListExisting bool
346+ }
347+
348+ // RuleSubscribeWithOptions works like RuleSubscribe but enables
349+ // additional options to modify the behavior.
350+ func RuleSubscribeWithOptions (ch chan <- RuleUpdate , done <- chan struct {}, options RuleSubscribeOptions ) error {
351+ if options .Namespace == nil {
352+ none := netns .None ()
353+ options .Namespace = & none
354+ }
355+ return ruleSubscribeAt (* options .Namespace , netns .None (), ch , done , options .ErrorCallback , options .ListExisting )
356+ }
357+
358+ func ruleSubscribeAt (newNs , curNs netns.NsHandle , ch chan <- RuleUpdate , done <- chan struct {}, cberr func (error ), listExisting bool ) error {
359+ s , err := nl .SubscribeAt (newNs , curNs , unix .NETLINK_ROUTE , unix .RTNLGRP_IPV4_RULE , unix .RTNLGRP_IPV6_RULE )
360+ if err != nil {
361+ return err
362+ }
363+ if done != nil {
364+ go func () {
365+ <- done
366+ s .Close ()
367+ }()
368+ }
369+ if listExisting {
370+ req := pkgHandle ().newNetlinkRequest (unix .RTM_GETRULE , unix .NLM_F_DUMP )
371+ infmsg := nl .NewIfInfomsg (unix .AF_UNSPEC )
372+ req .AddData (infmsg )
373+ if err := s .Send (req ); err != nil {
374+ return err
375+ }
376+ }
377+ go func () {
378+ defer close (ch )
379+ for {
380+ msgs , from , err := s .Receive ()
381+ if err != nil {
382+ if cberr != nil {
383+ cberr (fmt .Errorf ("Receive failed: %v" , err ))
384+ }
385+ return
386+ }
387+ if from .Pid != nl .PidKernel {
388+ if cberr != nil {
389+ cberr (fmt .Errorf ("Wrong sender portid %d, expected %d" , from .Pid , nl .PidKernel ))
390+ }
391+ continue
392+ }
393+ for _ , m := range msgs {
394+ if m .Header .Type == unix .NLMSG_DONE {
395+ continue
396+ }
397+ if m .Header .Type == unix .NLMSG_ERROR {
398+ error := int32 (native .Uint32 (m .Data [0 :4 ]))
399+ if error == 0 {
400+ continue
401+ }
402+ if cberr != nil {
403+ cberr (fmt .Errorf ("error message: %v" , syscall .Errno (- error )))
404+ }
405+ continue
406+ }
407+ rule , err := deserializeRule (m .Data )
408+ if err != nil {
409+ if cberr != nil {
410+ cberr (err )
411+ }
412+ continue
413+ }
414+ ch <- RuleUpdate {Type : m .Header .Type , Rule : rule }
415+ }
416+ }
417+ }()
418+
419+ return nil
420+ }
421+
325422func (pr * RulePortRange ) toRtAttrData () []byte {
326423 b := [][]byte {make ([]byte , 2 ), make ([]byte , 2 )}
327424 native .PutUint16 (b [0 ], pr .Start )
0 commit comments