Skip to content

Instantly share code, notes, and snippets.

@Nullcaller
Last active March 1, 2025 20:57
Show Gist options
  • Save Nullcaller/ec00480aa8ef9cf20d0f8835eff52896 to your computer and use it in GitHub Desktop.
Save Nullcaller/ec00480aa8ef9cf20d0f8835eff52896 to your computer and use it in GitHub Desktop.
[I no longer recommend this approach, see my comment: https://gist.github.com/Nullcaller/ec00480aa8ef9cf20d0f8835eff52896?permalink_comment_id=5464342#gistcomment-5464342] A RouterOS v7.8-compatible script for automatic generation of an address list containing all Facebook CDN addresses required for maintaining a normal connection from the DNS c…
:delay delay-time=#REPLACE_THIS_WITH_SOME_ARBITRARY_RESULT_OF_HITTING_YOUR_NUMPAD_WITH_A_FIST#ms;
:foreach i in=[/ip dns cache find] do={
# Turn this on while turning off other delays for ease of manual use. Don't forget to reenable later.
# :delay delay-time=5ms;
:delay delay-time=50ms;
:local cacheName [/ip dns cache all get $i name];
:local cacheType [/ip dns cache all get $i type];
:if (($cacheType="A" or $cacheType="CNAME") and (($cacheName~"^([0-9A-Za-z\\-]*\\.)*facebook(\\.[0-9A-Za-z\\-]*)*\\.?\$") or ($cacheName~"^([0-9A-Za-z\\-]*\\.)*fbcdn(\\.[0-9A-Za-z\\-]*)*\\.?\$") or ($cacheName~"^([0-9A-Za-z\\-]*\\.)*fbstatic(\\.[0-9A-Za-z\\-]*)*\\.?\$") or ($cacheName~"^([0-9A-Za-z\\-]*\\.)*fbexternal(\\.[0-9A-Za-z\\-]*)*\\.?\$"))) do={
# IP-based rule
:if ($cacheType="A") do={
:local cacheData [/ip dns cache all get $i data];
:local record [/ip firewall address-list find where (address=$cacheData) and (list=vpn_loopback_sites_dynamic)];
# One day I just randomly found 0.0.0.0 in the list. I'm not sure how it got there, so I introduced this safety measure.
:if (($cacheData~"^0\\.") or ($cacheData~"^10\\.") or ($cacheData~"^127\\.") or ($cacheData~"^192\\.168\\.")) do={
:put ("script tried putting $cacheData into the address list, was prevented");
} else={
:if ($record="") do={
:put ("add: $cacheName $cacheType $cacheData");
/ip firewall address-list add address=$cacheData comment=$cacheName timeout=14d list=vpn_loopback_sites_dynamic
} else={
:put ("renew: $cacheName $cacheType $cacheData");
/ip firewall address-list set $record timeout=14d;
}
}
}
# Domain-based rule
:if ($cacheType="A") do={
:local record [/ip firewall address-list find where (address=$cacheName) and (list=vpn_loopback_sites_dynamic)];
:if ($record="") do={
:put ("add: $cacheName $cacheType");
/ip firewall address-list add address=$cacheName timeout=14d list=vpn_loopback_sites_dynamic
} else={
:put ("renew: $cacheName $cacheType");
/ip firewall address-list set $record timeout=14d;
}
}
:if ($cacheType="CNAME") do={
:local cacheData [/ip dns cache all get $i data];
:local record [/ip firewall address-list find where (address=$cacheData) and (list=vpn_loopback_sites_dynamic)];
:if ($record="") do={
:put ("add: $cacheName $cacheType $cacheData");
/ip firewall address-list add address=$cacheData comment=$cacheName timeout=14d list=vpn_loopback_sites_dynamic
} else={
:put ("renew: $cacheName $cacheType $cacheData");
/ip firewall address-list set $record timeout=14d;
}
:local record [/ip firewall address-list find where (address=$cacheName) and (list=vpn_loopback_sites_dynamic)];
:if ($record="") do={
:put ("add: $cacheName $cacheType");
/ip firewall address-list add address=$cacheName timeout=14d list=vpn_loopback_sites_dynamic
} else={
:put ("renew: $cacheName $cacheType");
/ip firewall address-list set $record timeout=14d;
}
}
}
}
@Nullcaller
Copy link
Author

Nullcaller commented Mar 1, 2025

Just to be clear about this. When I wrote this script, I thought it was a neat concept. It kind of works, but I later found out that it has many problems:

  1. It relies on DNS, which is very finicky where CDNs are concerned due to DNS servers returning random IP addresses from a pool and due to on-device DNS caching.
  2. It requires you to keep using the service pretty much daily for the IP address list to stay up-to-date.
  3. It does not allow the end user any choice between direct and indirect Internet access in the most straightforward implementation.
  4. It breaks or inhibits functionality on some devices or in some usecases, because Google or Microsoft don't necessarily support or like you accessing all of their services from a VPN all of the time.

I thus recommend moving to a different approach:

  1. Each end device SHOULD use its own VPN client, and the VPN client MUST do split tunneling. Example client: v2rayNG for Android.
  2. A separate VLAN and/or a separate wireless network SHOULD be spun up for devices which don't support any such clients. Example devices: Oculus Quest 2/3, Smart TVs, etc.
  3. The VLAN and/or wireless network, if spun up, MAY be configured to do split tunneling.

Split tunneling is essentially on-device decision-making for how to route the packet, based on the destination IP address. (In case of the VLAN/wireless network, that device is the router)

There are pretty good lists of IP addresses (IP subnets, really) out there on the Internet that allow you to route packets based on service you're trying to connect to and/or the country the destination IP belongs to.

Many clients, like v2rayNG, allow extremely flexible configuration of routing rules and automatic updates of IP address lists.

The end result is that the system is more reliable and configurable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment