github.com/vishvananda/netlink@v1.3.1/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  //
   161  // If the returned error is [ErrDumpInterrupted], the search for a result may
   162  // be incomplete and the caller should retry.
   163  func (h *Handle) SocketGet(local, remote net.Addr) (*Socket, error) {
   164  	var protocol uint8
   165  	var localIP, remoteIP net.IP
   166  	var localPort, remotePort uint16
   167  	switch l := local.(type) {
   168  	case *net.TCPAddr:
   169  		r, ok := remote.(*net.TCPAddr)
   170  		if !ok {
   171  			return nil, ErrNotImplemented
   172  		}
   173  		localIP = l.IP
   174  		localPort = uint16(l.Port)
   175  		remoteIP = r.IP
   176  		remotePort = uint16(r.Port)
   177  		protocol = unix.IPPROTO_TCP
   178  	case *net.UDPAddr:
   179  		r, ok := remote.(*net.UDPAddr)
   180  		if !ok {
   181  			return nil, ErrNotImplemented
   182  		}
   183  		localIP = l.IP
   184  		localPort = uint16(l.Port)
   185  		remoteIP = r.IP
   186  		remotePort = uint16(r.Port)
   187  		protocol = unix.IPPROTO_UDP
   188  	default:
   189  		return nil, ErrNotImplemented
   190  	}
   191  
   192  	var family uint8
   193  	if localIP.To4() != nil && remoteIP.To4() != nil {
   194  		family = unix.AF_INET
   195  	}
   196  
   197  	if family == 0 && localIP.To16() != nil && remoteIP.To16() != nil {
   198  		family = unix.AF_INET6
   199  	}
   200  
   201  	if family == 0 {
   202  		return nil, ErrNotImplemented
   203  	}
   204  
   205  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   206  	req.AddData(&socketRequest{
   207  		Family:   family,
   208  		Protocol: protocol,
   209  		States:   0xffffffff,
   210  		ID: SocketID{
   211  			SourcePort:      localPort,
   212  			DestinationPort: remotePort,
   213  			Source:          localIP,
   214  			Destination:     remoteIP,
   215  			Cookie:          [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
   216  		},
   217  	})
   218  
   219  	msgs, err := req.Execute(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	if len(msgs) == 0 {
   224  		return nil, errors.New("no message nor error from netlink")
   225  	}
   226  	if len(msgs) > 2 {
   227  		return nil, fmt.Errorf("multiple (%d) matching sockets", len(msgs))
   228  	}
   229  
   230  	sock := &Socket{}
   231  	if err := sock.deserialize(msgs[0]); err != nil {
   232  		return nil, err
   233  	}
   234  	return sock, nil
   235  }
   236  
   237  // SocketGet returns the Socket identified by its local and remote addresses.
   238  //
   239  // If the returned error is [ErrDumpInterrupted], the search for a result may
   240  // be incomplete and the caller should retry.
   241  func SocketGet(local, remote net.Addr) (*Socket, error) {
   242  	return pkgHandle.SocketGet(local, remote)
   243  }
   244  
   245  // SocketDestroy kills the Socket identified by its local and remote addresses.
   246  func (h *Handle) SocketDestroy(local, remote net.Addr) error {
   247  	localTCP, ok := local.(*net.TCPAddr)
   248  	if !ok {
   249  		return ErrNotImplemented
   250  	}
   251  	remoteTCP, ok := remote.(*net.TCPAddr)
   252  	if !ok {
   253  		return ErrNotImplemented
   254  	}
   255  	localIP := localTCP.IP.To4()
   256  	if localIP == nil {
   257  		return ErrNotImplemented
   258  	}
   259  	remoteIP := remoteTCP.IP.To4()
   260  	if remoteIP == nil {
   261  		return ErrNotImplemented
   262  	}
   263  
   264  	s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
   265  	if err != nil {
   266  		return err
   267  	}
   268  	defer s.Close()
   269  	req := h.newNetlinkRequest(nl.SOCK_DESTROY, unix.NLM_F_ACK)
   270  	req.AddData(&socketRequest{
   271  		Family:   unix.AF_INET,
   272  		Protocol: unix.IPPROTO_TCP,
   273  		ID: SocketID{
   274  			SourcePort:      uint16(localTCP.Port),
   275  			DestinationPort: uint16(remoteTCP.Port),
   276  			Source:          localIP,
   277  			Destination:     remoteIP,
   278  			Cookie:          [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
   279  		},
   280  	})
   281  
   282  	_, err = req.Execute(unix.NETLINK_INET_DIAG, 0)
   283  	return err
   284  }
   285  
   286  // SocketDestroy kills the Socket identified by its local and remote addresses.
   287  func SocketDestroy(local, remote net.Addr) error {
   288  	return pkgHandle.SocketDestroy(local, remote)
   289  }
   290  
   291  // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
   292  //
   293  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   294  // or incomplete.
   295  func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
   296  	// Construct the request
   297  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   298  	req.AddData(&socketRequest{
   299  		Family:   family,
   300  		Protocol: unix.IPPROTO_TCP,
   301  		Ext:      (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
   302  		States:   uint32(0xfff), // all states
   303  	})
   304  
   305  	// Do the query and parse the result
   306  	var result []*InetDiagTCPInfoResp
   307  	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   308  		sockInfo := &Socket{}
   309  		var err error
   310  		if err = sockInfo.deserialize(msg); err != nil {
   311  			return false
   312  		}
   313  		var attrs []syscall.NetlinkRouteAttr
   314  		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
   315  			return false
   316  		}
   317  
   318  		var res *InetDiagTCPInfoResp
   319  		if res, err = attrsToInetDiagTCPInfoResp(attrs, sockInfo); err != nil {
   320  			return false
   321  		}
   322  
   323  		result = append(result, res)
   324  		return true
   325  	})
   326  
   327  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   328  		return nil, executeErr
   329  	}
   330  	return result, executeErr
   331  }
   332  
   333  // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
   334  //
   335  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   336  // or incomplete.
   337  func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
   338  	return pkgHandle.SocketDiagTCPInfo(family)
   339  }
   340  
   341  // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
   342  //
   343  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   344  // or incomplete.
   345  func (h *Handle) SocketDiagTCP(family uint8) ([]*Socket, error) {
   346  	// Construct the request
   347  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   348  	req.AddData(&socketRequest{
   349  		Family:   family,
   350  		Protocol: unix.IPPROTO_TCP,
   351  		Ext:      (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
   352  		States:   uint32(0xfff), // all states
   353  	})
   354  
   355  	// Do the query and parse the result
   356  	var result []*Socket
   357  	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   358  		sockInfo := &Socket{}
   359  		if err := sockInfo.deserialize(msg); err != nil {
   360  			return false
   361  		}
   362  		result = append(result, sockInfo)
   363  		return true
   364  	})
   365  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   366  		return nil, executeErr
   367  	}
   368  	return result, executeErr
   369  }
   370  
   371  // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
   372  //
   373  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   374  // or incomplete.
   375  func SocketDiagTCP(family uint8) ([]*Socket, error) {
   376  	return pkgHandle.SocketDiagTCP(family)
   377  }
   378  
   379  // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info.
   380  //
   381  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   382  // or incomplete.
   383  func (h *Handle) SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
   384  	// Construct the request
   385  	var extensions uint8
   386  	extensions = 1 << (INET_DIAG_VEGASINFO - 1)
   387  	extensions |= 1 << (INET_DIAG_INFO - 1)
   388  	extensions |= 1 << (INET_DIAG_MEMINFO - 1)
   389  
   390  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   391  	req.AddData(&socketRequest{
   392  		Family:   family,
   393  		Protocol: unix.IPPROTO_UDP,
   394  		Ext:      extensions,
   395  		States:   uint32(0xfff), // all states
   396  	})
   397  
   398  	// Do the query and parse the result
   399  	var result []*InetDiagUDPInfoResp
   400  	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   401  		sockInfo := &Socket{}
   402  		if err := sockInfo.deserialize(msg); err != nil {
   403  			return false
   404  		}
   405  
   406  		var attrs []syscall.NetlinkRouteAttr
   407  		var err error
   408  		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
   409  			return false
   410  		}
   411  
   412  		var res *InetDiagUDPInfoResp
   413  		if res, err = attrsToInetDiagUDPInfoResp(attrs, sockInfo); err != nil {
   414  			return false
   415  		}
   416  
   417  		result = append(result, res)
   418  		return true
   419  	})
   420  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   421  		return nil, executeErr
   422  	}
   423  	return result, executeErr
   424  }
   425  
   426  // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info.
   427  //
   428  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   429  // or incomplete.
   430  func SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
   431  	return pkgHandle.SocketDiagUDPInfo(family)
   432  }
   433  
   434  // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket.
   435  //
   436  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   437  // or incomplete.
   438  func (h *Handle) SocketDiagUDP(family uint8) ([]*Socket, error) {
   439  	// Construct the request
   440  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   441  	req.AddData(&socketRequest{
   442  		Family:   family,
   443  		Protocol: unix.IPPROTO_UDP,
   444  		Ext:      (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
   445  		States:   uint32(0xfff), // all states
   446  	})
   447  
   448  	// Do the query and parse the result
   449  	var result []*Socket
   450  	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   451  		sockInfo := &Socket{}
   452  		if err := sockInfo.deserialize(msg); err != nil {
   453  			return false
   454  		}
   455  		result = append(result, sockInfo)
   456  		return true
   457  	})
   458  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   459  		return nil, executeErr
   460  	}
   461  	return result, executeErr
   462  }
   463  
   464  // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket.
   465  //
   466  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   467  // or incomplete.
   468  func SocketDiagUDP(family uint8) ([]*Socket, error) {
   469  	return pkgHandle.SocketDiagUDP(family)
   470  }
   471  
   472  // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
   473  //
   474  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   475  // or incomplete.
   476  func (h *Handle) UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
   477  	// Construct the request
   478  	var extensions uint8
   479  	extensions = 1 << UNIX_DIAG_NAME
   480  	extensions |= 1 << UNIX_DIAG_PEER
   481  	extensions |= 1 << UNIX_DIAG_RQLEN
   482  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   483  	req.AddData(&unixSocketRequest{
   484  		Family: unix.AF_UNIX,
   485  		States: ^uint32(0), // all states
   486  		Show:   uint32(extensions),
   487  	})
   488  
   489  	var result []*UnixDiagInfoResp
   490  	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   491  		sockInfo := &UnixSocket{}
   492  		if err := sockInfo.deserialize(msg); err != nil {
   493  			return false
   494  		}
   495  
   496  		// Diagnosis also delivers sockets with AF_INET family, filter those
   497  		if sockInfo.Family != unix.AF_UNIX {
   498  			return false
   499  		}
   500  
   501  		var attrs []syscall.NetlinkRouteAttr
   502  		var err error
   503  		if attrs, err = nl.ParseRouteAttr(msg[sizeofUnixSocket:]); err != nil {
   504  			return false
   505  		}
   506  
   507  		var res *UnixDiagInfoResp
   508  		if res, err = attrsToUnixDiagInfoResp(attrs, sockInfo); err != nil {
   509  			return false
   510  		}
   511  		result = append(result, res)
   512  		return true
   513  	})
   514  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   515  		return nil, executeErr
   516  	}
   517  	return result, executeErr
   518  }
   519  
   520  // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
   521  //
   522  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   523  // or incomplete.
   524  func UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
   525  	return pkgHandle.UnixSocketDiagInfo()
   526  }
   527  
   528  // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
   529  //
   530  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   531  // or incomplete.
   532  func (h *Handle) UnixSocketDiag() ([]*UnixSocket, error) {
   533  	// Construct the request
   534  	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
   535  	req.AddData(&unixSocketRequest{
   536  		Family: unix.AF_UNIX,
   537  		States: ^uint32(0), // all states
   538  	})
   539  
   540  	var result []*UnixSocket
   541  	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
   542  		sockInfo := &UnixSocket{}
   543  		if err := sockInfo.deserialize(msg); err != nil {
   544  			return false
   545  		}
   546  
   547  		// Diagnosis also delivers sockets with AF_INET family, filter those
   548  		if sockInfo.Family == unix.AF_UNIX {
   549  			result = append(result, sockInfo)
   550  		}
   551  		return true
   552  	})
   553  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   554  		return nil, executeErr
   555  	}
   556  	return result, executeErr
   557  }
   558  
   559  // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
   560  //
   561  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   562  // or incomplete.
   563  func UnixSocketDiag() ([]*UnixSocket, error) {
   564  	return pkgHandle.UnixSocketDiag()
   565  }
   566  
   567  func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) {
   568  	info := &InetDiagTCPInfoResp{
   569  		InetDiagMsg: sockInfo,
   570  	}
   571  	for _, a := range attrs {
   572  		switch a.Attr.Type {
   573  		case INET_DIAG_INFO:
   574  			info.TCPInfo = &TCPInfo{}
   575  			if err := info.TCPInfo.deserialize(a.Value); err != nil {
   576  				return nil, err
   577  			}
   578  		case INET_DIAG_BBRINFO:
   579  			info.TCPBBRInfo = &TCPBBRInfo{}
   580  			if err := info.TCPBBRInfo.deserialize(a.Value); err != nil {
   581  				return nil, err
   582  			}
   583  		}
   584  	}
   585  
   586  	return info, nil
   587  }
   588  
   589  func attrsToInetDiagUDPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagUDPInfoResp, error) {
   590  	info := &InetDiagUDPInfoResp{
   591  		InetDiagMsg: sockInfo,
   592  	}
   593  	for _, a := range attrs {
   594  		switch a.Attr.Type {
   595  		case INET_DIAG_MEMINFO:
   596  			info.Memory = &MemInfo{}
   597  			if err := info.Memory.deserialize(a.Value); err != nil {
   598  				return nil, err
   599  			}
   600  		}
   601  	}
   602  
   603  	return info, nil
   604  }
   605  
   606  func attrsToUnixDiagInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *UnixSocket) (*UnixDiagInfoResp, error) {
   607  	info := &UnixDiagInfoResp{
   608  		DiagMsg: sockInfo,
   609  	}
   610  	for _, a := range attrs {
   611  		switch a.Attr.Type {
   612  		case UNIX_DIAG_NAME:
   613  			name := string(a.Value[:a.Attr.Len])
   614  			info.Name = &name
   615  		case UNIX_DIAG_PEER:
   616  			peer := native.Uint32(a.Value)
   617  			info.Peer = &peer
   618  		case UNIX_DIAG_RQLEN:
   619  			info.Queue = &QueueInfo{
   620  				RQueue: native.Uint32(a.Value[:4]),
   621  				WQueue: native.Uint32(a.Value[4:]),
   622  			}
   623  			// default:
   624  			// 	fmt.Println("unknown unix attribute type", a.Attr.Type, "with data", a.Value)
   625  		}
   626  	}
   627  
   628  	return info, nil
   629  }