Support for "OR" operator in mangle rules

Current situation:

If i want to mangle all traffic from an address list (from “x” address list and to “x” address list) i need to make 2 mangle rules:

/ip firewall mangle
add action=mark-packet chain=postrouting disabled=no new-packet-mark=MYMARK passthrough=yes src-address-list=TEST
add action=mark-packet chain=postrouting disabled=no dst-address-list=TEST new-packet-mark=MYMARK passthrough=yes

translated to a programming language will be something like:

if(packet.src-address-list == 'TEST'){
mark packet
}
if(packet.dst-address-list == 'TEST'){
mark packet
}

Router OS support ‘AND’ operator so this rule:

/ip firewall mangle
add action=mark-packet chain=postrouting disabled=no new-packet-mark=MYMARK passthrough=yes src-address-list=TEST dst-address-list=TEST

translated to a programming language will be something like:

if(packet.src-address-list == 'TEST' && packet.dst-address-list == 'TEST'){
mark packet
}

Also Router OS support ‘NOT’ operator:

/ip firewall mangle
add action=mark-packet chain=postrouting disabled=no new-packet-mark=MYMARK passthrough=yes src-address-list=TEST dst-address-list=!TEST

translated to a programming language will be something like:

if(packet.src-address-list == 'TEST' && packet.dst-address-list != 'TEST'){
mark packet
}

It will be possible that Router OS support ‘OR’ operator? (ie: with a ‘|’) so my first rule can be like:

/ip firewall mangle
add action=mark-packet chain=postrouting disabled=no new-packet-mark=MYMARK passthrough=yes src-address-list=|TEST dst-address-list=|TEST

translated to a programming language will be something like:

if(packet.src-address-list == 'TEST' || packet.dst-address-list == 'TEST'){
mark packet
}

I think this can reduce the number of mangle rules and maybe some precious cpu : )

Tell me what do you think. am i crazy? it’s a good idea?

it should be done this way - pseudo code:

if (connection state == new && src-address-list=TEST){
mark connection with this mark - test, and pass through}
if (connection state == new && dst-address-list=TEST){
mark connection with this mark - test, pass through}
if (connection-mark == test) {
mark the packet with mark test}

if you manage new connections elsewhere, then in the end you get something faster than OR.

Sorry for the delay

Thanks for your tips : ) the rules was only for demonstration purposes, currently I’m using the “!” (NOT) operator for make the mangle rules not re-mark connection, for sample:

/ip firewall mangle
add action=mark-connection chain=prerouting comment="Test Traffic" connection-mark=!MyConnMark disabled=no new-connection-mark=MyConnMark passthrough=yes src-address-list=TEST
add action=mark-connection chain=prerouting comment="Test Traffic" connection-mark=!MyConnMark disabled=no new-connection-mark=MyConnMark passthrough=yes dst-address-list=TEST
add action=mark-packet chain=prerouting connection-mark=MyConnMark disabled=no new-packet-mark=MyMark passthrough=no

I think that it works like you example but i will try it your way.

Even with your example the OR operator will work fast IMHO, because you have to check 2 times the same things (if(chain = prerouting, port = x, address-list = x) etc…) if we could use this operator your rule will be reduced to something like this:

if (connection state == new && (src-address-list=TEST || dst-address-list=TEST)){
mark connection with this mark - test, pass through}
if (connection-mark == test) {
mark the packet with mark test}

This multiplied for x rules maybe can use less cpu than make 2 or more rules for each situation

IE, this are my rules in real life for mark DNS connections:

add action=mark-connection chain=prerouting comment=DNS connection-mark=!QoS_DNS disabled=no new-connection-mark=QoS_DNS passthrough=yes protocol=udp dst-port=53 
add action=mark-connection chain=prerouting connection-mark=!QoS_DNS disabled=no new-connection-mark=QoS_DNS passthrough=yes src-address-list=DNS
add action=mark-connection chain=prerouting connection-mark=!QoS_DNS disabled=no dst-address-list=DNS new-connection-mark=QoS_DNS passthrough=yes
add action=mark-connection chain=prerouting connection-mark=!QoS_DNS disabled=no layer7-protocol=dns new-connection-mark=QoS_DNS passthrough=yes
add action=mark-packet chain=prerouting connection-mark=QoS_DNS disabled=no new-packet-mark=QoS_MainProtocols passthrough=no

Same rules if i could use the OR operator:

add action=mark-connection chain=prerouting comment=DNS connection-mark=!QoS_DNS disabled=no new-connection-mark=QoS_DNS passthrough=yes protocol=|udp dst-port=53 src-address-list=|DNS dst-address-list=|DNS layer7-protocol=|dns
add action=mark-packet chain=prerouting connection-mark=QoS_DNS disabled=no new-packet-mark=QoS_MainProtocols passthrough=no

