Skip to content

Commit 0df8543

Browse files
committed
base: more readable log-format
1 parent dfcf76b commit 0df8543

File tree

7 files changed

+143
-68
lines changed

7 files changed

+143
-68
lines changed

docs/source/usage/3_run.rst

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,34 +82,34 @@ Pass Example
8282
> 🛈 ROUTER: Packet inbound-route: 172.17.0.0/16, scope link
8383
> 🛈 FIREWALL: Processing Chain: Table nat ip4 | Chain PREROUTING ip4 nat
8484
> 🛈 FIREWALL: > Chain PREROUTING | Rule 0 | Match => jump
85-
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER
85+
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER (2 rules)
8686
> 🛈 FIREWALL: > Chain DOCKER | Rule 0 | Match => return
8787
> 🛈 ROUTER: Packet outbound-interface: wan
88-
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope remote
88+
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope global
8989
> 🛈 FIREWALL: Processing Chain: Table filter ip4 | Chain FORWARD ip4 filter
9090
> 🛈 FIREWALL: > Chain FORWARD | Rule 0 | Match => jump
91-
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-USER
91+
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-USER (1 rules)
9292
> 🛈 FIREWALL: > Chain DOCKER-USER | Rule 0 | Match => return
9393
> 🛈 FIREWALL: > Chain FORWARD | Rule 1
9494
> 🛈 FIREWALL: > Chain FORWARD | Rule 2
9595
> 🛈 FIREWALL: > Chain FORWARD | Rule 3
9696
> 🛈 FIREWALL: > Chain FORWARD | Rule 4 | Match => jump
97-
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-FORWARD
97+
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-FORWARD (4 rules)
9898
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Rule 0 | Match => jump
99-
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Sub-Chain: DOCKER-CT
99+
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Sub-Chain: DOCKER-CT (1 rules)
100100
> 🛈 FIREWALL: > Chain DOCKER-CT | Rule 0
101101
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Rule 1 | Match => jump
102-
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Sub-Chain: DOCKER-ISOLATION-STAGE-1
102+
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Sub-Chain: DOCKER-ISOLATION-STAGE-1 (1 rules)
103103
> 🛈 FIREWALL: > Chain DOCKER-ISOLATION-STAGE-1 | Rule 0 | Match => jump
104-
> 🛈 FIREWALL: > Chain DOCKER-ISOLATION-STAGE-1 | Sub-Chain: DOCKER-ISOLATION-STAGE-2
104+
> 🛈 FIREWALL: > Chain DOCKER-ISOLATION-STAGE-1 | Sub-Chain: DOCKER-ISOLATION-STAGE-2 (1 rules)
105105
> 🛈 FIREWALL: > Chain DOCKER-ISOLATION-STAGE-2 | Rule 0
106106
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Rule 2 | Match => jump
107-
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Sub-Chain: DOCKER-BRIDGE
107+
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Sub-Chain: DOCKER-BRIDGE (1 rules)
108108
> 🛈 FIREWALL: > Chain DOCKER-BRIDGE | Rule 0
109109
> 🛈 FIREWALL: > Chain DOCKER-FORWARD | Rule 3 | Match => accept
110110
> 🛈 FIREWALL: Processing Chain: Table nat ip4 | Chain POSTROUTING ip4 nat
111111
> 🛈 FIREWALL: > Chain POSTROUTING | Rule 0 | Match => snat
112-
> 🛈 FIREWALL: Performed SNAT
112+
> 🛈 FIREWALL: Performed SNAT: 172.17.11.5 => 10.255.255.48
113113
> ✓ FIREWALL: Packet passed
114114
115115
----
@@ -125,16 +125,17 @@ Block Example
125125
> 🛈 ROUTER: Packet inbound-route: 172.17.0.0/16, scope link
126126
> 🛈 FIREWALL: Processing Chain: Table nat ip4 | Chain PREROUTING ip4 nat
127127
> 🛈 FIREWALL: > Chain PREROUTING | Rule 0 | Match => jump
128-
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER
128+
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER (2 rules)
129129
> 🛈 FIREWALL: > Chain DOCKER | Rule 0 | Match => return
130130
> 🛈 ROUTER: Packet outbound-interface: wan
131-
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope remote
131+
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope global
132132
> 🛈 FIREWALL: Processing Chain: Table filter ip4 | Chain FORWARD ip4 filter
133133
> 🛈 FIREWALL: > Chain FORWARD | Rule 0 | Match => jump
134-
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-USER
134+
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-USER (1 rules)
135135
> 🛈 FIREWALL: > Chain DOCKER-USER | Rule 0 | Match => return
136136
> 🛈 FIREWALL: > Chain FORWARD | Rule 1 | Match => drop
137-
> ✖ FIREWALL: Packet blocked by rule: {'action': 'drop', 'seq': 1, 'raw': Rule: #101 "TEST DROP" | Matches: [proto_l3 == ip4 & ip_daddr == ['2.2.2.2/32']]}
137+
> ✖ FIREWALL: Packet blocked by rule: Seq 1, Action: drop, Rule: #101 "TEST IP4-DADDR DROP"
138+
> > Matches: {'proto_l3': {'==': 'ip4'}, 'ip_daddr': {'==': ['2.2.2.2/32']}}
138139
139140
----
140141

@@ -150,26 +151,38 @@ You can get more detailed output by increasing the verbosity:
150151
> 🛈 ROUTER: Packet inbound-interface: docker0
151152
> 🛈 ROUTER: Packet inbound-route: 172.17.0.0/16, scope link
152153
> 🛈 FIREWALL: Processing Chain: Table nat ip4 | Chain PREROUTING ip4 nat
153-
> 🛈 FIREWALL: > Chain PREROUTING | Rule 0 | Match => jump | {'action': 'jump', 'seq': 0, 'raw': Rule: #3 | Matches: []}
154-
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER
155-
> 🛈 FIREWALL: > Chain DOCKER | Rule 0 | Match => return | {'action': 'return', 'seq': 0, 'raw': Rule: #10 | Matches: [ni_in == ['docker0']]}
154+
> 🛈 FIREWALL: > Chain PREROUTING | Rule 0 | Match => jump | Seq 0, Action: jump, Rule: #3
155+
> > Matches: {}
156+
>
157+
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER (2 rules)
158+
> 🛈 FIREWALL: > Chain DOCKER | Rule 0 | Match => return | Seq 0, Action: return, Rule: #10
159+
> > Matches: {'ni_in': {'==': ['docker0']}}
160+
>
156161
> 🛈 FIREWALL: Flow-type: forward
157162
> 🛈 ROUTER: Packet outbound-interface: wan
158-
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope remote
163+
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope global
159164
> 🛈 FIREWALL: Processing Chain: Table filter ip4 | Chain FORWARD ip4 filter
160-
> 🛈 FIREWALL: > Chain FORWARD | Rule 0 | Match => jump | {'action': 'jump', 'seq': 0, 'raw': Rule: #20 | Matches: []}
161-
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-USER
162-
> 🛈 FIREWALL: > Chain DOCKER-USER | Rule 0 | Match => return | {'action': 'return', 'seq': 0, 'raw': Rule: #19 | Matches: []}
163-
> 🛈 FIREWALL: > Chain FORWARD | Rule 1 | Match => drop | {'action': 'drop', 'seq': 1, 'raw': Rule: #101 "TEST IP4-DADDR DROP" | Matches: [proto_l3 == ip4 & ip_daddr == ['2.2.2.2/32']]}
164-
> ✖ FIREWALL: Packet blocked by rule: {'action': 'drop', 'seq': 1, 'raw': Rule: #101 "TEST IP4-DADDR DROP" | Matches: [proto_l3 == ip4 & ip_daddr == ['2.2.2.2/32']]}
165+
> 🛈 FIREWALL: > Chain FORWARD | Rule 0 | Match => jump | Seq 0, Action: jump, Rule: #20
166+
> > Matches: {}
167+
>
168+
> 🛈 FIREWALL: > Chain FORWARD | Sub-Chain: DOCKER-USER (1 rules)
169+
> 🛈 FIREWALL: > Chain DOCKER-USER | Rule 0 | Match => return | Seq 0, Action: return, Rule: #19
170+
> > Matches: {}
171+
>
172+
> 🛈 FIREWALL: > Chain FORWARD | Rule 1 | Match => drop | Seq 1, Action: drop, Rule: #101 "TEST IP4-DADDR DROP"
173+
> > Matches: {'proto_l3': {'==': 'ip4'}, 'ip_daddr': {'==': ['2.2.2.2/32']}}
174+
>
175+
> ✖ FIREWALL: Packet blocked by rule: Seq 1, Action: drop, Rule: #101 "TEST IP4-DADDR DROP"
176+
> > Matches: {'proto_l3': {'==': 'ip4'}, 'ip_daddr': {'==': ['2.2.2.2/32']}}
165177
166178
Or use the silent-mode:
167179

168180
.. code-block:: bash
169181
170182
ftf-cli ... --src-ip 172.17.11.5 --dst-ip 2.2.2.2 --verbosity silent
171183
172-
> ✖ FIREWALL: Packet blocked by rule: {'action': 'drop', 'seq': 1, 'raw': Rule: #101 "TEST IP4-DADDR DROP" | Matches: [proto_l3 == ip4 & ip_daddr == ['2.2.2.2/32']]}
184+
> ✖ FIREWALL: Packet blocked by rule: Seq 1, Action: drop, Rule: #101 "TEST IP4-DADDR DROP"
185+
> > Matches: {'proto_l3': {'==': 'ip4'}, 'ip_daddr': {'==': ['2.2.2.2/32']}}
173186
174187
----
175188

@@ -186,7 +199,7 @@ Depending on the system-specific configuration traffic can be dropped by non-fir
186199
> 🛈 ROUTER: Packet inbound-route: 172.17.0.0/16, scope link
187200
> 🛈 FIREWALL: Processing Chain: Table nat ip4 | Chain PREROUTING ip4 nat
188201
> 🛈 FIREWALL: > Chain PREROUTING | Rule 0 | Match => jump
189-
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER
202+
> 🛈 FIREWALL: > Chain PREROUTING | Sub-Chain: DOCKER (2 rules)
190203
> 🛈 FIREWALL: > Chain DOCKER | Rule 0 | Match => return
191204
> 🛈 ROUTER: Packet outbound-interface: wan
192205
> 🛈 ROUTER: Packet outbound-route: 0.0.0.0/0, gw 10.255.255.254, metric 600, scope remote

src/firewall_test/plugins/translate/netfilter/elements.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from config import ProtoL3, ProtoL3IP4, ProtoL3IP6, MatchPort, ProtoL4ICMP, ProtoL4TCP, ProtoL4UDP, ProtoL3IP4IP6, \
55
PROTO_L4_MAPPING, PROTO_L3_MAPPING
66
from plugins.translate.netfilter.parts import RULE_ACTIONS, IGNORE_RULE_EXPRESSIONS, IGNORE_LEFT
7-
from utils.logger import log_warn
7+
from utils.logger import log_warn, rule_repr
88

99
# pylint: disable=R0801
1010

@@ -437,15 +437,4 @@ def get_matches(self) -> dict:
437437
return matches
438438

439439
def __repr__(self) -> str:
440-
cmt = ''
441-
if self.comment is not None:
442-
cmt = f' "{self.comment}"'
443-
444-
if self.handle is not None:
445-
cmt += f' (handle {self.handle})'
446-
447-
matches = str(self.matches)
448-
if len(matches) > 500:
449-
matches = matches[:500] + '...'
450-
451-
return f"Rule: #{self.handle}{cmt} | Matches: {matches}"
440+
return rule_repr(uid=self.handle, matches=self.get_matches(), cmt=self.comment)

src/firewall_test/plugins/translate/opnsense/rule.py

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from ipaddress import IPv4Network, IPv6Network
22

33
from config import ProtoL3IP4IP6, PROTOS_L3, PROTOS_L4
4+
from utils.logger import rule_repr
45

56
# pylint: disable=R0801
67

@@ -10,13 +11,16 @@ class OPNsenseRule:
1011
DIRECTION_OUT = 'out'
1112
DIRECTION_ANY = 'any'
1213

14+
OP_EQ = '=='
15+
OP_NE = '!='
16+
1317
def __init__(
1418
self,
1519
nr: int,
20+
uuid: str,
1621
nis: list[str] = None,
1722
ni_direction: str = None,
1823
desc: str = None,
19-
quick: bool = True,
2024
ipprotocol: PROTOS_L3 = ProtoL3IP4IP6,
2125
protocol: PROTOS_L4 = None,
2226
source: list[(IPv4Network, IPv6Network)] = None,
@@ -29,10 +33,10 @@ def __init__(
2933
destination_any: bool = False,
3034
):
3135
self.nr = nr
36+
self.uuid = uuid
3237
self.nis = nis
3338
self.ni_direction = ni_direction
3439
self.desc = desc
35-
self.quick = quick
3640
self.ipp = ipprotocol
3741
self.proto = protocol
3842
self.src = source
@@ -73,42 +77,49 @@ def match_ip_saddr(self) -> bool:
7377

7478
@property
7579
def match_ip_daddr(self) -> bool:
76-
if self.dst_any or (self.src is not None and len(self.src) > 0):
80+
if self.dst_any or (self.dst is not None and len(self.dst) > 0):
7781
return True
7882

7983
return False
8084

81-
def get_match_types(self) -> (list[str], None):
82-
match = []
85+
def get_matches(self) -> (dict, None):
86+
matches = {}
8387
if self.ipp is not None:
84-
match.append('proto_l3')
88+
matches['proto_l3'] = self.ipp.N
8589

8690
if self.proto is not None:
87-
match.append('proto_l4')
91+
matches['proto_l4'] = [v.N for v in self.proto]
8892

8993
if self.match_ip_saddr:
90-
match.append('ip_saddr')
94+
op = self.OP_NE if self.src_invert else self.OP_EQ
95+
src = 'any' if self.src_any else [str(v) for v in self.src]
96+
matches['ip_saddr'] = {op: src}
9197

9298
if self.match_ip_daddr:
93-
match.append('ip_daddr')
99+
op = self.OP_NE if self.dst_invert else self.OP_EQ
100+
dst = 'any' if self.dst_any else [str(v) for v in self.dst]
101+
matches['ip_daddr'] = {op: dst}
94102

95103
if self.match_ni_in:
96-
match.append('ni_in')
104+
matches['ni_in'] = self.nis
97105

98106
if self.match_ni_out:
99-
match.append('ni_out')
107+
matches['ni_out'] = self.nis
100108

101109
if self.src_port is not None and len(self.src_port) > 0:
102-
match.append('src-port')
110+
matches['src_port'] = self.src_port
103111

104112
if self.dst_port is not None and len(self.dst_port) > 0:
105-
match.append('dst-port')
113+
matches['dst_port'] = self.dst_port
106114

107-
if len(match) == 0:
108-
match = None
115+
if len(matches) == 0:
116+
return None
109117

110-
return match
118+
return matches
111119

112120
def __repr__(self) -> str:
113-
desc = '' if self.desc is None else f' ({self.desc})'
114-
return f"Rule: #{self.nr}{desc} | Matches: {self.get_match_types()}"
121+
cmt = '' if self.desc is None else f' "{self.desc}"'
122+
if self.uuid is not None:
123+
cmt += f' (UUID: {self.uuid})'
124+
125+
return rule_repr(uid=self.nr, matches=self.get_matches(), cmt=cmt)

src/firewall_test/plugins/translate/opnsense/ruleset_test.py

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_opnsense_ruleset():
2323
for c in table.chains:
2424
c.validate()
2525

26-
assert len(r.aliases) == 73 # todo: find missing 1 alias!
26+
assert len(r.aliases) == 72 # todo: find missing 1 alias!
2727
assert len(r.aliases['HOST_DNS_TRUSTED_REPOS']) > 0
2828
for e in r.aliases['HOST_DNS_TRUSTED_REPOS']:
2929
assert isinstance(e, (IPv4Network, IPv6Network))
@@ -55,23 +55,65 @@ def test_opnsense_ruleset():
5555
]
5656

5757
assert len(r.chain_dnat.rules) == 0
58-
assert len(r.chain_floating.rules) == 17
58+
assert len(r.chain_floating.rules) == 14
5959
assert len(r.chain_ni_grp.rules) == 7
60-
assert len(r.chain_ni.rules) == 87
60+
assert len(r.chain_ni.rules) == 82
6161
assert len(r.chain_snat.rules) == 0
6262

63+
# todo: mock external responses (IPLists, DNS-resolution) for stable tests
6364
# todo: validate that matches are correct..
65+
66+
# drop any traffic to blacklisted targets (dst = iplist/urltable)
6467
r1 = r.chain_floating.rules[1]
6568
assert r1.seq == 2
6669
assert r1.action == RuleActionDrop
67-
assert r1.raw.get_match_types() == ['proto_l3', 'ip_saddr']
68-
70+
m = r1.raw.get_matches()
71+
assert 'ip_daddr' in m
72+
assert '==' in m['ip_daddr']
73+
assert len(m['ip_daddr']['==']) > 10 # IP-List content
74+
assert 'ip_saddr' in m
75+
assert '==' in m['ip_saddr'] and m['ip_saddr']['=='] == 'any'
76+
assert 'proto_l3' in m
77+
assert m['proto_l3'] == 'ip4'
78+
79+
# allow some server to sync with external pop3s
6980
r2 = r.chain_ni_grp.rules[4]
7081
assert r2.seq == 5
7182
assert r2.action == RuleActionAccept
72-
assert r2.raw.get_match_types() == ['proto_l3', 'proto_l4', 'ip_saddr', 'ip_daddr', 'dst-port']
83+
m = r2.raw.get_matches()
84+
for e in ['dst_port', 'ip_daddr', 'ip_saddr', 'proto_l3', 'proto_l4']:
85+
assert e in m
86+
87+
assert m['dst_port'] == [993]
88+
assert '!=' in m['ip_daddr']
89+
assert m['ip_daddr']['!='] == [
90+
'10.38.0.0/16',
91+
'10.0.0.0/8',
92+
'172.16.0.0/12',
93+
]
94+
assert '==' in m['ip_saddr']
95+
assert m['ip_saddr']['=='] == ['10.34.28.206/32']
96+
assert m['proto_l3'] == 'ip4'
97+
assert m['proto_l4'] == ['tcp']
7398

99+
# allow some internal hosts http+s to an external service via DNS
74100
r3 = r.chain_ni.rules[42]
75-
assert r3.seq == 43
101+
assert r3.seq == 44
76102
assert r3.action == RuleActionAccept
77-
assert r3.raw.get_match_types() == ['proto_l3', 'proto_l4', 'ip_saddr', 'ip_daddr', 'dst-port']
103+
m = r3.raw.get_matches()
104+
for e in ['dst_port', 'ip_daddr', 'ip_saddr', 'proto_l3', 'proto_l4']:
105+
assert e in m
106+
107+
assert m['dst_port'] == [80, 443]
108+
assert '==' in m['ip_daddr']
109+
assert len(m['ip_daddr']['==']) > 10 # DNS-resolved alias
110+
assert '==' in m['ip_saddr']
111+
assert m['ip_saddr']['=='] == [
112+
'10.38.13.201/32',
113+
'10.34.28.101/32',
114+
]
115+
assert m['proto_l3'] == 'ip4'
116+
assert m['proto_l4'] == ['tcp']
117+
118+
119+
# todo: add tests for many possible real-life rule-expression-combinations to catch edge-cases

src/firewall_test/simulator/firewall.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def _log_match(self, chain: Chain, rule: Rule, debug: bool = False):
3333
lazy_action = ' (lazy)'
3434

3535
msg = f'> Chain {chain.name} | Rule {rule.seq} | Match => {rule.action.N}{lazy_action}'
36-
v2 = f' | {rule.dump()}'
36+
v2 = f' | {rule.log()}'
3737
if debug:
3838
log_debug('Firewall', msg + v2)
3939

@@ -116,7 +116,7 @@ def process(self, chain: Chain, packet: PACKET_KINDS) -> (bool, (Rule, None)):
116116

117117
log_info(
118118
label='Firewall',
119-
v1=f'> Chain {chain.name} | Sub-Chain: {target_chain.name}',
119+
v1=f'> Chain {chain.name} | Sub-Chain: {target_chain.name} ({len(target_chain.rules)} rules)',
120120
v3=f' {target_chain.family.N} {target_chain.type}'
121121
)
122122
target_chain.run_table = chain.run_table

src/firewall_test/simulator/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, packet: PACKET_KINDS, simulator):
5959
_, self.dnat = self._s.fw.process_dnat(packet=packet, flow=self.flow_type)
6060
self._dnat_done = True
6161
if self.dnat is not None:
62-
log_info(label='Firewall', v1='Performed DNAT', v2=f': {self.packet.dnat_str}')
62+
log_info(label='Firewall', v1=f'Performed DNAT: {self.packet.dnat_str}')
6363

6464
### UPDATE TRAFFIC FLOW AND OUTBOUND-NETWORK-INTERFACE ###
6565

@@ -114,7 +114,7 @@ def __init__(self, packet: PACKET_KINDS, simulator):
114114
else:
115115
self.packet.src = self._get_snat_masquerade_ip()
116116

117-
log_info(label='Firewall', v1='Performed SNAT', v2=f': {self.packet.snat_str()}')
117+
log_info(label='Firewall', v1=f'Performed SNAT: {self.packet.snat_str()}')
118118

119119
elif self.flow_type == FlowOutput:
120120
# use the correct outbound-IP if the traffic originated from this host itself
@@ -261,7 +261,7 @@ def _log_block(rule: (Rule, None)):
261261
log_error(label='Firewall', v1='Packet blocked by chain default-policy', final=True)
262262

263263
else:
264-
log_error(label='Firewall', v1='Packet blocked by rule', v2=f': {rule.dump()}', final=True)
264+
log_error(label='Firewall', v1='Packet blocked by rule', v2=f': {rule.log()}', final=True)
265265

266266

267267
class Simulator:

0 commit comments

Comments
 (0)