find addresses with same octets

You need to get a list of IP addresses from the address list in which the first three octets of the IP addresses are the same, but only the last one is different and there are more than four such addresses.
I understand that you need to use posix regex, but I’m not on friendly terms with this at all. I ask for the help of our dear Rex.

Ok. :wink:

Is there any reason the “in” operator wouldn’t work? The “in” checks if a type=ip/ip6/ip-prefex is included in a type=ip-prefix. Depending on what you’re doing, might be easier then mucking with regex to parse IP addresses.

e.g.

:put (1.1.1.1 in 1.0.0.0/8)
#true
:put (1.1.1.1 in 8.0.0.0/8)
#false

The OP question is not really clear to me…


@msatter is right, ask everyone, this is not my personal forum…

@Amm0 give you the soluction:

{
/ip firewall address-list
:local pool [find where (address in 1.2.3.0/24) or (address in 4.5.6.0/24) or (address in 7.8.9.0/24)]
}

You need to get a list of IP addresses from the address list myAddr, where the first three octets of the IP address are the same, but only the last one differs.

for example: 192.168.88.3, 192.168.88.67; 192.168.88.12; 192.168.0.11; 192.168.67.5; 192.168.88.34

From these, addresses with the first three single octets should be selected, that is, in this case, from the 88/0 network



{
:local listname octettest3
/ip/firewall/address-list
:foreach i in={192.168.88.3;192.168.88.67;192.168.88.12;192.168.0.11;192.168.67.5;192.168.88.34} do={add list=$listname address=$i}  
:foreach a in=[find (address in 192.168.88.0/24) and (list=$listname)] do={:put [get $a address]}
remove [find list=$listname]
}

Which outputs the items in bold:
192.168.88.3
192.168.88.67
192.168.88.12
192.168.88.34

Dear Amm0. If it were that easy, I wouldn’t be asking. Addresses and subnets are not known in advance. Dear Amm0. If it were that easy, I wouldn’t be asking. Addresses and subnets are not known in advance. This address list was given as an example

I guess I’m not understanding. If there is no address nor subnet… What are you trying to match? I just populated a new list to verify/show.

If the address-list was from DNS, it still search the dynamic entires with IP. But yes you’d have to know the subnet you were looking for.

I’ll try to explain again…
Let’s say we have a certain address list, to which arbitrary addresses are added by some kind of firewall rule. Of course, we do not know these addresses in advance. Among them, there may be the same and similar. We need to catch addresses in this list with the same first three octets, for example 45.140.168.XXX. And detect the moment when there are more identical ones, for example 5 (that is, someone knocked from the same subnet more than 5 times).

The most important thing is to explain yourself well, not only in words, but with concrete examples of how it is before and how you want it afterwards.

What I understand is that you want an IP aggregator so that many IP’s of the same subnet are represented only once, to reduce the number of items in the firewall.

This requires enormous computing power each time the list is processed,
which at which point you better do things with common sense: close open world services, as it should be,
and drop-all-at-the-end that’s more than enough.

I don’t know what this is for, one user from the Russian-speaking forum needs it. I don’t care what he wants to do with it. God bless them with computing power. We need a script with probably a posix regexp template that allows you to select addresses with the same first three octets.

We are always there, this magical RegEx, what is it supposed to do?
Automatically select the IPs and divide them by subnet, and then merge them back into /24?
As I said: concrete example, not novels.

It should probably be taken one IP at a time in the list, converted to x.x.x.0/24, and looked for how many other x.x.x.y addresses exist.
Above a certain threshold, add x.x.x.0/24 to a temporary address list, if it doesn’t already exist on that list, and so on…

Yes, probably so. I was thinking how can I use posix patterns to compare addresses…
And yes, probably, as you said, it will heavily load the processor

Posix? Not needed at all the RegEx…

This example display only text, do not alter nothing, and display the network only if more than one occurrance exist of x.x.x.0/24
/ip firewall address-list {
:local ip2net do={:return [[:parse “:return $($1 & 255.255.255.0)/$2”]]}
:local addr 0.0.0.0
:local net 0.0.0.0
:foreach item in=[find where ([:typeof [:toip $address]]=“ip”)] do={
:set addr [get $item address]
:set net [$ip2net $addr 24]
:if ([:len [find where $address in $net]] > 1) do={
:put “\r\nSearch results for $net”; print where $address in $net
}
}
}

I need help writing an efficient algorithm to convert (for example) this:
192.168.88.0
192.168.88.1
192.168.88.2
192.168.88.3
192.168.88.4
192.168.88.5
192.168.88.6
192.168.88.7
192.168.88.8
192.168.88.9
192.168.88.10
192.168.88.11
192.168.88.12
192.168.88.13
192.168.88.14
192.168.88.15
192.168.88.16
192.168.88.17
192.168.88.18
192.168.88.19
192.168.88.20
192.168.88.21
192.168.88.22
192.168.88.23
192.168.88.24
192.168.88.25
192.168.88.26
192.168.88.27
192.168.88.28
192.168.88.29
192.168.88.30
192.168.88.31
To this:
192.168.88.0/27
Using only RouterOS functions.





