Een betrouwbare GeoIP-filtering configureren op MikroTik RouterOS
Een CIDR-lijst per geografische zone genereren, deze valideren voor publicatie, importeren zonder de laatste werkende versie te wissen en toepassen op de juiste firewall-ketens.
RouterOS bevat geen ingebouwde GeoIP-database die het mogelijk maakt om een land te selecteren in een firewallregel. Het mechanisme steunt op externe CIDR-prefixlijsten : de router importeert deze in een address-list, waarna een regel input of forward deze lijst als criterium gebruikt.
Het moeilijke deel is niet de uiteindelijke regel. Het bestaat eruit verifieerbare gegevens te verkrijgen, een werkende lijst nooit te vervangen door een leeg bestand en het filter in de chain te plaatsen die daadwerkelijk overeenkomt met de dienst. Deze gids bouwt een IPv4-lijst voor België, terwijl het eenvoudig toevoegen van Frankrijk, Nederland of Luxemburg mogelijk blijft.
Hoe GeoIP-filtering werkt
Een geografische database koppelt adresblokken aan een territoriumcode. Voor een firewall worden deze blokken gewoon netwerken zoals 203.0.113.0/24. RouterOS voert geen geografische opzoeking uit tijdens de verwerking van een pakket : het controleert enkel of het bronadres tot een van de items in de lijst behoort.
| Component | Rol | Te controleren risico |
|---|---|---|
| RIR-gegevens | De geregistreerde prefixen per ISO-code leveren | Het registratieland kan afwijken van de werkelijke locatie |
| Generator | CIDR's valideren en omzetten naar RouterOS-commando's | Een lege download mag nooit de actieve lijst overschrijven |
| Address-list | De netwerken in RouterOS bewaren | Duizenden items verbruiken geheugen en importtijd |
| Firewall | Toestaan of weigeren op basis van de lijst | Een verkeerde chain of verkeerde volgorde maakt het filter ineffectief |
| Scheduler | De gegevens actualiseren | De permissies en fouten moeten zichtbaar zijn |
De hieronder gebruikte lijsten zijn afkomstig van de toewijzingsgegevens van de regionale internetregisters, gegroepeerd per ISO-code en dagelijks gepubliceerd. Ze zijn kleiner dan een zeer gedetailleerde geolocatiedatabase, wat beter geschikt is voor een router. Ze beschrijven echter de registratie van internetbronnen, niet een GPS-positie.
Aanbevolen architectuur
De router mag niet rechtstreeks afhangen van een webpagina die on the fly wordt getransformeerd. Een Linux-server of een NAS downloadt de gegevens, valideert elke CIDR, bouwt een bestand .rsc en publiceert het vervolgens via HTTPS. MikroTik downloadt dit bestand, voert een kale import uit en past het enkel toe als de syntaxis geldig is.
De lijstserver voorbereiden
Het voorbeeld veronderstelt een server met bash, curl en Python 3. Python gebruikt hier enkel de standaardmodule ipaddress : er is geen extra bibliotheek vereist.
Maak een map aan die door uw webserver wordt gepubliceerd, bijvoorbeeld /srv/www/geoip, en beveilig deze met HTTPS. Het volgende script downloadt de Belgische lijst, weigert een te kort bestand, valideert elk IPv4-netwerk, aggregeert de prefixen die geaggregeerd kunnen worden en genereert op atomische wijze een RouterOS-bestand.
#!/usr/bin/env bash
set -Eeuo pipefail
COUNTRIES=(be)
BASE_URL="https://raw.githubusercontent.com/ipverse/rir-ip/master/country"
PUBLISH_DIR="/srv/www/geoip"
FINAL_FILE="$PUBLISH_DIR/GeoIP-BE.rsc"
WORK_DIR="$(mktemp -d)"
PUBLISH_TMP="$(mktemp "$PUBLISH_DIR/.GeoIP-BE.XXXXXX")"
cleanup() {
rm -rf "$WORK_DIR"
if [[ -n "${PUBLISH_TMP:-}" && -f "$PUBLISH_TMP" ]]; then
rm -f "$PUBLISH_TMP"
fi
}
trap cleanup EXIT
RAW_FILE="$WORK_DIR/all-prefixes.txt"
VALID_FILE="$WORK_DIR/validated-prefixes.txt"
: > "$RAW_FILE"
for country in "${COUNTRIES[@]}"; do
curl --fail --location --silent --show-error --retry 3 \
"$BASE_URL/$country/ipv4-aggregated.txt" \
--output "$WORK_DIR/$country.txt"
grep -Ev '^(#|$)' "$WORK_DIR/$country.txt" >> "$RAW_FILE"
done
python3 - "$RAW_FILE" "$VALID_FILE" <<'PY'
import ipaddress
import sys
source, destination = sys.argv[1:3]
networks = []
with open(source, encoding="utf-8") as handle:
for raw_line in handle:
line = raw_line.strip()
if not line:
continue
network = ipaddress.ip_network(line, strict=True)
if network.version != 4:
raise SystemExit(f"Geen IPv4-prefix: {line}")
networks.append(network)
collapsed = list(ipaddress.collapse_addresses(networks))
if len(collapsed) < 100:
raise SystemExit("Abnormaal korte lijst: publicatie geannuleerd")
with open(destination, "w", encoding="ascii") as handle:
for network in collapsed:
handle.write(f"{network}\n")
PY
python3 - "$VALID_FILE" "$PUBLISH_TMP" <<'PY'
import sys
source, destination = sys.argv[1:3]
with open(source, encoding="ascii") as handle:
prefixes = [line.strip() for line in handle if line.strip()]
with open(destination, "w", encoding="ascii") as output:
output.write(':do { /ip firewall address-list remove '
'[find where list="GeoIP-BE-next"] } on-error={}\n')
for prefix in prefixes:
output.write('/ip firewall address-list add '
f'list="GeoIP-BE-next" address={prefix} '
'comment="GeoIP generated"\n')
output.write(':local imported [/ip firewall address-list print '
'count-only where list="GeoIP-BE-next"]\n')
output.write(':if ($imported < 100) do={ '
':error "Liste GeoIP trop courte" }\n')
output.write('/ip firewall address-list remove '
'[find where list="GeoIP-BE"]\n')
output.write(':foreach id in=[/ip firewall address-list find '
'where list="GeoIP-BE-next"] do={ '
'/ip firewall address-list set numbers=$id '
'list="GeoIP-BE" }\n')
output.write(':log info ("GeoIP: actieve lijst, " . '
'$imported . " prefixes")\n')
PY
chmod 0644 "$PUBLISH_TMP"
mv -f "$PUBLISH_TMP" "$FINAL_FILE"
PUBLISH_TMP=""
echo "Gepubliceerd: $FINAL_FILE"
Om een bredere zone te bouwen, vervangt u COUNTRIES=(be) door COUNTRIES=(be fr nl lu) en past u de namen GeoIP-BE en GeoIP-BE-next aan. Begin met één zone : een uitgebreide lijst verhoogt de importtijd en het geheugengebruik.
Waarom deze generator veiliger is
curl --failzet een HTTP-fout om in een mislukking in plaats van een foutpagina als lijst op te slaan ;ipaddressweigert een ongeldige CIDR-syntaxis en verifieert of het daadwerkelijk om IPv4 gaat ;- een minimale drempel voorkomt de publicatie van een leeg of duidelijk onvolledig bestand ;
- het publieke bestand wordt pas vervangen na volledige generatie ;
- het RouterOS-bestand laadt eerst
GeoIP-BE-next, controleert het volume, en schakelt dan over naarGeoIP-BE.
Voer de generator handmatig uit, controleer het gepubliceerde bestand, en plan het vervolgens dagelijks op de server. Bewaar de logs en verwijder niet onmiddellijk de laatst bekende geldige versie.
De import op MikroTik testen
Voor enige automatisering exporteert u de firewall en activeert u de Safe Mode. Vervang het documentatiedomein hieronder door uw eigen HTTPS-URL.
/ip firewall export file=avant-geoip
/system backup save name=avant-geoip
/tool fetch \
url="https://updates.example.net/geoip/GeoIP-BE.rsc" \
output=file dst-path="GeoIP-BE.rsc"
/import file-name="GeoIP-BE.rsc" verbose=yes dry-run=yes
/import file-name="GeoIP-BE.rsc" verbose=yes
De dry-run-modus van de import is beschikbaar op recente versies van RouterOS 7. Het analyseert het bestand zonder de configuratie te wijzigen. De omgeving van deze gids is gericht op RouterOS 7.16 of een latere versie.
/ip firewall address-list print count-only where list="GeoIP-BE"
/ip firewall address-list print where list="GeoIP-BE"
/log print where message~"GeoIP"
Een Belgische import produceert normaal ruim meer dan honderd prefixen. De drempel dient enkel als een veiligheidsmaatregel tegen een duidelijke breuk ; het bewijst noch de volledigheid, noch de geografische kwaliteit van de gegevensset.
De download in RouterOS automatiseren
Maak een script aan met de naam update-geoip met het beleid ftp, read, write, policy en test. Het beleid ftp is nodig voor bestandsbewerkingen, zelfs als de download zelf HTTPS gebruikt.
:local geoUrl "https://updates.example.net/geoip/GeoIP-BE.rsc"
:local geoFile "GeoIP-BE.rsc"
:do { /file remove [find where name=$geoFile] } on-error={}
:do {
/tool fetch url=$geoUrl output=file dst-path=$geoFile
/import file-name=$geoFile verbose=yes dry-run=yes
/import file-name=$geoFile verbose=yes
:log info "GeoIP: update voltooid"
} on-error={
:log error "GeoIP: mislukt, vorige lijst behouden"
}
Het geïmporteerde bestand werkt op de tijdelijke lijst. Een downloadstoring, een syntaxisfout of een abnormaal volume onderbreekt de procedure vóór de verwijdering van GeoIP-BE.
Na een geslaagde handmatige test plant u de uitvoering één keer per dag, op een tijdstip waarop de router weinig wordt belast.
/system scheduler add \
name=update-geoip-daily \
start-time=05:40:00 interval=1d \
on-event="/system script run update-geoip" \
policy=ftp,read,write,policy,test \
comment="GeoIP-lijst vernieuwen"
De lijst op de juiste plaats toepassen
De chain input verwerkt het verkeer dat bestemd is voor de router zelf. De chain forward verwerkt het verkeer dat door de MikroTik naar een interne server gaat. Een GeoIP-regel die enkel in input wordt geplaatst, beperkt dus geen server die via dst-nat wordt gepubliceerd.
Geval 1 : de toegang tot een VPN op de router beperken
Het voorbeeld staat een WireGuard-toegangspunt op UDP 51820 toe vanuit de GeoIP-lijst. Het veronderstelt dat er lager een regel bestaat die WAN-verkeer naar de router weigert. Publiceer WinBox of WebFig niet rechtstreeks op het internet.
/ip firewall address-list
add list=GeoIP-TRUSTED address=198.51.100.10 \
comment="Noodadres - RFC 5737-voorbeeld"
/ip firewall filter
add chain=input action=accept in-interface-list=WAN \
protocol=udp dst-port=51820 \
src-address-list=GeoIP-TRUSTED \
comment="VPN: noodtoegang"
add chain=input action=accept in-interface-list=WAN \
protocol=udp dst-port=51820 \
src-address-list=GeoIP-BE \
comment="VPN: GeoIP-zone toestaan"
Vervang het documentatie-adres door een echt gecontroleerd reserve-adres. Plaats de regels na de aanvaarding van established,related en de weigering van invalid-pakketten, maar vóór de algemene weigering van het WAN.
Geval 2 : een server gepubliceerd via dst-nat beperken
De volgende regel laat nieuwe TCP-verbindingen naar de publieke poort 443 vallen wanneer ze niet behoren tot GeoIP-BE. Een reserve-regel die ervoor wordt geplaatst, maakt een expliciete uitzondering mogelijk.
/ip firewall filter
add chain=forward action=accept in-interface-list=WAN \
connection-state=new connection-nat-state=dstnat \
protocol=tcp dst-port=443 \
src-address-list=GeoIP-TRUSTED \
comment="Server: noodtoegang"
add chain=forward action=drop in-interface-list=WAN \
connection-state=new connection-nat-state=dstnat \
protocol=tcp dst-port=443 \
src-address-list=!GeoIP-BE \
comment="Server: weigeren buiten GeoIP-zone"
Voeg deze regels in vóór een eventuele algemene aanvaarding van dstnat-verbindingen. De poort moet de publieke poort zijn die door het filter wordt gezien. Als de externe poort 8443 wordt vertaald naar 443, gebruik dan 8443 in dit criterium.
Testen zonder uzelf buiten te sluiten
- Werk vanuit het LAN en activeer de Safe Mode.
- Voeg eerst uw reserve-toegang toe in
GeoIP-TRUSTED. - Importeer de lijst en controleer het aantal items voordat u een weigeringsregel toevoegt.
- Test vanaf een externe verbinding die zich in de toegestane zone bevindt.
- Test daarna vanaf een andere gecontroleerde uitgang, bijvoorbeeld een mobiele toegang of een labo-VPN.
- Controleer de tellers zonder een log per pakket te activeren.
- Verlaat de Safe Mode pas wanneer de dienst en het reserve-pad werken.
/ip firewall filter print stats where comment~"GeoIP|zone"
/ip firewall address-list print count-only where list="GeoIP-BE"
/system resource print
/log print where message~"GeoIP"
Beperkingen en veelvoorkomende fouten
- Toewijzing en locatie verwarren : een in België geregistreerde prefix kan elders worden aangekondigd of gebruikt.
- Een zone toestaan als identiteitsbewijs : een relay in de zone passeert hetzelfde filter als een legitieme gebruiker.
- De actieve lijst verwijderen vóór de download : een storing verandert een restrictief filter in een volledige blokkering.
- Downloaden via HTTP : een beveiligingslijst moet via HTTPS worden getransporteerd vanaf een gecontroleerde bron.
- Importeren zonder
dry-run: een syntaxisfout kan een gedeeltelijke update achterlaten. - De regel in
inputplaatsen voor een interne server : het gepubliceerde verkeer passeert doorforward. - IPv6 vergeten : een IPv4-regel beschermt geen dienst die ook via IPv6 toegankelijk is.
- Te veel zones laden : grote lijsten vertragen de import en verbruiken de bronnen van de router.
- Elke weigering loggen : gebruik de regel-tellers om een overbelasting van logs te voorkomen.
Voor IPv6 genereert u een afzonderlijke lijst vanuit ipv6-aggregated.txt, importeert u deze in /ipv6 firewall address-list en maakt u de overeenkomstige regels aan in /ipv6 firewall filter. Laat IPv6 niet onbedoeld een omweg worden.
Conclusie
Een betrouwbare GeoIP-filtering op MikroTik steunt minder op de hoeveelheid geblokkeerde landen dan op de kwaliteit van de updateketen. De gegevens moeten via HTTPS worden opgehaald, gevalideerd als CIDR-netwerken, atomisch worden gepubliceerd, kale geïmporteerd en in een tijdelijke lijst worden geladen vóór enige overschakeling.
Eens deze solide basis is gelegd, wordt de address-list een eenvoudig criterium van de firewall : input voor een dienst van de router, forward voor een gepubliceerde server. De maatregel vermindert de ruis en de blootstelling, maar behoudt bewust een secundaire plaats achter de VPN, de authenticatie, de updates en een minimale firewallpolitiek.
Discussie
Reacties
Nog geen reacties. U kunt de discussie openen met een vraag of uw eigen ervaring.