diff --git a/routeros/cloudflare-ip-updater.rsc b/routeros/cloudflare-ip-updater.rsc index 7100ed1..fb595e7 100644 --- a/routeros/cloudflare-ip-updater.rsc +++ b/routeros/cloudflare-ip-updater.rsc @@ -1,116 +1,68 @@ # CloudFlare IP Address List Updater (IPv4 only) -# Работает на RouterOS 6.x и 7.x -# Скачивает и обновляет список IPv4-адресов CloudFlare -# +# Работает на RouterOS 6.43+ и 7.x +# Скачивает актуальный список IPv4-сетей CloudFlare и обновляет address-list. +# # Установка: # /system script add name=cloudflare-ip-updater source={ ... код ... } # /system script run cloudflare-ip-updater # # Автозапуск: -# /system scheduler add name=cloudflare-update interval=7d on-event=cloudflare-ip-updater start-time=03:31:00 +# /system scheduler add name=cloudflare-update interval=7d \ +# start-time=03:31:00 on-event="/system script run cloudflare-ip-updater" -:local url "https://www.cloudflare.com/ips-v4/#" +:local url "https://www.cloudflare.com/ips-v4/" :local listName "CF" -:local tempFile "cloudflare-ips.txt" -# --- 1. Удаляем старый файл --- +# --- 1. Скачиваем список прямо в переменную (без временного файла) --- +# output=user as-value отдаёт тело ответа в массив, минуя файловую систему: +# это убирает создание/удаление файла, ожидание загрузки и проверки файла. +:local content "" :do { - /file remove $tempFile - :delay 1s -} on-error={} - -:log info "CloudFlare IP updater: Downloading $url..." - -# --- 2. Скачиваем файл --- -:do { - /tool fetch url=$url dst-path=$tempFile + :local result [/tool fetch url=$url output=user as-value] + :if (($result->"status") = "finished") do={ + :set content ($result->"data") + } } on-error={ - :log error "CloudFlare IP updater: Fetch command failed" + :log error "CloudFlare IP updater: Fetch failed" :error "Fetch failed" } -# --- 3. Ждём завершения загрузки --- -:local maxWait 30 -:local waited 0 -:while ([:len [/file find name=$tempFile]] = 0 && $waited < $maxWait) do={ - :delay 1s - :set waited ($waited + 1) -} - -:if ($waited >= $maxWait) do={ - :log error "CloudFlare IP updater: Download timeout" - :error "Download timeout" -} - -:delay 2s - -# --- 4. Проверка файла --- -:if ([:len [/file find name=$tempFile]] = 0) do={ - :log error "CloudFlare IP updater: File not found after download" - :error "Download failed" -} - -:local fileSize [/file get $tempFile size] -:if ($fileSize = 0) do={ - :log error "CloudFlare IP updater: Downloaded file is empty" - /file remove $tempFile - :error "Empty file" -} - -:log info "CloudFlare IP updater: File downloaded successfully ($fileSize bytes)" - -# --- 5. Очищаем старые записи --- -:local oldCount [:len [/ip firewall address-list find list=$listName]] -:if ($oldCount > 0) do={ - /ip firewall address-list remove [find list=$listName] - :log info "cloudflare IP updater: Removed $oldCount old entries from '$listName'" +# --- 2. Проверяем, что что-то скачалось --- +:local size [:len $content] +:if ($size = 0) do={ + :log error "CloudFlare IP updater: Empty response" + :error "Empty response" } +:log info "CloudFlare IP updater: Downloaded successfully ($size bytes)" -# --- 6. Читаем файл и добавляем новые записи --- -:local content [/file get $tempFile contents] -:local start 0 -:local len [:len $content] -:local count 0 +# --- 3. Разбираем ответ во временный набор адресов --- +# Сначала собираем валидные IPv4-сети в массив и только потом меняем +# боевой address-list — так список не остаётся пустым во время обновления. +:local newList [:toarray ""] :local skipped 0 +:local start 0 +:local len $size :while ($start < $len) do={ :local pos [:find $content "\n" $start] - :if ([:typeof $pos] = "nil") do={ - :set pos $len - } - + :if ([:typeof $pos] = "nil") do={ :set pos $len } + :local line [:pick $content $start $pos] - - # Убираем \r + + # Убираем \r (CRLF) и пробелы по краям :local crPos [:find $line "\r"] - :if ([:typeof $crPos] != "nil") do={ - :set line [:pick $line 0 $crPos] - } - - # Убираем пробелы в начале + :if ([:typeof $crPos] != "nil") do={ :set line [:pick $line 0 $crPos] } :while ([:len $line] > 0 && [:pick $line 0 1] = " ") do={ :set line [:pick $line 1 [:len $line]] } - - # Убираем пробелы в конце :while ([:len $line] > 0 && [:pick $line ([:len $line] - 1)] = " ") do={ :set line [:pick $line 0 ([:len $line] - 1)] } - - # Пропускаем пустые строки и комментарии + + # Пропускаем пустые строки, комментарии и IPv6 (содержат двоеточие) :if ([:len $line] > 0 && [:pick $line 0 1] != "#") do={ - # Простая проверка: если есть двоеточие - это IPv6, пропускаем - :local colonPos [:find $line ":"] - - :if ([:typeof $colonPos] = "nil") do={ - # Нет двоеточия - пробуем добавить как IPv4 - :do { - /ip firewall address-list add list=$listName address=$line comment="cloudflare IPv4" - :set count ($count + 1) - } on-error={ - :set skipped ($skipped + 1) - :log warning "cloudflare IP updater: Skipped invalid IPv4 line: '$line'" - } + :if ([:typeof [:find $line ":"]] = "nil") do={ + :set newList ($newList , $line) } else={ :set skipped ($skipped + 1) } @@ -118,12 +70,28 @@ :set start ($pos + 1) } -# --- 7. Убираем временный файл --- -/file remove $tempFile - -# --- 8. Финальный лог --- -:if ($count > 0) do={ - :log info "cloudflare IP updater: Successfully added $count IPv4 entries to address list '$listName' (skipped $skipped IPv6 entries)" -} else={ +# --- 4. Обновляем address-list только при наличии валидных записей --- +:if ([:len $newList] = 0) do={ :log warning "cloudflare IP updater: No valid IPv4 entries found! (skipped $skipped entries)" + :error "No valid entries" } + +:local oldCount [:len [/ip firewall address-list find list=$listName]] +:if ($oldCount > 0) do={ + /ip firewall address-list remove [find list=$listName] + :log info "cloudflare IP updater: Removed $oldCount old entries from '$listName'" +} + +:local count 0 +:foreach ip in=$newList do={ + :do { + /ip firewall address-list add list=$listName address=$ip comment="cloudflare IPv4" + :set count ($count + 1) + } on-error={ + :set skipped ($skipped + 1) + :log warning "cloudflare IP updater: Skipped invalid IPv4 entry: '$ip'" + } +} + +# --- 5. Финальный лог --- +:log info "cloudflare IP updater: Added $count IPv4 entries to '$listName' (skipped $skipped non-IPv4/invalid entries)"