2019-12-01 20:10:49 +01:00
|
|
|
package netlink
|
|
|
|
|
|
|
|
import (
|
2020-03-06 21:02:34 +01:00
|
|
|
"encoding/binary"
|
2019-12-01 20:10:49 +01:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
2020-02-12 22:52:24 +01:00
|
|
|
"syscall"
|
2019-12-01 20:10:49 +01:00
|
|
|
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/log"
|
2019-12-01 20:10:49 +01:00
|
|
|
"github.com/vishvananda/netlink/nl"
|
|
|
|
)
|
|
|
|
|
2020-11-20 00:53:29 +01:00
|
|
|
// 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()
|
2019-12-01 20:10:49 +01:00
|
|
|
|
|
|
|
const (
|
2021-09-12 10:54:24 +02:00
|
|
|
SOCK_DESTROY = 21
|
2019-12-01 20:10:49 +01:00
|
|
|
sizeofSocketID = 0x30
|
|
|
|
sizeofSocketRequest = sizeofSocketID + 0x8
|
|
|
|
sizeofSocket = sizeofSocketID + 0x18
|
|
|
|
)
|
|
|
|
|
2020-11-20 00:53:29 +01:00
|
|
|
// 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 (
|
2020-11-20 00:53:29 +01:00
|
|
|
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
|
2025-01-22 00:16:17 +01:00
|
|
|
TCP_NEW_SYN_RECV
|
2020-11-20 00:53:29 +01:00
|
|
|
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
|
|
|
)
|
|
|
|
|
2025-01-22 00:33:10 +01: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{
|
2020-11-20 00:53:29 +01:00
|
|
|
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
|
2019-12-01 20:10:49 +01:00
|
|
|
type SocketID struct {
|
|
|
|
Source net.IP
|
|
|
|
Destination net.IP
|
|
|
|
Cookie [2]uint32
|
2025-01-22 00:16:17 +01:00
|
|
|
Interface uint32
|
|
|
|
SourcePort uint16
|
|
|
|
DestinationPort uint16
|
2019-12-01 20:10:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Socket represents a netlink socket.
|
|
|
|
type Socket struct {
|
|
|
|
ID SocketID
|
|
|
|
Expires uint32
|
|
|
|
RQueue uint32
|
|
|
|
WQueue uint32
|
2020-03-06 21:02:34 +01:00
|
|
|
UID uint32
|
2019-12-01 20:10:49 +01:00
|
|
|
INode uint32
|
2025-01-22 00:16:17 +01:00
|
|
|
Family uint8
|
|
|
|
State uint8
|
|
|
|
Timer uint8
|
|
|
|
Retrans uint8
|
2019-12-01 20:10:49 +01:00
|
|
|
}
|
|
|
|
|
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
|
2020-02-12 22:52:24 +01:00
|
|
|
type SocketRequest struct {
|
2025-01-22 00:16:17 +01:00
|
|
|
ID SocketID
|
|
|
|
States uint32
|
2019-12-01 20:10:49 +01:00
|
|
|
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.
|
2020-02-12 22:52:24 +01:00
|
|
|
func (r *SocketRequest) Serialize() []byte {
|
2019-12-01 20:10:49 +01:00
|
|
|
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)
|
2020-11-20 00:53:29 +01:00
|
|
|
if r.Family == syscall.AF_INET6 {
|
|
|
|
copy(b.Next(16), r.ID.Source)
|
|
|
|
copy(b.Next(16), r.ID.Destination)
|
|
|
|
} else {
|
2025-01-22 00:33:10 +01:00
|
|
|
copy(b.Next(16), r.ID.Source.To4())
|
|
|
|
copy(b.Next(16), r.ID.Destination.To4())
|
2020-11-20 00:53:29 +01:00
|
|
|
}
|
2019-12-01 20:10:49 +01:00
|
|
|
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
|
2020-02-12 22:52:24 +01:00
|
|
|
func (r *SocketRequest) Len() int { return sizeofSocketRequest }
|
2019-12-01 20:10:49 +01:00
|
|
|
|
|
|
|
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))
|
2020-11-20 00:53:29 +01:00
|
|
|
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)
|
|
|
|
}
|
2019-12-01 20:10:49 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-09-12 10:54:24 +02:00
|
|
|
// SocketKill kills a connection
|
2023-07-25 01:42:54 +02:00
|
|
|
func SocketKill(family, proto uint8, sockID SocketID) error {
|
2021-09-12 10:54:24 +02:00
|
|
|
|
|
|
|
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) {
|
2020-03-06 21:02:34 +01:00
|
|
|
_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},
|
2019-12-02 23:53:41 +01:00
|
|
|
}
|
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
|
|
|
|
2020-02-18 02:05:15 +01:00
|
|
|
sockReq := &SocketRequest{
|
2019-12-01 20:10:49 +01:00
|
|
|
Family: family,
|
|
|
|
Protocol: proto,
|
2020-02-13 23:19:15 +01:00
|
|
|
States: TCP_ALL,
|
2020-03-06 21:02:34 +01:00
|
|
|
ID: _Id,
|
2020-02-18 02:05:15 +01:00
|
|
|
}
|
2020-11-20 00:53:29 +01:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
2025-01-22 00:33:10 +01:00
|
|
|
return netlinkRequest(sockReq, family, proto, 0, 0, nil, nil)
|
2020-11-20 00:53:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func netlinkRequest(sockReq *SocketRequest, family uint8, proto uint8, srcPort, dstPort uint16, local, remote net.IP) ([]*Socket, error) {
|
2025-01-22 00:33:10 +01:00
|
|
|
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, syscall.NLM_F_REQUEST|syscall.NLM_F_DUMP)
|
2020-02-18 02:05:15 +01:00
|
|
|
req.AddData(sockReq)
|
2020-02-12 22:52:24 +01:00
|
|
|
msgs, err := req.Execute(syscall.NETLINK_INET_DIAG, 0)
|
2019-12-01 20:10:49 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(msgs) == 0 {
|
2021-05-29 00:16:18 +02:00
|
|
|
return nil, errors.New("Warning, no message nor error from netlink, or no connections found")
|
2019-12-01 20:10:49 +01:00
|
|
|
}
|
2025-01-22 00:16:17 +01:00
|
|
|
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
|
|
|
|
}
|
2025-01-22 00:16:17 +01:00
|
|
|
// 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
|
2019-12-01 20:10:49 +01:00
|
|
|
}
|
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
|
2019-12-01 20:10:49 +01:00
|
|
|
}
|