rules: allow to filter by network interface name

Now you can create rules to filter network interface name.
Regular expresions allowed: "eth[0-9]"

Closes #726
This commit is contained in:
Gustavo Iñiguez Goia 2022-09-24 17:12:09 +02:00
parent 92e5240b08
commit 4a0f7a3e2b
Failed to generate hash of commit
7 changed files with 114 additions and 52 deletions

View file

@ -31,7 +31,7 @@ type Connection struct {
Entry *netstat.Entry Entry *netstat.Entry
Process *procmon.Process Process *procmon.Process
pkt *netfilter.Packet Pkt *netfilter.Packet
} }
var showUnknownCons = false var showUnknownCons = false
@ -192,7 +192,7 @@ func NewConnection(nfp *netfilter.Packet) (c *Connection, err error) {
SrcIP: ip.SrcIP, SrcIP: ip.SrcIP,
DstIP: ip.DstIP, DstIP: ip.DstIP,
DstHost: dns.HostOr(ip.DstIP, ""), DstHost: dns.HostOr(ip.DstIP, ""),
pkt: nfp, Pkt: nfp,
} }
return newConnectionImpl(nfp, c, "") return newConnectionImpl(nfp, c, "")
} }
@ -211,14 +211,14 @@ func NewConnection6(nfp *netfilter.Packet) (c *Connection, err error) {
SrcIP: ip.SrcIP, SrcIP: ip.SrcIP,
DstIP: ip.DstIP, DstIP: ip.DstIP,
DstHost: dns.HostOr(ip.DstIP, ""), DstHost: dns.HostOr(ip.DstIP, ""),
pkt: nfp, Pkt: nfp,
} }
return newConnectionImpl(nfp, c, "6") return newConnectionImpl(nfp, c, "6")
} }
func (c *Connection) parseDirection(protoType string) bool { func (c *Connection) parseDirection(protoType string) bool {
ret := false ret := false
if tcpLayer := c.pkt.Packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { if tcpLayer := c.Pkt.Packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
if tcp, ok := tcpLayer.(*layers.TCP); ok == true && tcp != nil { if tcp, ok := tcpLayer.(*layers.TCP); ok == true && tcp != nil {
c.Protocol = "tcp" + protoType c.Protocol = "tcp" + protoType
c.DstPort = uint(tcp.DstPort) c.DstPort = uint(tcp.DstPort)
@ -226,10 +226,10 @@ func (c *Connection) parseDirection(protoType string) bool {
ret = true ret = true
if tcp.DstPort == 53 { if tcp.DstPort == 53 {
c.getDomains(c.pkt, c) c.getDomains(c.Pkt, c)
} }
} }
} else if udpLayer := c.pkt.Packet.Layer(layers.LayerTypeUDP); udpLayer != nil { } else if udpLayer := c.Pkt.Packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
if udp, ok := udpLayer.(*layers.UDP); ok == true && udp != nil { if udp, ok := udpLayer.(*layers.UDP); ok == true && udp != nil {
c.Protocol = "udp" + protoType c.Protocol = "udp" + protoType
c.DstPort = uint(udp.DstPort) c.DstPort = uint(udp.DstPort)
@ -237,10 +237,10 @@ func (c *Connection) parseDirection(protoType string) bool {
ret = true ret = true
if udp.DstPort == 53 { if udp.DstPort == 53 {
c.getDomains(c.pkt, c) c.getDomains(c.Pkt, c)
} }
} }
} else if udpliteLayer := c.pkt.Packet.Layer(layers.LayerTypeUDPLite); udpliteLayer != nil { } else if udpliteLayer := c.Pkt.Packet.Layer(layers.LayerTypeUDPLite); udpliteLayer != nil {
if udplite, ok := udpliteLayer.(*layers.UDPLite); ok == true && udplite != nil { if udplite, ok := udpliteLayer.(*layers.UDPLite); ok == true && udplite != nil {
c.Protocol = "udplite" + protoType c.Protocol = "udplite" + protoType
c.DstPort = uint(udplite.DstPort) c.DstPort = uint(udplite.DstPort)

View file

@ -14,6 +14,7 @@ const (
// Verdict holds the action to perform on a packet (NF_DROP, NF_ACCEPT, etc) // Verdict holds the action to perform on a packet (NF_DROP, NF_ACCEPT, etc)
type Verdict C.uint type Verdict C.uint
// VerdictContainer struct
type VerdictContainer struct { type VerdictContainer struct {
Verdict Verdict Verdict Verdict
Mark uint32 Mark uint32
@ -27,6 +28,8 @@ type Packet struct {
verdictChannel chan VerdictContainer verdictChannel chan VerdictContainer
UID uint32 UID uint32
NetworkProtocol uint8 NetworkProtocol uint8
IfaceInIdx int
IfaceOutIdx int
} }
// SetVerdict emits a veredict on a packet // SetVerdict emits a veredict on a packet
@ -40,13 +43,15 @@ func (p *Packet) SetVerdictAndMark(v Verdict, mark uint32) {
p.verdictChannel <- VerdictContainer{Verdict: v, Packet: nil, Mark: mark} p.verdictChannel <- VerdictContainer{Verdict: v, Packet: nil, Mark: mark}
} }
func (p *Packet) SetRequeueVerdict(newQueueId uint16) { // SetRequeueVerdict apply a verdict on a requeued packet
func (p *Packet) SetRequeueVerdict(newQueueID uint16) {
v := uint(NF_QUEUE) v := uint(NF_QUEUE)
q := (uint(newQueueId) << 16) q := (uint(newQueueID) << 16)
v = v | q v = v | q
p.verdictChannel <- VerdictContainer{Verdict: Verdict(v), Packet: nil, Mark: 0} p.verdictChannel <- VerdictContainer{Verdict: Verdict(v), Packet: nil, Mark: 0}
} }
// SetVerdictWithPacket apply a verdict, but with a new packet
func (p *Packet) SetVerdictWithPacket(v Verdict, packet []byte) { func (p *Packet) SetVerdictWithPacket(v Verdict, packet []byte) {
p.verdictChannel <- VerdictContainer{Verdict: v, Packet: packet, Mark: 0} p.verdictChannel <- VerdictContainer{Verdict: v, Packet: packet, Mark: 0}
} }

View file

@ -184,7 +184,7 @@ func (q *Queue) Packets() <-chan Packet {
// FYI: the export keyword is mandatory to specify that go_callback is defined elsewhere // FYI: the export keyword is mandatory to specify that go_callback is defined elsewhere
//export go_callback //export go_callback
func go_callback(queueID C.int, data *C.uchar, length C.int, mark C.uint, idx uint32, vc *VerdictContainerC, uid uint32) { func go_callback(queueID C.int, data *C.uchar, length C.int, mark C.uint, idx uint32, vc *VerdictContainerC, uid, devIn, devOut uint32) {
(*vc).verdict = C.uint(NF_ACCEPT) (*vc).verdict = C.uint(NF_ACCEPT)
(*vc).data = nil (*vc).data = nil
(*vc).mark_set = 0 (*vc).mark_set = 0
@ -205,6 +205,8 @@ func go_callback(queueID C.int, data *C.uchar, length C.int, mark C.uint, idx ui
Mark: uint32(mark), Mark: uint32(mark),
UID: uid, UID: uid,
NetworkProtocol: xdata[0] >> 4, // first 4 bits is the version NetworkProtocol: xdata[0] >> 4, // first 4 bits is the version
IfaceInIdx: int(devIn),
IfaceOutIdx: int(devOut),
} }
var packet gopacket.Packet var packet gopacket.Packet

View file

@ -24,7 +24,7 @@ typedef struct {
static void *get_uid = NULL; static void *get_uid = NULL;
extern void go_callback(int id, unsigned char* data, int len, unsigned int mark, uint32_t idx, verdictContainer *vc, uint32_t uid); extern void go_callback(int id, unsigned char* data, int len, unsigned int mark, uint32_t idx, verdictContainer *vc, uint32_t uid, uint32_t in_dev, uint32_t out_dev);
static uint8_t stop = 0; static uint8_t stop = 0;
@ -60,6 +60,10 @@ static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct n
int size = 0; int size = 0;
verdictContainer vc = {0}; verdictContainer vc = {0};
uint32_t uid = 0xffffffff; uint32_t uid = 0xffffffff;
uint32_t in_dev=0, out_dev=0;
in_dev = nfq_get_indev(nfa);
out_dev = nfq_get_outdev(nfa);
mark = nfq_get_nfmark(nfa); mark = nfq_get_nfmark(nfa);
ph = nfq_get_msg_packet_hdr(nfa); ph = nfq_get_msg_packet_hdr(nfa);
@ -72,7 +76,7 @@ static int nf_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct n
nfq_get_uid(nfa, &uid); nfq_get_uid(nfa, &uid);
#endif #endif
go_callback(id, buffer, size, mark, idx, &vc, uid); go_callback(id, buffer, size, mark, idx, &vc, uid, in_dev, out_dev);
if( vc.mark_set == 1 ) { if( vc.mark_set == 1 ) {
return nfq_set_verdict2(qh, id, vc.verdict, vc.mark, vc.length, vc.data); return nfq_set_verdict2(qh, id, vc.verdict, vc.mark, vc.length, vc.data);

View file

@ -47,6 +47,8 @@ const (
OpDstPort = Operand("dest.port") OpDstPort = Operand("dest.port")
OpDstNetwork = Operand("dest.network") OpDstNetwork = Operand("dest.network")
OpProto = Operand("protocol") OpProto = Operand("protocol")
OpIfaceIn = Operand("iface.in")
OpIfaceOut = Operand("iface.out")
OpList = Operand("list") OpList = Operand("list")
OpDomainsLists = Operand("lists.domains") OpDomainsLists = Operand("lists.domains")
OpDomainsRegexpLists = Operand("lists.domains_regexp") OpDomainsRegexpLists = Operand("lists.domains_regexp")
@ -287,6 +289,14 @@ func (o *Operator) Match(con *conman.Connection) bool {
return o.cb(con.DstHost) return o.cb(con.DstHost)
} else if o.Operand == OpProto { } else if o.Operand == OpProto {
return o.cb(con.Protocol) 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)
}
} else if o.Operand == OpIfaceOut {
if ifname, err := net.InterfaceByIndex(con.Pkt.IfaceOutIdx); err == nil {
return o.cb(ifname.Name)
}
} else if strings.HasPrefix(string(o.Operand), string(OpProcessEnvPrefix)) { } else if strings.HasPrefix(string(o.Operand), string(OpProcessEnvPrefix)) {
envVarName := core.Trim(string(o.Operand[OpProcessEnvPrefixLen:])) envVarName := core.Trim(string(o.Operand[OpProcessEnvPrefixLen:]))
envVarValue, _ := con.Process.Env[envVarName] envVarValue, _ := con.Process.Env[envVarName]

View file

@ -14,6 +14,8 @@ class Config:
OPERAND_PROCESS_COMMAND = "process.command" OPERAND_PROCESS_COMMAND = "process.command"
OPERAND_PROCESS_ENV = "process.env." OPERAND_PROCESS_ENV = "process.env."
OPERAND_USER_ID = "user.id" OPERAND_USER_ID = "user.id"
OPERAND_IFACE_OUT = "iface.out"
OPERAND_IFACE_IN = "iface.in"
OPERAND_DEST_IP = "dest.ip" OPERAND_DEST_IP = "dest.ip"
OPERAND_DEST_HOST = "dest.host" OPERAND_DEST_HOST = "dest.host"
OPERAND_DEST_PORT = "dest.port" OPERAND_DEST_PORT = "dest.port"

View file

@ -15,7 +15,7 @@ from opensnitch.config import Config
from opensnitch.nodes import Nodes from opensnitch.nodes import Nodes
from opensnitch.database import Database from opensnitch.database import Database
from opensnitch.version import version from opensnitch.version import version
from opensnitch.utils import Message, FileDialog, Icons from opensnitch.utils import Message, FileDialog, Icons, NetworkInterfaces
DIALOG_UI_PATH = "%s/../res/ruleseditor.ui" % os.path.dirname(sys.modules[__name__].__file__) DIALOG_UI_PATH = "%s/../res/ruleseditor.ui" % os.path.dirname(sys.modules[__name__].__file__)
class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
@ -58,6 +58,7 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.protoCheck.toggled.connect(self._cb_proto_check_toggled) self.protoCheck.toggled.connect(self._cb_proto_check_toggled)
self.procCheck.toggled.connect(self._cb_proc_check_toggled) self.procCheck.toggled.connect(self._cb_proc_check_toggled)
self.cmdlineCheck.toggled.connect(self._cb_cmdline_check_toggled) 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.dstPortCheck.toggled.connect(self._cb_dstport_check_toggled)
self.uidCheck.toggled.connect(self._cb_uid_check_toggled) self.uidCheck.toggled.connect(self._cb_uid_check_toggled)
self.pidCheck.toggled.connect(self._cb_pid_check_toggled) self.pidCheck.toggled.connect(self._cb_pid_check_toggled)
@ -81,6 +82,15 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if _rule != None: if _rule != None:
self._load_rule(rule=_rule) self._load_rule(rule=_rule)
def showEvent(self, event):
super(RulesEditorDialog, self).showEvent(event)
oldText = self.ifaceCombo.currentText()
self.ifaceCombo.clear()
if self._nodes.is_local(self.nodesCombo.currentText()):
self.ifaceCombo.addItems(NetworkInterfaces.list().keys())
self.ifaceCombo.setCurrentText(oldText)
def _bool(self, s): def _bool(self, s):
return s == 'True' return s == 'True'
@ -127,6 +137,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.cmdlineLine.setEnabled(state) self.cmdlineLine.setEnabled(state)
self.checkCmdlineRegexp.setEnabled(state) self.checkCmdlineRegexp.setEnabled(state)
def _cb_iface_check_toggled(self, state):
self.ifaceCombo.setEnabled(state)
def _cb_dstport_check_toggled(self, state): def _cb_dstport_check_toggled(self, state):
self.dstPortLine.setEnabled(state) self.dstPortLine.setEnabled(state)
@ -312,6 +325,9 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
self.pidCheck.setChecked(False) self.pidCheck.setChecked(False)
self.pidLine.setText("") self.pidLine.setText("")
self.ifaceCheck.setChecked(False)
self.ifaceCombo.setCurrentText("")
self.dstPortCheck.setChecked(False) self.dstPortCheck.setChecked(False)
self.dstPortLine.setText("") self.dstPortLine.setText("")
@ -371,41 +387,46 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
def _load_rule_operator(self, operator): def _load_rule_operator(self, operator):
self.sensitiveCheck.setChecked(operator.sensitive) self.sensitiveCheck.setChecked(operator.sensitive)
if operator.operand == "protocol": if operator.operand == Config.OPERAND_PROTOCOL:
self.protoCheck.setChecked(True) self.protoCheck.setChecked(True)
self.protoCombo.setEnabled(True) self.protoCombo.setEnabled(True)
self.protoCombo.setCurrentText(operator.data.upper()) self.protoCombo.setCurrentText(operator.data.upper())
if operator.operand == "process.path": if operator.operand == Config.OPERAND_PROCESS_PATH:
self.procCheck.setChecked(True) self.procCheck.setChecked(True)
self.procLine.setEnabled(True) self.procLine.setEnabled(True)
self.procLine.setText(operator.data) self.procLine.setText(operator.data)
self.checkProcRegexp.setEnabled(True) self.checkProcRegexp.setEnabled(True)
self.checkProcRegexp.setChecked(operator.type == Config.RULE_TYPE_REGEXP) self.checkProcRegexp.setChecked(operator.type == Config.RULE_TYPE_REGEXP)
if operator.operand == "process.command": if operator.operand == Config.OPERAND_PROCESS_COMMAND:
self.cmdlineCheck.setChecked(True) self.cmdlineCheck.setChecked(True)
self.cmdlineLine.setEnabled(True) self.cmdlineLine.setEnabled(True)
self.cmdlineLine.setText(operator.data) self.cmdlineLine.setText(operator.data)
self.checkCmdlineRegexp.setEnabled(True) self.checkCmdlineRegexp.setEnabled(True)
self.checkCmdlineRegexp.setChecked(operator.type == Config.RULE_TYPE_REGEXP) self.checkCmdlineRegexp.setChecked(operator.type == Config.RULE_TYPE_REGEXP)
if operator.operand == "user.id": if operator.operand == Config.OPERAND_USER_ID:
self.uidCheck.setChecked(True) self.uidCheck.setChecked(True)
self.uidLine.setEnabled(True) self.uidLine.setEnabled(True)
self.uidLine.setText(operator.data) self.uidLine.setText(operator.data)
if operator.operand == "process.id": if operator.operand == Config.OPERAND_PROCESS_ID:
self.pidCheck.setChecked(True) self.pidCheck.setChecked(True)
self.pidLine.setEnabled(True) self.pidLine.setEnabled(True)
self.pidLine.setText(operator.data) self.pidLine.setText(operator.data)
if operator.operand == "dest.port": if operator.operand == Config.OPERAND_IFACE_OUT:
self.ifaceCheck.setChecked(True)
self.ifaceCombo.setEnabled(True)
self.ifaceCombo.setCurrentText(operator.data)
if operator.operand == Config.OPERAND_DEST_PORT:
self.dstPortCheck.setChecked(True) self.dstPortCheck.setChecked(True)
self.dstPortLine.setEnabled(True) self.dstPortLine.setEnabled(True)
self.dstPortLine.setText(operator.data) self.dstPortLine.setText(operator.data)
if operator.operand == "dest.ip" or operator.operand == "dest.network": if operator.operand == Config.OPERAND_DEST_IP or operator.operand == Config.OPERAND_DEST_NETWORK:
self.dstIPCheck.setChecked(True) self.dstIPCheck.setChecked(True)
self.dstIPCombo.setEnabled(True) self.dstIPCombo.setEnabled(True)
if operator.data == self.LAN_RANGES: if operator.data == self.LAN_RANGES:
@ -413,30 +434,30 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
else: else:
self.dstIPCombo.setCurrentText(operator.data) self.dstIPCombo.setCurrentText(operator.data)
if operator.operand == "dest.host": if operator.operand == Config.OPERAND_DEST_HOST:
self.dstHostCheck.setChecked(True) self.dstHostCheck.setChecked(True)
self.dstHostLine.setEnabled(True) self.dstHostLine.setEnabled(True)
self.dstHostLine.setText(operator.data) self.dstHostLine.setText(operator.data)
if operator.operand == "lists.domains": if operator.operand == Config.OPERAND_LIST_DOMAINS:
self.dstListsCheck.setChecked(True) self.dstListsCheck.setChecked(True)
self.dstListsCheck.setEnabled(True) self.dstListsCheck.setEnabled(True)
self.dstListsLine.setText(operator.data) self.dstListsLine.setText(operator.data)
self.selectListButton.setEnabled(True) self.selectListButton.setEnabled(True)
if operator.operand == "lists.domains_regexp": if operator.operand == Config.OPERAND_LIST_DOMAINS_REGEXP:
self.dstListRegexpCheck.setChecked(True) self.dstListRegexpCheck.setChecked(True)
self.dstListRegexpCheck.setEnabled(True) self.dstListRegexpCheck.setEnabled(True)
self.dstRegexpListsLine.setText(operator.data) self.dstRegexpListsLine.setText(operator.data)
self.selectListRegexpButton.setEnabled(True) self.selectListRegexpButton.setEnabled(True)
if operator.operand == "lists.ips": if operator.operand == Config.OPERAND_LIST_IPS:
self.dstListIPsCheck.setChecked(True) self.dstListIPsCheck.setChecked(True)
self.dstListIPsCheck.setEnabled(True) self.dstListIPsCheck.setEnabled(True)
self.dstListIPsLine.setText(operator.data) self.dstListIPsLine.setText(operator.data)
self.selectIPsListButton.setEnabled(True) self.selectIPsListButton.setEnabled(True)
if operator.operand == "lists.nets": if operator.operand == Config.OPERAND_LIST_NETS:
self.dstListNetsCheck.setChecked(True) self.dstListNetsCheck.setChecked(True)
self.dstListNetsCheck.setEnabled(True) self.dstListNetsCheck.setEnabled(True)
self.dstListNetsLine.setText(operator.data) self.dstListNetsLine.setText(operator.data)
@ -552,12 +573,12 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self.protoCombo.currentText() == "": if self.protoCombo.currentText() == "":
return False, QC.translate("rules", "protocol can not be empty, or uncheck it") return False, QC.translate("rules", "protocol can not be empty, or uncheck it")
self.rule.operator.operand = "protocol" self.rule.operator.operand = Config.OPERAND_PROTOCOL
self.rule.operator.data = self.protoCombo.currentText() self.rule.operator.data = self.protoCombo.currentText()
rule_data.append( rule_data.append(
{ {
"type": Config.RULE_TYPE_SIMPLE, "type": Config.RULE_TYPE_SIMPLE,
"operand": "protocol", "operand": Config.OPERAND_PROTOCOL,
"data": self.protoCombo.currentText().lower(), "data": self.protoCombo.currentText().lower(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -570,12 +591,12 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self.procLine.text() == "": if self.procLine.text() == "":
return False, QC.translate("rules", "process path can not be empty") return False, QC.translate("rules", "process path can not be empty")
self.rule.operator.operand = "process.path" self.rule.operator.operand = Config.OPERAND_PROCESS_PATH
self.rule.operator.data = self.procLine.text() self.rule.operator.data = self.procLine.text()
rule_data.append( rule_data.append(
{ {
"type": Config.RULE_TYPE_SIMPLE, "type": Config.RULE_TYPE_SIMPLE,
"operand": "process.path", "operand": Config.OPERAND_PROCESS_PATH,
"data": self.procLine.text(), "data": self.procLine.text(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -588,12 +609,12 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self.cmdlineLine.text() == "": if self.cmdlineLine.text() == "":
return False, QC.translate("rules", "command line can not be empty") return False, QC.translate("rules", "command line can not be empty")
self.rule.operator.operand = "process.command" self.rule.operator.operand = Config.OPERAND_PROCESS_COMMAND
self.rule.operator.data = self.cmdlineLine.text() self.rule.operator.data = self.cmdlineLine.text()
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_SIMPLE, 'type': Config.RULE_TYPE_SIMPLE,
'operand': 'process.command', 'operand': Config.OPERAND_PROCESS_COMMAND,
'data': self.cmdlineLine.text(), 'data': self.cmdlineLine.text(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -602,16 +623,34 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self._is_valid_regex(self.cmdlineLine.text()) == False: if self._is_valid_regex(self.cmdlineLine.text()) == False:
return False, QC.translate("rules", "Command line regexp error") return False, QC.translate("rules", "Command line regexp error")
if self.ifaceCheck.isChecked():
if self.ifaceCombo.currentText() == "":
return False, QC.translate("rules", "Network interface can not be empty")
self.rule.operator.operand = Config.OPERAND_IFACE_OUT
self.rule.operator.data = self.ifaceCombo.currentText()
rule_data.append(
{
'type': Config.RULE_TYPE_SIMPLE,
'operand': Config.OPERAND_IFACE_OUT,
'data': self.ifaceCombo.currentText(),
"sensitive": self.sensitiveCheck.isChecked()
})
if self._is_regex(self.ifaceCombo.currentText()):
rule_data[len(rule_data)-1]['type'] = Config.RULE_TYPE_REGEXP
if self._is_valid_regex(self.ifaceCombo.currentText()) == False:
return False, QC.translate("rules", "Network interface regexp error")
if self.dstPortCheck.isChecked(): if self.dstPortCheck.isChecked():
if self.dstPortLine.text() == "": if self.dstPortLine.text() == "":
return False, QC.translate("rules", "Dest port can not be empty") return False, QC.translate("rules", "Dest port can not be empty")
self.rule.operator.operand = "dest.port" self.rule.operator.operand = Config.OPERAND_DEST_PORT
self.rule.operator.data = self.dstPortLine.text() self.rule.operator.data = self.dstPortLine.text()
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_SIMPLE, 'type': Config.RULE_TYPE_SIMPLE,
'operand': 'dest.port', 'operand': Config.OPERAND_DEST_PORT,
'data': self.dstPortLine.text(), 'data': self.dstPortLine.text(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -624,12 +663,12 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self.dstHostLine.text() == "": if self.dstHostLine.text() == "":
return False, QC.translate("rules", "Dest host can not be empty") return False, QC.translate("rules", "Dest host can not be empty")
self.rule.operator.operand = "dest.host" self.rule.operator.operand = Config.OPERAND_DEST_HOST
self.rule.operator.data = self.dstHostLine.text() self.rule.operator.data = self.dstHostLine.text()
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_SIMPLE, 'type': Config.RULE_TYPE_SIMPLE,
'operand': 'dest.host', 'operand': Config.OPERAND_DEST_HOST,
'data': self.dstHostLine.text(), 'data': self.dstHostLine.text(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -645,21 +684,21 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
dstIPtext = self.dstIPCombo.currentText() dstIPtext = self.dstIPCombo.currentText()
if dstIPtext == self.LAN_LABEL: if dstIPtext == self.LAN_LABEL:
self.rule.operator.operand = "dest.ip" self.rule.operator.operand = Config.OPERAND_DEST_IP
self.rule.operator.type = Config.RULE_TYPE_REGEXP self.rule.operator.type = Config.RULE_TYPE_REGEXP
dstIPtext = self.LAN_RANGES dstIPtext = self.LAN_RANGES
else: else:
try: try:
if type(ipaddress.ip_address(self.dstIPCombo.currentText())) == ipaddress.IPv4Address \ if type(ipaddress.ip_address(self.dstIPCombo.currentText())) == ipaddress.IPv4Address \
or type(ipaddress.ip_address(self.dstIPCombo.currentText())) == ipaddress.IPv6Address: or type(ipaddress.ip_address(self.dstIPCombo.currentText())) == ipaddress.IPv6Address:
self.rule.operator.operand = "dest.ip" self.rule.operator.operand = Config.OPERAND_DEST_IP
self.rule.operator.type = Config.RULE_TYPE_SIMPLE self.rule.operator.type = Config.RULE_TYPE_SIMPLE
except Exception: except Exception:
self.rule.operator.operand = "dest.network" self.rule.operator.operand = Config.OPERAND_DEST_NETWORK
self.rule.operator.type = Config.RULE_TYPE_NETWORK self.rule.operator.type = Config.RULE_TYPE_NETWORK
if self._is_regex(dstIPtext): if self._is_regex(dstIPtext):
self.rule.operator.operand = "dest.ip" self.rule.operator.operand = Config.OPERAND_DEST_IP
self.rule.operator.type = Config.RULE_TYPE_REGEXP self.rule.operator.type = Config.RULE_TYPE_REGEXP
if self._is_valid_regex(self.dstIPCombo.currentText()) == False: if self._is_valid_regex(self.dstIPCombo.currentText()) == False:
return False, QC.translate("rules", "Dst IP regexp error") return False, QC.translate("rules", "Dst IP regexp error")
@ -676,12 +715,12 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self.uidLine.text() == "": if self.uidLine.text() == "":
return False, QC.translate("rules", "User ID can not be empty") return False, QC.translate("rules", "User ID can not be empty")
self.rule.operator.operand = "user.id" self.rule.operator.operand = Config.OPERAND_USER_ID
self.rule.operator.data = self.uidLine.text() self.rule.operator.data = self.uidLine.text()
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_SIMPLE, 'type': Config.RULE_TYPE_SIMPLE,
'operand': 'user.id', 'operand': Config.OPERAND_USER_ID,
'data': self.uidLine.text(), 'data': self.uidLine.text(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -694,12 +733,12 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
if self.pidLine.text() == "": if self.pidLine.text() == "":
return False, QC.translate("rules", "PID field can not be empty") return False, QC.translate("rules", "PID field can not be empty")
self.rule.operator.operand = "process.id" self.rule.operator.operand = Config.OPERAND_PROCESS_ID
self.rule.operator.data = self.pidLine.text() self.rule.operator.data = self.pidLine.text()
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_SIMPLE, 'type': Config.RULE_TYPE_SIMPLE,
'operand': 'process.id', 'operand': Config.OPERAND_PROCESS_ID,
'data': self.pidLine.text(), 'data': self.pidLine.text(),
"sensitive": self.sensitiveCheck.isChecked() "sensitive": self.sensitiveCheck.isChecked()
}) })
@ -715,11 +754,11 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
return False, QC.translate("rules", "Lists field must be a directory") return False, QC.translate("rules", "Lists field must be a directory")
self.rule.operator.type = Config.RULE_TYPE_LISTS self.rule.operator.type = Config.RULE_TYPE_LISTS
self.rule.operator.operand = "lists.domains" self.rule.operator.operand = Config.OPERAND_LIST_DOMAINS
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_LISTS, 'type': Config.RULE_TYPE_LISTS,
'operand': 'lists.domains', 'operand': Config.OPERAND_LIST_DOMAINS,
'data': self.dstListsLine.text(), 'data': self.dstListsLine.text(),
'sensitive': self.sensitiveCheck.isChecked() 'sensitive': self.sensitiveCheck.isChecked()
}) })
@ -732,11 +771,11 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
return False, QC.translate("rules", "Lists field must be a directory") return False, QC.translate("rules", "Lists field must be a directory")
self.rule.operator.type = Config.RULE_TYPE_LISTS self.rule.operator.type = Config.RULE_TYPE_LISTS
self.rule.operator.operand = "lists.domains_regexp" self.rule.operator.operand = Config.OPERAND_LIST_DOMAINS_REGEXP
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_LISTS, 'type': Config.RULE_TYPE_LISTS,
'operand': 'lists.domains_regexp', 'operand': Config.OPERAND_LIST_DOMAINS_REGEXP,
'data': self.dstRegexpListsLine.text(), 'data': self.dstRegexpListsLine.text(),
'sensitive': self.sensitiveCheck.isChecked() 'sensitive': self.sensitiveCheck.isChecked()
}) })
@ -749,11 +788,11 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
return False, QC.translate("rules", "Lists field must be a directory") return False, QC.translate("rules", "Lists field must be a directory")
self.rule.operator.type = Config.RULE_TYPE_LISTS self.rule.operator.type = Config.RULE_TYPE_LISTS
self.rule.operator.operand = "lists.nets" self.rule.operator.operand = Config.OPERAND_LIST_NETS
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_LISTS, 'type': Config.RULE_TYPE_LISTS,
'operand': 'lists.nets', 'operand': Config.OPERAND_LIST_NETS,
'data': self.dstListNetsLine.text(), 'data': self.dstListNetsLine.text(),
'sensitive': self.sensitiveCheck.isChecked() 'sensitive': self.sensitiveCheck.isChecked()
}) })
@ -767,11 +806,11 @@ class RulesEditorDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]):
return False, QC.translate("rules", "Lists field must be a directory") return False, QC.translate("rules", "Lists field must be a directory")
self.rule.operator.type = Config.RULE_TYPE_LISTS self.rule.operator.type = Config.RULE_TYPE_LISTS
self.rule.operator.operand = "lists.ips" self.rule.operator.operand = Config.OPERAND_LIST_IPS
rule_data.append( rule_data.append(
{ {
'type': Config.RULE_TYPE_LISTS, 'type': Config.RULE_TYPE_LISTS,
'operand': 'lists.ips', 'operand': Config.OPERAND_LIST_IPS,
'data': self.dstListIPsLine.text(), 'data': self.dstListIPsLine.text(),
'sensitive': self.sensitiveCheck.isChecked() 'sensitive': self.sensitiveCheck.isChecked()
}) })