Or for example, from this:
192.168.88.0
192.168.88.1
192.168.88.2
192.168.88.3
192.168.88.5
192.168.88.6
192.168.88.7
192.168.88.8
192.168.88.9
192.168.88.10
192.168.88.11
192.168.88.12
192.168.88.13
192.168.88.14
192.168.88.15
192.168.88.16
192.168.88.17
192.168.88.19
192.168.88.20
192.168.88.21
192.168.88.26
192.168.88.27
192.168.88.28
192.168.88.29
192.168.88.30
192.168.88.31
To this:
192.168.88.0/30 (4 IPs)
192.168.88.5/32 (single IP, not aggregable)
192.168.88.6/31 (2 IPs)
192.168.88.8/29 (8 IPs)
192.168.88.16/31 (2 IPs)
192.168.88.19/32 (single IP, not aggregable)
192.168.88.20/31 (2 IPs)
192.168.88.26/31 (2 IPs)
192.168.88.28/30 (4 IPs)
This can be used, for example, for aggregate routes or IPs inside address list.


For example, as first step, try to convert all /32 to /31, like

What is the next IP for the /31 of 192.168.88.0/32? Is 192.168.88.1/32.
192.168.88.1 is on the list?
Yes, so delete 192.168.88.0/32 and 192.168.88.1/32 and add 192.168.88.0/31

Do all this for every /32 left,
And at the end are present only /32 and /31.

Next step, ignoring the /32, is to join the /31 if are present the next /31 and so on, until all the possibilities from 31 to /8 (or bettere less, more is excessive)
are tryed for compact the IPs…

So, from this
192.168.88.0
192.168.88.1
192.168.88.2
192.168.88.3
192.168.88.5
192.168.88.6
192.168.88.7
192.168.88.8
192.168.88.9
192.168.88.10
192.168.88.11
192.168.88.12
192.168.88.13
192.168.88.14
192.168.88.15
192.168.88.16
192.168.88.17
192.168.88.19
192.168.88.20
192.168.88.21
192.168.88.26
192.168.88.27
192.168.88.28
192.168.88.29
192.168.88.30
192.168.88.31
192.168.88.0/31
192.168.88.2/31
192.168.88.5/32
192.168.88.6/31
192.168.88.8/31
192.168.88.10/31
192.168.88.12/31
192.168.88.14/31
192.168.88.16/31
192.168.88.19/32
192.168.88.20/31
192.168.88.26/31
192.168.88.28/31
192.168.88.30/31
192.168.88.0/30
192.168.88.5/32
192.168.88.6/31
192.168.88.8/30
192.168.88.12/30
192.168.88.16/31
192.168.88.19/32
192.168.88.20/31
192.168.88.26/31
192.168.88.28/30
192.168.88.0/30
192.168.88.5/32
192.168.88.6/31
192.168.88.8/29
192.168.88.16/31
192.168.88.19/32
192.168.88.20/31
192.168.88.26/31
192.168.88.28/30
And on this case, a /29 is the last step, because /28 and /27 do not produce any results.


If at this point 192.168.88.4 must be added to the list, first check if 192.168.88.4 is already inside on any subnet,
then add the 192.168.88.4/32
then calc again the aggregation:
from
192.168.88.0/30
192.168.88.4/32 (just added)
192.168.88.5/32
192.168.88.6/31
192.168.88.8/29
192.168.88.16/31
192.168.88.19/32
192.168.88.20/31
192.168.88.26/31
192.168.88.28/30
to
192.168.88.0/28
192.168.88.16/31
192.168.88.19/32
192.168.88.20/31
192.168.88.26/31
192.168.88.28/30
because
on 1st step 192.168.88.4/32 + 192.168.88.5/32 = 192.168.88.4/31
on 2nd 192.168.88.4/31 + 192.168.88.6/31 = 192.168.88.4/30
on 3rd 192.168.88.0/30 + 192.168.88.4/30 = 192.168.88.0/29
on 4th 192.168.88.0/29 + 192.168.88.8/29 = 192.168.88.0/28
and can not be aggregated more.

Boy that’s above my pay grade…

But the Ubuntu “aggregate” command seem to take the approach to convert IP to int, in big endian, so normal compare operator work on these ints (e.g. called network byte order for a reason): https://git.launchpad.net/ubuntu/+source/aggregate/tree/aggregate.c

/* now hunt for adjacent entries that can be combined */

From the comment it seems thet the author reason the same way I do…
A lot of functions used on RouterOS don’t exist, on purpose I wrote “an algorithm that uses only functions present on RouterOS”…


Since I write something to aggregate /32 to /31 and /31 to /30, is a start to do a full aggregation, from /32 to /0.
As I already wrote, /9 can already be excessive, for not deplete uselessly the CPU must be ckecked a less number of bits.

LOL, well you start with...

I'm not even sure that's the best C example, I just know the answer involved converting to big endian. My thought is most algorithms in C (but NOT the code) can be model in RouterOS script so that's were I start when looking for an algorithm (not code)... e.g. some rextended script function that does some as c-runtime's ntohl(), and any C struct can be modeled as array maps :wink:

I get your requirement for RouterOS script... But RouterOS script is NOT particular "fast" however, even if well-written. So I suspect starting a container to run some aggregation command would likely be much fast (e.g. efficient, in some definitions) than executing the amount of script code required. But then again that only be only true on ARM & V7...

Uhm…

  • For the generic problem of aggregating prefixes...and your list large (thousands)... I'd bet on container**
    ** with Alpine or distroless, not starting a entire Ubuntu instance to do ip prefix aggregation

Each script line takes many milliseconds to execute and script goes through a lot of parsing. It's the lack of some ":toip-prefix" that adds even more since you'd like have to use the return//global/parse that reduce performance even more. It would not be your script code... :slight_smile:

Since I'm guessing there is implict requirement of V6 and all platforms... :wink:
I'm sure script can do it & not sure of a better way than what you describe without seeing code.