what translated in pseudocode will be like:
(if connection-mark != QoS_DNS && ( (protocol = udp && dst-port=53) || src-address-list = DNS || dst-address-list=DNS || layer7-protocol=dns) {
mark connection with this mark - QoS_DNS}
if (connection-mark == QoS_DNS) {
mark the packet with mark QoS_DNS}

I think that the CPU used by OR operator will be similar to AND operator, but we can save cpu is reducing rules.

why ‘(protocol = udp && dst-port=53)’? :slight_smile: maybe, ‘(dst-address-list = DNS && dst-port=53) || protocol=udp’? the main problem is that there’s no syntax for logical expressions

nope. when using ‘AND’, firewall checks all conditions one by one. it stops as soon as it face false statement. when you try to add ‘OR’ functionality, you will need to continue to evaluate all the rest. iptables are designed for ‘AND’ behaviour, and they are programmed keeping that in mind

Because you cannot check the port if you don't know the protocol so i follow winbox "guidelines", when you select a protocol it enable some fields in the form (like dst-port, src-port).

It is possible to make a "logical" way to work with this operator obviously with some limitations (ie: your rule cannot be possible)

"OR" work at same way but reverse:

Complicated rule with AND:

add action=mark-connection chain=prerouting comment=DNS disabled=no new-connection-mark=QoS_DNS passthrough=yes protocol=udp dst-port=53 src-address-list=DNS dst-address-list=DNS layer7-protocol=dns

Rule in Pseudo code:

if ( (protocol = udp && dst-port=53) && src-address-list = DNS && dst-address-list=DNS && layer7-protocol=dns) {
make something
}

Complicated rule with OR:

add action=mark-connection chain=prerouting comment=DNS disabled=no new-connection-mark=QoS_DNS passthrough=yes protocol=|udp dst-port=53 src-address-list=|DNS dst-address-list=|DNS layer7-protocol=|dns

Rule in Pseudo code:

if ( (protocol = udp && dst-port=53) || src-address-list = DNS || dst-address-list=DNS || layer7-protocol=dns) {
make something
}

Two sample packets, one that not mach the rules and another that match the rule
TCP 80 (Web)
UDP 53 (DNS)

\



Travel of Web Packet with AND rules:

if protocol = udp // the result is: false so we stop looking here
AND if dst-port=53 // NOT evaluated since last condition was false
AND if src-address-list = DNS // NOT evaluated since last condition was false
AND if dst-address-list=DNS // NOT evaluated since last condition was false
AND if layer7-protocol=dns // NOT evaluated since last condition was false

FINISH
Conditions processed: 1





Travel of DNS Packet with AND rules:

if protocol = udp // this is true so we continue checking conditions
AND if dst-port=53 // true, we continue
AND if src-address-list = DNS // true, we continue
AND if dst-address-list=DNS // true, we continue
AND if layer7-protocol=dns // true

FINISH
Conditions processed: 5


Travel of Web Packet with OR rules:

if protocol = udp // the result is: false but we have OR conditions so we continue processing it
AND if dst-port=53 // This condition are NOT evaluated since protocol match = false
OR if src-address-list = DNS // false but continue processing
OR if dst-address-list=DNS // false but continue processing
OR if layer7-protocol=dns // false

FINISH
Conditions processed: 4


Travel of DNS Packet with OR rules:

if protocol = udp // this is true so we continue checking conditions
AND if dst-port=53 // true
OR if src-address-list = DNS // NOT evaluated since last condition was true
OR if dst-address-list=DNS // NOT evaluated since last condition was true
OR if layer7-protocol=dns // NOT evaluated since last condition was true

FINISH
Conditions processed: 2


So i think that "OR" are not the "Bad Guy", it can be helpful for some people like me, and always the final user choose to use it or not. : P

I think you are fighting a losing battle here. Linux uses IPTables. IPTables is standard. Mikrotik uses Linux and IPTables.

IPTables is built the way it is… This is not going to change anytime soon.

This is not a “Mikrotik” thing. This is a Linux/IPTables thing.

really?.. if I need DNS, I must look for port 53, and I don’t care whether it will be tcp or udp - DNS uses them all :slight_smile: anyway,

that’s VERY bad example. in the light of your next ‘OR’ example you must split it into several rules:

  1. add chain=prerouting protocol=udp dst-port=53 passthrough=no bla-bla-bla
  2. add chain=prerouting src-address-list=DNS passthrough=no bla-bla-bla
  3. add chain=prerouting dst-address-list=DNS passthrough=no bla-bla-bla
  4. add chain=prerouting layer7-protocol=dns passthrough=no bla-bla-bla

so if packet is definitely 53/udp, it won’t be checked against address lists and layer7 filter. that’s how iptables designed to work :slight_smile: