Firewall

Yes, running regex against the entire payload of every packet requires some horsepower if you have any real amount of traffic.

You could probably speed this up by making the payload or layer-7 checking / address-list adding rule be located in a separate chain (check_x_ru)… change the existing rule into a jump rule that jumps if it’s outbound http traffic.

So the rule is currently:

/ip firewall filter
add chain=forward in-interface=LAN content=x.ru action=jump jump-target=add_redirected_site

Change it to this:

/ip firewall filter
add chain=forward in-interface=LAN protocol=tcp dst-port=80 action=jump jump-target=inspect_http
add chain=inspect_http content=x.ru action=jump jump-target=add_redirected_site
add chain=inspect_http action=return  (or just accept here if you don't want to have any more rules about http)

Keep the add_redirected_site chain just as it is.

This will only check the relatively small upstream requests from clients, and will only call the “content” checker when it’s actually http traffic. Otherwise, the inspection won’t happen because the chain won’t get called.
If you want to add multiple sites to check for in the content - you place the extra sites in the inspect_http chain.
This structure shouldn’t be as CPU-intense as checking the content on every packet going upstream.

The NAT rule / address-list match shouldn’t be slow even with 5000 IP addresses because address-list is designed to be a fast lookup - even for hundreds of thousands of IP addresses.

Maybe also check whether the IP is not already in the list, to avoid repeated rescans (in case “x.ru” is a very popular destination…), i.e.

add chain=forward in-interface=LAN protocol=tcp dst-port=80 dst-address-list=!redirected_sites action=jump jump-target=inspect_http

Also, as already stated, web proxy would be faster. Use a firewall only if you want to apply the rule only for some devices in the network, as opposed to all. And if that IS the case, make sure you filter out the source device beforehand to further minimize the number of checks.

I think you would want to say dst-address=!9.9.9.9 because by the time a packet reaches the forward chain in the filter table, dst-nat has already taken place… (as the last step of the [|prerouting|] block)