diff --git a/daemon/conman/connection.go b/daemon/conman/connection.go index 6448cf7393..2f6dcf7e09 100644 --- a/daemon/conman/connection.go +++ b/daemon/conman/connection.go @@ -22,16 +22,15 @@ import ( // Connection represents an outgoing connection. type Connection struct { + Entry *netstat.Entry + Process *procmon.Process + Pkt *netfilter.Packet Protocol string + DstHost string SrcIP net.IP - SrcPort uint DstIP net.IP + SrcPort uint DstPort uint - DstHost string - Entry *netstat.Entry - Process *procmon.Process - - Pkt *netfilter.Packet } var showUnknownCons = false diff --git a/daemon/dns/systemd/monitor.go b/daemon/dns/systemd/monitor.go index 15ef2ec14a..0b51e2bc5f 100644 --- a/daemon/dns/systemd/monitor.go +++ b/daemon/dns/systemd/monitor.go @@ -48,9 +48,9 @@ const ( // QuestionMonitorResponse represents a DNS query // "question": [{"class": 1, "type": 28,"name": "images.site.com"}], type QuestionMonitorResponse struct { + Name string `json:"name"` Class int `json:"class"` Type int `json:"type"` - Name string `json:"name"` } // KeyType holds question that generated the answer @@ -67,9 +67,9 @@ type QuestionMonitorResponse struct { "ifindex": 3 }]*/ type KeyType struct { + Name string `json:"name"` Class int `json:"class"` Type int `json:"type"` - Name string `json:"name"` } // RRType represents a DNS answer @@ -100,13 +100,13 @@ type MonitorResponse struct { // ResolvedMonitor represents a systemd-resolved monitor type ResolvedMonitor struct { + mu *sync.RWMutex Ctx context.Context Cancel context.CancelFunc // connection with the systemd-resolved unix socket: // /run/systemd/resolve/io.systemd.Resolve.Monitor - Conn *varlink.Connection - connected bool + Conn *varlink.Connection // channel where all the DNS respones will be sent ChanResponse chan *MonitorResponse @@ -117,7 +117,7 @@ type ResolvedMonitor struct { // callback that is emited when systemd-resolved resolves a domain name. receiverCb resolvedCallback - mu *sync.RWMutex + connected bool } // NewResolvedMonitor returns a new ResolvedMonitor object. diff --git a/daemon/firewall/config/config.go b/daemon/firewall/config/config.go index e25a63a509..43c6c9ee85 100644 --- a/daemon/firewall/config/config.go +++ b/daemon/firewall/config/config.go @@ -5,7 +5,6 @@ // The firewall rules defined by the user are reloaded in these cases: // - When the file system-fw.json changes. // - When the firewall rules are not present when listing them. -// package config import ( @@ -59,21 +58,18 @@ type Expressions struct { // FwRule holds the fields of a rule type FwRule struct { + *sync.RWMutex // we need to keep old fields in the struct. Otherwise when receiving a conf from the GUI, the legacy rules would be deleted. - Chain string // TODO: deprecated, remove - Table string // TODO: deprecated, remove - Parameters string // TODO: deprecated: remove - + Chain string // TODO: deprecated, remove + Table string // TODO: deprecated, remove + Parameters string // TODO: deprecated, remove UUID string Description string - Expressions []*Expressions Target string TargetParameters string - - Position uint64 `json:",string"` - Enabled bool - - *sync.RWMutex + Expressions []*Expressions + Position uint64 `json:",string"` + Enabled bool } // FwChain holds the information that defines a firewall chain. @@ -102,33 +98,31 @@ type rulesList struct { } type chainsList struct { - Chains []*FwChain Rule *FwRule // TODO: deprecated, remove + Chains []*FwChain } // SystemConfig holds the list of rules to be added to the system type SystemConfig struct { - sync.RWMutex SystemRules []*chainsList - Version uint32 - Enabled bool + sync.RWMutex + Version uint32 + Enabled bool } // Config holds the functionality to re/load the firewall configuration from disk. // This is the configuration to manage the system firewall (iptables, nftables). type Config struct { - sync.Mutex - file string watcher *fsnotify.Watcher monitorExitChan chan bool - SysConfig SystemConfig - - // preloadCallback is called before reloading the configuration, - // in order to delete old fw rules. + // preload will be called after daemon startup, whilst reload when a modification is performed. preloadCallback func() // reloadCallback is called after the configuration is written. reloadCallback func() - // preload will be called after daemon startup, whilst reload when a modification is performed. + file string + SysConfig SystemConfig + + sync.Mutex } // NewSystemFwConfig initializes config fields diff --git a/daemon/firewall/iptables/iptables.go b/daemon/firewall/iptables/iptables.go index d4b9dcc8b5..513ecd77d2 100644 --- a/daemon/firewall/iptables/iptables.go +++ b/daemon/firewall/iptables/iptables.go @@ -41,9 +41,9 @@ const ( // SystemRule blabla type SystemRule struct { + Rule *config.FwRule Table string Chain string - Rule *config.FwRule } // SystemChains keeps track of the fw rules that have been added to the system. @@ -54,17 +54,13 @@ type SystemChains struct { // Iptables struct holds the fields of the iptables fw type Iptables struct { - config.Config - common.Common - - bin string - bin6 string - regexRulesQuery *regexp.Regexp regexSystemRulesQuery *regexp.Regexp - - chains SystemChains - + bin string + bin6 string + chains SystemChains + common.Common + config.Config sync.Mutex } diff --git a/daemon/firewall/nftables/nftables.go b/daemon/firewall/nftables/nftables.go index d3e9d6d8f0..c0b314bd2a 100644 --- a/daemon/firewall/nftables/nftables.go +++ b/daemon/firewall/nftables/nftables.go @@ -41,12 +41,12 @@ var ( // Nft holds the fields of our nftables firewall type Nft struct { - sync.Mutex - config.Config - common.Common - Conn *nftables.Conn chains iptables.SystemChains + common.Common + config.Config + + sync.Mutex } // NewNft creates a new nftables object diff --git a/daemon/log/formats/json.go b/daemon/log/formats/json.go index 6baab58303..438c032b2b 100644 --- a/daemon/log/formats/json.go +++ b/daemon/log/formats/json.go @@ -19,9 +19,9 @@ const ( // JSONEventFormat object to be sent to the remote service. // TODO: Expand as needed: ebpf events, etc. type JSONEventFormat struct { + Event interface{} `json:"Event"` Rule string `json:"Rule"` Action string `json:"Action"` - Event interface{} `json:"Event"` Type uint8 `json:"Type"` } diff --git a/daemon/netfilter/packet.go b/daemon/netfilter/packet.go index 3795c2ca5b..7c3e95bbfd 100644 --- a/daemon/netfilter/packet.go +++ b/daemon/netfilter/packet.go @@ -16,20 +16,20 @@ type Verdict C.uint // VerdictContainer struct type VerdictContainer struct { - Verdict Verdict Mark uint32 + Verdict Verdict Packet []byte } // Packet holds the data of a network packet type Packet struct { Packet gopacket.Packet - Mark uint32 verdictChannel chan VerdictContainer - UID uint32 - NetworkProtocol uint8 IfaceInIdx int IfaceOutIdx int + Mark uint32 + UID uint32 + NetworkProtocol uint8 } // SetVerdict emits a veredict on a packet diff --git a/daemon/netfilter/queue.go b/daemon/netfilter/queue.go index 7d84611ff4..ac4cf7ae56 100644 --- a/daemon/netfilter/queue.go +++ b/daemon/netfilter/queue.go @@ -57,8 +57,8 @@ type VerdictContainerC C.verdictContainer type Queue struct { h *C.struct_nfq_handle qh *C.struct_nfq_q_handle - fd C.int packets chan Packet + fd C.int idx uint32 } diff --git a/daemon/netstat/entry.go b/daemon/netstat/entry.go index 6214a00ece..ebe433a179 100644 --- a/daemon/netstat/entry.go +++ b/daemon/netstat/entry.go @@ -11,11 +11,11 @@ import ( type Entry struct { Proto string SrcIP net.IP - SrcPort uint DstIP net.IP - DstPort uint UserId int INode int + SrcPort uint + DstPort uint } // NewEntry creates a new entry with values from /proc/net/ diff --git a/daemon/procmon/cache.go b/daemon/procmon/cache.go index 395fc42230..b1b1971225 100644 --- a/daemon/procmon/cache.go +++ b/daemon/procmon/cache.go @@ -12,35 +12,35 @@ import ( // InodeItem represents an item of the InodesCache. type InodeItem struct { - sync.RWMutex - - Pid int FdPath string LastSeen int64 + Pid int + + sync.RWMutex } // ProcItem represents an item of the pidsCache type ProcItem struct { - sync.RWMutex - - Pid int FdPath string Descriptors []string LastSeen int64 + Pid int + + sync.RWMutex } // CacheProcs holds the cache of processes that have established connections. type CacheProcs struct { - sync.RWMutex items []*ProcItem + sync.RWMutex } // CacheInodes holds the cache of Inodes. // The key is formed as follow: // inode+srcip+srcport+dstip+dstport type CacheInodes struct { - sync.RWMutex items map[string]*InodeItem + sync.RWMutex } var ( diff --git a/daemon/procmon/ebpf/cache.go b/daemon/procmon/ebpf/cache.go index ad4fa1ad16..af0b78c130 100644 --- a/daemon/procmon/ebpf/cache.go +++ b/daemon/procmon/ebpf/cache.go @@ -78,8 +78,8 @@ func (e *eventsStore) DeleteOldItems() { //----------------------------------------------------------------------------- type ebpfCacheItem struct { - Proc procmon.Process Key []byte + Proc procmon.Process LastSeen int64 } diff --git a/daemon/procmon/ebpf/ebpf.go b/daemon/procmon/ebpf/ebpf.go index 983f8099b0..a3e6ded9b1 100644 --- a/daemon/procmon/ebpf/ebpf.go +++ b/daemon/procmon/ebpf/ebpf.go @@ -16,15 +16,15 @@ import ( "github.com/vishvananda/netlink" ) -//contains pointers to ebpf maps for a given protocol (tcp/udp/v6) +// contains pointers to ebpf maps for a given protocol (tcp/udp/v6) type ebpfMapsForProto struct { bpfmap *elf.Map } //Not in use, ~4usec faster lookup compared to m.LookupElement() -//mimics union bpf_attr's anonymous struct used by BPF_MAP_*_ELEM commands -//from /include/uapi/linux/bpf.h +// mimics union bpf_attr's anonymous struct used by BPF_MAP_*_ELEM commands +// from /include/uapi/linux/bpf.h type bpf_lookup_elem_t struct { map_fd uint64 //even though in bpf.h its type is __u32, we must make it 8 bytes long //because "key" is of type __aligned_u64, i.e. "key" must be aligned on an 8-byte boundary @@ -47,8 +47,8 @@ const ( // Error returns the error type and a message with the explanation type Error struct { - What int // 1 global error, 2 events error, 3 ... Msg error + What int } var ( @@ -76,7 +76,7 @@ var ( hostByteOrder binary.ByteOrder ) -//Start installs ebpf kprobes +// Start installs ebpf kprobes func Start(modPath string) *Error { modulesPath = modPath @@ -84,8 +84,8 @@ func Start(modPath string) *Error { if err := mountDebugFS(); err != nil { log.Error("ebpf.Start -> mount debugfs error. Report on github please: %s", err) return &Error{ - NotAvailable, fmt.Errorf("ebpf.Start: mount debugfs error. Report on github please: %s", err), + NotAvailable, } } @@ -94,7 +94,10 @@ func Start(modPath string) *Error { if err != nil { log.Error("%s", err) dispatchErrorEvent(fmt.Sprint("[eBPF]: ", err.Error())) - return &Error{NotAvailable, fmt.Errorf("[eBPF] Error loading opensnitch.o: %s", err.Error())} + return &Error{ + fmt.Errorf("[eBPF] Error loading opensnitch.o: %s", err.Error()), + NotAvailable, + } } m.EnableOptionCompatProbe() @@ -104,10 +107,16 @@ func Start(modPath string) *Error { if err := m.EnableKprobes(0); err != nil { m.Close() if err := m.Load(nil); err != nil { - return &Error{NotAvailable, fmt.Errorf("eBPF failed to load /etc/opensnitchd/opensnitch.o (2): %v", err)} + return &Error{ + fmt.Errorf("eBPF failed to load /etc/opensnitchd/opensnitch.o (2): %v", err), + NotAvailable, + } } if err := m.EnableKprobes(0); err != nil { - return &Error{NotAvailable, fmt.Errorf("eBPF error when enabling kprobes: %v", err)} + return &Error{ + fmt.Errorf("eBPF error when enabling kprobes: %v", err), + NotAvailable, + } } } determineHostByteOrder() @@ -124,7 +133,10 @@ func Start(modPath string) *Error { } for prot, mfp := range ebpfMaps { if mfp.bpfmap == nil { - return &Error{NotAvailable, fmt.Errorf("eBPF module opensnitch.o malformed, bpfmap[%s] nil", prot)} + return &Error{ + fmt.Errorf("eBPF module opensnitch.o malformed, bpfmap[%s] nil", prot), + NotAvailable, + } } } @@ -202,7 +214,7 @@ func Stop() { } } -//make bpf() syscall with bpf_lookup prepared by the caller +// make bpf() syscall with bpf_lookup prepared by the caller func makeBpfSyscall(bpf_lookup *bpf_lookup_elem_t) uintptr { BPF_MAP_LOOKUP_ELEM := 1 //cmd number syscall_BPF := 321 //syscall number diff --git a/daemon/procmon/process.go b/daemon/procmon/process.go index 1859c9eb33..f6a2a658dd 100644 --- a/daemon/procmon/process.go +++ b/daemon/procmon/process.go @@ -39,10 +39,10 @@ type procNetStats struct { } type procDescriptors struct { + ModTime time.Time Name string SymLink string Size int64 - ModTime time.Time } type procStatm struct { @@ -57,12 +57,19 @@ type procStatm struct { // Process holds the details of a process. type Process struct { - ID int - PPID int - UID int - Comm string + Env map[string]string + IOStats *procIOstats + NetStats *procNetStats + Statm *procStatm + Maps string // Path is the absolute path to the binary - Path string + Path string + Comm string + CWD string + Status string + Stat string + Stack string + Descriptors []*procDescriptors // Args is the command that the user typed. It MAY contain the absolute path // of the binary: // $ curl https://... @@ -71,17 +78,11 @@ type Process struct { // $ /usr/bin/curl https://... // -> Path: /usr/bin/curl // -> Args: /usr/bin/curl https://.... - Args []string - Env map[string]string - CWD string - Descriptors []*procDescriptors - IOStats *procIOstats - NetStats *procNetStats - Status string - Stat string - Statm *procStatm - Stack string - Maps string + + Args []string + ID int + PPID int + UID int } // NewProcess returns a new Process structure. @@ -97,7 +98,7 @@ func NewProcess(pid int, comm string) *Process { } } -//Serialize transforms a Process object to gRPC protocol object +// Serialize transforms a Process object to gRPC protocol object func (p *Process) Serialize() *protocol.Process { ioStats := p.IOStats netStats := p.NetStats diff --git a/daemon/rule/loader.go b/daemon/rule/loader.go index c07b660e4c..8846427d4d 100644 --- a/daemon/rule/loader.go +++ b/daemon/rule/loader.go @@ -22,11 +22,11 @@ import ( // Loader is the object that holds the rules loaded from disk, as well as the // rules watcher. type Loader struct { + rules map[string]*Rule + watcher *fsnotify.Watcher + path string + rulesKeys []string sync.RWMutex - path string - rules map[string]*Rule - rulesKeys []string - watcher *fsnotify.Watcher liveReload bool liveReloadRunning bool } diff --git a/daemon/rule/operator.go b/daemon/rule/operator.go index a4c1b45d1a..e1ab34950f 100644 --- a/daemon/rule/operator.go +++ b/daemon/rule/operator.go @@ -63,20 +63,22 @@ type opCallback func(value interface{}) bool // Operator represents what we want to filter of a connection, and how. type Operator struct { - Type Type `json:"type"` + cb opCallback + re *regexp.Regexp + netMask *net.IPNet + lists map[string]interface{} + exitMonitorChan chan (bool) + Operand Operand `json:"operand"` - Sensitive Sensitive `json:"sensitive"` Data string `json:"data"` + Type Type `json:"type"` List []Operator `json:"list"` + Sensitive Sensitive `json:"sensitive"` - sync.RWMutex - cb opCallback - re *regexp.Regexp - netMask *net.IPNet - isCompiled bool - lists map[string]interface{} listsMonitorRunning bool - exitMonitorChan chan (bool) + isCompiled bool + + sync.RWMutex } // NewOperator returns a new operator object diff --git a/daemon/rule/rule.go b/daemon/rule/rule.go index 45e60b6af6..4d8f14e874 100644 --- a/daemon/rule/rule.go +++ b/daemon/rule/rule.go @@ -37,12 +37,12 @@ type Rule struct { Updated time.Time `json:"updated"` Name string `json:"name"` Description string `json:"description"` - Enabled bool `json:"enabled"` - Precedence bool `json:"precedence"` - Nolog bool `json:"nolog"` Action Action `json:"action"` Duration Duration `json:"duration"` Operator Operator `json:"operator"` + Enabled bool `json:"enabled"` + Precedence bool `json:"precedence"` + Nolog bool `json:"nolog"` } // Create creates a new rule object with the specified parameters. diff --git a/daemon/statistics/stats.go b/daemon/statistics/stats.go index c561ce72d7..ed8039a6c6 100644 --- a/daemon/statistics/stats.go +++ b/daemon/statistics/stats.go @@ -29,32 +29,30 @@ type conEvent struct { // Statistics holds the connections and statistics the daemon intercepts. // The connections are stored in the Events slice. type Statistics struct { - sync.RWMutex - + logger *loggers.LoggerManager + rules *rule.Loader Started time.Time - DNSResponses int - Connections int - Ignored int - Accepted int - Dropped int - RuleHits int - RuleMisses int - Events []*Event + ByExecutable map[string]uint64 + ByPort map[string]uint64 ByProto map[string]uint64 ByAddress map[string]uint64 ByHost map[string]uint64 - ByPort map[string]uint64 + jobs chan conEvent ByUID map[string]uint64 - ByExecutable map[string]uint64 - - rules *rule.Loader - jobs chan conEvent + Events []*Event + Dropped int // max number of events to keep in the buffer maxEvents int // max number of entries for each By* map - maxStats int + maxStats int + DNSResponses int + Connections int + Ignored int + Accepted int + RuleHits int + RuleMisses int - logger *loggers.LoggerManager + sync.RWMutex } // New returns a new Statistics object and initializes the go routines to update the stats. diff --git a/daemon/ui/client.go b/daemon/ui/client.go index 2de0e4b4f3..be013d2668 100644 --- a/daemon/ui/client.go +++ b/daemon/ui/client.go @@ -37,25 +37,23 @@ var ( // Client holds the connection information of a client. type Client struct { - sync.RWMutex - clientCtx context.Context - clientCancel context.CancelFunc - - stats *statistics.Statistics - rules *rule.Loader - socketPath string - unixSockPrefix string - isUnixSocket bool - con *grpc.ClientConn - client protocol.UIClient - configWatcher *fsnotify.Watcher - + rules *rule.Loader + stats *statistics.Statistics + con *grpc.ClientConn + configWatcher *fsnotify.Watcher + client protocol.UIClient + clientCtx context.Context + clientCancel context.CancelFunc + streamNotifications protocol.UI_NotificationsClient isConnected chan bool alertsChan chan protocol.Alert - streamNotifications protocol.UI_NotificationsClient - + socketPath string + unixSockPrefix string //isAsking is set to true if the client is awaiting a decision from the GUI - isAsking bool + isAsking bool + isUnixSocket bool + + sync.RWMutex } // NewClient creates and configures a new client. @@ -157,14 +155,14 @@ func (c *Client) Connected() bool { return true } -//GetIsAsking returns the isAsking flag +// GetIsAsking returns the isAsking flag func (c *Client) GetIsAsking() bool { c.RLock() defer c.RUnlock() return c.isAsking } -//SetIsAsking sets the isAsking flag +// SetIsAsking sets the isAsking flag func (c *Client) SetIsAsking(flag bool) { c.Lock() defer c.Unlock() diff --git a/daemon/ui/config/config.go b/daemon/ui/config/config.go index 398518ddc5..90e2001e8f 100644 --- a/daemon/ui/config/config.go +++ b/daemon/ui/config/config.go @@ -20,10 +20,10 @@ type ( ServerKey string `json:"ServerKey"` ClientCert string `json:"ClientCert"` ClientKey string `json:"ClientKey"` - // https://pkg.go.dev/crypto/tls#Config - SkipVerify bool `json:"SkipVerify"` // https://pkg.go.dev/crypto/tls#ClientAuthType ClientAuthType string `json:"ClientAuthType"` + // https://pkg.go.dev/crypto/tls#Config + SkipVerify bool `json:"SkipVerify"` // https://pkg.go.dev/crypto/tls#Conn.VerifyHostname // VerifyHostname bool @@ -39,10 +39,10 @@ type ( } serverConfig struct { + Loggers []loggers.LoggerConfig `json:"Loggers"` Address string `json:"Address"` - Authentication serverAuth `json:"Authentication"` LogFile string `json:"LogFile"` - Loggers []loggers.LoggerConfig `json:"Loggers"` + Authentication serverAuth `json:"Authentication"` } rulesOptions struct { @@ -56,19 +56,20 @@ type ( // Config holds the values loaded from configFile type Config struct { - sync.RWMutex - Server serverConfig `json:"Server"` - Stats statistics.StatsConfig `json:"Stats"` - Rules rulesOptions `json:"Rules"` - Ebpf ebpfOptions `json:"Ebpf"` + LogLevel *int32 `json:"LogLevel"` DefaultAction string `json:"DefaultAction"` DefaultDuration string `json:"DefaultDuration"` ProcMonitorMethod string `json:"ProcMonitorMethod"` Firewall string `json:"Firewall"` - LogLevel *int32 `json:"LogLevel"` - InterceptUnknown bool `json:"InterceptUnknown"` - LogUTC bool `json:"LogUTC"` - LogMicro bool `json:"LogMicro"` + Ebpf ebpfOptions `json:"Ebpf"` + Rules rulesOptions `json:"Rules"` + Server serverConfig `json:"Server"` + Stats statistics.StatsConfig `json:"Stats"` + + sync.RWMutex + InterceptUnknown bool `json:"InterceptUnknown"` + LogUTC bool `json:"LogUTC"` + LogMicro bool `json:"LogMicro"` } // Parse determines if the given configuration is ok.