-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathnetmon.go
More file actions
130 lines (111 loc) · 3.49 KB
/
netmon.go
File metadata and controls
130 lines (111 loc) · 3.49 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package main
import (
"context"
"fmt"
"sync"
"time"
"github.com/florianl/go-nflog/v2"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/pkg/errors"
)
const Unknown = "Unknown"
type NetworkMonitor struct {
CorrelationId string
Repo string
ApiClient *ApiClient
GlobalBlocklist *GlobalBlocklist
Status string
netMutex sync.RWMutex
}
var ipAddresses = make(map[string]bool)
func (netMonitor *NetworkMonitor) MonitorNetwork(ctx context.Context, nflogger AgentNflogger, errc chan error) []string {
//sysLogger, err := syslog.NewLogger(syslog.LOG_INFO|syslog.LOG_USER, 1)
var err error
config := nflog.Config{
Group: 100,
Copymode: nflog.CopyPacket,
// Logger: sysLogger,
//ReadTimeout: 100 * time.Millisecond,
}
var nf NfLogger
if nflogger == nil {
nf, err = nflog.Open(&config)
if err != nil {
errc <- errors.Wrap(err, "failed to open nflog")
}
} else {
nf, err = nflogger.Open(&config) // for mock
if err != nil {
errc <- errors.Wrap(err, "failed to open nflog")
}
}
defer nf.Close()
fn := func(attrs nflog.Attribute) int {
go netMonitor.handlePacket(attrs)
return 0
}
// Register your function to listen on nflog group 100
err = nf.Register(ctx, fn)
if err != nil {
errc <- errors.Wrap(err, "failed to register nflog")
}
// Block till the context expires
<-ctx.Done()
return nil
}
func (netMonitor *NetworkMonitor) handlePacket(attrs nflog.Attribute) {
timestamp := time.Now().UTC() // *attrs.Timestamp
data := *attrs.Payload
packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
port := ""
isSYN := false
isUDP := false
// Get the TCP layer from this packet
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
// Get actual TCP data from this layer
tcp, _ := tcpLayer.(*layers.TCP)
port = tcp.DstPort.String()
isSYN = tcp.SYN
} else if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
// Get actual UDP data from this layer
udp, _ := udpLayer.(*layers.UDP)
port = udp.DstPort.String()
isUDP = true
}
// Get the IP layer from this packet
if ipv4Layer := packet.Layer(layers.LayerTypeIPv4); ipv4Layer != nil {
// Get actual TCP data from this layer
ipv4, _ := ipv4Layer.(*layers.IPv4)
netMonitor.netMutex.Lock()
ipv4Address := ipv4.DstIP.String()
matchedPolicy := ""
reason := ""
status := netMonitor.Status
if netMonitor.GlobalBlocklist != nil && netMonitor.GlobalBlocklist.IsIPAddressBlocked(ipv4Address) {
status = "Dropped"
matchedPolicy = GlobalBlocklistMatchedPolicy
reason = netMonitor.GlobalBlocklist.BlockedIPAddressReason(ipv4Address)
}
cacheKey := fmt.Sprintf("%s:%s:%s", ipv4Address, port, status)
_, found := ipAddresses[cacheKey]
if !found {
ipAddresses[cacheKey] = true
if isSYN || isUDP {
if status == "Dropped" {
netMonitor.ApiClient.sendNetConnection(netMonitor.CorrelationId, netMonitor.Repo,
ipv4Address, port, "", status, matchedPolicy, reason, timestamp, Tool{Name: Unknown, SHA256: Unknown})
logMessage := fmt.Sprintf("ip address dropped: %s", ipv4Address)
if reason != "" {
logMessage = fmt.Sprintf("%s, reason: %s", logMessage, reason)
}
go WriteLog(logMessage)
if ipv4Address != StepSecuritySinkHoleIPAddress { // Sinkhole IP address will be covered by DNS block
go WriteAnnotation(fmt.Sprintf("StepSecurity Harden Runner: Traffic to IP Address %s was blocked", ipv4Address))
}
}
}
}
netMonitor.netMutex.Unlock()
}
}