opensnitch/daemon/netlink/socket_linux.go

261 lines
6.7 KiB
Go
Raw Permalink Normal View History

package netlink
import (
"encoding/binary"
"errors"
"fmt"
"net"
"syscall"
2020-12-09 18:18:42 +01:00
"github.com/evilsocket/opensnitch/daemon/log"
"github.com/vishvananda/netlink/nl"
)
// This is a modification of https://github.com/vishvananda/netlink socket_linux.go - Apache2.0 license
// which adds support for query UDP, UDPLITE and IPv6 sockets to SocketGet()
const (
SOCK_DESTROY = 21
sizeofSocketID = 0x30
sizeofSocketRequest = sizeofSocketID + 0x8
sizeofSocket = sizeofSocketID + 0x18
)
// https://elixir.bootlin.com/linux/latest/source/include/net/tcp_states.h
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
const (
TCP_INVALID = iota
TCP_ESTABLISHED
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
TCP_SYN_SENT
TCP_SYN_RECV
TCP_FIN_WAIT1
TCP_FIN_WAIT2
TCP_TIME_WAIT
TCP_CLOSE
TCP_CLOSE_WAIT
TCP_LAST_ACK
TCP_LISTEN
TCP_CLOSING
TCP_NEW_SYN_RECV
TCP_MAX_STATES
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
)
var (
native = nl.NativeEndian()
networkOrder = binary.BigEndian
TCP_ALL = uint32(1<<TCP_ESTABLISHED | 1<<TCP_SYN_SENT | 1<<TCP_SYN_RECV | 1<<TCP_FIN_WAIT1 | 1<<TCP_FIN_WAIT2 | 1<<TCP_TIME_WAIT | 1<<TCP_CLOSE | 1<<TCP_CLOSE_WAIT | 1<<TCP_LAST_ACK | 1<<TCP_LISTEN | 1<<TCP_CLOSING | 1<<TCP_NEW_SYN_RECV | 0x2001)
)
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
// TCPStatesMap holds the list of TCP states
var TCPStatesMap = map[uint8]string{
TCP_INVALID: "invalid",
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
TCP_ESTABLISHED: "established",
TCP_SYN_SENT: "syn_sent",
TCP_SYN_RECV: "syn_recv",
TCP_FIN_WAIT1: "fin_wait1",
TCP_FIN_WAIT2: "fin_wait2",
TCP_TIME_WAIT: "time_wait",
TCP_CLOSE: "close",
TCP_CLOSE_WAIT: "close_wait",
TCP_LAST_ACK: "last_ack",
TCP_LISTEN: "listen",
TCP_CLOSING: "closing",
}
// SocketID holds the socket information of a request/response to the kernel
type SocketID struct {
Source net.IP
Destination net.IP
Cookie [2]uint32
Interface uint32
SourcePort uint16
DestinationPort uint16
}
// Socket represents a netlink socket.
type Socket struct {
ID SocketID
Expires uint32
RQueue uint32
WQueue uint32
UID uint32
INode uint32
Family uint8
State uint8
Timer uint8
Retrans uint8
}
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
// SocketRequest holds the request/response of a connection to the kernel
type SocketRequest struct {
ID SocketID
States uint32
Family uint8
Protocol uint8
Ext uint8
pad uint8
}
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
}
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
// Serialize convert SocketRequest struct to bytes.
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)
if r.Family == syscall.AF_INET6 {
copy(b.Next(16), r.ID.Source)
copy(b.Next(16), r.ID.Destination)
} else {
copy(b.Next(16), r.ID.Source.To4())
copy(b.Next(16), r.ID.Destination.To4())
}
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
}
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
// Len returns the size of a socket request
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))
if s.Family == syscall.AF_INET6 {
s.ID.Source = net.IP(rb.Next(16))
s.ID.Destination = net.IP(rb.Next(16))
} else {
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
}
// SocketKill kills a connection
func SocketKill(family, proto uint8, sockID SocketID) error {
sockReq := &SocketRequest{
Family: family,
Protocol: proto,
ID: sockID,
}
req := nl.NewNetlinkRequest(SOCK_DESTROY, syscall.NLM_F_REQUEST|syscall.NLM_F_ACK)
req.AddData(sockReq)
_, err := req.Execute(syscall.NETLINK_INET_DIAG, 0)
if err != nil {
return err
}
return nil
}
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
// SocketGet returns the list of active connections in the kernel
// filtered by several fields. Currently it returns connections
// filtered by source port and protocol.
func SocketGet(family uint8, proto uint8, srcPort, dstPort uint16, local, remote net.IP) ([]*Socket, error) {
_Id := SocketID{
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
SourcePort: srcPort,
Cookie: [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
}
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
sockReq := &SocketRequest{
Family: family,
Protocol: proto,
2020-02-13 23:19:15 +01:00
States: TCP_ALL,
ID: _Id,
}
return netlinkRequest(sockReq, family, proto, srcPort, dstPort, local, remote)
}
// SocketsDump returns the list of all connections from the kernel
func SocketsDump(family uint8, proto uint8) ([]*Socket, error) {
sockReq := &SocketRequest{
Family: family,
Protocol: proto,
States: TCP_ALL,
}
return netlinkRequest(sockReq, family, proto, 0, 0, nil, nil)
}
func netlinkRequest(sockReq *SocketRequest, family uint8, proto uint8, srcPort, dstPort uint16, local, remote net.IP) ([]*Socket, error) {
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, syscall.NLM_F_REQUEST|syscall.NLM_F_DUMP)
req.AddData(sockReq)
msgs, err := req.Execute(syscall.NETLINK_INET_DIAG, 0)
if err != nil {
return nil, err
}
if len(msgs) == 0 {
return nil, errors.New("Warning, no message nor error from netlink, or no connections found")
}
sock := make([]*Socket, len(msgs))
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
for n, m := range msgs {
s := &Socket{}
if err = s.deserialize(m); err != nil {
log.Error("[%d] netlink socket error: %s, %d:%v -> %v:%d - %d:%v -> %v:%d",
n, TCPStatesMap[s.State],
srcPort, local, remote, dstPort,
s.ID.SourcePort, s.ID.Source, s.ID.Destination, s.ID.DestinationPort)
continue
}
// INode can be zero for some connections states, like TCP_FIN_WAT, TCP_TIME_WAIT, etc.
// so don't exclude those entries, in order to get all sockets.
sock[n] = s
}
netlink: get active connections by source port + protocol - Dump connections from kernel querying by source port + protocol. - Prioritize responses which match the outgoing connection. - If we don't get any response, apply the default action configured in /etc/opensnitchd/default-config.json -- A connection can be considered unique if: protocol + source port + source ip + destination ip + destination port We can be quite sure that only one process has created the connection. However, many times, querying the kernel for the connection details by all these parameters results in no response. A regular query and normal response would be: query: TCP:47344:192.168.1.106 -> 151.101.65.140:443 response: 47344:192.168.1.106 -> 151.101.65.140:443, inode: 1234567, ... But in another cases, the details of the outgoing connection differs from the kernel response, or it even doesn't exist. However, if we query by protocol+source port, we can get more entries, and somewhat guess what program opened the outgoing connection. Some examples of querying by outgoing connection and response from kernel: query: 8612:192.168.1.5 -> 192.168.1.255:8612 response: 8612:192.168.1.105 -> 0.0.0.0:0 query: 123:192.168.1.5 -> 217.144.138.234:123 response: 123:0.0.0.0 -> 0.0.0.0:0 query: 45015:127.0.0.1 -> 239.255.255.250:1900 response: 45015:127.0.0.1 -> 0.0.0.0:0 query: 50416:fe80::9fc2:ddcf:df22:aa50 -> fe80::1:53 response: 50416:254.128.0.0 -> 254.128.0.0:53 query: 51413:192.168.1.106 -> 103.224.182.250:1337 response: 51413:0.0.0.0 -> 0.0.0.0:0
2020-04-05 19:14:51 +02:00
return sock, err
}