allow to filter connections by source port

- Allow to filter connections by source port.
This commit is contained in:
Gustavo Iñiguez Goia 2023-05-01 14:48:34 +02:00
parent 57739cc974
commit 4570491523
Failed to generate hash of commit
4 changed files with 266 additions and 171 deletions

View file

@ -43,6 +43,7 @@ const (
OpProcessEnvPrefixLen = 12
OpUserID = Operand("user.id")
OpSrcIP = Operand("source.ip")
OpSrcPort = Operand("source.port")
OpDstIP = Operand("dest.ip")
OpDstHost = Operand("dest.host")
OpDstPort = Operand("dest.port")
@ -273,18 +274,14 @@ func (o *Operator) Match(con *conman.Connection) bool {
return o.cb(con.DstHost)
} else if o.Operand == OpDstIP {
return o.cb(con.DstIP.String())
} else if o.Operand == OpSrcIP {
return o.cb(con.SrcIP.String())
} else if o.Operand == OpDstPort {
return o.cb(fmt.Sprintf("%d", con.DstPort))
} else if o.Operand == OpUserID {
return o.cb(fmt.Sprintf("%d", con.Entry.UserId))
} else if o.Operand == OpProcessID {
return o.cb(fmt.Sprint(con.Process.ID))
} else if o.Operand == OpDomainsLists {
return o.cb(con.DstHost)
} else if o.Operand == OpIPLists {
return o.cb(con.DstIP.String())
} else if o.Operand == OpUserID {
return o.cb(fmt.Sprintf("%d", con.Entry.UserId))
} else if o.Operand == OpDstNetwork {
return o.cb(con.DstIP)
} else if o.Operand == OpSrcNetwork {
@ -293,8 +290,6 @@ func (o *Operator) Match(con *conman.Connection) bool {
return o.cb(con.DstIP)
} else if o.Operand == OpDomainsRegexpLists {
return o.cb(con.DstHost)
} else if o.Operand == OpProto {
return o.cb(con.Protocol)
} else if o.Operand == OpIfaceIn {
if ifname, err := net.InterfaceByIndex(con.Pkt.IfaceInIdx); err == nil {
return o.cb(ifname.Name)
@ -303,6 +298,14 @@ func (o *Operator) Match(con *conman.Connection) bool {
if ifname, err := net.InterfaceByIndex(con.Pkt.IfaceOutIdx); err == nil {
return o.cb(ifname.Name)
}
} else if o.Operand == OpProto {
return o.cb(con.Protocol)
} else if o.Operand == OpSrcIP {
return o.cb(con.SrcIP.String())
} else if o.Operand == OpSrcPort {
return o.cb(fmt.Sprintf("%d", con.SrcPort))
} else if o.Operand == OpProcessID {
return o.cb(fmt.Sprint(con.Process.ID))
} else if strings.HasPrefix(string(o.Operand), string(OpProcessEnvPrefix)) {
envVarName := core.Trim(string(o.Operand[OpProcessEnvPrefixLen:]))
envVarValue, _ := con.Process.Env[envVarName]

View file

@ -17,6 +17,7 @@ class Config:
OPERAND_IFACE_OUT = "iface.out"
OPERAND_IFACE_IN = "iface.in"
OPERAND_SOURCE_IP = "source.ip"
OPERAND_SOURCE_PORT = "source.port"
OPERAND_DEST_IP = "dest.ip"
OPERAND_DEST_HOST = "dest.host"
OPERAND_DEST_PORT = "dest.port"

View file

@ -7,6 +7,7 @@ import re
import json
import sys
import os
import pwd
from opensnitch import ui_pb2
import time
import ipaddress
@ -64,6 +65,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.cmdlineCheck.toggled.connect(self._cb_cmdline_check_toggled)
self.ifaceCheck.toggled.connect(self._cb_iface_check_toggled)
self.dstPortCheck.toggled.connect(self._cb_dstport_check_toggled)
self.srcPortCheck.toggled.connect(self._cb_srcport_check_toggled)
self.uidCheck.toggled.connect(self._cb_uid_check_toggled)
self.pidCheck.toggled.connect(self._cb_pid_check_toggled)
self.srcIPCheck.toggled.connect(self._cb_srcip_check_toggled)
@ -73,6 +75,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.dstListRegexpCheck.toggled.connect(self._cb_dstregexplists_check_toggled)
self.dstListIPsCheck.toggled.connect(self._cb_dstiplists_check_toggled)
self.dstListNetsCheck.toggled.connect(self._cb_dstnetlists_check_toggled)
self.uidCombo.currentIndexChanged.connect(self._cb_uid_combo_changed)
self._users_list = pwd.getpwall()
if QtGui.QIcon.hasThemeIcon("emblem-default"):
return
@ -95,11 +100,31 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def showEvent(self, event):
super(RulesEditorDialog, self).showEvent(event)
oldText = self.ifaceCombo.currentText()
# save old combo values so we don't overwrite them here.
oldIface = self.ifaceCombo.currentText()
oldUid = self.uidCombo.currentText()
self.ifaceCombo.clear()
self.uidCombo.clear()
if self._nodes.is_local(self.nodesCombo.currentText()):
self.ifaceCombo.addItems(NetworkInterfaces.list().keys())
self.ifaceCombo.setCurrentText(oldText)
try:
for ip in NetworkInterfaces.list().values():
if self.srcIPCombo.findText(ip) == -1:
self.srcIPCombo.insertItem(0, ip)
if self.dstIPCombo.findText(ip) == -1:
self.dstIPCombo.insertItem(0, ip)
self._users_list = pwd.getpwall()
self.uidCombo.blockSignals(True);
for user in self._users_list:
self.uidCombo.addItem("{0} ({1})".format(user[0], user[2]), user[2])
#self.uidCombo.setCurrentText("")
except Exception as e:
print("[ruleseditor] Error adding IPs:", e)
finally:
self.uidCombo.blockSignals(False);
self.ifaceCombo.setCurrentText(oldIface)
self.uidCombo.setCurrentText(oldUid)
def _bool(self, s):
return s == 'True'
@ -153,8 +178,11 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def _cb_dstport_check_toggled(self, state):
self.dstPortLine.setEnabled(state)
def _cb_srcport_check_toggled(self, state):
self.srcPortLine.setEnabled(state)
def _cb_uid_check_toggled(self, state):
self.uidLine.setEnabled(state)
self.uidCombo.setEnabled(state)
def _cb_pid_check_toggled(self, state):
self.pidLine.setEnabled(state)
@ -184,6 +212,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.dstListNetsLine.setEnabled(state)
self.selectNetsListButton.setEnabled(state)
def _cb_uid_combo_changed(self, index):
self.uidCombo.setCurrentText(str(self._users_list[index][2]))
def _set_status_error(self, msg):
self.statusLabel.setStyleSheet('color: red')
self.statusLabel.setText(msg)
@ -300,7 +331,8 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.dstIPCombo.setCurrentText(records.value(ConnFields.DstIP))
self.dstHostLine.setText(records.value(ConnFields.DstHost))
self.dstPortLine.setText(records.value(ConnFields.DstPort))
self.uidLine.setText(records.value(ConnFields.UID))
self.srcPortLine.setText(records.value(ConnFields.SrcPort))
self.uidCombo.setCurrentText(records.value(ConnFields.UID))
self.pidLine.setText(records.value(ConnFields.PID))
self.procLine.setText(records.value(ConnFields.Process))
self.cmdlineLine.setText(records.value(ConnFields.Cmdline))
@ -330,7 +362,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.cmdlineLine.setText("")
self.uidCheck.setChecked(False)
self.uidLine.setText("")
self.uidCombo.setCurrentText("")
self.pidCheck.setChecked(False)
self.pidLine.setText("")
@ -341,6 +373,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.dstPortCheck.setChecked(False)
self.dstPortLine.setText("")
self.srcPortCheck.setChecked(False)
self.srcPortLine.setText("")
self.srcIPCheck.setChecked(False)
self.srcIPCombo.setCurrentText("")
@ -421,8 +456,8 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if operator.operand == Config.OPERAND_USER_ID:
self.uidCheck.setChecked(True)
self.uidLine.setEnabled(True)
self.uidLine.setText(operator.data)
self.uidCombo.setEnabled(True)
self.uidCombo.setCurrentText(operator.data)
if operator.operand == Config.OPERAND_PROCESS_ID:
self.pidCheck.setChecked(True)
@ -434,6 +469,11 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.ifaceCombo.setEnabled(True)
self.ifaceCombo.setCurrentText(operator.data)
if operator.operand == Config.OPERAND_SOURCE_PORT:
self.srcPortCheck.setChecked(True)
self.srcPortLine.setEnabled(True)
self.srcPortLine.setText(operator.data)
if operator.operand == Config.OPERAND_DEST_PORT:
self.dstPortCheck.setChecked(True)
self.dstPortLine.setEnabled(True)
@ -666,6 +706,24 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self._is_valid_regex(self.ifaceCombo.currentText()) == False:
return False, QC.translate("rules", "Network interface regexp error")
if self.srcPortCheck.isChecked():
if self.srcPortLine.text() == "":
return False, QC.translate("rules", "Source port can not be empty")
self.rule.operator.operand = Config.OPERAND_SOURCE_PORT
self.rule.operator.data = self.srcPortLine.text()
rule_data.append(
{
'type': Config.RULE_TYPE_SIMPLE,
'operand': Config.OPERAND_SOURCE_PORT,
'data': self.srcPortLine.text(),
"sensitive": self.sensitiveCheck.isChecked()
})
if self._is_regex(self.srcPortLine.text()):
rule_data[len(rule_data)-1]['type'] = Config.RULE_TYPE_REGEXP
if self._is_valid_regex(self.srcPortLine.text()) == False:
return False, QC.translate("rules", "Source port regexp error")
if self.dstPortCheck.isChecked():
if self.dstPortLine.text() == "":
return False, QC.translate("rules", "Dest port can not be empty")
@ -779,21 +837,21 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
})
if self.uidCheck.isChecked():
if self.uidLine.text() == "":
if self.uidCombo.currentText() == "":
return False, QC.translate("rules", "User ID can not be empty")
self.rule.operator.operand = Config.OPERAND_USER_ID
self.rule.operator.data = self.uidLine.text()
self.rule.operator.data = self.uidCombo.currentText()
rule_data.append(
{
'type': Config.RULE_TYPE_SIMPLE,
'operand': Config.OPERAND_USER_ID,
'data': self.uidLine.text(),
'data': self.uidCombo.currentText(),
"sensitive": self.sensitiveCheck.isChecked()
})
if self._is_regex(self.uidLine.text()):
if self._is_regex(self.uidCombo.currentText()):
rule_data[len(rule_data)-1]['type'] = Config.RULE_TYPE_REGEXP
if self._is_valid_regex(self.uidLine.text()) == False:
if self._is_valid_regex(self.uidCombo.currentText()) == False:
return False, QC.translate("rules", "User ID regexp error")
if self.pidCheck.isChecked():

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>552</width>
<height>557</height>
<height>559</height>
</rect>
</property>
<property name="sizePolicy">
@ -437,25 +437,25 @@ You must name the rule in such manner that it'll be checked first, because they'
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="uidLine">
<widget class="QComboBox" name="uidCombo">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -485,20 +485,23 @@ You must name the rule in such manner that it'll be checked first, because they'
<string>Network</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="5" column="1">
<item row="6" column="1">
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>60</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="4" colspan="2">
<item row="7" column="4" colspan="2">
<widget class="QComboBox" name="ifaceCombo">
<property name="enabled">
<bool>false</bool>
@ -508,7 +511,7 @@ You must name the rule in such manner that it'll be checked first, because they'
</property>
</widget>
</item>
<item row="2" column="5">
<item row="0" column="5">
<widget class="QComboBox" name="protoCombo">
<property name="enabled">
<bool>false</bool>
@ -574,7 +577,7 @@ You must name the rule in such manner that it'll be checked first, because they'
</item>
</widget>
</item>
<item row="4" column="2" colspan="4">
<item row="5" column="2" colspan="4">
<widget class="QLineEdit" name="dstHostLine">
<property name="enabled">
<bool>false</bool>
@ -595,64 +598,157 @@ gnu.org - it'll only match gnu.org, nor www.gnu.org, nor ftp.gnu.org, ..
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QCheckBox" name="dstIPCheck">
<property name="text">
<string>To this IP / Network</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>133</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<item row="5" column="1">
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<width>60</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="5">
<widget class="QLineEdit" name="dstPortLine">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;You can specify multiple ports using regular expressions:&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;- 53, 80 or 443:&lt;/p&gt;&lt;p&gt;^(53|80|443)$&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;- 53, 443 or 5551, 5552, 5553, etc:&lt;/p&gt;&lt;p&gt;^(53|443|555[0-9])$&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<item row="0" column="0">
<widget class="QCheckBox" name="protoCheck">
<property name="text">
<string>Protocol</string>
</property>
</widget>
</item>
<item row="4" column="2" colspan="4">
<widget class="QComboBox" name="srcIPCombo">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>You can specify a single IP:
- 192.168.1.1
or a regular expression:
- 192\.168\.1\.[0-9]+
multiple IPs:
- ^(192\.168\.1\.1|172\.16\.0\.1)$
You can also specify a subnet:
- 192.168.1.0/24
Note: Commas or spaces are not allowed to separate IPs or networks.</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string notr="true">LAN</string>
</property>
<property name="placeholderText">
<string notr="true"/>
</property>
<item>
<property name="text">
<string>LAN</string>
</property>
</item>
<item>
<property name="text">
<string>MULTICAST</string>
</property>
</item>
<item>
<property name="text">
<string>127.0.0.0/8</string>
</property>
</item>
<item>
<property name="text">
<string>192.168.0.0/24</string>
</property>
</item>
<item>
<property name="text">
<string>192.168.1.0/24</string>
</property>
</item>
<item>
<property name="text">
<string>192.168.2.0/24</string>
</property>
</item>
<item>
<property name="text">
<string>192.168.0.0/16</string>
</property>
</item>
<item>
<property name="text">
<string>169.254.0.0/16</string>
</property>
</item>
<item>
<property name="text">
<string>172.16.0.0/12</string>
</property>
</item>
<item>
<property name="text">
<string>10.0.0.0/8</string>
</property>
</item>
<item>
<property name="text">
<string>::1/128</string>
</property>
</item>
<item>
<property name="text">
<string>fc00::/7</string>
</property>
</item>
<item>
<property name="text">
<string>ff00::/8</string>
</property>
</item>
<item>
<property name="text">
<string>fe80::/10</string>
</property>
</item>
<item>
<property name="text">
<string>fd00::/8</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="srcIPCheck">
<property name="text">
<string>From this IP / Network</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="dstHostCheck">
<property name="text">
<string>To this host</string>
</property>
</widget>
</item>
<item row="5" column="2" colspan="4">
<item row="6" column="2" colspan="4">
<widget class="QComboBox" name="dstIPCombo">
<property name="enabled">
<bool>false</bool>
@ -761,132 +857,69 @@ Note: Commas or spaces are not allowed to separate IPs or networks.</string>
</item>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QCheckBox" name="ifaceCheck">
<property name="text">
<string>Network interface</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="dstPortCheck">
<property name="text">
<string>To this port</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="srcIPCheck">
<property name="text">
<string>From this IP / Network</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="4">
<widget class="QComboBox" name="srcIPCombo">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>You can specify a single IP:
- 192.168.1.1
or a regular expression:
- 192\.168\.1\.[0-9]+
multiple IPs:
- ^(192\.168\.1\.1|172\.16\.0\.1)$
You can also specify a subnet:
- 192.168.1.0/24
Note: Commas or spaces are not allowed to separate IPs or networks.</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string notr="true">LAN</string>
</property>
<property name="placeholderText">
<string notr="true"/>
</property>
<item row="1" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<property name="text">
<string>LAN</string>
</property>
<widget class="QCheckBox" name="srcPortCheck">
<property name="text">
<string>From this port</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>MULTICAST</string>
</property>
<widget class="QLineEdit" name="srcPortLine">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;You can specify multiple ports using regular expressions:&lt;/p&gt;&lt;p&gt;- 53, 80 or 443:&lt;/p&gt;&lt;p&gt;^(53|80|443)$&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;- 53, 443 or 5551, 5552, 5553, etc:&lt;/p&gt;&lt;p&gt;^(53|443|555[0-9])$&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>127.0.0.0/8</string>
</property>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<property name="text">
<string>192.168.0.0/24</string>
</property>
<widget class="QCheckBox" name="dstPortCheck">
<property name="text">
<string>To this port</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>192.168.1.0/24</string>
</property>
<widget class="QLineEdit" name="dstPortLine">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;You can specify multiple ports using regular expressions:&lt;/p&gt;&lt;p&gt;- 53, 80 or 443:&lt;/p&gt;&lt;p&gt;^(53|80|443)$&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;- 53, 443 or 5551, 5552, 5553, etc:&lt;/p&gt;&lt;p&gt;^(53|443|555[0-9])$&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>192.168.2.0/24</string>
</property>
</item>
<item>
<property name="text">
<string>192.168.0.0/16</string>
</property>
</item>
<item>
<property name="text">
<string>169.254.0.0/16</string>
</property>
</item>
<item>
<property name="text">
<string>172.16.0.0/12</string>
</property>
</item>
<item>
<property name="text">
<string>10.0.0.0/8</string>
</property>
</item>
<item>
<property name="text">
<string>::1/128</string>
</property>
</item>
<item>
<property name="text">
<string>fc00::/7</string>
</property>
</item>
<item>
<property name="text">
<string>ff00::/8</string>
</property>
</item>
<item>
<property name="text">
<string>fe80::/10</string>
</property>
</item>
<item>
<property name="text">
<string>fd00::/8</string>
</property>
</item>
</widget>
</layout>
</item>
</layout>
</widget>