diff --git a/daemon/procmon/details.go b/daemon/procmon/details.go new file mode 100644 index 00000000..d099ccf3 --- /dev/null +++ b/daemon/procmon/details.go @@ -0,0 +1,164 @@ +package procmon + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "strconv" + "strings" + + "github.com/gustavo-iniguez-goya/opensnitch/daemon/core" +) + +// GetInfo collects information of a process. +func (p *Process) GetInfo() error { + if err := p.readPath(); err != nil { + return err + } + p.readCwd() + p.readCmdline() + p.readEnv() + p.readDescriptors() + p.readIOStats() + p.readStatus() + p.cleanPath() + + return nil +} + +func (p *Process) setCwd(cwd string) { + p.CWD = cwd +} + +func (p *Process) readCwd() { + if link, err := os.Readlink(fmt.Sprintf("/proc/%d/cwd", p.ID)); err == nil { + p.CWD = link + } +} + +// read and parse environment variables of a process. +func (p *Process) readEnv() { + if data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/environ", p.ID)); err == nil { + for _, s := range strings.Split(string(data), "\x00") { + parts := strings.SplitN(core.Trim(s), "=", 2) + if parts != nil && len(parts) == 2 { + key := core.Trim(parts[0]) + val := core.Trim(parts[1]) + p.Env[key] = val + } + } + } +} + +func (p *Process) readPath() error { + linkName := fmt.Sprint("/proc/", p.ID, "/exe") + if _, err := os.Lstat(linkName); err != nil { + return err + } + + if link, err := os.Readlink(linkName); err == nil { + p.Path = link + } + + return nil +} + +func (p *Process) readCmdline() { + if data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", p.ID)); err == nil { + for i, b := range data { + if b == 0x00 { + data[i] = byte(' ') + } + } + + p.Args = make([]string, 0) + + args := strings.Split(string(data), " ") + for _, arg := range args { + arg = core.Trim(arg) + if arg != "" { + p.Args = append(p.Args, arg) + } + } + } +} + +func (p *Process) readDescriptors() { + f, err := os.Open(fmt.Sprint("/proc/", p.ID, "/fd/")) + if err != nil { + return + } + fDesc, err := f.Readdir(-1) + f.Close() + p.Descriptors = nil + + for _, fd := range fDesc { + tempFd := &procDescriptors{ + Name: fd.Name(), + } + if link, err := os.Readlink(fmt.Sprint("/proc/", p.ID, "/fd/", fd.Name())); err == nil { + tempFd.SymLink = link + if linkInfo, err := os.Lstat(link); err == nil { + tempFd.Size = linkInfo.Size() + tempFd.ModTime = linkInfo.ModTime() + } + } + p.Descriptors = append(p.Descriptors, tempFd) + } +} + +func (p *Process) readIOStats() { + f, err := os.Open(fmt.Sprint("/proc/", p.ID, "/io")) + if err != nil { + return + } + defer f.Close() + + p.IOStats = &procIOstats{} + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + s := strings.Split(scanner.Text(), " ") + switch s[0] { + case "rchar:": + p.IOStats.RChar, _ = strconv.ParseInt(s[1], 10, 64) + case "wchar:": + p.IOStats.WChar, _ = strconv.ParseInt(s[1], 10, 64) + case "syscr:": + p.IOStats.SyscallRead, _ = strconv.ParseInt(s[1], 10, 64) + case "syscw:": + p.IOStats.SyscallWrite, _ = strconv.ParseInt(s[1], 10, 64) + case "read_bytes:": + p.IOStats.ReadBytes, _ = strconv.ParseInt(s[1], 10, 64) + case "write_bytes:": + p.IOStats.WriteBytes, _ = strconv.ParseInt(s[1], 10, 64) + } + } +} + +func (p *Process) readStatus() { + if data, err := ioutil.ReadFile(fmt.Sprint("/proc/", p.ID, "/status")); err == nil { + p.Status = string(data) + } + if data, err := ioutil.ReadFile(fmt.Sprint("/proc/", p.ID, "/stat")); err == nil { + p.Stat = string(data) + } + if data, err := ioutil.ReadFile(fmt.Sprint("/proc/", p.ID, "/stack")); err == nil { + p.Stack = string(data) + } + if data, err := ioutil.ReadFile(fmt.Sprint("/proc/", p.ID, "/maps")); err == nil { + p.Maps = string(data) + } + if data, err := ioutil.ReadFile(fmt.Sprint("/proc/", p.ID, "/statm")); err == nil { + p.Statm = &procStatm{} + fmt.Sscanf(string(data), "%d %d %d %d %d %d %d", &p.Statm.Size, &p.Statm.Resident, &p.Statm.Shared, &p.Statm.Text, &p.Statm.Lib, &p.Statm.Data, &p.Statm.Dt) + } +} + +func (p *Process) cleanPath() { + pathLen := len(p.Path) + if pathLen >= 10 && p.Path[pathLen-10:] == " (deleted)" { + p.Path = p.Path[:len(p.Path)-10] + } +} diff --git a/daemon/procmon/parse.go b/daemon/procmon/parse.go index f948ead2..45c49188 100644 --- a/daemon/procmon/parse.go +++ b/daemon/procmon/parse.go @@ -2,12 +2,10 @@ package procmon import ( "fmt" - "io/ioutil" "os" "strings" "time" - "github.com/gustavo-iniguez-goya/opensnitch/daemon/core" "github.com/gustavo-iniguez-goya/opensnitch/daemon/log" "github.com/gustavo-iniguez-goya/opensnitch/daemon/procmon/audit" ) @@ -85,50 +83,6 @@ func GetPIDFromINode(inode int, inodeKey string) int { return found } -func cleanPath(proc *Process) { - pathLen := len(proc.Path) - if pathLen >= 10 && proc.Path[pathLen-10:] == " (deleted)" { - proc.Path = proc.Path[:len(proc.Path)-10] - } -} - -func parseCmdLine(proc *Process) { - if data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", proc.ID)); err == nil { - for i, b := range data { - if b == 0x00 { - data[i] = byte(' ') - } - } - - args := strings.Split(string(data), " ") - for _, arg := range args { - arg = core.Trim(arg) - if arg != "" { - proc.Args = append(proc.Args, arg) - } - } - } -} - -func parseCWD(proc *Process) { - if link, err := os.Readlink(fmt.Sprintf("/proc/%d/cwd", proc.ID)); err == nil { - proc.CWD = link - } -} - -func parseEnv(proc *Process) { - if data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/environ", proc.ID)); err == nil { - for _, s := range strings.Split(string(data), "\x00") { - parts := strings.SplitN(core.Trim(s), "=", 2) - if parts != nil && len(parts) == 2 { - key := core.Trim(parts[0]) - val := core.Trim(parts[1]) - proc.Env[key] = val - } - } - } -} - // FindProcess checks if a process exists given a PID. // If it exists in /proc, a new Process{} object is returned with the details // to identify a process (cmdline, name, environment variables, etc). @@ -141,14 +95,14 @@ func FindProcess(pid int, interceptUnknown bool) *Process { audit.Lock.RLock() proc := NewProcess(pid, aevent.ProcPath) proc.Args = strings.Split(strings.Replace(aevent.ProcCmdLine, "\x00", " ", -1), " ") - proc.CWD = aevent.ProcDir + proc.setCwd(aevent.ProcDir) audit.Lock.RUnlock() // if the proc dir contains non alhpa-numeric chars the field is empty if proc.CWD == "" { - parseCWD(proc) + proc.readCwd() } - parseEnv(proc) - cleanPath(proc) + proc.readEnv() + proc.cleanPath() return proc } @@ -162,10 +116,10 @@ func FindProcess(pid int, interceptUnknown bool) *Process { if link, err := os.Readlink(linkName); err == nil { proc := NewProcess(pid, link) - parseCmdLine(proc) - parseCWD(proc) - parseEnv(proc) - cleanPath(proc) + proc.readCmdline() + proc.readCwd() + proc.readEnv() + proc.cleanPath() return proc } diff --git a/daemon/procmon/process.go b/daemon/procmon/process.go index 574d672f..fafd4dd5 100644 --- a/daemon/procmon/process.go +++ b/daemon/procmon/process.go @@ -1,17 +1,53 @@ package procmon import ( + "time" + "github.com/gustavo-iniguez-goya/opensnitch/daemon/log" "github.com/gustavo-iniguez-goya/opensnitch/daemon/procmon/audit" ) -// Process holds the information of a process. +// man 5 proc; man procfs +type procIOstats struct { + RChar int64 + WChar int64 + SyscallRead int64 + SyscallWrite int64 + ReadBytes int64 + WriteBytes int64 +} + +type procDescriptors struct { + Name string + SymLink string + Size int64 + ModTime time.Time +} + +type procStatm struct { + Size int64 + Resident int64 + Shared int64 + Text int64 + Lib int64 + Data int64 // data + stack + Dt int +} + +// Process holds the details of a process. type Process struct { - ID int - Path string - Args []string - Env map[string]string - CWD string + ID int + Path string + Args []string + Env map[string]string + CWD string + Descriptors []*procDescriptors + IOStats *procIOstats + Status string + Stat string + Statm *procStatm + Stack string + Maps string } // NewProcess returns a new Process structure. diff --git a/daemon/ui/notifications.go b/daemon/ui/notifications.go index 416012d3..9af18bcb 100644 --- a/daemon/ui/notifications.go +++ b/daemon/ui/notifications.go @@ -1,9 +1,11 @@ package ui import ( + "encoding/json" "fmt" "io" "io/ioutil" + "strconv" "strings" "time" @@ -16,6 +18,8 @@ import ( "golang.org/x/net/context" ) +var stopMonitoringProcess = make(chan int) + // NewReply constructs a new protocol notification reply func NewReply(rID uint64, replyCode protocol.NotificationReplyCode, data string) *protocol.NotificationReply { return &protocol.NotificationReply{ @@ -48,13 +52,42 @@ func (c *Client) getClientConfig() *protocol.ClientConfig { } } +func (c *Client) monitorProcessDetails(pid int, stream protocol.UI_NotificationsClient, notification *protocol.Notification) { + p := procmon.NewProcess(pid, "") + ticker := time.NewTicker(2 * time.Second) + + for { + select { + case _pid := <-stopMonitoringProcess: + if _pid != pid { + continue + } + goto Exit + case <-ticker.C: + if err := p.GetInfo(); err != nil { + c.sendNotificationReply(stream, notification.Id, notification.Data, err) + goto Exit + } + + pJSON, err := json.Marshal(p) + notification.Data = string(pJSON) + if errs := c.sendNotificationReply(stream, notification.Id, notification.Data, err); errs != nil { + goto Exit + } + } + } + +Exit: + ticker.Stop() +} + func (c *Client) handleActionChangeConfig(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { log.Info("[notification] Reloading configuration") // Parse received configuration first, to get the new proc monitor method. newConf, err := c.parseConf(notification.Data) if err != nil { log.Warning("[notification] error parsing received config: %v", notification.Data) - c.sendNotificationReply(stream, notification.Id, err) + c.sendNotificationReply(stream, notification.Id, "", err) return } @@ -73,7 +106,7 @@ func (c *Client) handleActionChangeConfig(stream protocol.UI_NotificationsClient procmon.Init() } - c.sendNotificationReply(stream, notification.Id, err) + c.sendNotificationReply(stream, notification.Id, "", err) } func (c *Client) handleActionEnableRule(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { @@ -86,7 +119,7 @@ func (c *Client) handleActionEnableRule(stream protocol.UI_NotificationsClient, // save to disk only if the duration is rule.Always err = c.rules.Replace(r, r.Duration == rule.Always) } - c.sendNotificationReply(stream, notification.Id, err) + c.sendNotificationReply(stream, notification.Id, "", err) } func (c *Client) handleActionDisableRule(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { @@ -97,7 +130,7 @@ func (c *Client) handleActionDisableRule(stream protocol.UI_NotificationsClient, r.Enabled = false err = c.rules.Replace(r, r.Duration == rule.Always) } - c.sendNotificationReply(stream, notification.Id, err) + c.sendNotificationReply(stream, notification.Id, "", err) } func (c *Client) handleActionChangeRule(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { @@ -114,7 +147,7 @@ func (c *Client) handleActionChangeRule(stream protocol.UI_NotificationsClient, rErr = err } } - c.sendNotificationReply(stream, notification.Id, rErr) + c.sendNotificationReply(stream, notification.Id, "", rErr) } func (c *Client) handleActionDeleteRule(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { @@ -126,23 +159,53 @@ func (c *Client) handleActionDeleteRule(stream protocol.UI_NotificationsClient, log.Error("[notification] Error deleting rule: ", err, rul) } } - c.sendNotificationReply(stream, notification.Id, err) + c.sendNotificationReply(stream, notification.Id, "", err) +} + +func (c *Client) handleActionMonitorProcess(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { + pid, err := strconv.Atoi(notification.Data) + if err != nil { + log.Error("parsing PID to monitor") + return + } + if !core.Exists(fmt.Sprint("/proc/", pid)) { + c.sendNotificationReply(stream, notification.Id, "", fmt.Errorf("The process is no longer running")) + return + } + go c.monitorProcessDetails(pid, stream, notification) +} + +func (c *Client) handleActionStopMonitorProcess(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { + pid, err := strconv.Atoi(notification.Data) + if err != nil { + log.Error("parsing PID to stop monitor") + c.sendNotificationReply(stream, notification.Id, "", fmt.Errorf("Error stopping monitor: ", notification.Data)) + return + } + stopMonitoringProcess <- pid + c.sendNotificationReply(stream, notification.Id, "", nil) } func (c *Client) handleNotification(stream protocol.UI_NotificationsClient, notification *protocol.Notification) { switch { + case notification.Type == protocol.Action_MONITOR_PROCESS: + c.handleActionMonitorProcess(stream, notification) + + case notification.Type == protocol.Action_STOP_MONITOR_PROCESS: + c.handleActionStopMonitorProcess(stream, notification) + case notification.Type == protocol.Action_CHANGE_CONFIG: c.handleActionChangeConfig(stream, notification) case notification.Type == protocol.Action_LOAD_FIREWALL: log.Info("[notification] starting firewall") firewall.Init(nil) - c.sendNotificationReply(stream, notification.Id, nil) + c.sendNotificationReply(stream, notification.Id, "", nil) case notification.Type == protocol.Action_UNLOAD_FIREWALL: log.Info("[notification] stopping firewall") firewall.Stop(nil) - c.sendNotificationReply(stream, notification.Id, nil) + c.sendNotificationReply(stream, notification.Id, "", nil) // ENABLE_RULE just replaces the rule on disk case notification.Type == protocol.Action_ENABLE_RULE: @@ -160,15 +223,18 @@ func (c *Client) handleNotification(stream protocol.UI_NotificationsClient, noti } } -func (c *Client) sendNotificationReply(stream protocol.UI_NotificationsClient, nID uint64, err error) { - reply := NewReply(nID, protocol.NotificationReplyCode_OK, "") +func (c *Client) sendNotificationReply(stream protocol.UI_NotificationsClient, nID uint64, data string, err error) error { + reply := NewReply(nID, protocol.NotificationReplyCode_OK, data) if err != nil { reply.Code = protocol.NotificationReplyCode_ERROR reply.Data = fmt.Sprint(err) } if err := stream.Send(reply); err != nil { log.Error("Error replying to notification:", err, reply.Id) + return err } + + return nil } // Subscribe opens a connection with the server (UI), to start diff --git a/daemon/ui/protocol/ui.pb.go b/daemon/ui/protocol/ui.pb.go index a2ea75ee..6e4f6e8e 100644 --- a/daemon/ui/protocol/ui.pb.go +++ b/daemon/ui/protocol/ui.pb.go @@ -27,42 +27,48 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type Action int32 const ( - Action_NONE Action = 0 - Action_LOAD_FIREWALL Action = 1 - Action_UNLOAD_FIREWALL Action = 2 - Action_CHANGE_CONFIG Action = 3 - Action_ENABLE_RULE Action = 4 - Action_DISABLE_RULE Action = 5 - Action_DELETE_RULE Action = 6 - Action_CHANGE_RULE Action = 7 - Action_LOG_LEVEL Action = 8 - Action_STOP Action = 9 + Action_NONE Action = 0 + Action_LOAD_FIREWALL Action = 1 + Action_UNLOAD_FIREWALL Action = 2 + Action_CHANGE_CONFIG Action = 3 + Action_ENABLE_RULE Action = 4 + Action_DISABLE_RULE Action = 5 + Action_DELETE_RULE Action = 6 + Action_CHANGE_RULE Action = 7 + Action_LOG_LEVEL Action = 8 + Action_STOP Action = 9 + Action_MONITOR_PROCESS Action = 10 + Action_STOP_MONITOR_PROCESS Action = 11 ) var Action_name = map[int32]string{ - 0: "NONE", - 1: "LOAD_FIREWALL", - 2: "UNLOAD_FIREWALL", - 3: "CHANGE_CONFIG", - 4: "ENABLE_RULE", - 5: "DISABLE_RULE", - 6: "DELETE_RULE", - 7: "CHANGE_RULE", - 8: "LOG_LEVEL", - 9: "STOP", + 0: "NONE", + 1: "LOAD_FIREWALL", + 2: "UNLOAD_FIREWALL", + 3: "CHANGE_CONFIG", + 4: "ENABLE_RULE", + 5: "DISABLE_RULE", + 6: "DELETE_RULE", + 7: "CHANGE_RULE", + 8: "LOG_LEVEL", + 9: "STOP", + 10: "MONITOR_PROCESS", + 11: "STOP_MONITOR_PROCESS", } var Action_value = map[string]int32{ - "NONE": 0, - "LOAD_FIREWALL": 1, - "UNLOAD_FIREWALL": 2, - "CHANGE_CONFIG": 3, - "ENABLE_RULE": 4, - "DISABLE_RULE": 5, - "DELETE_RULE": 6, - "CHANGE_RULE": 7, - "LOG_LEVEL": 8, - "STOP": 9, + "NONE": 0, + "LOAD_FIREWALL": 1, + "UNLOAD_FIREWALL": 2, + "CHANGE_CONFIG": 3, + "ENABLE_RULE": 4, + "DISABLE_RULE": 5, + "DELETE_RULE": 6, + "CHANGE_RULE": 7, + "LOG_LEVEL": 8, + "STOP": 9, + "MONITOR_PROCESS": 10, + "STOP_MONITOR_PROCESS": 11, } func (x Action) String() string { @@ -711,88 +717,90 @@ func init() { } var fileDescriptor_63867a62624c1283 = []byte{ - // 1292 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xdf, 0x73, 0xd3, 0xc6, - 0x13, 0x8f, 0x1d, 0x5b, 0x96, 0xd6, 0x76, 0xe2, 0x1c, 0x84, 0xaf, 0xbe, 0xa6, 0x85, 0x60, 0x68, - 0x9b, 0xc9, 0x74, 0x32, 0x6d, 0x60, 0x3a, 0xc0, 0xc0, 0x74, 0x8c, 0x11, 0xe0, 0xe2, 0xda, 0x99, - 0x0b, 0xa1, 0x8f, 0x1a, 0x49, 0x77, 0x38, 0x57, 0x84, 0xa4, 0xea, 0x4e, 0xa6, 0xfe, 0x9b, 0xfa, - 0x0f, 0xf4, 0xa9, 0xaf, 0x7d, 0xe9, 0x63, 0xff, 0x98, 0x3e, 0x76, 0xee, 0x4e, 0xb2, 0x94, 0x5f, - 0x74, 0xf2, 0x64, 0xed, 0x67, 0xf7, 0xb3, 0xb7, 0xbb, 0xb7, 0xb7, 0x6b, 0x30, 0x33, 0xb6, 0x9f, - 0xa4, 0xb1, 0x88, 0x91, 0xa9, 0x7e, 0x82, 0x38, 0x1c, 0x64, 0xd0, 0x74, 0x16, 0x34, 0x12, 0x08, - 0x41, 0x43, 0xb0, 0x0f, 0xd4, 0xae, 0xed, 0xd4, 0x76, 0x2d, 0xac, 0xbe, 0xd1, 0x03, 0x80, 0x20, - 0x8e, 0x22, 0x1a, 0x08, 0x16, 0x47, 0x76, 0x7d, 0xa7, 0xb6, 0xdb, 0x3e, 0xb8, 0xbe, 0x5f, 0x70, - 0xf7, 0x47, 0x2b, 0x1d, 0xae, 0xd8, 0xa1, 0x01, 0x34, 0xd2, 0x2c, 0xa4, 0xf6, 0xba, 0xb2, 0xdf, - 0x28, 0xed, 0x71, 0x16, 0x52, 0xac, 0x74, 0x83, 0x3f, 0x4d, 0x80, 0x23, 0xe1, 0x09, 0xc6, 0x05, - 0x0b, 0x38, 0xfa, 0x02, 0x36, 0x88, 0x47, 0x3f, 0xc4, 0x91, 0xbb, 0xa0, 0x29, 0x97, 0x87, 0xe9, - 0x30, 0xba, 0x1a, 0x7d, 0xab, 0x41, 0x74, 0x1d, 0x9a, 0x92, 0xcd, 0x55, 0x28, 0x0d, 0xac, 0x05, - 0x74, 0x03, 0x8c, 0x2c, 0x51, 0xb1, 0xaf, 0x2b, 0x38, 0x97, 0xd0, 0x5d, 0xe8, 0x92, 0x88, 0xbb, - 0x29, 0xe5, 0x49, 0x1c, 0x71, 0xca, 0xed, 0x86, 0x52, 0x77, 0x48, 0xc4, 0x71, 0x81, 0xa1, 0x1d, - 0x68, 0x97, 0xa1, 0x73, 0xbb, 0xa9, 0x4c, 0xaa, 0x10, 0xb2, 0xa1, 0xc5, 0xe6, 0x51, 0x9c, 0x52, - 0x62, 0x1b, 0x4a, 0x5b, 0x88, 0xa8, 0x0f, 0xa6, 0x17, 0x04, 0x34, 0x11, 0x94, 0xd8, 0x2d, 0xa5, - 0x5a, 0xc9, 0x92, 0x45, 0xd2, 0x38, 0x49, 0x28, 0xb1, 0x4d, 0xcd, 0xca, 0x45, 0x74, 0x13, 0x2c, - 0x19, 0xb7, 0x7b, 0xc2, 0x04, 0xb7, 0x2d, 0x4d, 0x93, 0xc0, 0x2b, 0x26, 0x38, 0xba, 0x0d, 0x6d, - 0xa5, 0xfc, 0xc0, 0xb8, 0x8c, 0x18, 0x94, 0x1a, 0x24, 0xf4, 0xa3, 0x42, 0xd0, 0x13, 0x30, 0xfd, - 0xa5, 0xab, 0x4a, 0x6a, 0xb7, 0x77, 0xd6, 0x77, 0xdb, 0x07, 0x77, 0xca, 0x02, 0x97, 0x15, 0xdd, - 0x7f, 0xb6, 0x3c, 0x94, 0xa8, 0x13, 0x89, 0x74, 0x89, 0x5b, 0xbe, 0x96, 0xd0, 0x33, 0x00, 0x7f, - 0xe9, 0x7a, 0x84, 0xa4, 0x94, 0x73, 0xbb, 0xa3, 0xf8, 0x77, 0x2f, 0xe1, 0x0f, 0xb5, 0x95, 0xf6, - 0x60, 0xf9, 0x85, 0x8c, 0x1e, 0x41, 0xcb, 0x5f, 0xba, 0x27, 0x31, 0x17, 0x76, 0x57, 0x39, 0xd8, - 0xb9, 0xc4, 0xc1, 0xab, 0x98, 0x0b, 0xcd, 0x36, 0x7c, 0x25, 0xe4, 0xd4, 0x24, 0x4e, 0x85, 0xbd, - 0xf1, 0x49, 0xea, 0x61, 0x9c, 0x96, 0x54, 0x29, 0xa0, 0xef, 0xc0, 0xf0, 0x97, 0x6e, 0xc6, 0x88, - 0xbd, 0xa9, 0x98, 0xb7, 0x2f, 0x61, 0x1e, 0x33, 0xa2, 0x89, 0x4d, 0x5f, 0x7e, 0xa3, 0xd7, 0xd0, - 0xf5, 0x97, 0x2e, 0xfd, 0x95, 0x06, 0x99, 0xf0, 0xfc, 0x90, 0xda, 0x3d, 0x45, 0xff, 0xf2, 0x12, - 0xba, 0xb3, 0x32, 0xd4, 0x5e, 0x3a, 0x7e, 0x05, 0x42, 0x5f, 0x81, 0x41, 0xe5, 0x63, 0xe1, 0xf6, - 0x96, 0xf2, 0xb2, 0x59, 0x7a, 0x51, 0x8f, 0x08, 0xe7, 0xea, 0xfe, 0x63, 0xe8, 0x54, 0x2f, 0x00, - 0xf5, 0x60, 0xfd, 0x3d, 0x5d, 0xe6, 0x4d, 0x2d, 0x3f, 0x65, 0x2b, 0x2f, 0xbc, 0x30, 0xa3, 0x45, - 0x2b, 0x2b, 0xe1, 0x71, 0xfd, 0x61, 0xad, 0xff, 0x04, 0x36, 0x4e, 0x17, 0xff, 0x4a, 0xec, 0x47, - 0xd0, 0xae, 0x54, 0xfe, 0xea, 0xd4, 0x55, 0xe5, 0xaf, 0x44, 0x7d, 0x08, 0x50, 0x96, 0xfe, 0x4a, - 0xcc, 0xef, 0x61, 0xeb, 0x5c, 0xd5, 0xaf, 0xe2, 0x60, 0x30, 0x86, 0xf6, 0x21, 0x8b, 0xe6, 0x98, - 0xfe, 0x92, 0x51, 0x2e, 0xd0, 0x06, 0xd4, 0x19, 0x51, 0xcc, 0x06, 0xae, 0x33, 0x82, 0xf6, 0xa0, - 0xc9, 0x85, 0x27, 0xf8, 0xf9, 0xe9, 0x55, 0xde, 0x3b, 0xd6, 0x26, 0x83, 0x9b, 0x60, 0x69, 0x57, - 0x49, 0xb8, 0x3c, 0xeb, 0x68, 0xf0, 0xd7, 0x3a, 0x40, 0x39, 0xf0, 0xe4, 0xdb, 0x2f, 0x3c, 0xe5, - 0x71, 0xae, 0x64, 0xb4, 0x0d, 0x06, 0x4f, 0x03, 0x97, 0x25, 0xea, 0x50, 0x0b, 0x37, 0x79, 0x1a, - 0x8c, 0x13, 0xf4, 0x7f, 0x30, 0x25, 0xac, 0xda, 0x5f, 0x4e, 0xaa, 0x2e, 0x6e, 0xf1, 0x34, 0x50, - 0xdd, 0xbd, 0x0d, 0x06, 0xe1, 0x42, 0x32, 0x1a, 0x9a, 0x41, 0xb8, 0xd0, 0x0c, 0x09, 0xab, 0xb7, - 0xd6, 0x54, 0x8a, 0x16, 0xe1, 0x42, 0x3d, 0xa5, 0x5c, 0xa5, 0x9c, 0x19, 0xda, 0x19, 0xe1, 0x42, - 0x39, 0xfb, 0x1f, 0xb4, 0x32, 0x4e, 0x53, 0x97, 0xe9, 0xa9, 0xd4, 0xc5, 0x86, 0x14, 0xc7, 0x04, - 0x7d, 0x0e, 0x90, 0xa4, 0x71, 0x40, 0x39, 0x97, 0x3a, 0x53, 0xe9, 0xac, 0x1c, 0x19, 0x13, 0x74, - 0x07, 0x3a, 0x85, 0x3a, 0xf1, 0xc4, 0x89, 0x9a, 0x4d, 0x16, 0x6e, 0xe7, 0xd8, 0xa1, 0x27, 0x4e, - 0xe4, 0x78, 0x2a, 0x4c, 0x82, 0x8f, 0x44, 0x8d, 0x27, 0x0b, 0x17, 0x4e, 0x47, 0x1f, 0x4f, 0xf9, - 0xf0, 0xd2, 0x39, 0x57, 0x23, 0xaa, 0xf4, 0x31, 0x4c, 0xe7, 0x1c, 0x39, 0xa5, 0x0f, 0x1a, 0x2d, - 0xf2, 0x21, 0x74, 0xef, 0xa2, 0xad, 0xb2, 0x7f, 0xa8, 0xed, 0x9c, 0x68, 0xa1, 0x5f, 0x63, 0x71, - 0x92, 0x13, 0x2d, 0xfa, 0x4f, 0x61, 0xf3, 0x8c, 0xfa, 0xbf, 0xda, 0xc6, 0xaa, 0xb6, 0xcd, 0xcf, - 0x60, 0xce, 0x12, 0x9a, 0x7a, 0x22, 0x4e, 0xd5, 0xea, 0x5b, 0x26, 0xe5, 0xea, 0x5b, 0x26, 0x54, - 0xce, 0xef, 0x58, 0xea, 0x23, 0x92, 0x73, 0x0b, 0x51, 0x5a, 0x13, 0x4f, 0x78, 0xea, 0x0a, 0x2d, - 0xac, 0xbe, 0xd1, 0x67, 0x60, 0x71, 0x1a, 0x71, 0x26, 0xd8, 0x82, 0xaa, 0x2b, 0x34, 0x71, 0x09, - 0x0c, 0x7e, 0xaf, 0x41, 0x43, 0xee, 0x3e, 0x49, 0x8d, 0xbc, 0x72, 0xc7, 0xca, 0x6f, 0x79, 0x10, - 0x8d, 0x64, 0xeb, 0xeb, 0x83, 0x4c, 0x5c, 0x88, 0xe8, 0x96, 0xbc, 0x2e, 0x1a, 0x50, 0x42, 0xa3, - 0x40, 0xef, 0x36, 0x13, 0x57, 0x10, 0xb9, 0xf7, 0x3c, 0xbd, 0x99, 0x75, 0xd3, 0xe4, 0x92, 0x6c, - 0x4d, 0x92, 0xa5, 0x9e, 0xd2, 0xe8, 0xae, 0x59, 0xc9, 0x68, 0x1f, 0xcc, 0x38, 0x4f, 0x5b, 0xb5, - 0x4d, 0xfb, 0x00, 0x95, 0x95, 0x2f, 0x0a, 0x82, 0x57, 0x36, 0x83, 0xbf, 0x6b, 0xd0, 0x19, 0x85, - 0x8c, 0x46, 0x62, 0x14, 0x47, 0xef, 0xd8, 0xfc, 0xdc, 0xfb, 0x2a, 0x52, 0xaa, 0x9f, 0x4e, 0xa9, - 0x58, 0xe3, 0xba, 0x48, 0x85, 0x88, 0xbe, 0x86, 0x2d, 0xc6, 0x5f, 0xb0, 0x94, 0x7e, 0xf4, 0xc2, - 0x10, 0x67, 0x51, 0xc4, 0xa2, 0x79, 0x5e, 0xaf, 0xf3, 0x0a, 0x99, 0x60, 0xa0, 0x4e, 0xcd, 0xd3, - 0xc8, 0x25, 0x99, 0x60, 0x18, 0xcf, 0x27, 0x74, 0x41, 0xc3, 0xbc, 0xf7, 0x57, 0x32, 0xba, 0x57, - 0xfc, 0x45, 0x68, 0xa9, 0xbe, 0x3a, 0xfb, 0xef, 0x43, 0x2b, 0x07, 0x7f, 0xd4, 0xa0, 0x33, 0x8d, - 0x05, 0x7b, 0xc7, 0x02, 0x5d, 0x97, 0xb3, 0x69, 0xdd, 0x02, 0x08, 0x54, 0xda, 0xd3, 0x32, 0xb9, - 0x0a, 0x22, 0xf5, 0x9c, 0xa6, 0x0b, 0x9a, 0x2a, 0xbd, 0xce, 0xb2, 0x82, 0xa0, 0x7b, 0x79, 0x4b, - 0xc9, 0xdc, 0x36, 0x0e, 0x7a, 0x65, 0x14, 0x43, 0xfd, 0x7f, 0x49, 0x37, 0x59, 0xd1, 0x4a, 0xcd, - 0x4a, 0x2b, 0xad, 0x12, 0x30, 0x3e, 0x95, 0x40, 0x08, 0x5b, 0xd5, 0xf8, 0x2f, 0x1c, 0x59, 0xe8, - 0x3e, 0x34, 0x82, 0x98, 0xe8, 0xf0, 0x37, 0xaa, 0x1b, 0xf3, 0x1c, 0x75, 0x14, 0x13, 0x8a, 0x95, - 0xf1, 0x45, 0xed, 0xbd, 0xf7, 0x5b, 0x0d, 0x0c, 0x1d, 0x38, 0x32, 0xa1, 0x31, 0x9d, 0x4d, 0x9d, - 0xde, 0x1a, 0xda, 0x82, 0xee, 0x64, 0x36, 0x7c, 0xee, 0xbe, 0x18, 0x63, 0xe7, 0xa7, 0xe1, 0x64, - 0xd2, 0xab, 0xa1, 0x6b, 0xb0, 0x79, 0x3c, 0x3d, 0x0d, 0xd6, 0xa5, 0xdd, 0xe8, 0xd5, 0x70, 0xfa, - 0xd2, 0x71, 0x47, 0xb3, 0xe9, 0x8b, 0xf1, 0xcb, 0xde, 0x3a, 0xda, 0x84, 0xb6, 0x33, 0x1d, 0x3e, - 0x9b, 0x38, 0x2e, 0x3e, 0x9e, 0x38, 0xbd, 0x06, 0xea, 0x41, 0xe7, 0xf9, 0xf8, 0xa8, 0x44, 0x9a, - 0xd2, 0xe4, 0xb9, 0x33, 0x71, 0xde, 0xe4, 0x80, 0x21, 0x81, 0xdc, 0x8d, 0x02, 0x5a, 0xa8, 0x0b, - 0xd6, 0x64, 0xf6, 0xd2, 0x9d, 0x38, 0x6f, 0x9d, 0x49, 0xcf, 0x94, 0x81, 0x1d, 0xbd, 0x99, 0x1d, - 0xf6, 0xac, 0xbd, 0x3d, 0xd8, 0xbe, 0x30, 0x41, 0x64, 0x40, 0x7d, 0xf6, 0xba, 0xb7, 0x86, 0x2c, - 0x68, 0x3a, 0x18, 0xcf, 0x70, 0xaf, 0x76, 0xf0, 0x4f, 0x0d, 0xea, 0xc7, 0x63, 0xf4, 0x00, 0x1a, - 0x72, 0xf2, 0xa3, 0xed, 0xb2, 0x46, 0x95, 0xa5, 0xd2, 0xbf, 0x76, 0x16, 0x4e, 0xc2, 0xe5, 0x60, - 0x0d, 0x7d, 0x0b, 0xad, 0x21, 0x7f, 0xaf, 0x5e, 0xf6, 0x85, 0xff, 0x8a, 0xfb, 0x67, 0x2e, 0x6f, - 0xb0, 0x86, 0x9e, 0x82, 0x75, 0x94, 0xf9, 0x3c, 0x48, 0x99, 0x4f, 0xd1, 0x8d, 0x0a, 0xa9, 0xf2, - 0xc6, 0xfa, 0x97, 0xe0, 0x83, 0x35, 0xf4, 0x03, 0x74, 0xab, 0xa9, 0x71, 0x74, 0xf3, 0x13, 0x97, - 0x5a, 0xf5, 0x53, 0x55, 0x0e, 0xd6, 0x76, 0x6b, 0xdf, 0xd4, 0x7c, 0x43, 0x29, 0xef, 0xff, 0x1b, - 0x00, 0x00, 0xff, 0xff, 0x75, 0xf5, 0x8c, 0x39, 0x16, 0x0c, 0x00, 0x00, + // 1315 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xdd, 0x73, 0xd3, 0x46, + 0x10, 0x8f, 0x1d, 0x5b, 0x96, 0xd6, 0x1f, 0x71, 0x16, 0x42, 0x55, 0xd3, 0x42, 0x30, 0xb4, 0xcd, + 0x64, 0x3a, 0x99, 0x36, 0x30, 0x1d, 0x60, 0x60, 0x3a, 0xc6, 0x08, 0x70, 0x31, 0xb6, 0xe7, 0x42, + 0xe8, 0xa3, 0x46, 0x1f, 0x87, 0xa3, 0x62, 0x24, 0x55, 0x77, 0x36, 0xf5, 0x7f, 0xd6, 0xa7, 0xbe, + 0xf6, 0xa5, 0x8f, 0x7d, 0xea, 0x5f, 0xd2, 0xc7, 0xce, 0xdd, 0x49, 0x96, 0xe2, 0x7c, 0x74, 0xf2, + 0x64, 0xed, 0xef, 0xb7, 0xbf, 0xd5, 0xee, 0x6a, 0xef, 0xd6, 0xa0, 0xcf, 0x83, 0x83, 0x38, 0x89, + 0x78, 0x84, 0xba, 0xfc, 0xf1, 0xa2, 0x59, 0x77, 0x0e, 0x55, 0x6b, 0x41, 0x43, 0x8e, 0x08, 0x15, + 0x1e, 0x7c, 0xa4, 0x66, 0x69, 0xb7, 0xb4, 0x67, 0x10, 0xf9, 0x8c, 0x0f, 0x00, 0xbc, 0x28, 0x0c, + 0xa9, 0xc7, 0x83, 0x28, 0x34, 0xcb, 0xbb, 0xa5, 0xbd, 0xfa, 0xe1, 0xf5, 0x83, 0x4c, 0x7b, 0xd0, + 0x5f, 0x71, 0xa4, 0xe0, 0x87, 0x5d, 0xa8, 0x24, 0xf3, 0x19, 0x35, 0x37, 0xa5, 0x7f, 0x2b, 0xf7, + 0x27, 0xf3, 0x19, 0x25, 0x92, 0xeb, 0xfe, 0xa9, 0x03, 0x1c, 0x71, 0x87, 0x07, 0x8c, 0x07, 0x1e, + 0xc3, 0xaf, 0xa0, 0xe5, 0x3b, 0xf4, 0x63, 0x14, 0xda, 0x0b, 0x9a, 0x30, 0xf1, 0x32, 0x95, 0x46, + 0x53, 0xa1, 0xef, 0x14, 0x88, 0xd7, 0xa1, 0x2a, 0xd4, 0x4c, 0xa6, 0x52, 0x21, 0xca, 0xc0, 0x1b, + 0xa0, 0xcd, 0x63, 0x99, 0xfb, 0xa6, 0x84, 0x53, 0x0b, 0xef, 0x42, 0xd3, 0x0f, 0x99, 0x9d, 0x50, + 0x16, 0x47, 0x21, 0xa3, 0xcc, 0xac, 0x48, 0xba, 0xe1, 0x87, 0x8c, 0x64, 0x18, 0xee, 0x42, 0x3d, + 0x4f, 0x9d, 0x99, 0x55, 0xe9, 0x52, 0x84, 0xd0, 0x84, 0x5a, 0x30, 0x0d, 0xa3, 0x84, 0xfa, 0xa6, + 0x26, 0xd9, 0xcc, 0xc4, 0x0e, 0xe8, 0x8e, 0xe7, 0xd1, 0x98, 0x53, 0xdf, 0xac, 0x49, 0x6a, 0x65, + 0x0b, 0x95, 0x9f, 0x44, 0x71, 0x4c, 0x7d, 0x53, 0x57, 0xaa, 0xd4, 0xc4, 0x9b, 0x60, 0x88, 0xbc, + 0xed, 0x93, 0x80, 0x33, 0xd3, 0x50, 0x32, 0x01, 0xbc, 0x0a, 0x38, 0xc3, 0xdb, 0x50, 0x97, 0xe4, + 0xc7, 0x80, 0x89, 0x8c, 0x41, 0xd2, 0x20, 0xa0, 0x37, 0x12, 0xc1, 0x27, 0xa0, 0xbb, 0x4b, 0x5b, + 0xb6, 0xd4, 0xac, 0xef, 0x6e, 0xee, 0xd5, 0x0f, 0xef, 0xe4, 0x0d, 0xce, 0x3b, 0x7a, 0xf0, 0x6c, + 0x39, 0x11, 0xa8, 0x15, 0xf2, 0x64, 0x49, 0x6a, 0xae, 0xb2, 0xf0, 0x19, 0x80, 0xbb, 0xb4, 0x1d, + 0xdf, 0x4f, 0x28, 0x63, 0x66, 0x43, 0xea, 0xef, 0x5e, 0xa0, 0xef, 0x29, 0x2f, 0x15, 0xc1, 0x70, + 0x33, 0x1b, 0x1f, 0x41, 0xcd, 0x5d, 0xda, 0x27, 0x11, 0xe3, 0x66, 0x53, 0x06, 0xd8, 0xbd, 0x20, + 0xc0, 0xab, 0x88, 0x71, 0xa5, 0xd6, 0x5c, 0x69, 0xa4, 0xd2, 0x38, 0x4a, 0xb8, 0xd9, 0xba, 0x54, + 0x3a, 0x89, 0x92, 0x5c, 0x2a, 0x0c, 0xfc, 0x01, 0x34, 0x77, 0x69, 0xcf, 0x03, 0xdf, 0xdc, 0x92, + 0xca, 0xdb, 0x17, 0x28, 0x8f, 0x03, 0x5f, 0x09, 0xab, 0xae, 0x78, 0xc6, 0xd7, 0xd0, 0x74, 0x97, + 0x36, 0xfd, 0x8d, 0x7a, 0x73, 0xee, 0xb8, 0x33, 0x6a, 0xb6, 0xa5, 0xfc, 0xeb, 0x0b, 0xe4, 0xd6, + 0xca, 0x51, 0x45, 0x69, 0xb8, 0x05, 0x08, 0xbf, 0x01, 0x8d, 0x8a, 0xc3, 0xc2, 0xcc, 0x6d, 0x19, + 0x65, 0x2b, 0x8f, 0x22, 0x0f, 0x11, 0x49, 0xe9, 0xce, 0x63, 0x68, 0x14, 0x3f, 0x00, 0xb6, 0x61, + 0xf3, 0x03, 0x5d, 0xa6, 0x43, 0x2d, 0x1e, 0xc5, 0x28, 0x2f, 0x9c, 0xd9, 0x9c, 0x66, 0xa3, 0x2c, + 0x8d, 0xc7, 0xe5, 0x87, 0xa5, 0xce, 0x13, 0x68, 0x9d, 0x6e, 0xfe, 0x95, 0xd4, 0x8f, 0xa0, 0x5e, + 0xe8, 0xfc, 0xd5, 0xa5, 0xab, 0xce, 0x5f, 0x49, 0xfa, 0x10, 0x20, 0x6f, 0xfd, 0x95, 0x94, 0x3f, + 0xc2, 0xf6, 0x99, 0xae, 0x5f, 0x25, 0x40, 0x77, 0x00, 0xf5, 0x49, 0x10, 0x4e, 0x09, 0xfd, 0x75, + 0x4e, 0x19, 0xc7, 0x16, 0x94, 0x03, 0x5f, 0x2a, 0x2b, 0xa4, 0x1c, 0xf8, 0xb8, 0x0f, 0x55, 0xc6, + 0x1d, 0xce, 0xce, 0xde, 0x5e, 0xf9, 0x77, 0x27, 0xca, 0xa5, 0x7b, 0x13, 0x0c, 0x15, 0x2a, 0x9e, + 0x2d, 0xd7, 0x03, 0x75, 0xff, 0xda, 0x04, 0xc8, 0x2f, 0x3c, 0x71, 0xf6, 0xb3, 0x48, 0x69, 0x9e, + 0x2b, 0x1b, 0x77, 0x40, 0x63, 0x89, 0x67, 0x07, 0xb1, 0x7c, 0xa9, 0x41, 0xaa, 0x2c, 0xf1, 0x06, + 0x31, 0x7e, 0x0e, 0xba, 0x80, 0xe5, 0xf8, 0x8b, 0x9b, 0xaa, 0x49, 0x6a, 0x2c, 0xf1, 0xe4, 0x74, + 0xef, 0x80, 0xe6, 0x33, 0x2e, 0x14, 0x15, 0xa5, 0xf0, 0x19, 0x57, 0x0a, 0x01, 0xcb, 0xb3, 0x56, + 0x95, 0x44, 0xcd, 0x67, 0x5c, 0x1e, 0xa5, 0x94, 0x92, 0xc1, 0x34, 0x15, 0xcc, 0x67, 0x5c, 0x06, + 0xfb, 0x0c, 0x6a, 0x73, 0x46, 0x13, 0x3b, 0x50, 0xb7, 0x52, 0x93, 0x68, 0xc2, 0x1c, 0xf8, 0xf8, + 0x25, 0x40, 0x9c, 0x44, 0x1e, 0x65, 0x4c, 0x70, 0xba, 0xe4, 0x8c, 0x14, 0x19, 0xf8, 0x78, 0x07, + 0x1a, 0x19, 0x1d, 0x3b, 0xfc, 0x44, 0xde, 0x4d, 0x06, 0xa9, 0xa7, 0xd8, 0xc4, 0xe1, 0x27, 0xe2, + 0x7a, 0xca, 0x5c, 0xbc, 0x4f, 0xbe, 0xbc, 0x9e, 0x0c, 0x92, 0x05, 0xed, 0x7f, 0x3a, 0x15, 0xc3, + 0x49, 0xa6, 0x4c, 0x5e, 0x51, 0x79, 0x8c, 0x5e, 0x32, 0x65, 0x68, 0xe5, 0x31, 0x68, 0xb8, 0x48, + 0x2f, 0xa1, 0x7b, 0xe7, 0x6d, 0x95, 0x83, 0x89, 0xf2, 0xb3, 0xc2, 0x85, 0x3a, 0x8d, 0xd9, 0x9b, + 0xac, 0x70, 0xd1, 0x79, 0x0a, 0x5b, 0x6b, 0xf4, 0xff, 0x8d, 0x8d, 0x51, 0x1c, 0x9b, 0x5f, 0x40, + 0x1f, 0xc7, 0x34, 0x71, 0x78, 0x94, 0xc8, 0xd5, 0xb7, 0x8c, 0xf3, 0xd5, 0xb7, 0x8c, 0xa9, 0xb8, + 0xbf, 0x23, 0xc1, 0x87, 0x7e, 0xaa, 0xcd, 0x4c, 0xe1, 0xed, 0x3b, 0xdc, 0x91, 0x9f, 0xd0, 0x20, + 0xf2, 0x19, 0xbf, 0x00, 0x83, 0xd1, 0x90, 0x05, 0x3c, 0x58, 0x50, 0xf9, 0x09, 0x75, 0x92, 0x03, + 0xdd, 0xdf, 0x4b, 0x50, 0x11, 0xbb, 0x4f, 0x48, 0x43, 0x27, 0xdf, 0xb1, 0xe2, 0x59, 0xbc, 0x88, + 0x86, 0x62, 0xf4, 0xd5, 0x8b, 0x74, 0x92, 0x99, 0x78, 0x4b, 0x7c, 0x2e, 0xea, 0x51, 0x9f, 0x86, + 0x9e, 0xda, 0x6d, 0x3a, 0x29, 0x20, 0x62, 0xef, 0x39, 0x6a, 0x33, 0xab, 0xa1, 0x49, 0x2d, 0x31, + 0x9a, 0xfe, 0x3c, 0x71, 0x24, 0xa3, 0xa6, 0x66, 0x65, 0xe3, 0x01, 0xe8, 0x51, 0x5a, 0xb6, 0x1c, + 0x9b, 0xfa, 0x21, 0xe6, 0x9d, 0xcf, 0x1a, 0x42, 0x56, 0x3e, 0xdd, 0xbf, 0x4b, 0xd0, 0xe8, 0xcf, + 0x02, 0x1a, 0xf2, 0x7e, 0x14, 0xbe, 0x0f, 0xa6, 0x67, 0xce, 0x57, 0x56, 0x52, 0xf9, 0x74, 0x49, + 0xd9, 0x1a, 0x57, 0x4d, 0xca, 0x4c, 0xfc, 0x16, 0xb6, 0x03, 0xf6, 0x22, 0x48, 0xe8, 0x27, 0x67, + 0x36, 0x23, 0xf3, 0x30, 0x0c, 0xc2, 0x69, 0xda, 0xaf, 0xb3, 0x84, 0x28, 0xd0, 0x93, 0x6f, 0x4d, + 0xcb, 0x48, 0x2d, 0x51, 0xe0, 0x2c, 0x9a, 0x0e, 0xe9, 0x82, 0xce, 0xd2, 0xd9, 0x5f, 0xd9, 0x78, + 0x2f, 0xfb, 0x8b, 0x50, 0x93, 0x73, 0xb5, 0xfe, 0xef, 0x43, 0x91, 0xdd, 0x3f, 0x4a, 0xd0, 0x18, + 0x45, 0x3c, 0x78, 0x1f, 0x78, 0xaa, 0x2f, 0xeb, 0x65, 0xdd, 0x02, 0xf0, 0x64, 0xd9, 0xa3, 0xbc, + 0xb8, 0x02, 0x22, 0x78, 0x46, 0x93, 0x05, 0x4d, 0x24, 0xaf, 0xaa, 0x2c, 0x20, 0x78, 0x2f, 0x1d, + 0x29, 0x51, 0x5b, 0xeb, 0xb0, 0x9d, 0x67, 0xd1, 0x53, 0xff, 0x97, 0xd4, 0x90, 0x65, 0xa3, 0x54, + 0x2d, 0x8c, 0xd2, 0xaa, 0x00, 0xed, 0xb2, 0x02, 0x66, 0xb0, 0x5d, 0xcc, 0xff, 0xdc, 0x2b, 0x0b, + 0xef, 0x43, 0xc5, 0x8b, 0x7c, 0x95, 0x7e, 0xab, 0xb8, 0x31, 0xcf, 0x48, 0xfb, 0x91, 0x4f, 0x89, + 0x74, 0x3e, 0x6f, 0xbc, 0xf7, 0xff, 0x29, 0x81, 0xa6, 0x12, 0x47, 0x1d, 0x2a, 0xa3, 0xf1, 0xc8, + 0x6a, 0x6f, 0xe0, 0x36, 0x34, 0x87, 0xe3, 0xde, 0x73, 0xfb, 0xc5, 0x80, 0x58, 0x3f, 0xf7, 0x86, + 0xc3, 0x76, 0x09, 0xaf, 0xc1, 0xd6, 0xf1, 0xe8, 0x34, 0x58, 0x16, 0x7e, 0xfd, 0x57, 0xbd, 0xd1, + 0x4b, 0xcb, 0xee, 0x8f, 0x47, 0x2f, 0x06, 0x2f, 0xdb, 0x9b, 0xb8, 0x05, 0x75, 0x6b, 0xd4, 0x7b, + 0x36, 0xb4, 0x6c, 0x72, 0x3c, 0xb4, 0xda, 0x15, 0x6c, 0x43, 0xe3, 0xf9, 0xe0, 0x28, 0x47, 0xaa, + 0xc2, 0xe5, 0xb9, 0x35, 0xb4, 0xde, 0xa6, 0x80, 0x26, 0x80, 0x34, 0x8c, 0x04, 0x6a, 0xd8, 0x04, + 0x63, 0x38, 0x7e, 0x69, 0x0f, 0xad, 0x77, 0xd6, 0xb0, 0xad, 0x8b, 0xc4, 0x8e, 0xde, 0x8e, 0x27, + 0x6d, 0x43, 0x64, 0xf1, 0x66, 0x3c, 0x1a, 0xbc, 0x1d, 0x13, 0x7b, 0x42, 0xc6, 0x7d, 0xeb, 0xe8, + 0xa8, 0x0d, 0x68, 0xc2, 0x75, 0x41, 0xdb, 0xeb, 0x4c, 0x7d, 0x7f, 0x1f, 0x76, 0xce, 0xed, 0x07, + 0x6a, 0x50, 0x1e, 0xbf, 0x6e, 0x6f, 0xa0, 0x01, 0x55, 0x8b, 0x90, 0x31, 0x69, 0x97, 0x0e, 0xff, + 0x2d, 0x41, 0xf9, 0x78, 0x80, 0x0f, 0xa0, 0x22, 0x16, 0x05, 0xee, 0xe4, 0x2d, 0x2d, 0xec, 0xa0, + 0xce, 0xb5, 0x75, 0x38, 0x9e, 0x2d, 0xbb, 0x1b, 0xf8, 0x3d, 0xd4, 0x7a, 0xec, 0x83, 0xbc, 0x08, + 0xce, 0xfd, 0x13, 0xdd, 0x59, 0xfb, 0xd6, 0xdd, 0x0d, 0x7c, 0x0a, 0xc6, 0xd1, 0xdc, 0x65, 0x5e, + 0x12, 0xb8, 0x14, 0x6f, 0x14, 0x44, 0x85, 0x23, 0xd9, 0xb9, 0x00, 0xef, 0x6e, 0xe0, 0x4f, 0xd0, + 0x2c, 0x96, 0xc6, 0xf0, 0xe6, 0x25, 0x33, 0x50, 0x8c, 0x53, 0x24, 0xbb, 0x1b, 0x7b, 0xa5, 0xef, + 0x4a, 0xae, 0x26, 0xc9, 0xfb, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xcb, 0xf1, 0x95, 0x55, 0x45, + 0x0c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/proto/ui.proto b/proto/ui.proto index 41a2e830..26487e3c 100644 --- a/proto/ui.proto +++ b/proto/ui.proto @@ -86,6 +86,8 @@ enum Action { CHANGE_RULE = 7; LOG_LEVEL = 8; STOP = 9; + MONITOR_PROCESS = 10; + STOP_MONITOR_PROCESS = 11; } // client configuration sent on Subscribe() diff --git a/ui/opensnitch/desktop_parser.py b/ui/opensnitch/desktop_parser.py index d854b01b..de6d5d9c 100644 --- a/ui/opensnitch/desktop_parser.py +++ b/ui/opensnitch/desktop_parser.py @@ -19,6 +19,7 @@ class LinuxDesktopParser(threading.Thread): self.daemon = True self.running = False self.apps = {} + self.apps_by_name = {} # some things are just weird # (not really, i don't want to keep track of parent pids # just because of icons tho, this hack is way easier) @@ -55,18 +56,45 @@ class LinuxDesktopParser(threading.Thread): return cmd + def _discover_app_icon(self, app_name): + # more hacks + # normally qt will find icons if the system if configured properly. + # if it's not, qt won't be able to find the icon by using QIcon().fromTheme(""), + # so we fallback to try to determine if the icon exist in some well known system paths. + icon_dirs = ("/usr/share/icons/gnome/48x48/apps/", "/usr/share/pixmaps/", "/usr/share/icons/hicolor/48x48/apps/") + icon_exts = (".png", ".xpm", ".svg") + + for idir in icon_dirs: + for iext in icon_exts: + iconPath = idir + app_name + iext + if os.path.exists(iconPath): + print("found on last chance: ", iconPath) + return iconPath + def _parse_desktop_file(self, desktop_path): parser = configparser.ConfigParser(strict=False) # Allow duplicate config entries try: + basename = os.path.basename(desktop_path)[:-8] parser.read(desktop_path, 'utf8') cmd = parser.get('Desktop Entry', 'exec', raw=True, fallback=None) + if cmd == None: + cmd = parser.get('Desktop Entry', 'Exec', raw=True, fallback=None) if cmd is not None: cmd = self._parse_exec(cmd) icon = parser.get('Desktop Entry', 'Icon', raw=True, fallback=None) name = parser.get('Desktop Entry', 'Name', raw=True, fallback=None) + if icon == None: + # Some .desktop files doesn't have the Icon entry + # FIXME: even if we return an icon, if the DE is not properly configured, + # it won't be loaded/displayed. + icon = self._discover_app_icon(basename) + with self.lock: + # The Exec entry may have an absolute path to a binary or just the binary with parameters. + # /path/binary or binary, so save both self.apps[cmd] = (name, icon, desktop_path) + self.apps[basename] = (name, icon, desktop_path) # if the command is a symlink, add the real binary too if os.path.islink(cmd): link_to = os.path.realpath(cmd) @@ -82,8 +110,16 @@ class LinuxDesktopParser(threading.Thread): path = to break + app_name = self.apps.get(path) + if app_name == None: + return self.apps.get(def_name, (def_name, default_icon, None)) + return self.apps.get(path, (def_name, default_icon, None)) + def get_info_by_binname(self, name, default_icon): + def_name = os.path.basename(name) + return self.apps.get(def_name, (def_name, default_icon, None)) + def run(self): self.running = True wm = pyinotify.WatchManager() diff --git a/ui/opensnitch/dialogs/stats.py b/ui/opensnitch/dialogs/stats.py index 2b729bb8..216c5aad 100644 --- a/ui/opensnitch/dialogs/stats.py +++ b/ui/opensnitch/dialogs/stats.py @@ -6,6 +6,7 @@ import sys import os import csv import time +import json from PyQt5 import Qt, QtCore, QtGui, uic, QtWidgets from PyQt5.QtSql import QSqlDatabase, QSqlDatabase, QSqlQueryModel, QSqlQuery, QSqlTableModel @@ -17,6 +18,7 @@ from version import version from nodes import Nodes from dialogs.preferences import PreferencesDialog from dialogs.ruleseditor import RulesEditorDialog +from dialogs.processdetails import ProcessDetailsDialog from customwidgets import ColorizedDelegate DIALOG_UI_PATH = "%s/../res/stats.ui" % os.path.dirname(sys.modules[__name__].__file__) @@ -228,6 +230,9 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self._cfg = Config.get() self._nodes = Nodes.instance() + # TODO: allow to display multiples dialogs + self._proc_details_dialog = ProcessDetailsDialog() + self.daemon_connected = False # skip table updates if a context menu is active self._context_menu_active = False @@ -265,6 +270,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self.delRuleButton.setVisible(False) self.editRuleButton.setVisible(False) self.nodeRuleLabel.setVisible(False) + self.cmdProcDetails.clicked.connect(self._cb_proc_details_clicked) self.TABLES[self.TAB_MAIN]['view'] = self._setup_table(QtWidgets.QTreeView, self.eventsTable, "connections", self.TABLES[self.TAB_MAIN]['display_fields'], @@ -463,21 +469,38 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self._db.remove("DELETE FROM rules WHERE name='%s' AND node='%s'" % (rule.name, node_addr)) self._refresh_active_table() + def _cb_proc_details_clicked(self): + table = self._tables[self.tabWidget.currentIndex()] + nrows = table.model().rowCount() + pids = {} + for row in range(0, nrows): + pid = table.model().index(row, 6).data() + node = table.model().index(row, 1).data() + if pid not in pids: + pids[pid] = node + + self._proc_details_dialog.monitor(pids) + @QtCore.pyqtSlot(ui_pb2.NotificationReply) def _cb_notification_callback(self, reply): #print("[stats dialog] notification reply: ", reply.id, reply.code) if reply.id in self._notifications_sent: - #print("[stats] not received: ", self._notifications_sent[reply.id].type) if reply.code == ui_pb2.ERROR: msgBox = QtWidgets.QMessageBox() msgBox.setText(reply.data) msgBox.setIcon(QtWidgets.QMessageBox.Warning) msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok) + else: + print("[stats] unknown notification received: ", self._notifications_sent[reply.id].type) + def _cb_tab_changed(self, index): if index == self.TAB_MAIN: self._set_events_query() else: + if index == self.TAB_PROCS: + self.cmdProcDetails.setVisible(False) + self._refresh_active_table() def _cb_table_context_menu(self, pos): @@ -571,6 +594,9 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self.editRuleButton.setVisible(False) self.nodeRuleLabel.setText("") self.rulesFilterLine.setVisible(True) + elif cur_idx == StatsDialog.TAB_PROCS: + self.cmdProcDetails.setVisible(False) + model = self._get_active_table().model() self.setQuery(model, self._db.get_query(self.TABLES[cur_idx]['name'], self.TABLES[cur_idx]['display_fields']) + self._get_order()) @@ -586,7 +612,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): elif idx == StatsDialog.COL_PROCS: cur_idx = 4 self.tabWidget.setCurrentIndex(cur_idx) - self._set_process_query(data) + self._set_process_tab_active(data) elif idx == StatsDialog.COL_RULES: cur_idx = 2 self._set_rules_tab_active(row, cur_idx) @@ -715,6 +741,10 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): if self.TABLES[cur_idx].get('cmdCleanStats') != None: self.TABLES[cur_idx]['cmdCleanStats'].setVisible(not state) + def _set_proc_tab_active(self, data): + self.cmdProcDetails.setVisible(False) + self._set_process_query(data) + def _set_rules_tab_active(self, row, cur_idx): data = row.data() self.delRuleButton.setVisible(True) @@ -837,6 +867,9 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): "FROM procs as p, connections as c " \ "WHERE p.what = '%s' AND p.what = c.process GROUP BY c.dst_ip, c.dst_host, c.dst_port, UserID, Action, Node %s" % (data, self._get_order())) + nrows = self._get_active_table().model().rowCount() + self.cmdProcDetails.setVisible(nrows != 0) + def _set_addrs_query(self, data): model = self._get_active_table().model() self.setQuery(model, "SELECT " \ diff --git a/ui/opensnitch/nodes.py b/ui/opensnitch/nodes.py index d4293715..30f86a6c 100644 --- a/ui/opensnitch/nodes.py +++ b/ui/opensnitch/nodes.py @@ -3,6 +3,7 @@ from datetime import datetime import time import json +import ui_pb2 from database import Database class Nodes(): @@ -155,7 +156,10 @@ class Nodes(): try: notification.id = int(str(time.time()).replace(".", "")) self._nodes[addr]['notifications'].put(notification) - self._notifications_sent[notification.id] = callback_signal + self._notifications_sent[notification.id] = { + 'callback': callback_signal, + 'type': notification.type + } except Exception as e: print(self.LOG_TAG + " exception sending notification: ", e, addr, notification) @@ -170,20 +174,28 @@ class Nodes(): notification.id = int(str(time.time()).replace(".", "")) for c in self._nodes: self._nodes[c]['notifications'].put(notification) - self._notifications_sent[notification.id] = callback_signal + self._notifications_sent[notification.id] = { + 'callback': callback_signal, + 'type': notification.type + } except Exception as e: print(self.LOG_TAG + " exception sending notifications: ", e, notification) return notification.id - def reply_notification(self, reply): + def reply_notification(self, addr, reply): if reply == None: print(self.LOG_TAG, " reply notification None") return if reply.id in self._notifications_sent: if self._notifications_sent[reply.id] != None: - self._notifications_sent[reply.id].emit(reply) - del self._notifications_sent[reply.id] + self._notifications_sent[reply.id]['callback'].emit(reply) + + # delete only one-time notifications + # we need the ID of streaming notifications from the server + # (monitor_process for example) to keep track of the data sent to us. + if self._notifications_sent[reply.id]['type'] != ui_pb2.MONITOR_PROCESS: + del self._notifications_sent[reply.id] def update(self, proto, addr, status=ONLINE): try: diff --git a/ui/opensnitch/res/process_details.ui b/ui/opensnitch/res/process_details.ui new file mode 100644 index 00000000..36c36745 --- /dev/null +++ b/ui/opensnitch/res/process_details.ui @@ -0,0 +1,259 @@ + + + ProcessDetailsDialog + + + + 0 + 0 + 731 + 478 + + + + Process details + + + + + + + + + + + 48 + 48 + + + + + 64 + 64 + + + + + + + + + + + + + QFrame::NoFrame + + + loading... + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + loading... + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + CWD: loading... + + + + + + + + + mem stats: loading... + + + + + + + + + + + Qt::Horizontal + + + + + + + QTabWidget::South + + + 0 + + + true + + + + Status + + + + + + false + + + + + + + + Open files + + + + + + false + + + + + + + + I/O Statistics + + + + + + false + + + + + + + + Memory mapped files + + + + + + false + + + + + + + + Stack + + + + + + false + + + + + + + + Environment variables + + + + + + false + + + + + + + + + + + + + Application pids + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Start or stop monitoring this process + + + + + + + + + true + + + + + + + Close + + + + + + + + + + + + + diff --git a/ui/opensnitch/res/stats.ui b/ui/opensnitch/res/stats.ui index a1eac6f5..dcf90885 100644 --- a/ui/opensnitch/res/stats.ui +++ b/ui/opensnitch/res/stats.ui @@ -72,7 +72,7 @@ - ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup + ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -81,7 +81,7 @@ - ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup + ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -153,7 +153,8 @@ - + + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -191,7 +192,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -210,7 +211,7 @@ - + Qt::Horizontal @@ -260,7 +261,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -278,7 +279,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -289,7 +290,7 @@ - ../../../../../../../../.designer/backup../../../../../../../../.designer/backup + ../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -384,7 +385,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -431,7 +432,8 @@ - + + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -472,7 +474,17 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup + + + + + + + + + + @@ -519,7 +531,8 @@ - + + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -557,7 +570,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -601,7 +614,8 @@ - + + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -639,7 +653,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -683,7 +697,8 @@ - + + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -721,7 +736,7 @@ - .. + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -775,7 +790,8 @@ - + + ../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -1105,7 +1121,7 @@ - ../../../../../../../../.designer/backup../../../../../../../../.designer/backup + ../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup Ctrl+S @@ -1131,7 +1147,7 @@ - ../../../../../../../../.designer/backup../../../../../../../../.designer/backup + ../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup @@ -1153,8 +1169,7 @@ - - .. + @@ -1171,7 +1186,7 @@ - ../../../../../../../../.designer/backup../../../../../../../../.designer/backup + ../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup true diff --git a/ui/opensnitch/service.py b/ui/opensnitch/service.py index 1890a511..a3188711 100644 --- a/ui/opensnitch/service.py +++ b/ui/opensnitch/service.py @@ -509,7 +509,7 @@ class UIService(ui_pb2_grpc.UIServicer, QtWidgets.QGraphicsObject): in_message = next(node_iter) if in_message == None: continue - self._nodes.reply_notification(in_message) + self._nodes.reply_notification(addr, in_message) except StopIteration as e: print("[Notifications] Node exited") except Exception as e: diff --git a/ui/opensnitch/ui_pb2.py b/ui/opensnitch/ui_pb2.py index aef9b549..5a6006ea 100644 --- a/ui/opensnitch/ui_pb2.py +++ b/ui/opensnitch/ui_pb2.py @@ -20,7 +20,7 @@ DESCRIPTOR = _descriptor.FileDescriptor( name='ui.proto', package='protocol', syntax='proto3', - serialized_pb=_b('\n\x08ui.proto\x12\x08protocol\"]\n\x05\x45vent\x12\x0c\n\x04time\x18\x01 \x01(\t\x12(\n\nconnection\x18\x02 \x01(\x0b\x32\x14.protocol.Connection\x12\x1c\n\x04rule\x18\x03 \x01(\x0b\x32\x0e.protocol.Rule\"\xd3\x06\n\nStatistics\x12\x16\n\x0e\x64\x61\x65mon_version\x18\x01 \x01(\t\x12\r\n\x05rules\x18\x02 \x01(\x04\x12\x0e\n\x06uptime\x18\x03 \x01(\x04\x12\x15\n\rdns_responses\x18\x04 \x01(\x04\x12\x13\n\x0b\x63onnections\x18\x05 \x01(\x04\x12\x0f\n\x07ignored\x18\x06 \x01(\x04\x12\x10\n\x08\x61\x63\x63\x65pted\x18\x07 \x01(\x04\x12\x0f\n\x07\x64ropped\x18\x08 \x01(\x04\x12\x11\n\trule_hits\x18\t \x01(\x04\x12\x13\n\x0brule_misses\x18\n \x01(\x04\x12\x33\n\x08\x62y_proto\x18\x0b \x03(\x0b\x32!.protocol.Statistics.ByProtoEntry\x12\x37\n\nby_address\x18\x0c \x03(\x0b\x32#.protocol.Statistics.ByAddressEntry\x12\x31\n\x07\x62y_host\x18\r \x03(\x0b\x32 .protocol.Statistics.ByHostEntry\x12\x31\n\x07\x62y_port\x18\x0e \x03(\x0b\x32 .protocol.Statistics.ByPortEntry\x12/\n\x06\x62y_uid\x18\x0f \x03(\x0b\x32\x1f.protocol.Statistics.ByUidEntry\x12=\n\rby_executable\x18\x10 \x03(\x0b\x32&.protocol.Statistics.ByExecutableEntry\x12\x1f\n\x06\x65vents\x18\x11 \x03(\x0b\x32\x0f.protocol.Event\x1a.\n\x0c\x42yProtoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a\x30\n\x0e\x42yAddressEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a-\n\x0b\x42yHostEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a-\n\x0b\x42yPortEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a,\n\nByUidEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a\x33\n\x11\x42yExecutableEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\">\n\x0bPingRequest\x12\n\n\x02id\x18\x01 \x01(\x04\x12#\n\x05stats\x18\x02 \x01(\x0b\x32\x14.protocol.Statistics\"\x17\n\tPingReply\x12\n\n\x02id\x18\x01 \x01(\x04\"\xc8\x02\n\nConnection\x12\x10\n\x08protocol\x18\x01 \x01(\t\x12\x0e\n\x06src_ip\x18\x02 \x01(\t\x12\x10\n\x08src_port\x18\x03 \x01(\r\x12\x0e\n\x06\x64st_ip\x18\x04 \x01(\t\x12\x10\n\x08\x64st_host\x18\x05 \x01(\t\x12\x10\n\x08\x64st_port\x18\x06 \x01(\r\x12\x0f\n\x07user_id\x18\x07 \x01(\r\x12\x12\n\nprocess_id\x18\x08 \x01(\r\x12\x14\n\x0cprocess_path\x18\t \x01(\t\x12\x13\n\x0bprocess_cwd\x18\n \x01(\t\x12\x14\n\x0cprocess_args\x18\x0b \x03(\t\x12\x39\n\x0bprocess_env\x18\x0c \x03(\x0b\x32$.protocol.Connection.ProcessEnvEntry\x1a\x31\n\x0fProcessEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x08Operator\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0f\n\x07operand\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t\x12\x11\n\tsensitive\x18\x04 \x01(\x08\"\x81\x01\n\x04Rule\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08\x12\x12\n\nprecedence\x18\x03 \x01(\x08\x12\x0e\n\x06\x61\x63tion\x18\x04 \x01(\t\x12\x10\n\x08\x64uration\x18\x05 \x01(\t\x12$\n\x08operator\x18\x06 \x01(\x0b\x32\x12.protocol.Operator\"\x95\x01\n\x0c\x43lientConfig\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x19\n\x11isFirewallRunning\x18\x04 \x01(\x08\x12\x0e\n\x06\x63onfig\x18\x05 \x01(\t\x12\x10\n\x08logLevel\x18\x06 \x01(\r\x12\x1d\n\x05rules\x18\x07 \x03(\x0b\x32\x0e.protocol.Rule\"\x8f\x01\n\x0cNotification\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x12\n\nclientName\x18\x02 \x01(\t\x12\x12\n\nserverName\x18\x03 \x01(\t\x12\x1e\n\x04type\x18\x04 \x01(\x0e\x32\x10.protocol.Action\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\t\x12\x1d\n\x05rules\x18\x06 \x03(\x0b\x32\x0e.protocol.Rule\"\\\n\x11NotificationReply\x12\n\n\x02id\x18\x01 \x01(\x04\x12-\n\x04\x63ode\x18\x02 \x01(\x0e\x32\x1f.protocol.NotificationReplyCode\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t*\xab\x01\n\x06\x41\x63tion\x12\x08\n\x04NONE\x10\x00\x12\x11\n\rLOAD_FIREWALL\x10\x01\x12\x13\n\x0fUNLOAD_FIREWALL\x10\x02\x12\x11\n\rCHANGE_CONFIG\x10\x03\x12\x0f\n\x0b\x45NABLE_RULE\x10\x04\x12\x10\n\x0c\x44ISABLE_RULE\x10\x05\x12\x0f\n\x0b\x44\x45LETE_RULE\x10\x06\x12\x0f\n\x0b\x43HANGE_RULE\x10\x07\x12\r\n\tLOG_LEVEL\x10\x08\x12\x08\n\x04STOP\x10\t**\n\x15NotificationReplyCode\x12\x06\n\x02OK\x10\x00\x12\t\n\x05\x45RROR\x10\x01\x32\xf8\x01\n\x02UI\x12\x34\n\x04Ping\x12\x15.protocol.PingRequest\x1a\x13.protocol.PingReply\"\x00\x12\x31\n\x07\x41skRule\x12\x14.protocol.Connection\x1a\x0e.protocol.Rule\"\x00\x12=\n\tSubscribe\x12\x16.protocol.ClientConfig\x1a\x16.protocol.ClientConfig\"\x00\x12J\n\rNotifications\x12\x1b.protocol.NotificationReply\x1a\x16.protocol.Notification\"\x00(\x01\x30\x01\x62\x06proto3') + serialized_pb=_b('\n\x08ui.proto\x12\x08protocol\"]\n\x05\x45vent\x12\x0c\n\x04time\x18\x01 \x01(\t\x12(\n\nconnection\x18\x02 \x01(\x0b\x32\x14.protocol.Connection\x12\x1c\n\x04rule\x18\x03 \x01(\x0b\x32\x0e.protocol.Rule\"\xd3\x06\n\nStatistics\x12\x16\n\x0e\x64\x61\x65mon_version\x18\x01 \x01(\t\x12\r\n\x05rules\x18\x02 \x01(\x04\x12\x0e\n\x06uptime\x18\x03 \x01(\x04\x12\x15\n\rdns_responses\x18\x04 \x01(\x04\x12\x13\n\x0b\x63onnections\x18\x05 \x01(\x04\x12\x0f\n\x07ignored\x18\x06 \x01(\x04\x12\x10\n\x08\x61\x63\x63\x65pted\x18\x07 \x01(\x04\x12\x0f\n\x07\x64ropped\x18\x08 \x01(\x04\x12\x11\n\trule_hits\x18\t \x01(\x04\x12\x13\n\x0brule_misses\x18\n \x01(\x04\x12\x33\n\x08\x62y_proto\x18\x0b \x03(\x0b\x32!.protocol.Statistics.ByProtoEntry\x12\x37\n\nby_address\x18\x0c \x03(\x0b\x32#.protocol.Statistics.ByAddressEntry\x12\x31\n\x07\x62y_host\x18\r \x03(\x0b\x32 .protocol.Statistics.ByHostEntry\x12\x31\n\x07\x62y_port\x18\x0e \x03(\x0b\x32 .protocol.Statistics.ByPortEntry\x12/\n\x06\x62y_uid\x18\x0f \x03(\x0b\x32\x1f.protocol.Statistics.ByUidEntry\x12=\n\rby_executable\x18\x10 \x03(\x0b\x32&.protocol.Statistics.ByExecutableEntry\x12\x1f\n\x06\x65vents\x18\x11 \x03(\x0b\x32\x0f.protocol.Event\x1a.\n\x0c\x42yProtoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a\x30\n\x0e\x42yAddressEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a-\n\x0b\x42yHostEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a-\n\x0b\x42yPortEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a,\n\nByUidEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\x1a\x33\n\x11\x42yExecutableEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04:\x02\x38\x01\">\n\x0bPingRequest\x12\n\n\x02id\x18\x01 \x01(\x04\x12#\n\x05stats\x18\x02 \x01(\x0b\x32\x14.protocol.Statistics\"\x17\n\tPingReply\x12\n\n\x02id\x18\x01 \x01(\x04\"\xc8\x02\n\nConnection\x12\x10\n\x08protocol\x18\x01 \x01(\t\x12\x0e\n\x06src_ip\x18\x02 \x01(\t\x12\x10\n\x08src_port\x18\x03 \x01(\r\x12\x0e\n\x06\x64st_ip\x18\x04 \x01(\t\x12\x10\n\x08\x64st_host\x18\x05 \x01(\t\x12\x10\n\x08\x64st_port\x18\x06 \x01(\r\x12\x0f\n\x07user_id\x18\x07 \x01(\r\x12\x12\n\nprocess_id\x18\x08 \x01(\r\x12\x14\n\x0cprocess_path\x18\t \x01(\t\x12\x13\n\x0bprocess_cwd\x18\n \x01(\t\x12\x14\n\x0cprocess_args\x18\x0b \x03(\t\x12\x39\n\x0bprocess_env\x18\x0c \x03(\x0b\x32$.protocol.Connection.ProcessEnvEntry\x1a\x31\n\x0fProcessEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x08Operator\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0f\n\x07operand\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t\x12\x11\n\tsensitive\x18\x04 \x01(\x08\"\x81\x01\n\x04Rule\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08\x12\x12\n\nprecedence\x18\x03 \x01(\x08\x12\x0e\n\x06\x61\x63tion\x18\x04 \x01(\t\x12\x10\n\x08\x64uration\x18\x05 \x01(\t\x12$\n\x08operator\x18\x06 \x01(\x0b\x32\x12.protocol.Operator\"\x95\x01\n\x0c\x43lientConfig\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07version\x18\x03 \x01(\t\x12\x19\n\x11isFirewallRunning\x18\x04 \x01(\x08\x12\x0e\n\x06\x63onfig\x18\x05 \x01(\t\x12\x10\n\x08logLevel\x18\x06 \x01(\r\x12\x1d\n\x05rules\x18\x07 \x03(\x0b\x32\x0e.protocol.Rule\"\x8f\x01\n\x0cNotification\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x12\n\nclientName\x18\x02 \x01(\t\x12\x12\n\nserverName\x18\x03 \x01(\t\x12\x1e\n\x04type\x18\x04 \x01(\x0e\x32\x10.protocol.Action\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\t\x12\x1d\n\x05rules\x18\x06 \x03(\x0b\x32\x0e.protocol.Rule\"\\\n\x11NotificationReply\x12\n\n\x02id\x18\x01 \x01(\x04\x12-\n\x04\x63ode\x18\x02 \x01(\x0e\x32\x1f.protocol.NotificationReplyCode\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\t*\xda\x01\n\x06\x41\x63tion\x12\x08\n\x04NONE\x10\x00\x12\x11\n\rLOAD_FIREWALL\x10\x01\x12\x13\n\x0fUNLOAD_FIREWALL\x10\x02\x12\x11\n\rCHANGE_CONFIG\x10\x03\x12\x0f\n\x0b\x45NABLE_RULE\x10\x04\x12\x10\n\x0c\x44ISABLE_RULE\x10\x05\x12\x0f\n\x0b\x44\x45LETE_RULE\x10\x06\x12\x0f\n\x0b\x43HANGE_RULE\x10\x07\x12\r\n\tLOG_LEVEL\x10\x08\x12\x08\n\x04STOP\x10\t\x12\x13\n\x0fMONITOR_PROCESS\x10\n\x12\x18\n\x14STOP_MONITOR_PROCESS\x10\x0b**\n\x15NotificationReplyCode\x12\x06\n\x02OK\x10\x00\x12\t\n\x05\x45RROR\x10\x01\x32\xf8\x01\n\x02UI\x12\x34\n\x04Ping\x12\x15.protocol.PingRequest\x1a\x13.protocol.PingReply\"\x00\x12\x31\n\x07\x41skRule\x12\x14.protocol.Connection\x1a\x0e.protocol.Rule\"\x00\x12=\n\tSubscribe\x12\x16.protocol.ClientConfig\x1a\x16.protocol.ClientConfig\"\x00\x12J\n\rNotifications\x12\x1b.protocol.NotificationReply\x1a\x16.protocol.Notification\"\x00(\x01\x30\x01\x62\x06proto3') ) _ACTION = _descriptor.EnumDescriptor( @@ -69,11 +69,19 @@ _ACTION = _descriptor.EnumDescriptor( name='STOP', index=9, number=9, options=None, type=None), + _descriptor.EnumValueDescriptor( + name='MONITOR_PROCESS', index=10, number=10, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='STOP_MONITOR_PROCESS', index=11, number=11, + options=None, + type=None), ], containing_type=None, options=None, serialized_start=1992, - serialized_end=2163, + serialized_end=2210, ) _sym_db.RegisterEnumDescriptor(_ACTION) @@ -95,8 +103,8 @@ _NOTIFICATIONREPLYCODE = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=2165, - serialized_end=2207, + serialized_start=2212, + serialized_end=2254, ) _sym_db.RegisterEnumDescriptor(_NOTIFICATIONREPLYCODE) @@ -111,6 +119,8 @@ DELETE_RULE = 6 CHANGE_RULE = 7 LOG_LEVEL = 8 STOP = 9 +MONITOR_PROCESS = 10 +STOP_MONITOR_PROCESS = 11 OK = 0 ERROR = 1 @@ -1226,8 +1236,8 @@ _UI = _descriptor.ServiceDescriptor( file=DESCRIPTOR, index=0, options=None, - serialized_start=2210, - serialized_end=2458, + serialized_start=2257, + serialized_end=2505, methods=[ _descriptor.MethodDescriptor( name='Ping', diff --git a/ui/opensnitch/version.py b/ui/opensnitch/version.py index ee965d3a..1447bd8e 100644 --- a/ui/opensnitch/version.py +++ b/ui/opensnitch/version.py @@ -1 +1 @@ -version = '1.2.0' +version = '1.3.0rc1'