File: socket_test.go

package info (click to toggle)
opensnitch 1.6.9-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,980 kB
  • sloc: python: 12,604; ansic: 1,965; sh: 435; makefile: 239; xml: 50; sql: 3
file content (116 lines) | stat: -rw-r--r-- 2,982 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package netlink

import (
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"
	"testing"
)

type Connection struct {
	SrcIP    net.IP
	DstIP    net.IP
	Protocol string
	SrcPort  uint
	DstPort  uint
	OutConn  net.Conn
	Listener net.Listener
}

func EstablishConnection(proto, dst string) (net.Conn, error) {
	c, err := net.Dial(proto, dst)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return c, nil
}

func ListenOnPort(proto, port string) (net.Listener, error) {
	// TODO: UDP -> ListenUDP() or ListenPacket()
	l, err := net.Listen(proto, port)
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return l, nil
}

func setupConnection(proto string, connChan chan *Connection) {
	listnr, _ := ListenOnPort(proto, "127.0.0.1:55555")
	conn, err := EstablishConnection(proto, "127.0.0.1:55555")
	if err != nil {
		connChan <- nil
		return
	}
	laddr := strings.Split(conn.LocalAddr().String(), ":")
	daddr := strings.Split(conn.RemoteAddr().String(), ":")
	sport, _ := strconv.Atoi(laddr[1])
	dport, _ := strconv.Atoi(daddr[1])

	lconn := &Connection{
		SrcPort:  uint(sport),
		DstPort:  uint(dport),
		SrcIP:    net.ParseIP(laddr[0]),
		DstIP:    net.ParseIP(daddr[0]),
		Protocol: "tcp",
		Listener: listnr,
		OutConn:  conn,
	}
	connChan <- lconn
}

// TestNetlinkQueries tests queries to the kernel to get the inode of a connection.
// When using ProcFS as monitor method, we need that value to get the PID of an application.
// We also need it if for any reason auditd or ebpf doesn't return the PID of the application.
// TODO: test all the cases described in the GetSocketInfo() description.
func TestNetlinkTCPQueries(t *testing.T) {
	// netlink tests disabled by default, they cause random failures on restricted
	// environments.
	if os.Getenv("NETLINK_TESTS") == "" {
		t.Skip("Skipping netlink tests. Use NETLINK_TESTS=1 to launch these tests.")
	}

	connChan := make(chan *Connection)
	go setupConnection("tcp", connChan)
	conn := <-connChan
	if conn == nil {
		t.Error("TestParseTCPConnection, conn nil")
	}

	var inodes []int
	uid := -1
	t.Run("Test GetSocketInfo", func(t *testing.T) {
		uid, inodes = GetSocketInfo("tcp", conn.SrcIP, conn.SrcPort, conn.DstIP, conn.DstPort)

		if len(inodes) == 0 {
			t.Error("inodes empty")
		}
		if uid != os.Getuid() {
			t.Error("GetSocketInfo UID error:", uid, os.Getuid())
		}
	})

	t.Run("Test GetSocketInfoByInode", func(t *testing.T) {
		socket, err := GetSocketInfoByInode(fmt.Sprint(inodes[0]))
		if err != nil {
			t.Error("GetSocketInfoByInode error:", err)
		}
		if socket == nil {
			t.Error("GetSocketInfoByInode inode not found")
		}
		if socket.ID.SourcePort != uint16(conn.SrcPort) {
			t.Error("GetSocketInfoByInode dstPort error:", socket)
		}
		if socket.ID.DestinationPort != uint16(conn.DstPort) {
			t.Error("GetSocketInfoByInode dstPort error:", socket)
		}
		if socket.UID != uint32(os.Getuid()) {
			t.Error("GetSocketInfoByInode UID error:", socket, os.Getuid())
		}
	})

	conn.Listener.Close()
}