github.com/vishvananda/netlink@v1.3.0/socket_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"syscall"
     8  
     9  	"github.com/vishvananda/netlink/nl"
    10  	"golang.org/x/sys/unix"
    11  )
    12  
    13  const (
    14  	sizeofSocketID          = 0x30
    15  	sizeofSocketRequest     = sizeofSocketID + 0x8
    16  	sizeofSocket            = sizeofSocketID + 0x18
    17  	sizeofUnixSocketRequest = 0x18 // 24 byte
    18  	sizeofUnixSocket        = 0x10 // 16 byte
    19  )
    20  
    21  type socketRequest struct {
    22  	Family   uint8
    23  	Protocol uint8
    24  	Ext      uint8
    25  	pad      uint8
    26  	States   uint32
    27  	ID       SocketID
    28  }
    29  
    30  type writeBuffer struct {
    31  	Bytes []byte
    32  	pos   int
    33  }
    34  
    35  func (b *writeBuffer) Write(c byte) {
    36  	b.Bytes[b.pos] = c
    37  	b.pos++
    38  }
    39  
    40  func (b *writeBuffer) Next(n int) []byte {
    41  	s := b.Bytes[b.pos : b.pos+n]
    42  	b.pos += n
    43  	return s
    44  }
    45  
    46  func (r *socketRequest) Serialize() []byte {
    47  	b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)}
    48  	b.Write(r.Family)
    49  	b.Write(r.Protocol)
    50  	b.Write(r.Ext)
    51  	b.Write(r.pad)
    52  	native.PutUint32(b.Next(4), r.States)
    53  	networkOrder.PutUint16(b.Next(2), r.ID.SourcePort)
    54  	networkOrder.PutUint16(b.Next(2), r.ID.DestinationPort)
    55  	if r.Family == unix.AF_INET6 {
    56  		copy(b.Next(16), r.ID.Source)
    57  		copy(b.Next(16), r.ID.Destination)
    58  	} else {
    59  		copy(b.Next(16), r.ID.Source.To4())
    60  		copy(b.Next(16), r.ID.Destination.To4())
    61  	}
    62  	native.PutUint32(b.Next(4), r.ID.Interface)
    63  	native.PutUint32(b.Next(4), r.ID.Cookie[0])
    64  	native.PutUint32(b.Next(4), r.ID.Cookie[1])
    65  	return b.Bytes
    66  }
    67  
    68  func (r *socketRequest) Len() int { return sizeofSocketRequest }
    69  
    70  // According to linux/include/uapi/linux/unix_diag.h
    71  type unixSocketRequest struct {
    72  	Family   uint8
    73  	Protocol uint8
    74  	pad      uint16
    75  	States   uint32
    76  	INode    uint32
    77  	Show     uint32
    78  	Cookie   [2]uint32
    79  }
    80  
    81  func (r *unixSocketRequest) Serialize() []byte {
    82  	b := writeBuffer{Bytes: make([]byte, sizeofUnixSocketRequest)}
    83  	b.Write(r.Family)
    84  	b.Write(r.Protocol)
    85  	native.PutUint16(b.Next(2), r.pad)
    86  	native.PutUint32(b.Next(4), r.States)
    87  	native.PutUint32(b.Next(4), r.INode)
    88  	native.PutUint32(b.Next(4), r.Show)
    89  	native.PutUint32(b.Next(4), r.Cookie[0])
    90  	native.PutUint32(b.Next(4), r.Cookie[1])
    91  	return b.Bytes
    92  }
    93  
    94  func (r *unixSocketRequest) Len() int { return sizeofUnixSocketRequest }
    95  
    96  type readBuffer struct {
    97  	Bytes []byte
    98  	pos   int
    99  }
   100  
   101  func (b *readBuffer) Read() byte {
   102  	c := b.Bytes[b.pos]
   103  	b.pos++
   104  	return c
   105  }
   106  
   107  func (b *readBuffer) Next(n int) []byte {
   108  	s := b.Bytes[b.pos : b.pos+n]
   109  	b.pos += n
   110  	return s
   111  }
   112  
   113  func (s *Socket) deserialize(b []byte) error {
   114  	if len(b) < sizeofSocket {
   115  		return fmt.Errorf("socket data short read (%d); want %d", len(b), sizeofSocket)
   116  	}
   117  	rb := readBuffer{Bytes: b}
   118  	s.Family = rb.Read()
   119  	s.State = rb.Read()
   120  	s.Timer = rb.Read()
   121  	s.Retrans = rb.Read()
   122  	s.ID.SourcePort = networkOrder.Uint16(rb.Next(2))
   123  	s.ID.DestinationPort = networkOrder.Uint16(rb.Next(2))
   124  	if s.Family == unix.AF_INET6 {
   125  		s.ID.Source = net.IP(rb.Next(16))
   126  		s.ID.Destination = net.IP(rb.Next(16))
   127  	} else {
   128  		s.ID.Source = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
   129  		rb.Next(12)
   130  		s.ID.Destination = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
   131  		rb.Next(12)
   132  	}
   133  	s.ID.Interface = native.Uint32(rb.Next(4))
   134  	s.ID.Cookie[0] = native.Uint32(rb.Next(4))
   135  	s.ID.Cookie[1] = native.Uint32(rb.Next(4))
   136  	s.Expires = native.Uint32(rb.Next(4))
   137  	s.RQueue = native.Uint32(rb.Next(4))
   138  	s.WQueue = native.Uint32(rb.Next(4))
   139  	s.UID = native.Uint32(rb.Next(4))
   140  	s.INode = native.Uint32(rb.Next(4))
   141  	return nil
   142  }
   143  
   144  func (u *UnixSocket) deserialize(b []byte) error {
   145  	if len(b) < sizeofUnixSocket {
   146  		return fmt.Errorf("unix diag data short read (%d); want %d", len(b), sizeofUnixSocket)
   147  	}
   148  	rb := readBuffer{Bytes: b}
   149  	u.Type = rb.Read()
   150  	u.Family = rb.Read()
   151  	u.State = rb.Read()
   152  	u.pad = rb.Read()
   153  	u.INode = native.Uint32(rb.Next(4))
   154  	u.Cookie[0] = native.Uint32(rb.Next(4))
   155  	u.Cookie[1] = native.Uint32(rb.Next(4))
   156  	return nil
   157  }
   158  
   159  // SocketGet returns the Socket identified by its local and remote addresses.
   160  func (h *Handle) SocketGet(local, remote net.Addr) (*Socket, error) {
   161  	var protocol uint8
   162  	var localIP, remoteIP net.IP
   163  	var localPort, remotePort uint16
   164  	switch l := local.(type) {
   165  	case *net.TCPAddr:
   166  		r, ok := remote.(*net.TCPAddr)
   167  		if !ok {
   168  			return nil, ErrNotImplemented
   169  		}
   170  		localIP = l.IP
   171  		localPort = uint16(l.Port)
   172  		remoteIP = r.IP
   173  		remotePort = uint16(r.Port)
   174  		protocol = unix.IPPROTO_TCP
   175  	case *net.UDPAddr:
   176  		r, ok := remote.(*net.UDPAddr)
   177  		if !ok {
   178  			return nil, ErrNotImplemented
   179  		}
   180  		localIP = l.IP
   181  		localPort = uint16(l.Port)
   182  		remoteIP = r.IP
   183  		remotePort = uint16(r.Port)
   184  		protocol = unix.IPPROTO_UDP
   185  	default:
   186  		return nil, ErrNotImplemented
   187  	}
   188  
   189  	var family uint8
   190  	if localIP.To4() != nil && remoteIP.To4() != nil {
   191  		family = unix.AF_INET
   192  	}
   193  
   194  	if family == 0 && localIP.To16() != nil && remoteIP.To16() != nil {
   195  		family = unix.AF_INET6
   196  	}
   197  
   198  	if family == 0 {
   199  		return nil, ErrNotImplemented
   200  	}
   201  
   202  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   203  	req.AddData(&socketRequest{
   204  		Family:   family,
   205  		Protocol: protocol,
   206  		States:   0xffffffff,
   207  		ID: SocketID{
   208  			SourcePort:      localPort,
   209  			DestinationPort: remotePort,
   210  			Source:          localIP,
   211  			Destination:     remoteIP,
   212  			Cookie:          [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
   213  		},
   214  	})
   215  
   216  	msgs, err := req.Execute(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	if len(msgs) == 0 {
   221  		return nil, errors.New("no message nor error from netlink")
   222  	}
   223  	if len(msgs) > 2 {
   224  		return nil, fmt.Errorf("multiple (%d) matching sockets", len(msgs))
   225  	}
   226  
   227  	sock := &Socket{}
   228  	if err := sock.deserialize(msgs[0]); err != nil {
   229  		return nil, err
   230  	}
   231  	return sock, nil
   232  }
   233  
   234  // SocketGet returns the Socket identified by its local and remote addresses.
   235  func SocketGet(local, remote net.Addr) (*Socket, error) {
   236  	return pkgHandle.SocketGet(local, remote)
   237  }
   238  
   239  // SocketDestroy kills the Socket identified by its local and remote addresses.
   240  func (h *Handle) SocketDestroy(local, remote net.Addr) error {
   241  	localTCP, ok := local.(*net.TCPAddr)
   242  	if !ok {
   243  		return ErrNotImplemented
   244  	}
   245  	remoteTCP, ok := remote.(*net.TCPAddr)
   246  	if !ok {
   247  		return ErrNotImplemented
   248  	}
   249  	localIP := localTCP.IP.To4()
   250  	if localIP == nil {
   251  		return ErrNotImplemented
   252  	}
   253  	remoteIP := remoteTCP.IP.To4()
   254  	if remoteIP == nil {
   255  		return ErrNotImplemented
   256  	}
   257  
   258  	s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	defer s.Close()
   263  	req := h.newNetlinkRequest(nl.SOCK_DESTROY, unix.NLM_F_ACK)
   264  	req.AddData(&socketRequest{
   265  		Family:   unix.AF_INET,
   266  		Protocol: unix.IPPROTO_TCP,
   267  		ID: SocketID{
   268  			SourcePort:      uint16(localTCP.Port),
   269  			DestinationPort: uint16(remoteTCP.Port),
   270  			Source:          localIP,
   271  			Destination:     remoteIP,
   272  			Cookie:          [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
   273  		},
   274  	})
   275  
   276  	_, err = req.Execute(unix.NETLINK_INET_DIAG, 0)
   277  	return err
   278  }
   279  
   280  // SocketDestroy kills the Socket identified by its local and remote addresses.
   281  func SocketDestroy(local, remote net.Addr) error {
   282  	return pkgHandle.SocketDestroy(local, remote)
   283  }
   284  
   285  // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
   286  func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
   287  	// Construct the request
   288  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   289  	req.AddData(&socketRequest{
   290  		Family:   family,
   291  		Protocol: unix.IPPROTO_TCP,
   292  		Ext:      (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
   293  		States:   uint32(0xfff), // all states
   294  	})
   295  
   296  	// Do the query and parse the result
   297  	var result []*InetDiagTCPInfoResp
   298  	var err error
   299  	err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   300  		sockInfo := &Socket{}
   301  		if err = sockInfo.deserialize(msg); err != nil {
   302  			return false
   303  		}
   304  		var attrs []syscall.NetlinkRouteAttr
   305  		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
   306  			return false
   307  		}
   308  
   309  		var res *InetDiagTCPInfoResp
   310  		if res, err = attrsToInetDiagTCPInfoResp(attrs, sockInfo); err != nil {
   311  			return false
   312  		}
   313  
   314  		result = append(result, res)
   315  		return true
   316  	})
   317  
   318  	if err != nil {
   319  		return nil, err
   320  	}
   321  	return result, nil
   322  }
   323  
   324  // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
   325  func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
   326  	return pkgHandle.SocketDiagTCPInfo(family)
   327  }
   328  
   329  // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
   330  func (h *Handle) SocketDiagTCP(family uint8) ([]*Socket, error) {
   331  	// Construct the request
   332  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   333  	req.AddData(&socketRequest{
   334  		Family:   family,
   335  		Protocol: unix.IPPROTO_TCP,
   336  		Ext:      (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
   337  		States:   uint32(0xfff), // all states
   338  	})
   339  
   340  	// Do the query and parse the result
   341  	var result []*Socket
   342  	var err error
   343  	err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   344  		sockInfo := &Socket{}
   345  		if err = sockInfo.deserialize(msg); err != nil {
   346  			return false
   347  		}
   348  		result = append(result, sockInfo)
   349  		return true
   350  	})
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  	return result, nil
   355  }
   356  
   357  // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
   358  func SocketDiagTCP(family uint8) ([]*Socket, error) {
   359  	return pkgHandle.SocketDiagTCP(family)
   360  }
   361  
   362  // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info.
   363  func (h *Handle) SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
   364  	// Construct the request
   365  	var extensions uint8
   366  	extensions = 1 << (INET_DIAG_VEGASINFO - 1)
   367  	extensions |= 1 << (INET_DIAG_INFO - 1)
   368  	extensions |= 1 << (INET_DIAG_MEMINFO - 1)
   369  
   370  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   371  	req.AddData(&socketRequest{
   372  		Family:   family,
   373  		Protocol: unix.IPPROTO_UDP,
   374  		Ext:      extensions,
   375  		States:   uint32(0xfff), // all states
   376  	})
   377  
   378  	// Do the query and parse the result
   379  	var result []*InetDiagUDPInfoResp
   380  	var err error
   381  	err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   382  		sockInfo := &Socket{}
   383  		if err = sockInfo.deserialize(msg); err != nil {
   384  			return false
   385  		}
   386  
   387  		var attrs []syscall.NetlinkRouteAttr
   388  		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
   389  			return false
   390  		}
   391  
   392  		var res *InetDiagUDPInfoResp
   393  		if res, err = attrsToInetDiagUDPInfoResp(attrs, sockInfo); err != nil {
   394  			return false
   395  		}
   396  
   397  		result = append(result, res)
   398  		return true
   399  	})
   400  	if err != nil {
   401  		return nil, err
   402  	}
   403  	return result, nil
   404  }
   405  
   406  // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info.
   407  func SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
   408  	return pkgHandle.SocketDiagUDPInfo(family)
   409  }
   410  
   411  // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket.
   412  func (h *Handle) SocketDiagUDP(family uint8) ([]*Socket, error) {
   413  	// Construct the request
   414  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   415  	req.AddData(&socketRequest{
   416  		Family:   family,
   417  		Protocol: unix.IPPROTO_UDP,
   418  		Ext:      (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
   419  		States:   uint32(0xfff), // all states
   420  	})
   421  
   422  	// Do the query and parse the result
   423  	var result []*Socket
   424  	var err error
   425  	err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   426  		sockInfo := &Socket{}
   427  		if err = sockInfo.deserialize(msg); err != nil {
   428  			return false
   429  		}
   430  		result = append(result, sockInfo)
   431  		return true
   432  	})
   433  	if err != nil {
   434  		return nil, err
   435  	}
   436  	return result, nil
   437  }
   438  
   439  // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket.
   440  func SocketDiagUDP(family uint8) ([]*Socket, error) {
   441  	return pkgHandle.SocketDiagUDP(family)
   442  }
   443  
   444  // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
   445  func (h *Handle) UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
   446  	// Construct the request
   447  	var extensions uint8
   448  	extensions = 1 << UNIX_DIAG_NAME
   449  	extensions |= 1 << UNIX_DIAG_PEER
   450  	extensions |= 1 << UNIX_DIAG_RQLEN
   451  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   452  	req.AddData(&unixSocketRequest{
   453  		Family: unix.AF_UNIX,
   454  		States: ^uint32(0), // all states
   455  		Show:   uint32(extensions),
   456  	})
   457  
   458  	var result []*UnixDiagInfoResp
   459  	var err error
   460  	err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   461  		sockInfo := &UnixSocket{}
   462  		if err = sockInfo.deserialize(msg); err != nil {
   463  			return false
   464  		}
   465  
   466  		// Diagnosis also delivers sockets with AF_INET family, filter those
   467  		if sockInfo.Family != unix.AF_UNIX {
   468  			return false
   469  		}
   470  
   471  		var attrs []syscall.NetlinkRouteAttr
   472  		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
   473  			return false
   474  		}
   475  
   476  		var res *UnixDiagInfoResp
   477  		if res, err = attrsToUnixDiagInfoResp(attrs, sockInfo); err != nil {
   478  			return false
   479  		}
   480  		result = append(result, res)
   481  		return true
   482  	})
   483  	if err != nil {
   484  		return nil, err
   485  	}
   486  	return result, nil
   487  }
   488  
   489  // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
   490  func UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
   491  	return pkgHandle.UnixSocketDiagInfo()
   492  }
   493  
   494  // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
   495  func (h *Handle) UnixSocketDiag() ([]*UnixSocket, error) {
   496  	// Construct the request
   497  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   498  	req.AddData(&unixSocketRequest{
   499  		Family: unix.AF_UNIX,
   500  		States: ^uint32(0), // all states
   501  	})
   502  
   503  	var result []*UnixSocket
   504  	var err error
   505  	err = req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   506  		sockInfo := &UnixSocket{}
   507  		if err = sockInfo.deserialize(msg); err != nil {
   508  			return false
   509  		}
   510  
   511  		// Diagnosis also delivers sockets with AF_INET family, filter those
   512  		if sockInfo.Family == unix.AF_UNIX {
   513  			result = append(result, sockInfo)
   514  		}
   515  		return true
   516  	})
   517  	if err != nil {
   518  		return nil, err
   519  	}
   520  	return result, nil
   521  }
   522  
   523  // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
   524  func UnixSocketDiag() ([]*UnixSocket, error) {
   525  	return pkgHandle.UnixSocketDiag()
   526  }
   527  
   528  func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) {
   529  	info := &InetDiagTCPInfoResp{
   530  		InetDiagMsg: sockInfo,
   531  	}
   532  	for _, a := range attrs {
   533  		switch a.Attr.Type {
   534  		case INET_DIAG_INFO:
   535  			info.TCPInfo = &TCPInfo{}
   536  			if err := info.TCPInfo.deserialize(a.Value); err != nil {
   537  				return nil, err
   538  			}
   539  		case INET_DIAG_BBRINFO:
   540  			info.TCPBBRInfo = &TCPBBRInfo{}
   541  			if err := info.TCPBBRInfo.deserialize(a.Value); err != nil {
   542  				return nil, err
   543  			}
   544  		}
   545  	}
   546  
   547  	return info, nil
   548  }
   549  
   550  func attrsToInetDiagUDPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagUDPInfoResp, error) {
   551  	info := &InetDiagUDPInfoResp{
   552  		InetDiagMsg: sockInfo,
   553  	}
   554  	for _, a := range attrs {
   555  		switch a.Attr.Type {
   556  		case INET_DIAG_MEMINFO:
   557  			info.Memory = &MemInfo{}
   558  			if err := info.Memory.deserialize(a.Value); err != nil {
   559  				return nil, err
   560  			}
   561  		}
   562  	}
   563  
   564  	return info, nil
   565  }
   566  
   567  func attrsToUnixDiagInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *UnixSocket) (*UnixDiagInfoResp, error) {
   568  	info := &UnixDiagInfoResp{
   569  		DiagMsg: sockInfo,
   570  	}
   571  	for _, a := range attrs {
   572  		switch a.Attr.Type {
   573  		case UNIX_DIAG_NAME:
   574  			name := string(a.Value[:a.Attr.Len])
   575  			info.Name = &name
   576  		case UNIX_DIAG_PEER:
   577  			peer := native.Uint32(a.Value)
   578  			info.Peer = &peer
   579  		case UNIX_DIAG_RQLEN:
   580  			info.Queue = &QueueInfo{
   581  				RQueue: native.Uint32(a.Value[:4]),
   582  				WQueue: native.Uint32(a.Value[4:]),
   583  			}
   584  			// default:
   585  			// 	fmt.Println("unknown unix attribute type", a.Attr.Type, "with data", a.Value)
   586  		}
   587  	}
   588  
   589  	return info, nil
   590  }