diff --git a/daemon/rule/rule.go b/daemon/rule/rule.go
index b51cf8fa..0fb04bdf 100644
--- a/daemon/rule/rule.go
+++ b/daemon/rule/rule.go
@@ -33,26 +33,28 @@ const (
// The fields match the ones saved as json to disk.
// If a .json rule file is modified on disk, it's reloaded automatically.
type Rule struct {
- Created time.Time `json:"created"`
- Updated time.Time `json:"updated"`
- Name string `json:"name"`
- Enabled bool `json:"enabled"`
- Precedence bool `json:"precedence"`
- Action Action `json:"action"`
- Duration Duration `json:"duration"`
- Operator Operator `json:"operator"`
+ Created time.Time `json:"created"`
+ Updated time.Time `json:"updated"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Enabled bool `json:"enabled"`
+ Precedence bool `json:"precedence"`
+ Action Action `json:"action"`
+ Duration Duration `json:"duration"`
+ Operator Operator `json:"operator"`
}
// Create creates a new rule object with the specified parameters.
-func Create(name string, enabled bool, precedence bool, action Action, duration Duration, op *Operator) *Rule {
+func Create(name, description string, enabled bool, precedence bool, action Action, duration Duration, op *Operator) *Rule {
return &Rule{
- Created: time.Now(),
- Enabled: enabled,
- Precedence: precedence,
- Name: name,
- Action: action,
- Duration: duration,
- Operator: *op,
+ Created: time.Now(),
+ Enabled: enabled,
+ Precedence: precedence,
+ Name: name,
+ Description: description,
+ Action: action,
+ Duration: duration,
+ Operator: *op,
}
}
@@ -86,6 +88,7 @@ func Deserialize(reply *protocol.Rule) (*Rule, error) {
return Create(
reply.Name,
+ reply.Description,
reply.Enabled,
reply.Precedence,
Action(reply.Action),
@@ -100,11 +103,12 @@ func (r *Rule) Serialize() *protocol.Rule {
return nil
}
return &protocol.Rule{
- Name: string(r.Name),
- Enabled: bool(r.Enabled),
- Precedence: bool(r.Precedence),
- Action: string(r.Action),
- Duration: string(r.Duration),
+ Name: string(r.Name),
+ Description: string(r.Description),
+ Enabled: bool(r.Enabled),
+ Precedence: bool(r.Precedence),
+ Action: string(r.Action),
+ Duration: string(r.Duration),
Operator: &protocol.Operator{
Type: string(r.Operator.Type),
Sensitive: bool(r.Operator.Sensitive),
diff --git a/daemon/ui/client.go b/daemon/ui/client.go
index 010a0bbb..6fc78480 100644
--- a/daemon/ui/client.go
+++ b/daemon/ui/client.go
@@ -23,10 +23,10 @@ import (
var (
configFile = "/etc/opensnitchd/default-config.json"
dummyOperator, _ = rule.NewOperator(rule.Simple, false, rule.OpTrue, "", make([]rule.Operator, 0))
- clientDisconnectedRule = rule.Create("ui.client.disconnected", true, false, rule.Allow, rule.Once, dummyOperator)
+ clientDisconnectedRule = rule.Create("ui.client.disconnected", "", true, false, rule.Allow, rule.Once, dummyOperator)
// While the GUI is connected, deny by default everything until the user takes an action.
- clientConnectedRule = rule.Create("ui.client.connected", true, false, rule.Deny, rule.Once, dummyOperator)
- clientErrorRule = rule.Create("ui.client.error", true, false, rule.Allow, rule.Once, dummyOperator)
+ clientConnectedRule = rule.Create("ui.client.connected", "", true, false, rule.Deny, rule.Once, dummyOperator)
+ clientErrorRule = rule.Create("ui.client.error", "", true, false, rule.Allow, rule.Once, dummyOperator)
config Config
)
diff --git a/proto/ui.proto b/proto/ui.proto
index f4224d25..fc46ae06 100644
--- a/proto/ui.proto
+++ b/proto/ui.proto
@@ -71,11 +71,12 @@ message Operator {
message Rule {
string name = 1;
- bool enabled = 2;
- bool precedence = 3;
- string action = 4;
- string duration = 5;
- Operator operator = 6;
+ string description = 2;
+ bool enabled = 3;
+ bool precedence = 4;
+ string action = 5;
+ string duration = 6;
+ Operator operator = 7;
}
enum Action {
diff --git a/ui/opensnitch/database.py b/ui/opensnitch/database/__init__.py
similarity index 87%
rename from ui/opensnitch/database.py
rename to ui/opensnitch/database/__init__.py
index ed93a115..83b69ad7 100644
--- a/ui/opensnitch/database.py
+++ b/ui/opensnitch/database/__init__.py
@@ -1,6 +1,7 @@
from PyQt5.QtSql import QSqlDatabase, QSqlQueryModel, QSqlQuery
import threading
import sys
+import os
from datetime import datetime, timedelta
class Database:
@@ -10,6 +11,8 @@ class Database:
DB_TYPE_MEMORY = 0
DB_TYPE_FILE = 1
+ DB_VERSION = 1
+
@staticmethod
def instance():
if Database.__instance == None:
@@ -26,6 +29,8 @@ class Database:
if dbtype != Database.DB_TYPE_MEMORY:
self.db_file = dbfile
+ is_new_file = not os.path.isfile(self.db_file)
+
self.db = QSqlDatabase.addDatabase("QSQLITE", self.db_name)
self.db.setDatabaseName(self.db_file)
if not self.db.open():
@@ -38,7 +43,13 @@ class Database:
print("db.initialize() error:", db_error)
return False, db_error
+
+ if is_new_file:
+ print("is new file, or IN MEMORY, setting initial schema version")
+ self.set_schema_version(self.DB_VERSION)
+
self._create_tables()
+ self._upgrade_db_schema()
return True, None
def close(self):
@@ -77,6 +88,7 @@ class Database:
def _create_tables(self):
# https://www.sqlite.org/wal.html
if self.db_file == Database.DB_IN_MEMORY:
+ self.set_schema_version(self.DB_VERSION)
q = QSqlQuery("PRAGMA journal_mode = OFF", self.db)
q.exec_()
q = QSqlQuery("PRAGMA synchronous = OFF", self.db)
@@ -137,6 +149,7 @@ class Database:
"operator_sensitive text, " \
"operator_operand text, " \
"operator_data text, " \
+ "description text, " \
"UNIQUE(node, name)"
")", self.db)
q.exec_()
@@ -168,6 +181,49 @@ class Database:
, self.db)
q.exec_()
+ def get_schema_version(self):
+ q = QSqlQuery("PRAGMA user_version;", self.db)
+ q.exec_()
+ if q.next():
+ print("schema version:", q.value(0))
+ return int(q.value(0))
+
+ return 0
+
+ def set_schema_version(self, version):
+ print("setting schema version to:", version)
+ q = QSqlQuery("PRAGMA user_version = {0}".format(version), self.db)
+ q.exec_()
+
+ def _upgrade_db_schema(self):
+ migrations_path = os.path.dirname(os.path.realpath(__file__)) + "/migrations"
+ schema_version = self.get_schema_version()
+ if schema_version == self.DB_VERSION:
+ print("db schema is up to date")
+ return
+ while schema_version < self.DB_VERSION:
+ schema_version += 1
+ try:
+ print("applying schema upgrade:", schema_version)
+ self._apply_db_upgrade("{0}/upgrade_{1}.sql".format(migrations_path, schema_version))
+ except Exception:
+ print("Not applyging upgrade_{0}.sql".format(schema_version))
+ self.set_schema_version(schema_version)
+
+ def _apply_db_upgrade(self, file):
+ print("applying upgrade from:", file)
+ q = QSqlQuery(self.db)
+ with open(file) as f:
+ for line in f.readlines():
+ # skip comments
+ if line.startswith("--"):
+ continue
+ print("applying upgrade:", line, end="")
+ if q.exec(line) == False:
+ print("\tError:", q.lastError().text())
+ else:
+ print("\tOK")
+
def optimize(self):
"""https://www.sqlite.org/pragma.html#pragma_optimize
"""
@@ -430,9 +486,9 @@ class Database:
def insert_rule(self, rule, node_addr):
self.insert("rules",
- "(time, node, name, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
+ "(time, node, name, description, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- node_addr, rule.name,
+ node_addr, rule.name, rule.description,
str(rule.enabled), str(rule.precedence),
rule.action, rule.duration, rule.operator.type,
str(rule.operator.sensitive), rule.operator.operand, rule.operator.data),
diff --git a/ui/opensnitch/database/migrations/upgrade_1.sql b/ui/opensnitch/database/migrations/upgrade_1.sql
new file mode 100644
index 00000000..c5f1be8a
--- /dev/null
+++ b/ui/opensnitch/database/migrations/upgrade_1.sql
@@ -0,0 +1,2 @@
+--ALTER TABLE rules ADD COLUMN description;
+create table x(id int);
diff --git a/ui/opensnitch/dialogs/ruleseditor.py b/ui/opensnitch/dialogs/ruleseditor.py
index 562c6ea6..b46319dd 100644
--- a/ui/opensnitch/dialogs/ruleseditor.py
+++ b/ui/opensnitch/dialogs/ruleseditor.py
@@ -269,6 +269,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
rule.operator.sensitive = self._bool(records.value(8))
rule.operator.operand = records.value(9)
rule.operator.data = "" if records.value(10) == None else str(records.value(10))
+ rule.description = records.value(11)
return rule
@@ -277,6 +278,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.rule = None
self.ruleNameEdit.setText("")
+ self.ruleDescEdit.setPlainText("")
self.statusLabel.setText("")
self.actionDenyRadio.setChecked(True)
@@ -327,6 +329,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
return False
self.ruleNameEdit.setText(rule.name)
+ self.ruleDescEdit.setPlainText(rule.description)
self.enableCheck.setChecked(rule.enabled)
self.precedenceCheck.setChecked(rule.precedence)
if rule.action == Config.ACTION_DENY:
@@ -449,9 +452,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def _insert_rule_to_db(self, node_addr):
self._db.insert("rules",
- "(time, node, name, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
+ "(time, node, name, description, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- node_addr, self.rule.name,
+ node_addr, self.rule.name, self.rule.description,
str(self.rule.enabled), str(self.rule.precedence),
self.rule.action, self.rule.duration, self.rule.operator.type,
str(self.rule.operator.sensitive), self.rule.operator.operand, self.rule.operator.data),
@@ -509,6 +512,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
"""
self.rule = ui_pb2.Rule()
self.rule.name = self.ruleNameEdit.text()
+ self.rule.description = self.ruleDescEdit.toPlainText()
self.rule.enabled = self.enableCheck.isChecked()
self.rule.precedence = self.precedenceCheck.isChecked()
self.rule.operator.type = Config.RULE_TYPE_SIMPLE
diff --git a/ui/opensnitch/dialogs/stats.py b/ui/opensnitch/dialogs/stats.py
index ae6d35c1..dae71eb3 100644
--- a/ui/opensnitch/dialogs/stats.py
+++ b/ui/opensnitch/dialogs/stats.py
@@ -200,7 +200,13 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
"filterLine": None,
"model": None,
"delegate": commonDelegateConf,
- "display_fields": "*",
+ "display_fields": "time as Time," \
+ "node as Node," \
+ "name as Name," \
+ "enabled as Enabled," \
+ "action as Action," \
+ "duration as Duration," \
+ "description as Description",
"header_labels": [],
"last_order_by": "2",
"last_order_to": 0,
@@ -336,6 +342,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.COL_STR_TIME = QC.translate("stats", "Time", "This is a word, without spaces and symbols.")
self.COL_STR_ACTION = QC.translate("stats", "Action", "This is a word, without spaces and symbols.")
self.COL_STR_DURATION = QC.translate("stats", "Duration", "This is a word, without spaces and symbols.")
+ self.COL_STR_DESCRIPTION = QC.translate("stats", "Description", "This is a word, without spaces and symbols.")
self.COL_STR_NODE = QC.translate("stats", "Node", "This is a word, without spaces and symbols.")
self.COL_STR_ENABLED = QC.translate("stats", "Enabled", "This is a word, without spaces and symbols.")
self.COL_STR_PRECEDENCE = QC.translate("stats", "Precedence", "This is a word, without spaces and symbols.")
@@ -447,13 +454,9 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.COL_STR_NODE,
self.COL_STR_NAME,
self.COL_STR_ENABLED,
- self.COL_STR_PRECEDENCE,
self.COL_STR_ACTION,
self.COL_STR_DURATION,
- "operator_type",
- "operator_sensitive",
- "operator_operand",
- "operator_data",
+ self.COL_STR_DESCRIPTION,
]
stats_headers = [
@@ -492,8 +495,8 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
verticalScrollBar=self.verticalScrollBar,
sort_direction=self.SORT_ORDER[1],
delegate=self.TABLES[self.TAB_NODES]['delegate'])
- self.TABLES[self.TAB_RULES]['view'] = self._setup_table(QtWidgets.QTableView,
- self.rulesTable, "rules",
+ self.TABLES[self.TAB_RULES]['view'] = self._setup_table(QtWidgets.QTableView, self.rulesTable, "rules",
+ fields=self.TABLES[self.TAB_RULES]['display_fields'],
model=GenericTableModel("rules", self.TABLES[self.TAB_RULES]['header_labels']),
verticalScrollBar=self.rulesScrollBar,
delegate=self.TABLES[self.TAB_RULES]['delegate'],
@@ -688,6 +691,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def _configure_buttons_icons(self):
self.iconStart = self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_MediaPlay"))
self.iconPause = self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_MediaPause"))
+ fwIcon = self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_VistaShield"))
self.newRuleButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_FileIcon")))
self.delRuleButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_TrashIcon")))
@@ -695,6 +699,7 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.saveButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_DialogSaveButton")))
self.prefsButton.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_FileDialogDetailedView")))
self.startButton.setIcon(self.iconStart)
+ self.fwButton.setIcon(fwIcon)
self.cmdProcDetails.setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_FileDialogContentsView")))
self.TABLES[self.TAB_MAIN]['cmdCleanStats'].setIcon(self.style().standardIcon(getattr(QtWidgets.QStyle, "SP_DialogResetButton")))
for idx in range(1,8):
@@ -1869,7 +1874,12 @@ class StatsDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
what = what + " AND"
what = what + " r.name LIKE '%{0}%'".format(filter_text)
model = self._get_active_table().model()
- self.setQuery(model, "SELECT * FROM rules as r %s %s %s" % (what, self._get_order(), self._get_limit()))
+ self.setQuery(model, "SELECT {0} FROM rules as r {1} {2} {3}".format(
+ self.TABLES[self.TAB_RULES]['display_fields'],
+ what,
+ self._get_order(),
+ self._get_limit()
+ ))
self._restore_details_view_columns(
self.TABLES[self.TAB_RULES]['view'].horizontalHeader(),
"{0}{1}".format(Config.STATS_VIEW_COL_STATE, self.TAB_RULES)
diff --git a/ui/opensnitch/nodes.py b/ui/opensnitch/nodes.py
index 29d0ee28..e663c4ec 100644
--- a/ui/opensnitch/nodes.py
+++ b/ui/opensnitch/nodes.py
@@ -70,27 +70,27 @@ class Nodes(QObject):
def add_fw_rules(self, addr, fwconfig):
self._nodes[addr]['fwrules'] = fwconfig
- def add_rule(self, time, node, name, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data):
+ def add_rule(self, time, node, name, description, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data):
# don't add rule if the user has selected to exclude temporary
# rules
if duration in Config.RULES_DURATION_FILTER:
return
self._db.insert("rules",
- "(time, node, name, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
- (time, node, name, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data),
+ "(time, node, name, description, enabled, precedence, action, duration, operator_type, operator_sensitive, operator_operand, operator_data)",
+ (time, node, name, description, enabled, precedence, action, duration, op_type, op_sensitive, op_operand, op_data),
action_on_conflict="REPLACE")
def add_rules(self, addr, rules):
try:
for _,r in enumerate(rules):
self.add_rule(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- addr,
- r.name, str(r.enabled), str(r.precedence), r.action, r.duration,
- r.operator.type,
- str(r.operator.sensitive),
- r.operator.operand,
- r.operator.data)
+ addr,
+ r.name, r.description, str(r.enabled),
+ str(r.precedence), r.action, r.duration,
+ r.operator.type,
+ str(r.operator.sensitive),
+ r.operator.operand, r.operator.data)
except Exception as e:
print(self.LOG_TAG + " exception adding node to db: ", e)
diff --git a/ui/opensnitch/res/ruleseditor.ui b/ui/opensnitch/res/ruleseditor.ui
index 91d25bbe..03309a64 100644
--- a/ui/opensnitch/res/ruleseditor.ui
+++ b/ui/opensnitch/res/ruleseditor.ui
@@ -6,39 +6,202 @@
0
0
- 540
- 490
+ 552
+ 528
+
+
+ 0
+ 0
+
+
Rule
- -
-
-
-
-
-
- Enable
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
+ -
+
+
+
+ 0
+ 0
+
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+
+ QLayout::SetDefaultConstraint
+
+
+ 0
+
+
+ 2
+
+
+ 12
+
+
-
+
+
+ Action
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Duration
+
+
+
+ -
+
+
-
+
+ once
+
+
+ -
+
+ 30s
+
+
+ -
+
+ 5m
+
+
+ -
+
+ 15m
+
+
+ -
+
+ 30m
+
+
+ -
+
+ 1h
+
+
+ -
+
+ until reboot
+
+
+ -
+
+ always
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Deny will just discard the connection
+
+
+ Deny
+
+
+
+ ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup
+
+
+ true
+
+
+
+ -
+
+
+ Reject will drop the connection, and kill the socket that initiated it
+
+
+ Reject
+
+
+
+ ..
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Allow will allow the connection
+
+
+ Qt::LeftToRight
+
+
+ Allow
+
+
+
+ ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup
+
+
+
+
+
+
+
- -
+
-
-
@@ -80,7 +243,63 @@ You must name the rule in such manner that it'll be checked first, because they'
- -
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 60
+
+
+
+ Description...
+
+
+
+ -
+
+
-
+
+
+ Enable
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Name
+
+
+
+ -
-
@@ -110,7 +329,53 @@ You must name the rule in such manner that it'll be checked first, because they'
- -
+
-
+
+
+ true
+
+
+
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ The rules are checked in alphabetical order, so you can name them accordingly to prioritize them.
+
+000-allow-localhost
+001-deny-broadcast
+...
+
+
+ leave blank to autocreate
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
-
@@ -144,7 +409,7 @@ You must name the rule in such manner that it'll be checked first, because they'
- -
+
-
0
@@ -155,9 +420,10 @@ You must name the rule in such manner that it'll be checked first, because they'
true
-
+
-
+
+ ..
Applications
@@ -213,7 +479,7 @@ You must name the rule in such manner that it'll be checked first, because they'
false
- <html><head/><body><p>This field will only match the executable path. It is not modifiable by the user.<br/></p><p>You can use regular expressions to deny executions from /tmp for example:<br/></p><p>^/tmp/.*$</p></body></html>
+ <html><head/><body><p>The value of this field is always the absolute path to the executable: /path/to/binary<br/></p><p>Examples:</p><p>- Simple: /path/to/binary</p><p>- Multiple paths: ^/usr/lib(64|)/firefox/firefox$</p><p>- Multiple binaries: ^(/usr/sbin/ntpd|/lib/systemd/systemd-timesyncd|/usr/bin/xbrlapi|/usr/bin/dirmngr)$ </p><p>- Deny/Allow executions from /tmp:</p><p>^/(var/|)tmp/.*$<br/></p><p>For more examples visit the <a href="https://github.com/evilsocket/opensnitch/wiki/Rules-examples">wiki page</a> or ask on the <a href="https://github.com/evilsocket/opensnitch/discussions">Discussion forums</a>.</p></body></html>
/path/to/executable, .*/bin/executable[0-9\.]+$, ...
@@ -279,9 +545,10 @@ You must name the rule in such manner that it'll be checked first, because they'
-
+
-
+
+ ..
Network
@@ -528,9 +795,10 @@ Note: Commas or spaces are not allowed to separate IPs or networks.
-
+
-
+
+ ..
List of domains/IPs
@@ -561,7 +829,8 @@ Note: Commas or spaces are not allowed to separate IPs or networks.
-
+
+ ..
@@ -595,7 +864,8 @@ Note: Commas or spaces are not allowed to separate IPs or networks.
-
+
+ ..
@@ -664,7 +934,8 @@ Note: Commas or spaces are not allowed to separate IPs or networks.
-
+
+ ..
@@ -684,222 +955,6 @@ Note: Commas or spaces are not allowed to separate IPs or networks.
- -
-
-
- true
-
-
-
-
-
- true
-
-
-
- -
-
-
- true
-
-
- The rules are checked in alphabetical order, so you can name them accordingly to prioritize them.
-
-000-allow-localhost
-001-deny-broadcast
-...
-
-
- leave blank to autocreate
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- false
-
-
- false
-
-
- false
-
-
-
- QLayout::SetDefaultConstraint
-
-
- 0
-
-
- 2
-
-
- 12
-
-
-
-
-
- Action
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Duration
-
-
-
- -
-
-
-
-
- once
-
-
- -
-
- 30s
-
-
- -
-
- 5m
-
-
- -
-
- 15m
-
-
- -
-
- 30m
-
-
- -
-
- 1h
-
-
- -
-
- until reboot
-
-
- -
-
- always
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
- Deny
-
-
-
- ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup
-
-
- true
-
-
-
- -
-
-
- Reject
-
-
-
- ..
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::LeftToRight
-
-
- Allow
-
-
-
- ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.designer/backup
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Name
-
-
-
diff --git a/ui/opensnitch/service.py b/ui/opensnitch/service.py
index 9b066c3d..04ffded8 100644
--- a/ui/opensnitch/service.py
+++ b/ui/opensnitch/service.py
@@ -549,9 +549,10 @@ class UIService(ui_pb2_grpc.UIServicer, QtWidgets.QGraphicsObject):
proto, addr = self._get_peer(kwargs['peer'])
self._nodes.add_rule((datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
"{0}:{1}".format(proto, addr),
- rule.name, str(rule.enabled), str(rule.precedence), rule.action, rule.duration,
- rule.operator.type, str(rule.operator.sensitive), rule.operator.operand,
- rule.operator.data)
+ rule.name, rule.description, str(rule.enabled),
+ str(rule.precedence), rule.action, rule.duration,
+ rule.operator.type, str(rule.operator.sensitive), rule.operator.operand,
+ rule.operator.data)
elif kwargs['action'] == self.DELETE_RULE:
self._db.delete_rule(kwargs['name'], kwargs['addr'])