@@ -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,168 @@ 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 = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
293+ case nl .FRA_FWMASK :
294+ rule .Mask = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
295+ case nl .FRA_TUN_ID :
296+ rule .TunID = uint (native .Uint64 (attrs [j ].Value [0 :8 ]))
297+ case nl .FRA_IIFNAME :
298+ rule .IifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
299+ case nl .FRA_OIFNAME :
300+ rule .OifName = string (attrs [j ].Value [:len (attrs [j ].Value )- 1 ])
301+ case nl .FRA_SUPPRESS_PREFIXLEN :
302+ i := native .Uint32 (attrs [j ].Value [0 :4 ])
303+ if i != 0xffffffff {
304+ rule .SuppressPrefixlen = int (i )
305+ }
306+ case nl .FRA_SUPPRESS_IFGROUP :
307+ i := native .Uint32 (attrs [j ].Value [0 :4 ])
308+ if i != 0xffffffff {
309+ rule .SuppressIfgroup = int (i )
310+ }
311+ case nl .FRA_FLOW :
312+ rule .Flow = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
313+ case nl .FRA_GOTO :
314+ rule .Goto = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
315+ case nl .FRA_PRIORITY :
316+ rule .Priority = int (native .Uint32 (attrs [j ].Value [0 :4 ]))
317+ case nl .FRA_DPORT_RANGE :
318+ rule .Dport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
319+ case nl .FRA_SPORT_RANGE :
320+ rule .Sport = NewRulePortRange (native .Uint16 (attrs [j ].Value [0 :2 ]), native .Uint16 (attrs [j ].Value [2 :4 ]))
321+ }
322+ }
323+
324+ return * rule , nil
325+ }
326+
327+ // RuleSubscribe takes a chan down which notifications will be sent
328+ // when rules are added or deleted. Close the 'done' chan to stop subscription.
329+ func RuleSubscribe (ch chan <- RuleUpdate , done <- chan struct {}) error {
330+ return ruleSubscribeAt (netns .None (), netns .None (), ch , done , nil , false )
331+ }
332+
333+ // RuleSubscribeAt works like RuleSubscribe plus it allows the caller
334+ // to choose the network namespace in which to subscribe (ns).
335+ func RuleSubscribeAt (ns netns.NsHandle , ch chan <- RuleUpdate , done <- chan struct {}) error {
336+ return ruleSubscribeAt (ns , netns .None (), ch , done , nil , false )
337+ }
338+
339+ // RuleSubscribeOptions contains a set of options to use with
340+ // RuleSubscribeWithOptions.
341+ type RuleSubscribeOptions struct {
342+ Namespace * netns.NsHandle
343+ ErrorCallback func (error )
344+ ListExisting bool
345+ }
346+
347+ // RuleSubscribeWithOptions works like RuleSubscribe but enables
348+ // additional options to modify the behavior.
349+ func RuleSubscribeWithOptions (ch chan <- RuleUpdate , done <- chan struct {}, options RuleSubscribeOptions ) error {
350+ if options .Namespace == nil {
351+ none := netns .None ()
352+ options .Namespace = & none
353+ }
354+ return ruleSubscribeAt (* options .Namespace , netns .None (), ch , done , options .ErrorCallback , options .ListExisting )
355+ }
356+
357+ func ruleSubscribeAt (newNs , curNs netns.NsHandle , ch chan <- RuleUpdate , done <- chan struct {}, cberr func (error ), listExisting bool ) error {
358+ s , err := nl .SubscribeAt (newNs , curNs , unix .NETLINK_ROUTE , unix .RTNLGRP_IPV4_RULE , unix .RTNLGRP_IPV6_RULE )
359+ if err != nil {
360+ return err
361+ }
362+ if done != nil {
363+ go func () {
364+ <- done
365+ s .Close ()
366+ }()
367+ }
368+ if listExisting {
369+ req := pkgHandle .newNetlinkRequest (unix .RTM_GETRULE , unix .NLM_F_DUMP )
370+ infmsg := nl .NewIfInfomsg (unix .AF_UNSPEC )
371+ req .AddData (infmsg )
372+ if err := s .Send (req ); err != nil {
373+ return err
374+ }
375+ }
376+ go func () {
377+ defer close (ch )
378+ for {
379+ msgs , from , err := s .Receive ()
380+ if err != nil {
381+ if cberr != nil {
382+ cberr (fmt .Errorf ("Receive failed: %v" , err ))
383+ }
384+ return
385+ }
386+ if from .Pid != nl .PidKernel {
387+ if cberr != nil {
388+ cberr (fmt .Errorf ("Wrong sender portid %d, expected %d" , from .Pid , nl .PidKernel ))
389+ }
390+ continue
391+ }
392+ for _ , m := range msgs {
393+ if m .Header .Type == unix .NLMSG_DONE {
394+ continue
395+ }
396+ if m .Header .Type == unix .NLMSG_ERROR {
397+ error := int32 (native .Uint32 (m .Data [0 :4 ]))
398+ if error == 0 {
399+ continue
400+ }
401+ if cberr != nil {
402+ cberr (fmt .Errorf ("error message: %v" , syscall .Errno (- error )))
403+ }
404+ continue
405+ }
406+ rule , err := deserializeRule (m .Data )
407+ if err != nil {
408+ if cberr != nil {
409+ cberr (err )
410+ }
411+ continue
412+ }
413+ ch <- RuleUpdate {Type : m .Header .Type , Rule : rule }
414+ }
415+ }
416+ }()
417+
418+ return nil
419+ }
420+
325421func (pr * RulePortRange ) toRtAttrData () []byte {
326422 b := [][]byte {make ([]byte , 2 ), make ([]byte , 2 )}
327423 native .PutUint16 (b [0 ], pr .Start )
0 commit comments