2018-04-02 05:25:32 +02:00
|
|
|
package conman
|
|
|
|
|
|
|
|
import (
|
2020-11-26 16:25:48 +01:00
|
|
|
"errors"
|
2018-04-02 05:25:32 +02:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2018-04-07 03:28:44 +02:00
|
|
|
"os"
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/core"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/dns"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/log"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/netfilter"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/netlink"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/netstat"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/procmon"
|
2022-06-24 01:09:45 +02:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/procmon/audit"
|
2021-04-05 09:28:16 +00:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/procmon/ebpf"
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/ui/protocol"
|
2018-04-02 05:25:32 +02:00
|
|
|
|
|
|
|
"github.com/google/gopacket/layers"
|
|
|
|
)
|
|
|
|
|
2020-12-23 13:24:59 -05:00
|
|
|
// Connection represents an outgoing connection.
|
2018-04-02 05:25:32 +02:00
|
|
|
type Connection struct {
|
2023-09-22 00:36:26 +02:00
|
|
|
Pkt *netfilter.Packet
|
|
|
|
Entry *netstat.Entry
|
|
|
|
Process *procmon.Process
|
|
|
|
|
2018-04-02 05:25:32 +02:00
|
|
|
Protocol string
|
2023-09-22 00:36:26 +02:00
|
|
|
DstHost string
|
2018-04-02 05:25:32 +02:00
|
|
|
SrcIP net.IP
|
|
|
|
DstIP net.IP
|
|
|
|
|
2023-09-22 00:36:26 +02:00
|
|
|
SrcPort uint
|
|
|
|
DstPort uint
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
2019-11-01 01:00:10 +01:00
|
|
|
var showUnknownCons = false
|
|
|
|
|
2020-03-06 21:44:47 +01:00
|
|
|
// Parse extracts the IP layers from a network packet to determine what
|
|
|
|
// process generated a connection.
|
2019-11-01 01:00:10 +01:00
|
|
|
func Parse(nfp netfilter.Packet, interceptUnknown bool) *Connection {
|
2020-03-06 21:44:47 +01:00
|
|
|
showUnknownCons = interceptUnknown
|
2025-01-22 01:06:10 +01:00
|
|
|
log.Trace("Connection.Parse(): %v", nfp)
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2020-11-26 16:25:48 +01:00
|
|
|
if nfp.IsIPv4() {
|
|
|
|
con, err := NewConnection(&nfp)
|
2018-11-21 00:25:47 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Debug("%s", err)
|
|
|
|
return nil
|
|
|
|
} else if con == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return con
|
2020-03-06 21:44:47 +01:00
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2020-11-26 16:25:48 +01:00
|
|
|
if core.IPv6Enabled == false {
|
|
|
|
return nil
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
2020-11-26 16:25:48 +01:00
|
|
|
con, err := NewConnection6(&nfp)
|
|
|
|
if err != nil {
|
|
|
|
log.Debug("%s", err)
|
|
|
|
return nil
|
|
|
|
} else if con == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return con
|
2020-03-06 21:44:47 +01:00
|
|
|
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2020-11-24 01:35:36 +01:00
|
|
|
func newConnectionImpl(nfp *netfilter.Packet, c *Connection, protoType string) (cr *Connection, err error) {
|
2018-04-02 05:25:32 +02:00
|
|
|
// no errors but not enough info neither
|
2020-11-24 01:35:36 +01:00
|
|
|
if c.parseDirection(protoType) == false {
|
2025-01-22 01:06:10 +01:00
|
|
|
log.Trace("discarding connection (proto %s): %+v", protoType, c)
|
2018-04-02 05:25:32 +02:00
|
|
|
return nil, nil
|
|
|
|
}
|
2023-04-21 23:28:13 +02:00
|
|
|
log.Debug("new connection %s => %d:%v -> %v (%s):%d uid: %d, mark: %x", c.Protocol, c.SrcPort, c.SrcIP, c.DstIP, c.DstHost, c.DstPort, nfp.UID, nfp.Mark)
|
2018-04-02 05:25:32 +02: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
|
|
|
c.Entry = &netstat.Entry{
|
|
|
|
Proto: c.Protocol,
|
|
|
|
SrcIP: c.SrcIP,
|
|
|
|
SrcPort: c.SrcPort,
|
|
|
|
DstIP: c.DstIP,
|
|
|
|
DstPort: c.DstPort,
|
|
|
|
UserId: -1,
|
|
|
|
INode: -1,
|
|
|
|
}
|
|
|
|
|
2021-04-05 09:28:16 +00:00
|
|
|
pid := -1
|
2021-11-15 13:26:52 +01:00
|
|
|
uid := -1
|
2021-04-05 09:28:16 +00:00
|
|
|
if procmon.MethodIsEbpf() {
|
2022-12-20 17:16:20 +01:00
|
|
|
swap := false
|
|
|
|
c.Process, swap, err = ebpf.GetPid(c.Protocol, c.SrcPort, c.SrcIP, c.DstIP, c.DstPort)
|
|
|
|
if swap {
|
|
|
|
c.swapFields()
|
|
|
|
}
|
|
|
|
|
2022-06-24 01:09:45 +02:00
|
|
|
if c.Process != nil {
|
|
|
|
c.Entry.UserId = c.Process.UID
|
|
|
|
return c, nil
|
|
|
|
}
|
2021-04-05 09:28:16 +00:00
|
|
|
if err != nil {
|
2022-12-20 17:16:20 +01:00
|
|
|
log.Debug("ebpf warning: %v", err)
|
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
|
|
|
}
|
2023-09-22 00:36:26 +02:00
|
|
|
log.Debug("[ebpf conn] PID not found via eBPF, falling back to proc")
|
2022-06-24 01:09:45 +02:00
|
|
|
} else if procmon.MethodIsAudit() {
|
|
|
|
if aevent := audit.GetEventByPid(pid); aevent != nil {
|
|
|
|
audit.Lock.RLock()
|
2023-09-30 18:31:19 +02:00
|
|
|
c.Process = procmon.NewProcessEmpty(pid, aevent.ProcName)
|
2022-06-24 01:09:45 +02:00
|
|
|
c.Process.Path = aevent.ProcPath
|
|
|
|
c.Process.ReadCmdline()
|
|
|
|
c.Process.CWD = aevent.ProcDir
|
|
|
|
audit.Lock.RUnlock()
|
|
|
|
// if the proc dir contains non alhpa-numeric chars the field is empty
|
|
|
|
if c.Process.CWD == "" {
|
|
|
|
c.Process.ReadCwd()
|
|
|
|
}
|
|
|
|
c.Process.ReadEnv()
|
|
|
|
c.Process.CleanPath()
|
|
|
|
|
2023-09-30 18:31:19 +02:00
|
|
|
procmon.EventsCache.Add(c.Process)
|
2022-06-24 01:09:45 +02:00
|
|
|
return c, nil
|
|
|
|
}
|
2023-09-22 00:36:26 +02:00
|
|
|
log.Debug("[auditd conn] PID not found via auditd, falling back to proc")
|
2021-06-08 14:11:19 +02:00
|
|
|
}
|
2022-06-24 01:09:45 +02:00
|
|
|
|
|
|
|
// Sometimes when using eBPF, the PID is not found by the connection's parameters,
|
|
|
|
// but falling back to legacy methods helps to find it and avoid "unknown/kernel pop-ups".
|
|
|
|
//
|
|
|
|
// One of the reasons is because after coming back from suspend state, for some reason (bug?),
|
|
|
|
// gobpf/libbpf is unable to delete ebpf map entries, so when they reach the maximum capacity no
|
|
|
|
// more entries are added, nor updated.
|
2021-06-08 14:11:19 +02:00
|
|
|
if pid < 0 {
|
2021-04-05 09:28:16 +00:00
|
|
|
// 0. lookup uid and inode via netlink. Can return several inodes.
|
|
|
|
// 1. lookup uid and inode using /proc/net/(udp|tcp|udplite)
|
|
|
|
// 2. lookup pid by inode
|
|
|
|
// 3. if this is coming from us, just accept
|
|
|
|
// 4. lookup process info by pid
|
|
|
|
var inodeList []int
|
|
|
|
uid, inodeList = netlink.GetSocketInfo(c.Protocol, c.SrcIP, c.SrcPort, c.DstIP, c.DstPort)
|
|
|
|
if len(inodeList) == 0 {
|
2023-02-04 16:43:24 +01:00
|
|
|
procmon.GetInodeFromNetstat(c.Entry, &inodeList, c.Protocol, c.SrcIP, c.SrcPort, c.DstIP, c.DstPort)
|
2021-04-05 09:28:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for n, inode := range inodeList {
|
|
|
|
pid = procmon.GetPIDFromINode(inode, fmt.Sprint(inode, c.SrcIP, c.SrcPort, c.DstIP, c.DstPort))
|
|
|
|
if pid != -1 {
|
2021-11-15 13:26:52 +01:00
|
|
|
log.Debug("[%d] PID found %d [%d]", n, pid, inode)
|
2021-04-05 09:28:16 +00:00
|
|
|
c.Entry.INode = inode
|
|
|
|
break
|
|
|
|
}
|
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
|
|
|
}
|
2020-04-12 01:38:39 +02:00
|
|
|
|
2021-04-05 09:28:16 +00:00
|
|
|
if pid == os.Getpid() {
|
|
|
|
// return a Process object with our PID, to be able to exclude our own connections
|
|
|
|
// (to the UI on a local socket for example)
|
2023-09-30 18:31:19 +02:00
|
|
|
c.Process = procmon.NewProcessEmpty(pid, "")
|
2021-04-05 09:28:16 +00:00
|
|
|
return c, 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
|
|
|
}
|
2021-04-05 09:28:16 +00:00
|
|
|
|
2022-06-24 01:09:45 +02:00
|
|
|
if nfp.UID != 0xffffffff {
|
|
|
|
uid = int(nfp.UID)
|
|
|
|
}
|
|
|
|
c.Entry.UserId = uid
|
|
|
|
|
|
|
|
if c.Process == nil {
|
|
|
|
if c.Process = procmon.FindProcess(pid, showUnknownCons); c.Process == nil {
|
|
|
|
return nil, fmt.Errorf("Could not find process by its pid %d for: %s", pid, c)
|
|
|
|
}
|
2018-04-02 05:25:32 +02: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
|
|
|
|
2018-04-02 05:25:32 +02:00
|
|
|
return c, nil
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
|
|
|
|
2020-03-06 21:44:47 +01:00
|
|
|
// NewConnection creates a new Connection object, and returns the details of it.
|
2020-11-26 16:25:48 +01:00
|
|
|
func NewConnection(nfp *netfilter.Packet) (c *Connection, err error) {
|
|
|
|
ipv4 := nfp.Packet.Layer(layers.LayerTypeIPv4)
|
|
|
|
if ipv4 == nil {
|
|
|
|
return nil, errors.New("Error getting IPv4 layer")
|
|
|
|
}
|
|
|
|
ip, ok := ipv4.(*layers.IPv4)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("Error getting IPv4 layer data")
|
|
|
|
}
|
2018-11-21 00:25:47 +01:00
|
|
|
c = &Connection{
|
|
|
|
SrcIP: ip.SrcIP,
|
|
|
|
DstIP: ip.DstIP,
|
2020-10-19 01:29:00 +02:00
|
|
|
DstHost: dns.HostOr(ip.DstIP, ""),
|
2022-09-24 17:12:09 +02:00
|
|
|
Pkt: nfp,
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
2023-09-22 00:36:26 +02:00
|
|
|
|
2020-11-24 01:35:36 +01:00
|
|
|
return newConnectionImpl(nfp, c, "")
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
|
|
|
|
2020-03-06 21:44:47 +01:00
|
|
|
// NewConnection6 creates a IPv6 new Connection object, and returns the details of it.
|
2020-11-26 16:25:48 +01:00
|
|
|
func NewConnection6(nfp *netfilter.Packet) (c *Connection, err error) {
|
|
|
|
ipv6 := nfp.Packet.Layer(layers.LayerTypeIPv6)
|
|
|
|
if ipv6 == nil {
|
|
|
|
return nil, errors.New("Error getting IPv6 layer")
|
|
|
|
}
|
|
|
|
ip, ok := ipv6.(*layers.IPv6)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("Error getting IPv6 layer data")
|
|
|
|
}
|
2018-11-21 00:25:47 +01:00
|
|
|
c = &Connection{
|
|
|
|
SrcIP: ip.SrcIP,
|
|
|
|
DstIP: ip.DstIP,
|
2020-10-19 01:29:00 +02:00
|
|
|
DstHost: dns.HostOr(ip.DstIP, ""),
|
2022-09-24 17:12:09 +02:00
|
|
|
Pkt: nfp,
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
2020-11-24 01:35:36 +01:00
|
|
|
return newConnectionImpl(nfp, c, "6")
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
2020-11-24 01:35:36 +01:00
|
|
|
func (c *Connection) parseDirection(protoType string) bool {
|
2018-11-21 00:25:47 +01:00
|
|
|
ret := false
|
2022-09-24 17:12:09 +02:00
|
|
|
if tcpLayer := c.Pkt.Packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
|
2020-11-24 01:35:36 +01:00
|
|
|
if tcp, ok := tcpLayer.(*layers.TCP); ok == true && tcp != nil {
|
|
|
|
c.Protocol = "tcp" + protoType
|
|
|
|
c.DstPort = uint(tcp.DstPort)
|
|
|
|
c.SrcPort = uint(tcp.SrcPort)
|
|
|
|
ret = true
|
|
|
|
|
|
|
|
if tcp.DstPort == 53 {
|
2022-09-24 17:12:09 +02:00
|
|
|
c.getDomains(c.Pkt, c)
|
2019-10-29 20:01:45 +01:00
|
|
|
}
|
2018-04-16 19:28:28 +02:00
|
|
|
}
|
2022-09-24 17:12:09 +02:00
|
|
|
} else if udpLayer := c.Pkt.Packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
|
2020-11-24 01:35:36 +01:00
|
|
|
if udp, ok := udpLayer.(*layers.UDP); ok == true && udp != nil {
|
|
|
|
c.Protocol = "udp" + protoType
|
|
|
|
c.DstPort = uint(udp.DstPort)
|
|
|
|
c.SrcPort = uint(udp.SrcPort)
|
|
|
|
ret = true
|
|
|
|
|
|
|
|
if udp.DstPort == 53 {
|
2022-09-24 17:12:09 +02:00
|
|
|
c.getDomains(c.Pkt, c)
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
|
|
|
}
|
2022-09-24 17:12:09 +02:00
|
|
|
} else if udpliteLayer := c.Pkt.Packet.Layer(layers.LayerTypeUDPLite); udpliteLayer != nil {
|
2020-11-24 01:35:36 +01:00
|
|
|
if udplite, ok := udpliteLayer.(*layers.UDPLite); ok == true && udplite != nil {
|
|
|
|
c.Protocol = "udplite" + protoType
|
|
|
|
c.DstPort = uint(udplite.DstPort)
|
|
|
|
c.SrcPort = uint(udplite.SrcPort)
|
|
|
|
ret = true
|
|
|
|
}
|
2022-12-18 00:41:06 +01:00
|
|
|
} else if sctpLayer := c.Pkt.Packet.Layer(layers.LayerTypeSCTP); sctpLayer != nil {
|
|
|
|
if sctp, ok := sctpLayer.(*layers.SCTP); ok == true && sctp != nil {
|
|
|
|
c.Protocol = "sctp" + protoType
|
|
|
|
c.DstPort = uint(sctp.DstPort)
|
|
|
|
c.SrcPort = uint(sctp.SrcPort)
|
|
|
|
ret = true
|
|
|
|
}
|
|
|
|
} else if icmpLayer := c.Pkt.Packet.Layer(layers.LayerTypeICMPv4); icmpLayer != nil {
|
|
|
|
if icmp, ok := icmpLayer.(*layers.ICMPv4); ok == true && icmp != nil {
|
|
|
|
c.Protocol = "icmp"
|
|
|
|
c.DstPort = 0
|
|
|
|
c.SrcPort = 0
|
|
|
|
ret = true
|
|
|
|
}
|
|
|
|
} else if icmp6Layer := c.Pkt.Packet.Layer(layers.LayerTypeICMPv6); icmp6Layer != nil {
|
|
|
|
if icmp6, ok := icmp6Layer.(*layers.ICMPv6); ok == true && icmp6 != nil {
|
|
|
|
c.Protocol = "icmp" + protoType
|
|
|
|
c.DstPort = 0
|
|
|
|
c.SrcPort = 0
|
|
|
|
ret = true
|
|
|
|
}
|
2018-11-21 00:25:47 +01:00
|
|
|
}
|
2020-11-24 01:35:36 +01:00
|
|
|
|
2018-11-21 00:25:47 +01:00
|
|
|
return ret
|
2018-04-16 19:28:28 +02:00
|
|
|
}
|
|
|
|
|
2022-12-20 17:16:20 +01:00
|
|
|
// swapFields swaps connection's fields.
|
|
|
|
// Used to workaround an issue where outbound connections
|
|
|
|
// have the fields swapped (procmon/ebpf/find.go).
|
|
|
|
func (c *Connection) swapFields() {
|
|
|
|
oEntry := c.Entry
|
|
|
|
c.Entry = &netstat.Entry{
|
|
|
|
Proto: c.Protocol,
|
|
|
|
SrcIP: oEntry.DstIP,
|
|
|
|
DstIP: oEntry.SrcIP,
|
|
|
|
SrcPort: oEntry.DstPort,
|
|
|
|
DstPort: oEntry.SrcPort,
|
|
|
|
UserId: oEntry.UserId,
|
|
|
|
INode: oEntry.INode,
|
|
|
|
}
|
|
|
|
c.SrcIP = oEntry.DstIP
|
|
|
|
c.DstIP = oEntry.SrcIP
|
|
|
|
c.DstPort = oEntry.SrcPort
|
|
|
|
c.SrcPort = oEntry.DstPort
|
|
|
|
}
|
|
|
|
|
2019-11-08 01:38:26 +01:00
|
|
|
func (c *Connection) getDomains(nfp *netfilter.Packet, con *Connection) {
|
|
|
|
domains := dns.GetQuestions(nfp)
|
2023-02-04 16:43:24 +01:00
|
|
|
if len(domains) < 1 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, dns := range domains {
|
|
|
|
con.DstHost = dns
|
2019-11-08 01:38:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-24 01:35:36 +01:00
|
|
|
// To returns the destination host of a connection.
|
2018-04-02 05:25:32 +02:00
|
|
|
func (c *Connection) To() string {
|
|
|
|
if c.DstHost == "" {
|
|
|
|
return c.DstIP.String()
|
|
|
|
}
|
2023-03-10 22:02:02 +01:00
|
|
|
return fmt.Sprintf("%s (%s)", c.DstHost, c.DstIP)
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Connection) String() string {
|
|
|
|
if c.Entry == nil {
|
2022-06-24 01:09:45 +02:00
|
|
|
return fmt.Sprintf("%d:%s ->(%s)-> %s:%d", c.SrcPort, c.SrcIP, c.Protocol, c.To(), c.DstPort)
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if c.Process == nil {
|
2022-06-24 01:09:45 +02:00
|
|
|
return fmt.Sprintf("%d:%s (uid:%d) ->(%s)-> %s:%d", c.SrcPort, c.SrcIP, c.Entry.UserId, c.Protocol, c.To(), c.DstPort)
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s (%d) -> %s:%d (proto:%s uid:%d)", c.Process.Path, c.Process.ID, c.To(), c.DstPort, c.Protocol, c.Entry.UserId)
|
|
|
|
}
|
2018-04-02 19:10:42 +02:00
|
|
|
|
2020-03-06 21:44:47 +01:00
|
|
|
// Serialize returns a connection serialized.
|
2018-04-08 15:32:20 +02:00
|
|
|
func (c *Connection) Serialize() *protocol.Connection {
|
2023-10-04 00:58:17 +02:00
|
|
|
c.Process.RLock()
|
|
|
|
defer c.Process.RUnlock()
|
2018-04-08 15:32:20 +02:00
|
|
|
return &protocol.Connection{
|
2023-09-22 00:36:26 +02:00
|
|
|
Protocol: c.Protocol,
|
|
|
|
SrcIp: c.SrcIP.String(),
|
|
|
|
SrcPort: uint32(c.SrcPort),
|
|
|
|
DstIp: c.DstIP.String(),
|
|
|
|
DstHost: c.DstHost,
|
|
|
|
DstPort: uint32(c.DstPort),
|
|
|
|
UserId: uint32(c.Entry.UserId),
|
|
|
|
ProcessId: uint32(c.Process.ID),
|
|
|
|
ProcessPath: c.Process.Path,
|
|
|
|
ProcessArgs: c.Process.Args,
|
|
|
|
ProcessEnv: c.Process.Env,
|
|
|
|
ProcessCwd: c.Process.CWD,
|
|
|
|
ProcessChecksums: c.Process.Checksums,
|
2023-09-30 18:31:19 +02:00
|
|
|
ProcessTree: c.Process.Tree,
|
2018-04-02 19:10:42 +02:00
|
|
|
}
|
|
|
|
}
|