123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- package netlink
- import (
- "errors"
- "fmt"
- "net"
- "syscall"
- "github.com/vishvananda/netlink/nl"
- )
- const (
- sizeofSocketID = 0x30
- sizeofSocketRequest = sizeofSocketID + 0x8
- sizeofSocket = sizeofSocketID + 0x18
- )
- type socketRequest struct {
- Family uint8
- Protocol uint8
- Ext uint8
- pad uint8
- States uint32
- ID SocketID
- }
- type writeBuffer struct {
- Bytes []byte
- pos int
- }
- func (b *writeBuffer) Write(c byte) {
- b.Bytes[b.pos] = c
- b.pos++
- }
- func (b *writeBuffer) Next(n int) []byte {
- s := b.Bytes[b.pos : b.pos+n]
- b.pos += n
- return s
- }
- func (r *socketRequest) Serialize() []byte {
- b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)}
- b.Write(r.Family)
- b.Write(r.Protocol)
- b.Write(r.Ext)
- b.Write(r.pad)
- native.PutUint32(b.Next(4), r.States)
- networkOrder.PutUint16(b.Next(2), r.ID.SourcePort)
- networkOrder.PutUint16(b.Next(2), r.ID.DestinationPort)
- copy(b.Next(4), r.ID.Source.To4())
- b.Next(12)
- copy(b.Next(4), r.ID.Destination.To4())
- b.Next(12)
- native.PutUint32(b.Next(4), r.ID.Interface)
- native.PutUint32(b.Next(4), r.ID.Cookie[0])
- native.PutUint32(b.Next(4), r.ID.Cookie[1])
- return b.Bytes
- }
- func (r *socketRequest) Len() int { return sizeofSocketRequest }
- type readBuffer struct {
- Bytes []byte
- pos int
- }
- func (b *readBuffer) Read() byte {
- c := b.Bytes[b.pos]
- b.pos++
- return c
- }
- func (b *readBuffer) Next(n int) []byte {
- s := b.Bytes[b.pos : b.pos+n]
- b.pos += n
- return s
- }
- func (s *Socket) deserialize(b []byte) error {
- if len(b) < sizeofSocket {
- return fmt.Errorf("socket data short read (%d); want %d", len(b), sizeofSocket)
- }
- rb := readBuffer{Bytes: b}
- s.Family = rb.Read()
- s.State = rb.Read()
- s.Timer = rb.Read()
- s.Retrans = rb.Read()
- s.ID.SourcePort = networkOrder.Uint16(rb.Next(2))
- s.ID.DestinationPort = networkOrder.Uint16(rb.Next(2))
- s.ID.Source = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
- rb.Next(12)
- s.ID.Destination = net.IPv4(rb.Read(), rb.Read(), rb.Read(), rb.Read())
- rb.Next(12)
- s.ID.Interface = native.Uint32(rb.Next(4))
- s.ID.Cookie[0] = native.Uint32(rb.Next(4))
- s.ID.Cookie[1] = native.Uint32(rb.Next(4))
- s.Expires = native.Uint32(rb.Next(4))
- s.RQueue = native.Uint32(rb.Next(4))
- s.WQueue = native.Uint32(rb.Next(4))
- s.UID = native.Uint32(rb.Next(4))
- s.INode = native.Uint32(rb.Next(4))
- return nil
- }
- // SocketGet returns the Socket identified by its local and remote addresses.
- func SocketGet(local, remote net.Addr) (*Socket, error) {
- localTCP, ok := local.(*net.TCPAddr)
- if !ok {
- return nil, ErrNotImplemented
- }
- remoteTCP, ok := remote.(*net.TCPAddr)
- if !ok {
- return nil, ErrNotImplemented
- }
- localIP := localTCP.IP.To4()
- if localIP == nil {
- return nil, ErrNotImplemented
- }
- remoteIP := remoteTCP.IP.To4()
- if remoteIP == nil {
- return nil, ErrNotImplemented
- }
- s, err := nl.Subscribe(syscall.NETLINK_INET_DIAG)
- if err != nil {
- return nil, err
- }
- defer s.Close()
- req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, 0)
- req.AddData(&socketRequest{
- Family: syscall.AF_INET,
- Protocol: syscall.IPPROTO_TCP,
- ID: SocketID{
- SourcePort: uint16(localTCP.Port),
- DestinationPort: uint16(remoteTCP.Port),
- Source: localIP,
- Destination: remoteIP,
- Cookie: [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
- },
- })
- s.Send(req)
- msgs, err := s.Receive()
- if err != nil {
- return nil, err
- }
- if len(msgs) == 0 {
- return nil, errors.New("no message nor error from netlink")
- }
- if len(msgs) > 2 {
- return nil, fmt.Errorf("multiple (%d) matching sockets", len(msgs))
- }
- sock := &Socket{}
- if err := sock.deserialize(msgs[0].Data); err != nil {
- return nil, err
- }
- return sock, nil
- }
|