BGP route filter "dst in address_list" exact prefix match question

Hi Mikrotik folks,

with great joy i saw ROS v7.6 brought back displaying route advertisements - awesome!

This way i could see an, from my point of view, unexpected behavior of a route filter.
According to the documentation of (BGP) route filters

Prefix Operators
IN - Return true if the prefix is the subnet of the provided network. If an operator is used to match prefixes from the address list (e.g “dst in list_name”), then it will match only the exact prefix.

I am using the following rule:
chain=ipv4-ebgp-provider-out rule=“if (afi ipv4 && dst in ipv4-subnets-own-remote) {set bgp-path-prepend 2;accept}”

And i have the following entry in the list “ipv4-subnets-own-remote”:
list=ipv4-subnets-own-remote address=123.87.184.0/24

For my understanding according to the documentation, the rule should only accept exactly “123.87.184.0/24”
Not 123.87.184.0/25, not 123.87.184.123/32 or anything else, only the exactly prefix match.

Looking at the advertisements, i see
peer=ipv4-ebgp-provider-1 dst=123.87.184.16 nexthop=99.115.135.123 origin=2

When i disable the rule above, the IP is not advertised - so i can be sure it’s this rule which is accepting.

Is my understanding of the documentation wrong
(If an operator is used to match prefixes from the address list (e.g “dst in list_name”), then it will match only the exact prefix)
or is there a difference between the implementation and the documentation?

Do you have any other hint how i can make sure only the exact prefix of the address is accepted?

Thanks and best regards,
Stephan

Login point of view:
3 in 0-10 = true
4 in 0-5 = true
5 in 0-4 = false
24 on 24 = true

is the same for IPs, for match exactly 123.87.184.0/24

chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in 123.87.184.0/24 && dst-len in 24) {set bgp-path-prepend 2;accept}"

# OR

chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 123.87.184.0/24) {set bgp-path-prepend 2;accept}"

But as wroted on help guide, is possible to use address-list with an operator (“in”, “==” and “!=”), but really can be used only with “in”.
But it work “eactly” if used “in”, do not check that is exact also the “dst-len”
In this case is like are present multiple rules

/ip firewall address-list add list=test_list address=123.87.184.0/24
/ip firewall address-list add list=test_list address=132.74.14.0/22
/ip firewall address-list add list=test_list address=6.0.0.0/8
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in test_list) {set bgp-path-prepend 2;accept}"

# OR

chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in 123.87.184.0/24) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in 132.74.14.0/22) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in 6.0.0.0/8) {set bgp-path-prepend 2;accept}"

Hi rextended,

thanks for your fast reply.

Indeed, your example will match the first part of the documentation
IN - Return true if the prefix is the subnet of the provided network
3 in 0-10 = true
4 in 0-5 = true
5 in 0-4 = false
24 on 24 = true

But for my understanding it will not match the second part of the documentation
If an operator is used to match prefixes from the address list (e.g “dst in list_name”), then it will match only the exact prefix

Many thanks for your edited example config checking on address lists with “==”, i didnt notice that option so far and will try that

Thanks,
Stephan

please read again the previous post, I added a 2nd part as example at time your write your reply

I hope I have helped, is first time today I can help on BGPv7 because only from today I use it on production…

I just checked, but “==” cannot be used on address lists.

/routing/filter/rule/set numbers=2 rule=“if (afi ipv4 && dst == ipv4-subnets-own-remote) {set bgp-path-prepend 2;accept}”
failure: "Word {dst} == Word {ipv4-subnets-own-remote} " - invalid argument

The documentation i am referring to is
https://help.mikrotik.com/docs/display/ROS/Route+Selection+and+Filters

True, is not writed well…

Must not writed “If an operator is used” but something like «If “in” operator is used»
on this way do not cause misunderstandings

I have updated the 2nd example again for consistency

Sorry, but I must CONFIRM that the guide is wrong, I have updated all my previous post on this tread for keep consistency on this.

For check also the “dst-len”, must be do something like that:

/ip firewall address-list add list=test_list_24 address=135.71.184.0/24
/ip firewall address-list add list=test_list_24 address=122.99.22.0/24
/ip firewall address-list add list=test_list_22 address=87.86.85.0/22
/ip firewall address-list add list=test_list_22 address=92.74.15.0/22
/ip firewall address-list add list=test_list_8 address=6.0.0.0/8
/ip firewall address-list add list=test_list_8 address=7.0.0.0/8

chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in test_list_24 && dst-len in 24) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in test_list_22 && dst-len in 22) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst in test_list_8 && dst-len in 8) {set bgp-path-prepend 2;accept}"

# and the 3 rules are the equivalent of

chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 135.71.184.0/24 && dst-len in 24) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 122.99.22.0/24 && dst-len in 24) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 87.86.85.0/22 && dst-len in 22) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 92.74.15.0/22 && dst-len in 22) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 6.0.0.0/8 && dst-len in 8) {set bgp-path-prepend 2;accept}"
chain=ipv4-ebgp-provider-out rule="if (afi ipv4 && dst == 7.0.0.0/8 && dst-len in 8) {set bgp-path-prepend 2;accept}"

But if you have only /24 inside your “test_list” is sufficent only one line

Hi rextended,

thanks for the idea to build separate address lists, depending on the subnet size.
This could indeed be a workaround, depending on how many different subnet sizes we have to maintain.

Thanks,
Stephan

This is one of the dumber things MT did with ROS7. 192.168.234.0/24 is IN 192.168.232/21 and should therefore match perfectly.

Would also be useful for BOGON filtering. If you’re using 172.28.0.0/16 for your internal management network, it’s IN 172.16.0.0/12 and should match just like it would in a firewall rule.

IMO, route filters are broke in ROS7 anyways. I can break BGP quite easily and even managed to crash 7.5 CHR by simply adding/moving filter rules.

Hi troy,

I am not sure if I misunderstand your answer or you misunderstood my finding and question.

The IN operator actually works on address lists as you describe.
But for me the documentation is writing that the IN operator is only matching on exact matches (and not on smaller subnets of the subnet listed in the address list), which is not the case.

I am looking for a way to write a rule to only match on exact match and not on smaller subnets.

Thanks,
Stephan

For everyone facing the same issue, i did further testing and Mikrotik support just confirmed:
The exact match is actually working, but has a bug to match on /32 subnets as well.

No other subnet sizes are affected.

This issue still exists in RouterOS v7.12rc4. Matching the exact prefixes defined in an address list using in “if (dst in address-list) {accept}” does not work properly and will accept every single /32 in the specified prefixes as well.

I would also like to get a resolution or final clarification for this behavior will either remain as is, or if the operator will be modified. I currently using this bug/feature to my advantage for BGP filtering to allow in from customers the proper prefix with strict matching of what is set in the customer prefix list. By a stroke of luck if a /32 or /128 is advertised from the customer it passes through the initial filter rule in the customer chain and is captured by a blackhole rule.

In AS0000_CID_IPV6_PL

192.168.0.0/22

In Customer Chain

if ( dst in AS0000_CID_IPV6_PL ) { jump ALL_CUSTOMER_IPV6_IN; } else { reject; }

In ALL_CUSTOMER_IPV6_IN

if (  bgp-large-communities equal 0000:666:666 && ( dst-len == 32 || dst-len == 128 ) ) { set blackhole yes; return; } else { return; }

Curious if anyone has suggestions on a better way to accomplish this?

This behavior is very non intuitive and makes filter automation much more difficult.

IMO, when using lists, the following should occur:

address-list add list=test_list address=192.168.1.0/24
address-list add list=test_list address=10.0.0.0/8

#accept 192.168.1.0/24, 192.168.1.128/29, 10.1.2.0/24
#deny 1.1.1.0/24
chain=test_bgp_rule="if (afi ipv4 && dst in test_list) {set bgp-path-prepend 2;accept}"
chain=test_bgp_rule="reject;"

#accept 192.168.1.0/24
#deny 1.1.1.0/24, 192.168.1.128/29, 10.1.2.0/24
chain=test_bgp_rule="if (afi ipv4 && dst == test_list) {set bgp-path-prepend 2;accept}"
chain=test_bgp_rule="reject;"

#accept 1.1.1.0/24, 192.168.1.128/29, 10.1.2.0/24
#deny 192.168.1.0/24
chain=test_bgp_rule="if (afi ipv4 && dst != test_list) {set bgp-path-prepend 2;accept}"
chain=test_bgp_rule="reject;"

Then also perhaps consider adding a new, not in prefix operator, “!in

address-list add list=test_list address=192.168.1.0/24
address-list add list=test_list address=10.0.0.0/8

#accept 1.1.1.0/24
#deny 192.168.1.0/24, 192.168.1.128/29, 10.1.2.0/24
chain=test_bgp_rule="if (afi ipv4 && dst !in test_list) {set bgp-path-prepend 2;accept}"
chain=test_bgp_rule="reject;"

