github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/genetlink_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"fmt"
     5  	"syscall"
     6  
     7  	"github.com/sagernet/netlink/nl"
     8  	"golang.org/x/sys/unix"
     9  )
    10  
    11  type GenlOp struct {
    12  	ID    uint32
    13  	Flags uint32
    14  }
    15  
    16  type GenlMulticastGroup struct {
    17  	ID   uint32
    18  	Name string
    19  }
    20  
    21  type GenlFamily struct {
    22  	ID      uint16
    23  	HdrSize uint32
    24  	Name    string
    25  	Version uint32
    26  	MaxAttr uint32
    27  	Ops     []GenlOp
    28  	Groups  []GenlMulticastGroup
    29  }
    30  
    31  func parseOps(b []byte) ([]GenlOp, error) {
    32  	attrs, err := nl.ParseRouteAttr(b)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  	ops := make([]GenlOp, 0, len(attrs))
    37  	for _, a := range attrs {
    38  		nattrs, err := nl.ParseRouteAttr(a.Value)
    39  		if err != nil {
    40  			return nil, err
    41  		}
    42  		var op GenlOp
    43  		for _, na := range nattrs {
    44  			switch na.Attr.Type {
    45  			case nl.GENL_CTRL_ATTR_OP_ID:
    46  				op.ID = native.Uint32(na.Value)
    47  			case nl.GENL_CTRL_ATTR_OP_FLAGS:
    48  				op.Flags = native.Uint32(na.Value)
    49  			}
    50  		}
    51  		ops = append(ops, op)
    52  	}
    53  	return ops, nil
    54  }
    55  
    56  func parseMulticastGroups(b []byte) ([]GenlMulticastGroup, error) {
    57  	attrs, err := nl.ParseRouteAttr(b)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	groups := make([]GenlMulticastGroup, 0, len(attrs))
    62  	for _, a := range attrs {
    63  		nattrs, err := nl.ParseRouteAttr(a.Value)
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  		var g GenlMulticastGroup
    68  		for _, na := range nattrs {
    69  			switch na.Attr.Type {
    70  			case nl.GENL_CTRL_ATTR_MCAST_GRP_NAME:
    71  				g.Name = nl.BytesToString(na.Value)
    72  			case nl.GENL_CTRL_ATTR_MCAST_GRP_ID:
    73  				g.ID = native.Uint32(na.Value)
    74  			}
    75  		}
    76  		groups = append(groups, g)
    77  	}
    78  	return groups, nil
    79  }
    80  
    81  func (f *GenlFamily) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
    82  	for _, a := range attrs {
    83  		switch a.Attr.Type {
    84  		case nl.GENL_CTRL_ATTR_FAMILY_NAME:
    85  			f.Name = nl.BytesToString(a.Value)
    86  		case nl.GENL_CTRL_ATTR_FAMILY_ID:
    87  			f.ID = native.Uint16(a.Value)
    88  		case nl.GENL_CTRL_ATTR_VERSION:
    89  			f.Version = native.Uint32(a.Value)
    90  		case nl.GENL_CTRL_ATTR_HDRSIZE:
    91  			f.HdrSize = native.Uint32(a.Value)
    92  		case nl.GENL_CTRL_ATTR_MAXATTR:
    93  			f.MaxAttr = native.Uint32(a.Value)
    94  		case nl.GENL_CTRL_ATTR_OPS:
    95  			ops, err := parseOps(a.Value)
    96  			if err != nil {
    97  				return err
    98  			}
    99  			f.Ops = ops
   100  		case nl.GENL_CTRL_ATTR_MCAST_GROUPS:
   101  			groups, err := parseMulticastGroups(a.Value)
   102  			if err != nil {
   103  				return err
   104  			}
   105  			f.Groups = groups
   106  		}
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  func parseFamilies(msgs [][]byte) ([]*GenlFamily, error) {
   113  	families := make([]*GenlFamily, 0, len(msgs))
   114  	for _, m := range msgs {
   115  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   116  		if err != nil {
   117  			return nil, err
   118  		}
   119  		family := &GenlFamily{}
   120  		if err := family.parseAttributes(attrs); err != nil {
   121  			return nil, err
   122  		}
   123  
   124  		families = append(families, family)
   125  	}
   126  	return families, nil
   127  }
   128  
   129  func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
   130  	msg := &nl.Genlmsg{
   131  		Command: nl.GENL_CTRL_CMD_GETFAMILY,
   132  		Version: nl.GENL_CTRL_VERSION,
   133  	}
   134  	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
   135  	req.AddData(msg)
   136  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	return parseFamilies(msgs)
   141  }
   142  
   143  func GenlFamilyList() ([]*GenlFamily, error) {
   144  	return pkgHandle.GenlFamilyList()
   145  }
   146  
   147  func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
   148  	msg := &nl.Genlmsg{
   149  		Command: nl.GENL_CTRL_CMD_GETFAMILY,
   150  		Version: nl.GENL_CTRL_VERSION,
   151  	}
   152  	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0)
   153  	req.AddData(msg)
   154  	req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name)))
   155  	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	families, err := parseFamilies(msgs)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	if len(families) != 1 {
   164  		return nil, fmt.Errorf("invalid response for GENL_CTRL_CMD_GETFAMILY")
   165  	}
   166  	return families[0], nil
   167  }
   168  
   169  func GenlFamilyGet(name string) (*GenlFamily, error) {
   170  	return pkgHandle.GenlFamilyGet(name)
   171  }