2018-04-02 05:25:32 +02:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
2018-04-02 18:26:04 +02:00
|
|
|
"fmt"
|
2018-04-02 05:25:32 +02:00
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/conman"
|
2021-08-09 00:21:43 +02:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/firewall/iptables"
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/log"
|
2022-05-17 16:15:40 +02:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/log/loggers"
|
2023-09-22 00:36:26 +02:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/procmon"
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/rule"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/statistics"
|
introducing daemon tasks
daemon tasks are actions that are executed in background by the daemon.
They're started from the GUI (server) via a Notification (protobuf),
with the type TASK_START (protobuf).
Once received in the daemon, the TaskManager starts the task in
background.
Tasks may run at interval times (every 5s, 2days, etc), until they
finish an operation, until a timeout, etc.
Each task has each own configuration options, which will customize the
behaviour of its operations.
In this version, if the GUI is closed, the daemon will stop all the
running tasks.
Each Task has a flag to ignore this behaviour, for example if they need
to run until they finish and only send a notification to the GUI,
instead of streaming data continuously to the GUI (server).
- Up until now we only had one task that could be initiated from the GUI:
the process monitor dialog. It has been migrated to a Task{}.
- go.mod bumped to v1.20, to use unsafe string functions.
- go.sum updated accordingly.
2024-09-25 01:00:38 +02:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/tasks"
|
added option to secure channel communications
Allow to cypher channel communications with certificates.
There are 3 authentication types: simple, tls-simple and tls-mutual.
- 'simple' wont't cypher communications.
- 'tls-simple' uses a server key and certificate for the server, and a
common CA certificate or the server certificate to authenticate all
nodes.
- 'tls-mutual' uses a server key and certificate for the server, and a
client key and certificate per node.
There are 2 options to verify how gRPC validates credentials:
- SkipVerify: https://pkg.go.dev/crypto/tls#Config
- ClientAuthType: https://pkg.go.dev/crypto/tls#ClientAuthType
Example configuration:
"Server": {
"Address": "127.0.0.1:12345",
"Authentication": {
"Type": "tls-simple",
"TLSOptions": {
"CACert": "/etc/opensnitchd/auth/ca-cert.pem",
"ServerCert": "/etc/opensnitchd/auth/server-cert.pem",
"ClientCert": "/etc/opensnitchd/auth/client-cert.pem",
"ClientKey": "/etc/opensnitchd/auth/client-key.pem",
"SkipVerify": false,
"ClientAuthType": "req-and-verify-cert"
}
}
}
More info: https://github.com/evilsocket/opensnitch/wiki/Nodes
2023-06-23 16:51:36 +02:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/ui/auth"
|
|
|
|
"github.com/evilsocket/opensnitch/daemon/ui/config"
|
2020-12-09 18:18:42 +01:00
|
|
|
"github.com/evilsocket/opensnitch/daemon/ui/protocol"
|
2018-04-02 18:11:36 +02:00
|
|
|
|
2019-11-01 01:00:10 +01:00
|
|
|
"github.com/fsnotify/fsnotify"
|
2020-04-19 20:13:31 +02:00
|
|
|
"golang.org/x/net/context"
|
2018-04-02 05:25:32 +02:00
|
|
|
"google.golang.org/grpc"
|
2018-04-02 18:11:36 +02:00
|
|
|
"google.golang.org/grpc/connectivity"
|
2021-04-11 20:55:14 +02:00
|
|
|
"google.golang.org/grpc/keepalive"
|
2018-04-02 05:25:32 +02:00
|
|
|
)
|
|
|
|
|
2018-04-07 13:52:25 +02:00
|
|
|
var (
|
2020-03-16 01:37:33 +01:00
|
|
|
configFile = "/etc/opensnitchd/default-config.json"
|
2020-10-23 00:02:16 +02:00
|
|
|
dummyOperator, _ = rule.NewOperator(rule.Simple, false, rule.OpTrue, "", make([]rule.Operator, 0))
|
2022-07-04 11:14:26 +02:00
|
|
|
clientDisconnectedRule = rule.Create("ui.client.disconnected", "", true, false, false, rule.Allow, rule.Once, dummyOperator)
|
2021-06-16 09:50:36 +02:00
|
|
|
// While the GUI is connected, deny by default everything until the user takes an action.
|
2022-07-04 11:14:26 +02:00
|
|
|
clientConnectedRule = rule.Create("ui.client.connected", "", true, false, false, rule.Deny, rule.Once, dummyOperator)
|
|
|
|
clientErrorRule = rule.Create("ui.client.error", "", true, false, false, rule.Allow, rule.Once, dummyOperator)
|
2022-10-12 13:31:45 +02:00
|
|
|
|
|
|
|
maxQueuedAlerts = 1024
|
introducing daemon tasks
daemon tasks are actions that are executed in background by the daemon.
They're started from the GUI (server) via a Notification (protobuf),
with the type TASK_START (protobuf).
Once received in the daemon, the TaskManager starts the task in
background.
Tasks may run at interval times (every 5s, 2days, etc), until they
finish an operation, until a timeout, etc.
Each task has each own configuration options, which will customize the
behaviour of its operations.
In this version, if the GUI is closed, the daemon will stop all the
running tasks.
Each Task has a flag to ignore this behaviour, for example if they need
to run until they finish and only send a notification to the GUI,
instead of streaming data continuously to the GUI (server).
- Up until now we only had one task that could be initiated from the GUI:
the process monitor dialog. It has been migrated to a Task{}.
- go.mod bumped to v1.20, to use unsafe string functions.
- go.sum updated accordingly.
2024-09-25 01:00:38 +02:00
|
|
|
|
|
|
|
TaskMgr = tasks.NewTaskManager()
|
2018-04-07 13:52:25 +02:00
|
|
|
)
|
2018-04-02 18:11:36 +02:00
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// Client holds the connection information of a client.
|
2018-04-02 05:25:32 +02:00
|
|
|
type Client struct {
|
2024-01-14 20:44:49 +01:00
|
|
|
client protocol.UIClient
|
|
|
|
streamNotifications protocol.UI_NotificationsClient
|
|
|
|
clientCtx context.Context
|
|
|
|
clientCancel context.CancelFunc
|
2024-05-11 18:23:20 +02:00
|
|
|
config config.Config
|
2024-01-14 20:44:49 +01:00
|
|
|
|
2024-05-02 21:14:59 +02:00
|
|
|
loggers *loggers.LoggerManager
|
2024-01-14 20:44:49 +01:00
|
|
|
stats *statistics.Statistics
|
|
|
|
rules *rule.Loader
|
|
|
|
con *grpc.ClientConn
|
|
|
|
configWatcher *fsnotify.Watcher
|
|
|
|
|
|
|
|
alertsChan chan protocol.Alert
|
|
|
|
isConnected chan bool
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2023-07-19 01:17:49 +02:00
|
|
|
socketPath string
|
|
|
|
unixSockPrefix string
|
2022-10-12 13:31:45 +02:00
|
|
|
|
2021-02-18 17:21:50 +03:00
|
|
|
//isAsking is set to true if the client is awaiting a decision from the GUI
|
2024-01-14 20:44:49 +01:00
|
|
|
isAsking bool
|
|
|
|
isUnixSocket bool
|
|
|
|
|
|
|
|
sync.RWMutex
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// NewClient creates and configures a new client.
|
2023-12-17 00:22:07 +01:00
|
|
|
func NewClient(socketPath, localConfigFile string, stats *statistics.Statistics, rules *rule.Loader, loggers *loggers.LoggerManager) *Client {
|
|
|
|
if localConfigFile != "" {
|
|
|
|
configFile = localConfigFile
|
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
c := &Client{
|
2024-05-02 21:14:59 +02:00
|
|
|
loggers: loggers,
|
2020-03-16 01:37:33 +01:00
|
|
|
stats: stats,
|
2020-05-10 17:17:05 +02:00
|
|
|
rules: rules,
|
2018-04-07 01:52:43 +02:00
|
|
|
isUnixSocket: false,
|
2021-02-18 17:21:50 +03:00
|
|
|
isAsking: false,
|
2022-10-12 13:31:45 +02:00
|
|
|
isConnected: make(chan bool),
|
|
|
|
alertsChan: make(chan protocol.Alert, maxQueuedAlerts),
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
improved rules reloading, cli parameters
- When reloading rules from a path:
stop existing (domains,ips,regexp) lists monitors, stop rules
watcher and start watching the new dir for changes, delete existing
rules from memory, etc.
- Previously, cli parameters (queue number, log file, etc) were taking
into account before loading the configuration.
Now the configuration file is loaded first (default-config.json), and
if any of the cli parameter has been specified, it'll overwrite the
loaded configuration from file.
This means for example that if you use "-process-monitor-method proc",
and "ebpf" is configured in default-config.json, firstly "ebpf" will
be configured, and later "proc".
(-queue-num option for now requires to match config option
cfg.FwOptions.QueueNumber)
2024-05-22 00:47:54 +02:00
|
|
|
c.config.Rules.Path = rules.Path
|
2022-10-12 13:31:45 +02:00
|
|
|
//for i := 0; i < 4; i++ {
|
|
|
|
go c.alertsDispatcher()
|
|
|
|
|
2020-07-17 01:29:58 +02:00
|
|
|
c.clientCtx, c.clientCancel = context.WithCancel(context.Background())
|
|
|
|
|
2019-11-01 01:00:10 +01:00
|
|
|
if watcher, err := fsnotify.NewWatcher(); err == nil {
|
|
|
|
c.configWatcher = watcher
|
|
|
|
}
|
2020-04-19 20:13:31 +02:00
|
|
|
c.loadDiskConfiguration(false)
|
2020-10-26 23:16:27 +01:00
|
|
|
if socketPath != "" {
|
2020-10-30 22:06:33 +01:00
|
|
|
c.setSocketPath(c.getSocketPath(socketPath))
|
2020-10-26 23:16:27 +01:00
|
|
|
}
|
2024-05-11 18:23:20 +02:00
|
|
|
procmon.EventsCache.SetComputeChecksums(c.config.Rules.EnableChecksums)
|
|
|
|
rules.EnableChecksums(c.config.Rules.EnableChecksums)
|
2020-10-26 23:16:27 +01:00
|
|
|
|
2018-04-02 05:25:32 +02:00
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2022-12-16 17:03:36 +01:00
|
|
|
// Connect starts the connection poller
|
|
|
|
func (c *Client) Connect() {
|
|
|
|
go c.poller()
|
|
|
|
}
|
|
|
|
|
2020-07-17 01:29:58 +02:00
|
|
|
// Close cancels the running tasks: pinging the server and (re)connection poller.
|
|
|
|
func (c *Client) Close() {
|
|
|
|
c.clientCancel()
|
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// ProcMonitorMethod returns the monitor method configured.
|
2020-12-23 13:24:59 -05:00
|
|
|
// If it's not present in the config file, it'll return an empty string.
|
2020-03-16 01:37:33 +01:00
|
|
|
func (c *Client) ProcMonitorMethod() string {
|
2024-05-11 18:23:20 +02:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
|
|
|
return c.config.ProcMonitorMethod
|
2020-03-16 01:37:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// InterceptUnknown returns
|
2019-11-01 01:00:10 +01:00
|
|
|
func (c *Client) InterceptUnknown() bool {
|
2024-05-11 18:23:20 +02:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
|
|
|
return c.config.InterceptUnknown
|
2019-07-02 23:41:41 +02:00
|
|
|
}
|
|
|
|
|
2021-08-09 00:21:43 +02:00
|
|
|
// GetFirewallType returns the firewall to use
|
|
|
|
func (c *Client) GetFirewallType() string {
|
2024-05-11 18:23:20 +02:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
|
|
|
if c.config.Firewall == "" {
|
2021-08-09 00:21:43 +02:00
|
|
|
return iptables.Name
|
|
|
|
}
|
2024-05-11 18:23:20 +02:00
|
|
|
return c.config.Firewall
|
2021-08-09 00:21:43 +02:00
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// DefaultAction returns the default configured action for
|
2019-10-21 00:04:15 +02:00
|
|
|
func (c *Client) DefaultAction() rule.Action {
|
2021-06-16 09:50:36 +02:00
|
|
|
isConnected := c.Connected()
|
|
|
|
|
2020-11-03 15:29:08 +01:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
2021-06-16 09:50:36 +02:00
|
|
|
|
|
|
|
if isConnected {
|
|
|
|
return clientConnectedRule.Action
|
|
|
|
}
|
|
|
|
|
2019-10-21 00:04:15 +02:00
|
|
|
return clientDisconnectedRule.Action
|
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// DefaultDuration returns the default duration configured for a rule.
|
|
|
|
// For example it can be: once, always, "until restart".
|
2019-10-21 00:04:15 +02:00
|
|
|
func (c *Client) DefaultDuration() rule.Duration {
|
2020-11-03 15:29:08 +01:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
2019-10-21 00:04:15 +02:00
|
|
|
return clientDisconnectedRule.Duration
|
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// Connected checks if the client has established a connection with the server.
|
2018-04-06 14:48:43 +02:00
|
|
|
func (c *Client) Connected() bool {
|
2021-02-18 17:21:50 +03:00
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
2018-04-06 14:48:43 +02:00
|
|
|
if c.con == nil || c.con.GetState() != connectivity.Ready {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-02-18 17:21:50 +03:00
|
|
|
//GetIsAsking returns the isAsking flag
|
|
|
|
func (c *Client) GetIsAsking() bool {
|
|
|
|
c.RLock()
|
|
|
|
defer c.RUnlock()
|
|
|
|
return c.isAsking
|
|
|
|
}
|
|
|
|
|
|
|
|
//SetIsAsking sets the isAsking flag
|
|
|
|
func (c *Client) SetIsAsking(flag bool) {
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
c.isAsking = flag
|
|
|
|
}
|
|
|
|
|
2018-04-02 05:25:32 +02:00
|
|
|
func (c *Client) poller() {
|
|
|
|
log.Debug("UI service poller started for socket %s", c.socketPath)
|
2018-04-06 14:48:43 +02:00
|
|
|
wasConnected := false
|
2020-07-17 01:29:58 +02:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-c.clientCtx.Done():
|
2020-10-26 23:16:27 +01:00
|
|
|
log.Info("Client.poller() exit, Done()")
|
2020-07-17 01:29:58 +02:00
|
|
|
goto Exit
|
|
|
|
default:
|
|
|
|
isConnected := c.Connected()
|
|
|
|
if wasConnected != isConnected {
|
|
|
|
c.onStatusChange(isConnected)
|
|
|
|
wasConnected = isConnected
|
|
|
|
}
|
2018-04-06 14:48:43 +02:00
|
|
|
|
2020-07-17 01:29:58 +02:00
|
|
|
if c.Connected() == false {
|
|
|
|
// connect and create the client if needed
|
|
|
|
if err := c.connect(); err != nil {
|
|
|
|
log.Warning("Error while connecting to UI service: %s", err)
|
|
|
|
}
|
2019-10-20 23:25:21 +02:00
|
|
|
}
|
2020-07-17 01:29:58 +02:00
|
|
|
if c.Connected() == true {
|
|
|
|
// if the client is connected and ready, send a ping
|
|
|
|
if err := c.ping(time.Now()); err != nil {
|
2021-04-11 20:55:14 +02:00
|
|
|
log.Warning("Error while pinging UI service: %s, state: %v", err, c.con.GetState())
|
2020-07-17 01:29:58 +02:00
|
|
|
}
|
2018-04-02 18:26:04 +02:00
|
|
|
}
|
2018-04-06 18:34:33 +02:00
|
|
|
|
2020-07-17 01:29:58 +02:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
2020-07-17 01:29:58 +02:00
|
|
|
Exit:
|
|
|
|
log.Info("uiClient exit")
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
2018-04-06 14:48:43 +02:00
|
|
|
func (c *Client) onStatusChange(connected bool) {
|
|
|
|
if connected {
|
|
|
|
log.Info("Connected to the UI service on %s", c.socketPath)
|
2020-04-19 20:13:31 +02:00
|
|
|
go c.Subscribe()
|
2022-10-12 13:31:45 +02:00
|
|
|
|
|
|
|
select {
|
|
|
|
case c.isConnected <- true:
|
|
|
|
default:
|
|
|
|
}
|
2018-04-06 14:48:43 +02:00
|
|
|
} else {
|
|
|
|
log.Error("Connection to the UI service lost.")
|
2020-10-26 23:16:27 +01:00
|
|
|
c.disconnect()
|
2018-04-06 14:48:43 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2018-04-06 14:48:43 +02:00
|
|
|
func (c *Client) connect() (err error) {
|
|
|
|
if c.Connected() {
|
2018-04-02 05:25:32 +02:00
|
|
|
return
|
|
|
|
}
|
2019-06-29 13:55:44 +02:00
|
|
|
|
2019-10-20 23:25:21 +02:00
|
|
|
if c.con != nil {
|
|
|
|
if c.con.GetState() == connectivity.TransientFailure || c.con.GetState() == connectivity.Shutdown {
|
2020-10-26 23:16:27 +01:00
|
|
|
c.disconnect()
|
2019-10-20 23:25:21 +02:00
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2020-10-30 22:06:33 +01:00
|
|
|
if err := c.openSocket(); err != nil {
|
2023-07-19 01:17:49 +02:00
|
|
|
log.Debug("connect() %s", err)
|
2020-10-30 22:06:33 +01:00
|
|
|
c.disconnect()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.client == nil {
|
|
|
|
c.client = protocol.NewUIClient(c.con)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) openSocket() (err error) {
|
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2024-05-11 18:23:20 +02:00
|
|
|
dialOption, err := auth.New(&c.config)
|
2023-07-19 01:17:49 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Invalid client auth options: %s", err)
|
|
|
|
}
|
2018-04-07 01:52:43 +02:00
|
|
|
if c.isUnixSocket {
|
2023-07-19 01:17:49 +02:00
|
|
|
c.con, err = grpc.Dial(c.socketPath, dialOption,
|
2018-04-07 01:52:43 +02:00
|
|
|
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
|
2023-07-19 01:17:49 +02:00
|
|
|
return net.DialTimeout(c.unixSockPrefix, addr, timeout)
|
2018-04-07 01:52:43 +02:00
|
|
|
}))
|
|
|
|
} else {
|
2021-04-11 20:55:14 +02:00
|
|
|
// https://pkg.go.dev/google.golang.org/grpc/keepalive#ClientParameters
|
|
|
|
var kacp = keepalive.ClientParameters{
|
|
|
|
Time: 5 * time.Second,
|
|
|
|
// if there's no activity after ^, wait 20s and close
|
|
|
|
// server timeout is 20s by default.
|
|
|
|
Timeout: 22 * time.Second,
|
|
|
|
// send pings even without active streams
|
|
|
|
PermitWithoutStream: true,
|
|
|
|
}
|
|
|
|
|
added option to secure channel communications
Allow to cypher channel communications with certificates.
There are 3 authentication types: simple, tls-simple and tls-mutual.
- 'simple' wont't cypher communications.
- 'tls-simple' uses a server key and certificate for the server, and a
common CA certificate or the server certificate to authenticate all
nodes.
- 'tls-mutual' uses a server key and certificate for the server, and a
client key and certificate per node.
There are 2 options to verify how gRPC validates credentials:
- SkipVerify: https://pkg.go.dev/crypto/tls#Config
- ClientAuthType: https://pkg.go.dev/crypto/tls#ClientAuthType
Example configuration:
"Server": {
"Address": "127.0.0.1:12345",
"Authentication": {
"Type": "tls-simple",
"TLSOptions": {
"CACert": "/etc/opensnitchd/auth/ca-cert.pem",
"ServerCert": "/etc/opensnitchd/auth/server-cert.pem",
"ClientCert": "/etc/opensnitchd/auth/client-cert.pem",
"ClientKey": "/etc/opensnitchd/auth/client-key.pem",
"SkipVerify": false,
"ClientAuthType": "req-and-verify-cert"
}
}
}
More info: https://github.com/evilsocket/opensnitch/wiki/Nodes
2023-06-23 16:51:36 +02:00
|
|
|
c.con, err = grpc.Dial(c.socketPath, dialOption, grpc.WithKeepaliveParams(kacp))
|
2018-04-07 01:52:43 +02:00
|
|
|
}
|
|
|
|
|
2020-10-30 22:06:33 +01:00
|
|
|
return err
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
|
|
|
|
2020-10-26 23:16:27 +01:00
|
|
|
func (c *Client) disconnect() {
|
2020-10-30 22:06:33 +01:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2022-10-12 13:31:45 +02:00
|
|
|
select {
|
|
|
|
case c.isConnected <- false:
|
|
|
|
default:
|
|
|
|
}
|
2020-10-26 23:16:27 +01:00
|
|
|
if c.con != nil {
|
|
|
|
c.con.Close()
|
|
|
|
c.con = nil
|
2020-10-27 01:40:03 +01:00
|
|
|
log.Debug("client.disconnect()")
|
2020-10-26 23:16:27 +01:00
|
|
|
}
|
2022-10-12 13:31:45 +02:00
|
|
|
c.client = nil
|
2020-10-26 23:16:27 +01:00
|
|
|
}
|
|
|
|
|
2018-04-02 18:26:04 +02:00
|
|
|
func (c *Client) ping(ts time.Time) (err error) {
|
2018-04-06 14:48:43 +02:00
|
|
|
if c.Connected() == false {
|
2020-03-16 01:37:33 +01:00
|
|
|
return fmt.Errorf("service is not connected")
|
2018-04-02 18:26:04 +02:00
|
|
|
}
|
|
|
|
|
2018-04-06 14:48:43 +02:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2018-04-02 18:26:04 +02:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
2020-03-16 01:37:33 +01:00
|
|
|
reqID := uint64(ts.UnixNano())
|
2018-04-06 01:44:15 +02:00
|
|
|
|
2019-10-20 23:25:21 +02:00
|
|
|
pReq := &protocol.PingRequest{
|
2020-03-16 01:37:33 +01:00
|
|
|
Id: reqID,
|
2018-04-08 15:32:20 +02:00
|
|
|
Stats: c.stats.Serialize(),
|
2019-06-29 13:46:26 +02:00
|
|
|
}
|
2019-10-20 23:25:21 +02:00
|
|
|
c.stats.RLock()
|
|
|
|
pong, err := c.client.Ping(ctx, pReq)
|
|
|
|
c.stats.RUnlock()
|
2018-04-02 18:26:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
if pong.Id != reqID {
|
|
|
|
return fmt.Errorf("Expected pong with id 0x%x, got 0x%x", reqID, pong.Id)
|
2018-04-02 18:26:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
// Ask sends a request to the server, with the values of a connection to be
|
|
|
|
// allowed or denied.
|
2021-02-18 17:21:50 +03:00
|
|
|
func (c *Client) Ask(con *conman.Connection) *rule.Rule {
|
2021-04-11 20:55:14 +02:00
|
|
|
if c.client == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-04 00:38:11 +02:00
|
|
|
// FIXME: if timeout is fired, the rule is not added to the list in the GUI
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*120)
|
2018-04-02 18:11:36 +02:00
|
|
|
defer cancel()
|
2018-04-08 15:32:20 +02:00
|
|
|
reply, err := c.client.AskRule(ctx, con.Serialize())
|
2018-04-02 18:11:36 +02:00
|
|
|
if err != nil {
|
2020-06-04 00:38:11 +02:00
|
|
|
log.Warning("Error while asking for rule: %s - %v", err, con)
|
2021-02-18 17:21:50 +03:00
|
|
|
return nil
|
2018-04-02 18:11:36 +02:00
|
|
|
}
|
2018-04-02 05:25:32 +02:00
|
|
|
|
2020-06-19 18:02:09 +02:00
|
|
|
r, err := rule.Deserialize(reply)
|
|
|
|
if err != nil {
|
2021-02-18 17:21:50 +03:00
|
|
|
return nil
|
2020-06-19 18:02:09 +02:00
|
|
|
}
|
2021-02-18 17:21:50 +03:00
|
|
|
return r
|
2018-04-02 05:25:32 +02:00
|
|
|
}
|
2019-11-01 01:00:10 +01:00
|
|
|
|
2022-10-12 13:31:45 +02:00
|
|
|
// PostAlert queues a new message to be delivered to the server
|
|
|
|
func (c *Client) PostAlert(atype protocol.Alert_Type, awhat protocol.Alert_What, action protocol.Alert_Action, prio protocol.Alert_Priority, data interface{}) {
|
|
|
|
if len(c.alertsChan) > maxQueuedAlerts-1 {
|
|
|
|
// pop oldest alert if channel is full
|
|
|
|
log.Debug("PostAlert() queue full, popping alert (%d)", len(c.alertsChan))
|
|
|
|
<-c.alertsChan
|
|
|
|
}
|
|
|
|
if c.Connected() == false {
|
|
|
|
log.Debug("UI not connected, queueing alert: %d", len(c.alertsChan))
|
|
|
|
}
|
|
|
|
c.alertsChan <- *NewAlert(atype, awhat, action, prio, data)
|
|
|
|
}
|
|
|
|
|
2020-03-16 01:37:33 +01:00
|
|
|
func (c *Client) monitorConfigWorker() {
|
2019-11-01 01:00:10 +01:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case event := <-c.configWatcher.Events:
|
|
|
|
if (event.Op&fsnotify.Write == fsnotify.Write) || (event.Op&fsnotify.Remove == fsnotify.Remove) {
|
2020-04-19 20:13:31 +02:00
|
|
|
c.loadDiskConfiguration(true)
|
2019-11-01 01:00:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|