Any chance you’ve received an update from support?

Almost a year later and the issue is still present. I’m not being able to find a workaround. all /32 that are announced from BGP peer are filtered by the rule

chain=BGP_IN_VPN_VDF rule="if ( dst in BGP_NETWORKS_VPN_VDF ) { reject; }"

The following output is taken when the filter rule is active:

[local@NSG_MB_Core] /routing/filter/rule> /routing/route/print detail where gateway=10.1.255.1 and 81.181.171.131 in dst-address
Flags: X - disabled, F - filtered, U - unreachable, A - active; c - connect, s - static, r - rip, b - bgp, o - ospf, i - isis, d - dhcp, v - vpn, m - modem, a - ldp-address, l - ldp-mapping, g - slaac, y - bgp-mpls-vpn; H - hw-offloaded; 
+ - ecmp, B - blackhole 
  b   afi=ip4 contribution=best-candidate dst-address=0.0.0.0/0 routing-table=main gateway=10.1.255.1 immediate-gw=10.1.255.1%vlan4004 distance=150 scope=40 target-scope=10 belongs-to="bgp-IP-10.1.255.1" 
       bgp.session=VDF_VPN-1 .as-path="64891,12302,12302,207737" .communities=64891:1,64891:100,64891:1006 .weight=90 .local-pref=90 .origin=igp 
       debug.fwp-ptr=0x20342BA0 

 Fb   afi=ip4 contribution=filtered dst-address=81.181.171.131/32 routing-table=main gateway=10.1.255.1 immediate-gw=10.1.255.1%vlan4004 distance=20 scope=40 target-scope=10 belongs-to="bgp-IP-10.1.255.1" 
       bgp.session=VDF_VPN-1 .as-path="64891,12302,12302,207737" .communities=64891:1 .origin=igp 
       debug.fwp-ptr=0x20342BA0

And when the rule is disabled:

[local@NSG_MB_Core] /routing/filter/rule> /routing/route/print detail where gateway=10.1.255.1 and 81.181.171.131 in dst-address
Flags: X - disabled, F - filtered, U - unreachable, A - active; c - connect, s - static, r - rip, b - bgp, o - ospf, i - isis, d - dhcp, v - vpn, m - modem, a - ldp-address, l - ldp-mapping, g - slaac, y - bgp-mpls-vpn; H - hw-offloaded; 
+ - ecmp, B - blackhole 
  b   afi=ip4 contribution=best-candidate dst-address=0.0.0.0/0 routing-table=main gateway=10.1.255.1 immediate-gw=10.1.255.1%vlan4004 distance=150 scope=40 target-scope=10 belongs-to="bgp-IP-10.1.255.1" 
       bgp.session=VDF_VPN-1 .as-path="64891,12302,12302,207737" .communities=64891:1,64891:100,64891:1006 .weight=90 .local-pref=90 .origin=igp 
       debug.fwp-ptr=0x20342BA0 

 Ab   afi=ip4 contribution=active dst-address=81.181.171.131/32 routing-table=main gateway=10.1.255.1 immediate-gw=10.1.255.1%vlan4004 distance=20 scope=40 target-scope=10 belongs-to="bgp-IP-10.1.255.1" 
       bgp.session=VDF_VPN-1 .as-path="64891,12302,12302,207737" .communities=64891:1 .origin=igp 
       debug.fwp-ptr=0x20342BA0

My address-list contains only:

[local@NSG_MB_Core] /routing/filter/rule> /ip fi address-list/print where 81.181.171.131 in address and list=BGP_NETWORKS_VPN_VDF 
Columns: LIST, ADDRESS, CREATION-TIME
# LIST                  ADDRESS          CREATION-TIME      
;;; NSG #001 - ICI
2 BGP_NETWORKS_VPN_VDF  81.181.171.0/24  2025-04-22 01:13:18
;;; NSG #000 - ICI
3 BGP_NETWORKS_VPN_VDF  81.181.170.0/23  2025-04-22 01:13:18

I didn’t had the chance to check the advertisements yet, but definitely the received routes are affected.
Any advice here?

if ( dst in BGP_NETWORKS_VPN_VDF  && dst-len > 32 )

Thanks mrz. Actually i was thinking to a similar approach, before i went to sleep, but i didn’t test it.
So, your solution is working! Thank you. I will need to replace in all rules where similar behavior is expected.

Cheers,
Have a nice day!