// deserializeRoute decodes a binary netlink message into a Route struct func deserializeRoute(m []byte) (Route, error) { msg := nl.DeserializeRtMsg(m) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return Route{}, err } route := Route{ Scope: Scope(msg.Scope), Protocol: int(msg.Protocol), Table: int(msg.Table), Type: int(msg.Type), Tos: int(msg.Tos), Flags: int(msg.Flags), } native := nl.NativeEndian() for _, attr := range attrs { switch attr.Attr.Type { case syscall.RTA_GATEWAY: route.Gw = net.IP(attr.Value) case syscall.RTA_PREFSRC: route.Src = net.IP(attr.Value) case syscall.RTA_DST: route.Dst = &net.IPNet{ IP: attr.Value, Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)), } case syscall.RTA_OIF: route.LinkIndex = int(native.Uint32(attr.Value[0:4])) case syscall.RTA_IIF: route.ILinkIndex = int(native.Uint32(attr.Value[0:4])) case syscall.RTA_PRIORITY: route.Priority = int(native.Uint32(attr.Value[0:4])) case syscall.RTA_TABLE: route.Table = int(native.Uint32(attr.Value[0:4])) } } return route, nil }
// RuleList lists rules in the system. // Equivalent to: ip rule list func RuleList(family int) ([]Rule, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST) msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWRULE) if err != nil { return nil, err } native := nl.NativeEndian() var res = make([]Rule, 0) for i := range msgs { msg := nl.DeserializeRtMsg(msgs[i]) attrs, err := nl.ParseRouteAttr(msgs[i][msg.Len():]) if err != nil { return nil, err } rule := NewRule() rule.RtMsg = msg for j := range attrs { switch attrs[j].Attr.Type { case syscall.RTA_TABLE: rule.Table = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_SRC: rule.Src = &net.IPNet{ IP: attrs[j].Value, Mask: net.CIDRMask(int(msg.Src_len), 8*len(attrs[j].Value)), } case nl.FRA_DST: rule.Dst = &net.IPNet{ IP: attrs[j].Value, Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attrs[j].Value)), } case nl.FRA_FWMARK: rule.Mark = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_FWMASK: rule.Mask = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_TUN_ID: rule.TunID = uint(native.Uint64(attrs[j].Value[0:4])) case nl.FRA_IIFNAME: rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1]) case nl.FRA_OIFNAME: rule.OifName = string(attrs[j].Value[:len(attrs[j].Value)-1]) case nl.FRA_SUPPRESS_PREFIXLEN: i := native.Uint32(attrs[j].Value[0:4]) if i != 0xffffffff { rule.SuppressPrefixlen = int(i) } case nl.FRA_SUPPRESS_IFGROUP: i := native.Uint32(attrs[j].Value[0:4]) if i != 0xffffffff { rule.SuppressIfgroup = int(i) } case nl.FRA_FLOW: rule.Flow = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_GOTO: rule.Goto = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_PRIORITY: rule.Priority = int(native.Uint32(attrs[j].Value[0:4])) } } res = append(res, *rule) } return res, nil }
// RouteListFiltered gets a list of routes in the system filtered with specified rules. // All rules must be defined in RouteFilter struct func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) infmsg := nl.NewIfInfomsg(family) req.AddData(infmsg) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE) if err != nil { return nil, err } var res []Route for _, m := range msgs { msg := nl.DeserializeRtMsg(m) if msg.Flags&syscall.RTM_F_CLONED != 0 { // Ignore cloned routes continue } if msg.Table != syscall.RT_TABLE_MAIN { if filter == nil || filter != nil && filterMask&RT_FILTER_TABLE == 0 { // Ignore non-main tables continue } } route, err := deserializeRoute(m) if err != nil { return nil, err } if filter != nil { switch { case filterMask&RT_FILTER_TABLE != 0 && route.Table != filter.Table: continue case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol: continue case filterMask&RT_FILTER_SCOPE != 0 && route.Scope != filter.Scope: continue case filterMask&RT_FILTER_TYPE != 0 && route.Type != filter.Type: continue case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos: continue case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex: continue case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex: continue case filterMask&RT_FILTER_GW != 0 && !route.Gw.Equal(filter.Gw): continue case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src): continue case filterMask&RT_FILTER_DST != 0 && filter.Dst != nil: if route.Dst == nil { continue } aMaskLen, aMaskBits := route.Dst.Mask.Size() bMaskLen, bMaskBits := filter.Dst.Mask.Size() if !(route.Dst.IP.Equal(filter.Dst.IP) && aMaskLen == bMaskLen && aMaskBits == bMaskBits) { continue } } } res = append(res, route) } return res, nil }