mirror of
https://github.com/vishvananda/netlink
synced 2024-12-24 23:52:37 +00:00
192 lines
4.9 KiB
Go
192 lines
4.9 KiB
Go
package netlink
|
|
|
|
import (
|
|
"fmt"
|
|
"syscall"
|
|
|
|
"github.com/vishvananda/netlink/nl"
|
|
)
|
|
|
|
// FilterDel will delete a filter from the system.
|
|
// Equivalent to: `tc filter del $filter`
|
|
func FilterDel(filter Filter) error {
|
|
req := nl.NewNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK)
|
|
base := filter.Attrs()
|
|
msg := &nl.TcMsg{
|
|
Family: nl.FAMILY_ALL,
|
|
Ifindex: int32(base.LinkIndex),
|
|
Handle: base.Handle,
|
|
Parent: base.Parent,
|
|
Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)),
|
|
}
|
|
req.AddData(msg)
|
|
|
|
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
|
return err
|
|
}
|
|
|
|
// FilterAdd will add a filter to the system.
|
|
// Equivalent to: `tc filter add $filter`
|
|
func FilterAdd(filter Filter) error {
|
|
req := nl.NewNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
base := filter.Attrs()
|
|
msg := &nl.TcMsg{
|
|
Family: nl.FAMILY_ALL,
|
|
Ifindex: int32(base.LinkIndex),
|
|
Handle: base.Handle,
|
|
Parent: base.Parent,
|
|
Info: MakeHandle(base.Priority, nl.Swap16(base.Protocol)),
|
|
}
|
|
req.AddData(msg)
|
|
req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type())))
|
|
|
|
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
|
|
if u32, ok := filter.(*U32); ok {
|
|
// match all
|
|
sel := nl.TcU32Sel{
|
|
Nkeys: 1,
|
|
Flags: nl.TC_U32_TERMINAL,
|
|
}
|
|
sel.Keys = append(sel.Keys, nl.TcU32Key{})
|
|
nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
|
|
actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
|
|
table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil)
|
|
nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred"))
|
|
// redirect to other interface
|
|
mir := nl.TcMirred{
|
|
Action: nl.TC_ACT_STOLEN,
|
|
Eaction: nl.TCA_EGRESS_REDIR,
|
|
Ifindex: uint32(u32.RedirIndex),
|
|
}
|
|
aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil)
|
|
nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize())
|
|
}
|
|
req.AddData(options)
|
|
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
|
|
return err
|
|
}
|
|
|
|
// FilterList gets a list of filters in the system.
|
|
// Equivalent to: `tc filter show`.
|
|
// Generally retunrs nothing if link and parent are not specified.
|
|
func FilterList(link Link, parent uint32) ([]Filter, error) {
|
|
req := nl.NewNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP)
|
|
msg := &nl.TcMsg{
|
|
Family: nl.FAMILY_ALL,
|
|
Parent: parent,
|
|
}
|
|
if link != nil {
|
|
base := link.Attrs()
|
|
ensureIndex(base)
|
|
msg.Ifindex = int32(base.Index)
|
|
}
|
|
req.AddData(msg)
|
|
|
|
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTFILTER)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var res []Filter
|
|
for _, m := range msgs {
|
|
msg := nl.DeserializeTcMsg(m)
|
|
|
|
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
base := FilterAttrs{
|
|
LinkIndex: int(msg.Ifindex),
|
|
Handle: msg.Handle,
|
|
Parent: msg.Parent,
|
|
}
|
|
base.Priority, base.Protocol = MajorMinor(msg.Info)
|
|
base.Protocol = nl.Swap16(base.Protocol)
|
|
|
|
var filter Filter
|
|
filterType := ""
|
|
detailed := false
|
|
for _, attr := range attrs {
|
|
switch attr.Attr.Type {
|
|
case nl.TCA_KIND:
|
|
filterType = string(attr.Value[:len(attr.Value)-1])
|
|
switch filterType {
|
|
case "u32":
|
|
filter = &U32{}
|
|
default:
|
|
filter = &GenericFilter{FilterType: filterType}
|
|
}
|
|
case nl.TCA_OPTIONS:
|
|
switch filterType {
|
|
case "u32":
|
|
data, err := nl.ParseRouteAttr(attr.Value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
detailed, err = parseU32Data(filter, data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// only return the detailed version of the filter
|
|
if detailed {
|
|
*filter.Attrs() = base
|
|
res = append(res, filter)
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
|
|
native = nl.NativeEndian()
|
|
u32 := filter.(*U32)
|
|
detailed := false
|
|
for _, datum := range data {
|
|
switch datum.Attr.Type {
|
|
case nl.TCA_U32_SEL:
|
|
detailed = true
|
|
sel := nl.DeserializeTcU32Sel(datum.Value)
|
|
// only parse if we have a very basic redirect
|
|
if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 {
|
|
return detailed, nil
|
|
}
|
|
case nl.TCA_U32_ACT:
|
|
table, err := nl.ParseRouteAttr(datum.Value)
|
|
if err != nil {
|
|
return detailed, err
|
|
}
|
|
if len(table) != 1 || table[0].Attr.Type != nl.TCA_ACT_TAB {
|
|
return detailed, fmt.Errorf("Action table not formed properly")
|
|
}
|
|
aattrs, err := nl.ParseRouteAttr(table[0].Value)
|
|
for _, aattr := range aattrs {
|
|
switch aattr.Attr.Type {
|
|
case nl.TCA_KIND:
|
|
actionType := string(aattr.Value[:len(aattr.Value)-1])
|
|
// only parse if the action is mirred
|
|
if actionType != "mirred" {
|
|
return detailed, nil
|
|
}
|
|
case nl.TCA_OPTIONS:
|
|
adata, err := nl.ParseRouteAttr(aattr.Value)
|
|
if err != nil {
|
|
return detailed, err
|
|
}
|
|
for _, adatum := range adata {
|
|
switch adatum.Attr.Type {
|
|
case nl.TCA_MIRRED_PARMS:
|
|
mir := nl.DeserializeTcMirred(adatum.Value)
|
|
u32.RedirIndex = int(mir.Ifindex)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return detailed, nil
|
|
}
|