40 сервисов как у Linux: primary, custom и CDN. Имена совпадают с vernette/ipregion. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -111,7 +111,7 @@ MikroTik 7.22+: `:global "vt-srcIp" "1.2.3.4"; /tool fetch url="https://vt.shnt.
|
|||||||
|
|
||||||
- **Vendor:** `apps/api/scripts/ipregion/ipregion.sh` (pin SHA `7d1c25c`, MIT, [vernette/ipregion](https://github.com/vernette/ipregion))
|
- **Vendor:** `apps/api/scripts/ipregion/ipregion.sh` (pin SHA `7d1c25c`, MIT, [vernette/ipregion](https://github.com/vernette/ipregion))
|
||||||
- **Launcher:** `GET /ic` минтит HMAC ingest-токен (тот же `CENSORCHECK_INGEST_SECRET`); `GET /ic/vendor` — pinned скрипт (LF); `--daily` / `--remove-daily`
|
- **Launcher:** `GET /ic` минтит HMAC ingest-токен (тот же `CENSORCHECK_INGEST_SECRET`); `GET /ic/vendor` — pinned скрипт (LF); `--daily` / `--remove-daily`
|
||||||
- **MikroTik:** `GET /ic.rsc` — primary GeoIP JSON + Cloudflare CDN; обязателен `:global vt-srcIp`; scheduler `vt-ic`
|
- **MikroTik:** `GET /ic.rsc` — полный список vernette/ipregion (primary + custom + cdn, как Linux); обязателен `:global vt-srcIp`; scheduler `vt-ic`
|
||||||
- **Ingest:** `POST /api/integrations/ipregion/runs` (без portal JWT)
|
- **Ingest:** `POST /api/integrations/ipregion/runs` (без portal JWT)
|
||||||
- **UI:** `/geo` — матрица ISO-стран VPS × сервисы (primary / custom / cdn)
|
- **UI:** `/geo` — матрица ISO-стран VPS × сервисы (primary / custom / cdn)
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# VPS Tracker — GeoIP launcher for RouterOS 7.22+
|
# VPS Tracker — GeoIP launcher for RouterOS 7.22+
|
||||||
# First run: :global "vt-srcIp" "1.2.3.4"; /tool fetch url="__VT_API_URL__/ic.rsc" dst-path=vt-ic.rsc; /import file-name=vt-ic.rsc
|
# First run: :global "vt-srcIp" "1.2.3.4"; /tool fetch url="__VT_API_URL__/ic.rsc" dst-path=vt-ic.rsc; /import file-name=vt-ic.rsc
|
||||||
# Primary GeoIP JSON + Cloudflare CDN. Ingest: POST /api/integrations/ipregion/runs
|
# Полный список vernette/ipregion (primary + custom + cdn, без Google Search Captcha). Ingest: POST /api/integrations/ipregion/runs
|
||||||
|
|
||||||
:local vtApi "__VT_API_URL__"
|
:local vtApi "__VT_API_URL__"
|
||||||
:local vtToken "__VT_INGEST_TOKEN__"
|
:local vtToken "__VT_INGEST_TOKEN__"
|
||||||
:local vtDaily "__VT_DAILY__"
|
:local vtDaily "__VT_DAILY__"
|
||||||
:local vtRemove "__VT_REMOVE_DAILY__"
|
:local vtRemove "__VT_REMOVE_DAILY__"
|
||||||
:local launcherVer "ros-7"
|
:local launcherVer "ros-8"
|
||||||
:local schedName "vt-ic"
|
:local schedName "vt-ic"
|
||||||
:local dstFile "vt-ic.rsc"
|
:local dstFile "vt-ic.rsc"
|
||||||
|
|
||||||
@@ -44,6 +44,20 @@
|
|||||||
:put ("vt-srcIp: " . $srcIp)
|
:put ("vt-srcIp: " . $srcIp)
|
||||||
:local ingestOk false
|
:local ingestOk false
|
||||||
|
|
||||||
|
:local ua "Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0"
|
||||||
|
:local twitchClientId "kimne78kx3ncx6brgo4mv6wki5h1ko"
|
||||||
|
:local chatgptKey "client-zUdXdSTygXJdzoE0sWTkP8GKTVsUMF2IRM7ShVO2JAG"
|
||||||
|
:local spotifyKey "142b583129b2df829de3656f9eb484e6"
|
||||||
|
:local spotifyClientId "9a8d2f0ce77a4e248bb71fefcb557637"
|
||||||
|
:local netflixKey "YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm"
|
||||||
|
:local redditBasic "b2hYcG9xclpZdWIxa2c6"
|
||||||
|
:local disneyKey "ZGlzbmV5JmFuZHJvaWQmMS4wLjA.bkeb0m230uUhv8qrAXuNu39tbE_mD5EEhM_NAcohjyA"
|
||||||
|
:local youtubeSocs "CAISNQgDEitib3FfaWRlbnRpdHlmcm9udGVuZHVpc2VydmVyXzIwMjUwNzMwLjA1X3AwGgJlbiACGgYIgPC_xAY"
|
||||||
|
:local disneyBody "{\"query\":\" mutation registerDevice($registerDevice: RegisterDeviceInput!) { registerDevice(registerDevice: $registerDevice) { __typename } } \",\"variables\":{\"registerDevice\":{\"applicationRuntime\":\"android\",\"attributes\":{\"operatingSystem\":\"Android\",\"operatingSystemVersion\":\"13\"},\"deviceFamily\":\"android\",\"deviceLanguage\":\"en\",\"deviceProfile\":\"phone\",\"devicePlatformId\":\"android\"}},\"operationName\":\"registerDevice\"}"
|
||||||
|
:local twitchBody "[{\"operationName\":\"VerifyEmail_CurrentUser\",\"variables\":{},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f9e7dcdf7e99c314c82d8f7f725fab5f99d1df3d7359b53c9ae122deec590198\"}}}]"
|
||||||
|
:local redditGqlBody "{\"operationName\":\"UserLocation\",\"variables\":{},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f07de258c54537e24d7856080f662c1b1268210251e5789c8c08f20d76cc8ab2\"}}}"
|
||||||
|
:local redditUa "Reddit/Version 2025.29.0/Build 2529021/Android 13"
|
||||||
|
|
||||||
:local r
|
:local r
|
||||||
:local j
|
:local j
|
||||||
:local isp
|
:local isp
|
||||||
@@ -99,7 +113,12 @@
|
|||||||
"maxmind.com";"rdap.db.ripe.net";"ipinfo.io";"cloudflare.com";"ipregistry.co";\
|
"maxmind.com";"rdap.db.ripe.net";"ipinfo.io";"cloudflare.com";"ipregistry.co";\
|
||||||
"ipapi.co";"ifconfig.co";"ip2location.io";"iplocation.com";"country.is";\
|
"ipapi.co";"ifconfig.co";"ip2location.io";"iplocation.com";"country.is";\
|
||||||
"geoapify.com";"geojs.io";"ipapi.is";"ipbase.com";"ipquery.io";"ipwho.is";\
|
"geoapify.com";"geojs.io";"ipapi.is";"ipbase.com";"ipquery.io";"ipwho.is";\
|
||||||
"ip-api.com";"cloudflare cdn"\
|
"ip-api.com";\
|
||||||
|
"Google";"YouTube";"Twitch";"ChatGPT";"Netflix";"Spotify";"Reddit";"Disney+";\
|
||||||
|
"Gemini Supported";"Reddit (Guest Access)";"YouTube Premium";"Spotify Signup";\
|
||||||
|
"Disney+ Access";"Apple";"Steam";"Tiktok";"Ookla Speedtest";"JetBrains";\
|
||||||
|
"PlayStation";"Microsoft";\
|
||||||
|
"Cloudflare CDN";"YouTube CDN";"Netflix CDN"\
|
||||||
}
|
}
|
||||||
|
|
||||||
:local resultJson ""
|
:local resultJson ""
|
||||||
@@ -107,6 +126,7 @@
|
|||||||
:local url ""
|
:local url ""
|
||||||
:local method "get"
|
:local method "get"
|
||||||
:local postData ""
|
:local postData ""
|
||||||
|
:local fetchHdrs ""
|
||||||
:local iso "N/A"
|
:local iso "N/A"
|
||||||
:local httpCode 0
|
:local httpCode 0
|
||||||
:local body ""
|
:local body ""
|
||||||
@@ -128,15 +148,42 @@
|
|||||||
:local colo
|
:local colo
|
||||||
:local iata
|
:local iata
|
||||||
:local ci
|
:local ci
|
||||||
|
:local marker
|
||||||
|
:local tmp
|
||||||
|
:local tmp2
|
||||||
|
:local tmp3
|
||||||
|
:local googleCode ""
|
||||||
|
:local token ""
|
||||||
|
:local statusStr ""
|
||||||
|
:local launched ""
|
||||||
|
:local errCnt ""
|
||||||
|
:local inLoc ""
|
||||||
|
:local countryName ""
|
||||||
|
:local regionsMd ""
|
||||||
|
:local lineStart ""
|
||||||
|
:local iataLoc ""
|
||||||
|
:local word3 ""
|
||||||
|
:local dashPos ""
|
||||||
|
:local hdrData ""
|
||||||
|
:local wi 0
|
||||||
|
:local wc 0
|
||||||
|
|
||||||
:foreach name in=$names do={
|
:foreach name in=$names do={
|
||||||
:set url ""
|
:set url ""
|
||||||
:set method "get"
|
:set method "get"
|
||||||
:set postData ""
|
:set postData ""
|
||||||
:if ($name = "maxmind.com") do={ :set url "https://geoip.maxmind.com/geoip/v2.1/city/me" }
|
:set fetchHdrs ""
|
||||||
|
:if ($name = "maxmind.com") do={
|
||||||
|
:set url "https://geoip.maxmind.com/geoip/v2.1/city/me"
|
||||||
|
:set fetchHdrs "Referer: https://www.maxmind.com"
|
||||||
|
}
|
||||||
:if ($name = "rdap.db.ripe.net") do={ :set url ("https://rdap.db.ripe.net/ip/" . $publicIp) }
|
:if ($name = "rdap.db.ripe.net") do={ :set url ("https://rdap.db.ripe.net/ip/" . $publicIp) }
|
||||||
:if ($name = "ipinfo.io") do={ :set url ("https://ipinfo.io/widget/demo/" . $publicIp) }
|
:if ($name = "ipinfo.io") do={ :set url ("https://ipinfo.io/widget/demo/" . $publicIp) }
|
||||||
:if ($name = "cloudflare.com") do={ :set url "https://speed.cloudflare.com/meta" }
|
:if ($name = "cloudflare.com") do={ :set url "https://speed.cloudflare.com/meta" }
|
||||||
:if ($name = "ipregistry.co") do={ :set url ("https://api.ipregistry.co/" . $publicIp . "?hostname=true&key=sb69ksjcajfs4c") }
|
:if ($name = "ipregistry.co") do={
|
||||||
|
:set url ("https://api.ipregistry.co/" . $publicIp . "?hostname=true&key=sb69ksjcajfs4c")
|
||||||
|
:set fetchHdrs "Origin: https://ipregistry.co"
|
||||||
|
}
|
||||||
:if ($name = "ipapi.co") do={ :set url ("https://ipapi.co/" . $publicIp . "/json") }
|
:if ($name = "ipapi.co") do={ :set url ("https://ipapi.co/" . $publicIp . "/json") }
|
||||||
:if ($name = "ifconfig.co") do={ :set url ("https://ifconfig.co/country-iso?ip=" . $publicIp) }
|
:if ($name = "ifconfig.co") do={ :set url ("https://ifconfig.co/country-iso?ip=" . $publicIp) }
|
||||||
:if ($name = "ip2location.io") do={ :set url ("https://api.ip2location.io/?ip=" . $publicIp) }
|
:if ($name = "ip2location.io") do={ :set url ("https://api.ip2location.io/?ip=" . $publicIp) }
|
||||||
@@ -144,6 +191,7 @@
|
|||||||
:set url "https://iplocation.com"
|
:set url "https://iplocation.com"
|
||||||
:set method "post"
|
:set method "post"
|
||||||
:set postData ("ip=" . $publicIp)
|
:set postData ("ip=" . $publicIp)
|
||||||
|
:set fetchHdrs ("User-Agent: " . $ua)
|
||||||
}
|
}
|
||||||
:if ($name = "country.is") do={ :set url ("https://api.country.is/" . $publicIp) }
|
:if ($name = "country.is") do={ :set url ("https://api.country.is/" . $publicIp) }
|
||||||
:if ($name = "geoapify.com") do={ :set url ("https://api.geoapify.com/v1/ipinfo?&ip=" . $publicIp . "&apiKey=b8568cb9afc64fad861a69edbddb2658") }
|
:if ($name = "geoapify.com") do={ :set url ("https://api.geoapify.com/v1/ipinfo?&ip=" . $publicIp . "&apiKey=b8568cb9afc64fad861a69edbddb2658") }
|
||||||
@@ -152,53 +200,201 @@
|
|||||||
:if ($name = "ipbase.com") do={ :set url ("https://api.ipbase.com/v2/info?ip=" . $publicIp) }
|
:if ($name = "ipbase.com") do={ :set url ("https://api.ipbase.com/v2/info?ip=" . $publicIp) }
|
||||||
:if ($name = "ipquery.io") do={ :set url ("https://api.ipquery.io/" . $publicIp) }
|
:if ($name = "ipquery.io") do={ :set url ("https://api.ipquery.io/" . $publicIp) }
|
||||||
:if ($name = "ipwho.is") do={ :set url ("https://ipwho.is/" . $publicIp) }
|
:if ($name = "ipwho.is") do={ :set url ("https://ipwho.is/" . $publicIp) }
|
||||||
:if ($name = "ip-api.com") do={ :set url ("https://demo.ip-api.com/json/" . $publicIp . "?fields=countryCode") }
|
:if ($name = "ip-api.com") do={
|
||||||
:if ($name = "cloudflare cdn") do={ :set url "https://speed.cloudflare.com/meta" }
|
:set url ("https://demo.ip-api.com/json/" . $publicIp . "?fields=countryCode")
|
||||||
|
:set fetchHdrs "Origin: https://ip-api.com"
|
||||||
|
}
|
||||||
|
:if ($name = "Google") do={
|
||||||
|
:set url "https://accounts.google.com/v3/signin/identifier?flowName=GlifSetupAndroid"
|
||||||
|
:set fetchHdrs ("User-Agent: " . $ua)
|
||||||
|
}
|
||||||
|
:if ($name = "YouTube") do={ :set url "https://www.youtube.com/sw.js_data" }
|
||||||
|
:if ($name = "Twitch") do={
|
||||||
|
:set url "https://gql.twitch.tv/gql"
|
||||||
|
:set method "post"
|
||||||
|
:set postData $twitchBody
|
||||||
|
:set fetchHdrs ("Client-Id: " . $twitchClientId . ",Content-Type: application/json")
|
||||||
|
}
|
||||||
|
:if ($name = "ChatGPT") do={
|
||||||
|
:set url "https://ab.chatgpt.com/v1/initialize"
|
||||||
|
:set method "post"
|
||||||
|
:set postData "{}"
|
||||||
|
:set fetchHdrs ("Statsig-Api-Key: " . $chatgptKey . ",Content-Type: application/json")
|
||||||
|
}
|
||||||
|
:if ($name = "Netflix") do={ :set url ("https://api.fast.com/netflix/speedtest/v2?https=true&token=" . $netflixKey . "&urlCount=1") }
|
||||||
|
:if ($name = "Spotify") do={
|
||||||
|
:set url ("https://spclient.wg.spotify.com/signup/public/v1/account/?validate=1&key=" . $spotifyKey)
|
||||||
|
:set fetchHdrs ("X-Client-Id: " . $spotifyClientId)
|
||||||
|
}
|
||||||
|
:if ($name = "Reddit") do={ :set url "reddit-oauth" }
|
||||||
|
:if ($name = "Disney+") do={
|
||||||
|
:set url "https://disney.api.edge.bamgrid.com/graph/v1/device/graphql"
|
||||||
|
:set method "post"
|
||||||
|
:set postData $disneyBody
|
||||||
|
:set fetchHdrs ("Authorization: Bearer " . $disneyKey . ",Content-Type: application/json")
|
||||||
|
}
|
||||||
|
:if ($name = "Gemini Supported") do={ :set url "gemini-check" }
|
||||||
|
:if ($name = "Reddit (Guest Access)") do={
|
||||||
|
:set url "https://www.reddit.com"
|
||||||
|
:set fetchHdrs ("User-Agent: " . $ua)
|
||||||
|
}
|
||||||
|
:if ($name = "YouTube Premium") do={
|
||||||
|
:set url "https://www.youtube.com/premium"
|
||||||
|
:set fetchHdrs ("User-Agent: " . $ua . ",Cookie: SOCS=" . $youtubeSocs . ",Accept-Language: en-US,en;q=0.9")
|
||||||
|
}
|
||||||
|
:if ($name = "Spotify Signup") do={
|
||||||
|
:set url ("https://spclient.wg.spotify.com/signup/public/v1/account/?validate=1&key=" . $spotifyKey)
|
||||||
|
:set fetchHdrs ("X-Client-Id: " . $spotifyClientId)
|
||||||
|
}
|
||||||
|
:if ($name = "Disney+ Access") do={
|
||||||
|
:set url "https://disney.api.edge.bamgrid.com/graph/v1/device/graphql"
|
||||||
|
:set method "post"
|
||||||
|
:set postData $disneyBody
|
||||||
|
:set fetchHdrs ("Authorization: Bearer " . $disneyKey . ",Content-Type: application/json")
|
||||||
|
}
|
||||||
|
:if ($name = "Apple") do={ :set url "https://gspe1-ssl.ls.apple.com/pep/gcc" }
|
||||||
|
:if ($name = "Steam") do={
|
||||||
|
:set url "https://store.steampowered.com"
|
||||||
|
:set method "head"
|
||||||
|
}
|
||||||
|
:if ($name = "Tiktok") do={ :set url "https://www.tiktok.com/api/v1/web-cookie-privacy/config?appId=1988" }
|
||||||
|
:if ($name = "Ookla Speedtest") do={ :set url "https://www.speedtest.net/api/js/config-sdk" }
|
||||||
|
:if ($name = "JetBrains") do={ :set url "https://data.services.jetbrains.com/geo" }
|
||||||
|
:if ($name = "PlayStation") do={
|
||||||
|
:set url "https://www.playstation.com"
|
||||||
|
:set method "head"
|
||||||
|
}
|
||||||
|
:if ($name = "Microsoft") do={ :set url "https://login.live.com" }
|
||||||
|
:if ($name = "Cloudflare CDN") do={
|
||||||
|
:set url "https://speed.cloudflare.com/meta"
|
||||||
|
:set fetchHdrs "Referer: https://speed.cloudflare.com"
|
||||||
|
}
|
||||||
|
:if ($name = "YouTube CDN") do={ :set url "https://redirector.googlevideo.com/report_mapping?di=no" }
|
||||||
|
:if ($name = "Netflix CDN") do={ :set url ("https://api.fast.com/netflix/speedtest/v2?https=true&token=" . $netflixKey . "&urlCount=1") }
|
||||||
|
|
||||||
:set iso "N/A"
|
:set iso "N/A"
|
||||||
:set httpCode 0
|
:set httpCode 0
|
||||||
:set body ""
|
:set body ""
|
||||||
:do {
|
:set hdrData ""
|
||||||
:if ($method = "post") do={
|
|
||||||
:set r [/tool fetch url=$url http-method=post http-data=$postData http-header-field="Content-Type: application/x-www-form-urlencoded" src-address=$srcIp output=user-with-headers as-value]
|
:if ($url = "reddit-oauth") do={
|
||||||
} else={
|
:set token ""
|
||||||
:set r [/tool fetch url=$url src-address=$srcIp output=user-with-headers as-value]
|
:do {
|
||||||
|
:set r [/tool fetch url="https://www.reddit.com/auth/v2/oauth/access-token/loid" src-address=$srcIp http-method=post http-header-field=("Authorization: Basic " . $redditBasic . ",Content-Type: application/json,User-Agent: " . $redditUa) http-data="{\"scopes\":[\"email\"]}" output=user as-value]
|
||||||
|
:if (($r->"status") = "finished") do={
|
||||||
|
:set j [:deserialize from=json value=($r->"data")]
|
||||||
|
:set token [:tostr ($j->"access_token")]
|
||||||
|
}
|
||||||
|
} on-error={}
|
||||||
|
:if ([:len $token] > 0) do={
|
||||||
|
:do {
|
||||||
|
:set r [/tool fetch url="https://gql-fed.reddit.com" src-address=$srcIp http-method=post http-header-field=("Authorization: Bearer " . $token . ",Content-Type: application/json,User-Agent: " . $redditUa) http-data=$redditGqlBody output=user as-value]
|
||||||
|
:if (($r->"status") = "finished") do={
|
||||||
|
:set body ($r->"data")
|
||||||
|
:set httpCode 200
|
||||||
|
}
|
||||||
|
} on-error={}
|
||||||
}
|
}
|
||||||
:if (($r->"status") != "finished") do={
|
} else={
|
||||||
:set httpCode -1
|
:if ($url = "gemini-check") do={
|
||||||
} else={
|
:set googleCode ""
|
||||||
:set data ($r->"data")
|
:do {
|
||||||
:set line $data
|
:set r [/tool fetch url="https://accounts.google.com/v3/signin/identifier?flowName=GlifSetupAndroid" src-address=$srcIp http-header-field=("User-Agent: " . $ua) output=user-with-headers as-value]
|
||||||
:set nl [:find $data "\n"]
|
:if (($r->"status") = "finished") do={
|
||||||
:if ([:typeof $nl] != "nil") do={ :set line [:pick $data 0 $nl] }
|
:set data ($r->"data")
|
||||||
:set cr2 [:find $line "\r"]
|
:set sep "\r\n\r\n"
|
||||||
:if ([:typeof $cr2] != "nil") do={ :set line [:pick $line 0 $cr2] }
|
:set p [:find $data $sep]
|
||||||
:set httpCode 200
|
:if ([:typeof $p] = "nil") do={ :set sep "\n\n"; :set p [:find $data $sep] }
|
||||||
:if ([:pick $line 0 4] = "HTTP") do={
|
:if ([:typeof $p] != "nil") do={ :set plain [:pick $data ($p + [:len $sep]) [:len $data]] } else={ :set plain $data }
|
||||||
:set sp1 [:find $line " "]
|
:set marker [:find $plain "name=\"region\" value=\""]
|
||||||
:if ([:typeof $sp1] != "nil") do={
|
:if ([:typeof $marker] != "nil") do={ :set googleCode [:pick $plain ($marker + 21) ($marker + 23)] }
|
||||||
:set rest2 [:pick $line ($sp1 + 1) [:len $line]]
|
}
|
||||||
:set sp2 [:find $rest2 " "]
|
} on-error={}
|
||||||
:set codeStr $rest2
|
:if ([:len $googleCode] = 2) do={
|
||||||
:if ([:typeof $sp2] != "nil") do={ :set codeStr [:pick $rest2 0 $sp2] }
|
:set countryName ""
|
||||||
:set n [:tonum $codeStr]
|
:do {
|
||||||
:if ([:typeof $n] = "num") do={ :set httpCode $n }
|
:set r [/tool fetch url=("https://www.apicountries.com/alpha/" . $googleCode) src-address=$srcIp output=user as-value]
|
||||||
|
:if (($r->"status") = "finished") do={
|
||||||
|
:set j [:deserialize from=json value=($r->"data")]
|
||||||
|
:set countryName [:tostr ($j->"name")]
|
||||||
|
}
|
||||||
|
} on-error={}
|
||||||
|
:if (([:len $countryName] > 0) and ($countryName != "nil")) do={
|
||||||
|
:set regionsMd ""
|
||||||
|
:do {
|
||||||
|
:set r [/tool fetch url="https://ai.google.dev/gemini-api/docs/available-regions.md.txt" src-address=$srcIp output=user as-value]
|
||||||
|
:if (($r->"status") = "finished") do={ :set regionsMd ($r->"data") }
|
||||||
|
} on-error={}
|
||||||
|
:set lineStart ("- " . $countryName)
|
||||||
|
:if ([:find $regionsMd $lineStart] != nil) do={ :set iso "Yes" } else={ :set iso "No" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:set sep "\r\n\r\n"
|
:set httpCode 200
|
||||||
:set p [:find $data $sep]
|
} else={
|
||||||
:if ([:typeof $p] = "nil") do={
|
:do {
|
||||||
:set sep "\n\n"
|
:if ($method = "head") do={
|
||||||
:set p [:find $data $sep]
|
:if ([:len $fetchHdrs] > 0) do={
|
||||||
}
|
:set r [/tool fetch url=$url src-address=$srcIp http-method=head http-header-field=$fetchHdrs output=user-with-headers as-value]
|
||||||
:if ([:typeof $p] != "nil") do={
|
} else={
|
||||||
:set body [:pick $data ($p + [:len $sep]) [:len $data]]
|
:set r [/tool fetch url=$url src-address=$srcIp http-method=head output=user-with-headers as-value]
|
||||||
} else={
|
}
|
||||||
:set body $data
|
} else={
|
||||||
|
:if ($method = "post") do={
|
||||||
|
:if ([:len $fetchHdrs] = 0) do={ :set fetchHdrs "Content-Type: application/x-www-form-urlencoded" }
|
||||||
|
:if ([:find $fetchHdrs "Content-Type:"] = nil) do={
|
||||||
|
:if ([:find $postData "{"] = 0) do={
|
||||||
|
:set fetchHdrs ($fetchHdrs . ",Content-Type: application/json")
|
||||||
|
} else={
|
||||||
|
:set fetchHdrs ($fetchHdrs . ",Content-Type: application/x-www-form-urlencoded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set r [/tool fetch url=$url http-method=post http-data=$postData http-header-field=$fetchHdrs src-address=$srcIp output=user-with-headers as-value]
|
||||||
|
} else={
|
||||||
|
:if ([:len $fetchHdrs] > 0) do={
|
||||||
|
:set r [/tool fetch url=$url src-address=$srcIp http-header-field=$fetchHdrs output=user-with-headers as-value]
|
||||||
|
} else={
|
||||||
|
:set r [/tool fetch url=$url src-address=$srcIp output=user-with-headers as-value]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if (($r->"status") != "finished") do={
|
||||||
|
:set httpCode -1
|
||||||
|
} else={
|
||||||
|
:set data ($r->"data")
|
||||||
|
:set hdrData $data
|
||||||
|
:set line $data
|
||||||
|
:set nl [:find $data "\n"]
|
||||||
|
:if ([:typeof $nl] != "nil") do={ :set line [:pick $data 0 $nl] }
|
||||||
|
:set cr2 [:find $line "\r"]
|
||||||
|
:if ([:typeof $cr2] != "nil") do={ :set line [:pick $line 0 $cr2] }
|
||||||
|
:set httpCode 200
|
||||||
|
:if ([:pick $line 0 4] = "HTTP") do={
|
||||||
|
:set sp1 [:find $line " "]
|
||||||
|
:if ([:typeof $sp1] != "nil") do={
|
||||||
|
:set rest2 [:pick $line ($sp1 + 1) [:len $line]]
|
||||||
|
:set sp2 [:find $rest2 " "]
|
||||||
|
:set codeStr $rest2
|
||||||
|
:if ([:typeof $sp2] != "nil") do={ :set codeStr [:pick $rest2 0 $sp2] }
|
||||||
|
:set n [:tonum $codeStr]
|
||||||
|
:if ([:typeof $n] = "num") do={ :set httpCode $n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:set sep "\r\n\r\n"
|
||||||
|
:set p [:find $data $sep]
|
||||||
|
:if ([:typeof $p] = "nil") do={
|
||||||
|
:set sep "\n\n"
|
||||||
|
:set p [:find $data $sep]
|
||||||
|
}
|
||||||
|
:if ([:typeof $p] != "nil") do={
|
||||||
|
:set body [:pick $data ($p + [:len $sep]) [:len $data]]
|
||||||
|
} else={
|
||||||
|
:set body $data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} on-error={
|
||||||
|
:set httpCode 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on-error={
|
|
||||||
:set httpCode 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:if (($httpCode = 0) or ($httpCode = -1)) do={ :set iso "N/A" }
|
:if (($httpCode = 0) or ($httpCode = -1)) do={ :set iso "N/A" }
|
||||||
@@ -214,45 +410,166 @@
|
|||||||
:if ([:typeof $plf] != "nil") do={ :set plain [:pick $plain 0 $plf] }
|
:if ([:typeof $plf] != "nil") do={ :set plain [:pick $plain 0 $plf] }
|
||||||
:if ([:len $plain] > 0) do={ :set iso $plain } else={ :set iso "N/A" }
|
:if ([:len $plain] > 0) do={ :set iso $plain } else={ :set iso "N/A" }
|
||||||
} else={
|
} else={
|
||||||
:do {
|
:if ($name = "Google") do={
|
||||||
:set j [:deserialize from=json value=$body]
|
:set marker [:find $body "name=\"region\" value=\""]
|
||||||
:if ($name = "maxmind.com") do={ :set iso [:tostr ($j->"country"->"iso_code")] }
|
:if ([:typeof $marker] != "nil") do={ :set iso [:pick $body ($marker + 21) ($marker + 23)] } else={ :set iso "N/A" }
|
||||||
:if ($name = "rdap.db.ripe.net") do={ :set iso [:tostr ($j->"country")] }
|
} else={
|
||||||
:if ($name = "ipinfo.io") do={
|
:if ($name = "YouTube") do={
|
||||||
:set iso [:tostr ($j->"data"->"country")]
|
:set plain $body
|
||||||
:if (([:len $iso] = 0) or ($iso = "nil")) do={ :set iso [:tostr ($j->"country")] }
|
:set nl [:find $plain "\n"]
|
||||||
}
|
:if ([:typeof $nl] != "nil") do={ :set plain [:pick $plain ($nl + 1) [:len $plain]] }
|
||||||
:if ($name = "cloudflare.com") do={ :set iso [:tostr ($j->"country")] }
|
:set nl [:find $plain "\n"]
|
||||||
:if ($name = "ipregistry.co") do={ :set iso [:tostr ($j->"location"->"country"->"code")] }
|
:if ([:typeof $nl] != "nil") do={ :set plain [:pick $plain ($nl + 1) [:len $plain]] }
|
||||||
:if ($name = "ipapi.co") do={ :set iso [:tostr ($j->"country")] }
|
:do {
|
||||||
:if ($name = "ip2location.io") do={ :set iso [:tostr ($j->"country_code")] }
|
:set j [:deserialize from=json value=$plain]
|
||||||
:if ($name = "iplocation.com") do={ :set iso [:tostr ($j->"country_code")] }
|
:set iso [:tostr (($j->0)->2->0->0->1)]
|
||||||
:if ($name = "country.is") do={ :set iso [:tostr ($j->"country")] }
|
:if (([:len $iso] = 0) or ($iso = "nil")) do={ :set iso "N/A" }
|
||||||
:if ($name = "geoapify.com") do={ :set iso [:tostr ($j->"country"->"iso_code")] }
|
} on-error={ :set iso "N/A" }
|
||||||
:if ($name = "geojs.io") do={ :set iso [:tostr ($j->0->"country")] }
|
} else={
|
||||||
:if ($name = "ipapi.is") do={ :set iso [:tostr ($j->"location"->"country_code")] }
|
:if ($name = "Reddit (Guest Access)") do={
|
||||||
:if ($name = "ipbase.com") do={ :set iso [:tostr ($j->"data"->"location"->"country"->"alpha2")] }
|
:if ([:find $body "Denied"] != nil) do={ :set iso "No" } else={ :set iso "Yes" }
|
||||||
:if ($name = "ipquery.io") do={ :set iso [:tostr ($j->"location"->"country_code")] }
|
|
||||||
:if ($name = "ipwho.is") do={ :set iso [:tostr ($j->"country_code")] }
|
|
||||||
:if ($name = "ip-api.com") do={ :set iso [:tostr ($j->"countryCode")] }
|
|
||||||
:if ($name = "cloudflare cdn") do={
|
|
||||||
:set ctry [:tostr ($j->"country")]
|
|
||||||
:set colo ($j->"colo")
|
|
||||||
:set iata ""
|
|
||||||
:if ([:typeof $colo] = "str") do={ :set iata $colo }
|
|
||||||
:if ([:typeof $colo] = "array") do={
|
|
||||||
:set ci ($colo->"iata")
|
|
||||||
:if ([:typeof $ci] = "str") do={ :set iata $ci }
|
|
||||||
}
|
|
||||||
:if (([:len $ctry] > 0) and ($ctry != "nil") and ([:len $iata] > 0)) do={
|
|
||||||
:set iso ($ctry . " (" . $iata . ")")
|
|
||||||
} else={
|
} else={
|
||||||
:if (([:len $ctry] > 0) and ($ctry != "nil")) do={ :set iso $ctry } else={ :set iso "N/A" }
|
:if ($name = "YouTube Premium") do={
|
||||||
|
:if ([:find $body "youtube premium is not available in your country"] != nil) do={ :set iso "No" } else={ :set iso "Yes" }
|
||||||
|
} else={
|
||||||
|
:if ($name = "Apple") do={
|
||||||
|
:set plain $body
|
||||||
|
:set pcr [:find $plain "\r"]
|
||||||
|
:if ([:typeof $pcr] != "nil") do={ :set plain [:pick $plain 0 $pcr] }
|
||||||
|
:set plf [:find $plain "\n"]
|
||||||
|
:if ([:typeof $plf] != "nil") do={ :set plain [:pick $plain 0 $plf] }
|
||||||
|
:if ([:len $plain] > 0) do={ :set iso $plain } else={ :set iso "N/A" }
|
||||||
|
} else={
|
||||||
|
:if ($name = "Steam") do={
|
||||||
|
:set marker [:find $hdrData "steamCountry="]
|
||||||
|
:if ([:typeof $marker] != "nil") do={
|
||||||
|
:set tmp [:pick $hdrData ($marker + 13) [:len $hdrData]]
|
||||||
|
:set tmp2 [:find $tmp ";"]
|
||||||
|
:if ([:typeof $tmp2] != "nil") do={ :set iso [:pick $tmp 0 $tmp2] } else={ :set iso $tmp }
|
||||||
|
} else={ :set iso "N/A" }
|
||||||
|
} else={
|
||||||
|
:if ($name = "PlayStation") do={
|
||||||
|
:set marker [:find $hdrData "country="]
|
||||||
|
:if ([:typeof $marker] != "nil") do={
|
||||||
|
:set tmp [:pick $hdrData ($marker + 8) [:len $hdrData]]
|
||||||
|
:set tmp2 [:find $tmp ";"]
|
||||||
|
:if ([:typeof $tmp2] != "nil") do={ :set iso [:pick $tmp 0 $tmp2] } else={ :set iso $tmp }
|
||||||
|
} else={ :set iso "N/A" }
|
||||||
|
} else={
|
||||||
|
:if ($name = "Microsoft") do={
|
||||||
|
:set marker [:find $body "\"sRequestCountry\":\""]
|
||||||
|
:if ([:typeof $marker] != "nil") do={ :set iso [:pick $body ($marker + 19) ($marker + 21)] } else={ :set iso "N/A" }
|
||||||
|
} else={
|
||||||
|
:if ($name = "YouTube CDN") do={
|
||||||
|
:set iata ""
|
||||||
|
:set word3 ""
|
||||||
|
:set tmp $body
|
||||||
|
:set wi 0
|
||||||
|
:set wc 0
|
||||||
|
:while ($wi < [:len $tmp]) do={
|
||||||
|
:if ([:pick $tmp $wi ($wi + 1)] = " ") do={ :set wc ($wc + 1) }
|
||||||
|
:if ($wc = 3) do={
|
||||||
|
:set word3 [:pick $tmp $wi [:len $tmp]]
|
||||||
|
:set wi [:len $tmp]
|
||||||
|
}
|
||||||
|
:set wi ($wi + 1)
|
||||||
|
}
|
||||||
|
:if ([:len $word3] > 0) do={
|
||||||
|
:set dashPos [:find $word3 "-"]
|
||||||
|
:if ([:typeof $dashPos] != "nil") do={
|
||||||
|
:set tmp2 [:pick $word3 ($dashPos + 1) [:len $word3]]
|
||||||
|
:if ([:len $tmp2] >= 3) do={ :set iata [:pick $tmp2 0 3] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if ([:len $iata] = 3) do={
|
||||||
|
:set iataLoc ""
|
||||||
|
:do {
|
||||||
|
:set r [/tool fetch url="https://www.air-port-codes.com/api/v1/single" src-address=$srcIp http-method=post http-header-field="APC-Auth: 96dc04b3fb,Referer: https://www.air-port-codes.com/,Content-Type: application/x-www-form-urlencoded" http-data=("iata=" . $iata) output=user as-value]
|
||||||
|
:if (($r->"status") = "finished") do={
|
||||||
|
:set j [:deserialize from=json value=($r->"data")]
|
||||||
|
:set iataLoc [:tostr ($j->"airport"->"country"->"iso")]
|
||||||
|
}
|
||||||
|
} on-error={}
|
||||||
|
:if (([:len $iataLoc] > 0) and ($iataLoc != "nil")) do={ :set iso ($iataLoc . " (" . $iata . ")") } else={ :set iso ("N/A (" . $iata . ")") }
|
||||||
|
} else={ :set iso "N/A" }
|
||||||
|
} else={
|
||||||
|
:do {
|
||||||
|
:set j [:deserialize from=json value=$body]
|
||||||
|
:if ($name = "maxmind.com") do={ :set iso [:tostr ($j->"country"->"iso_code")] }
|
||||||
|
:if ($name = "rdap.db.ripe.net") do={ :set iso [:tostr ($j->"country")] }
|
||||||
|
:if ($name = "ipinfo.io") do={
|
||||||
|
:set iso [:tostr ($j->"data"->"country")]
|
||||||
|
:if (([:len $iso] = 0) or ($iso = "nil")) do={ :set iso [:tostr ($j->"country")] }
|
||||||
|
}
|
||||||
|
:if ($name = "cloudflare.com") do={ :set iso [:tostr ($j->"country")] }
|
||||||
|
:if ($name = "ipregistry.co") do={ :set iso [:tostr ($j->"location"->"country"->"code")] }
|
||||||
|
:if ($name = "ipapi.co") do={ :set iso [:tostr ($j->"country")] }
|
||||||
|
:if ($name = "ip2location.io") do={ :set iso [:tostr ($j->"country_code")] }
|
||||||
|
:if ($name = "iplocation.com") do={ :set iso [:tostr ($j->"country_code")] }
|
||||||
|
:if ($name = "country.is") do={ :set iso [:tostr ($j->"country")] }
|
||||||
|
:if ($name = "geoapify.com") do={ :set iso [:tostr ($j->"country"->"iso_code")] }
|
||||||
|
:if ($name = "geojs.io") do={ :set iso [:tostr ($j->0->"country")] }
|
||||||
|
:if ($name = "ipapi.is") do={ :set iso [:tostr ($j->"location"->"country_code")] }
|
||||||
|
:if ($name = "ipbase.com") do={ :set iso [:tostr ($j->"data"->"location"->"country"->"alpha2")] }
|
||||||
|
:if ($name = "ipquery.io") do={ :set iso [:tostr ($j->"location"->"country_code")] }
|
||||||
|
:if ($name = "ipwho.is") do={ :set iso [:tostr ($j->"country_code")] }
|
||||||
|
:if ($name = "ip-api.com") do={ :set iso [:tostr ($j->"countryCode")] }
|
||||||
|
:if ($name = "Twitch") do={ :set iso [:tostr ($j->0->"data"->"requestInfo"->"countryCode")] }
|
||||||
|
:if ($name = "ChatGPT") do={ :set iso [:tostr ($j->"derived_fields"->"country")] }
|
||||||
|
:if ($name = "Netflix") do={ :set iso [:tostr ($j->"client"->"location"->"country")] }
|
||||||
|
:if ($name = "Spotify") do={ :set iso [:tostr ($j->"country")] }
|
||||||
|
:if ($name = "Reddit") do={ :set iso [:tostr ($j->"data"->"userLocation"->"countryCode")] }
|
||||||
|
:if ($name = "Disney+") do={ :set iso [:tostr ($j->"extensions"->"sdk"->"session"->"location"->"countryCode")] }
|
||||||
|
:if ($name = "Spotify Signup") do={
|
||||||
|
:set statusStr [:tostr ($j->"status")]
|
||||||
|
:set launched [:tostr ($j->"is_country_launched")]
|
||||||
|
:if (($statusStr = "120") or ($statusStr = "320") or ($launched = "false")) do={ :set iso "No" } else={ :set iso "Yes" }
|
||||||
|
}
|
||||||
|
:if ($name = "Disney+ Access") do={
|
||||||
|
:set inLoc [:tostr ($j->"extensions"->"sdk"->"session"->"inSupportedLocation")]
|
||||||
|
:if ($inLoc = "true") do={ :set iso "Yes" } else={ :set iso "No" }
|
||||||
|
}
|
||||||
|
:if ($name = "Tiktok") do={ :set iso [:tostr ($j->"body"->"appProps"->"region")] }
|
||||||
|
:if ($name = "Ookla Speedtest") do={ :set iso [:tostr ($j->"location"->"countryCode")] }
|
||||||
|
:if ($name = "JetBrains") do={ :set iso [:tostr ($j->"code")] }
|
||||||
|
:if ($name = "Netflix CDN") do={ :set iso [:tostr ($j->"targets"->0->"location"->"country")] }
|
||||||
|
:if ($name = "Cloudflare CDN") do={
|
||||||
|
:set ctry [:tostr ($j->"country")]
|
||||||
|
:set colo ($j->"colo")
|
||||||
|
:set iata ""
|
||||||
|
:if ([:typeof $colo] = "str") do={ :set iata $colo }
|
||||||
|
:if ([:typeof $colo] = "array") do={
|
||||||
|
:set ci ($colo->"iata")
|
||||||
|
:if ([:typeof $ci] = "str") do={ :set iata $ci }
|
||||||
|
}
|
||||||
|
:if (([:len $iata] = 3)) do={
|
||||||
|
:set iataLoc ""
|
||||||
|
:do {
|
||||||
|
:set r [/tool fetch url="https://www.air-port-codes.com/api/v1/single" src-address=$srcIp http-method=post http-header-field="APC-Auth: 96dc04b3fb,Referer: https://www.air-port-codes.com/,Content-Type: application/x-www-form-urlencoded" http-data=("iata=" . $iata) output=user as-value]
|
||||||
|
:if (($r->"status") = "finished") do={
|
||||||
|
:set j [:deserialize from=json value=($r->"data")]
|
||||||
|
:set iataLoc [:tostr ($j->"airport"->"country"->"iso")]
|
||||||
|
}
|
||||||
|
} on-error={}
|
||||||
|
:if (([:len $iataLoc] > 0) and ($iataLoc != "nil")) do={ :set iso ($iataLoc . " (" . $iata . ")") } else={
|
||||||
|
:if (([:len $ctry] > 0) and ($ctry != "nil")) do={ :set iso ($ctry . " (" . $iata . ")") } else={ :set iso ("N/A (" . $iata . ")") }
|
||||||
|
}
|
||||||
|
} else={
|
||||||
|
:if (([:len $ctry] > 0) and ($ctry != "nil")) do={ :set iso $ctry } else={ :set iso "N/A" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:if (([:len $iso] = 0) or ($iso = "nil")) do={ :set iso "N/A" }
|
||||||
|
} on-error={
|
||||||
|
:set iso "Server error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:if (([:len $iso] = 0) or ($iso = "nil")) do={ :set iso "N/A" }
|
|
||||||
} on-error={
|
|
||||||
:set iso "Server error"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,10 +189,13 @@ describe('GET /ic.rsc RouterOS launcher', () => {
|
|||||||
expect(res.body).toContain('https://vt.shnt.top')
|
expect(res.body).toContain('https://vt.shnt.top')
|
||||||
expect(res.body).toContain('/tool fetch')
|
expect(res.body).toContain('/tool fetch')
|
||||||
expect(res.body).toContain('/api/integrations/ipregion/runs')
|
expect(res.body).toContain('/api/integrations/ipregion/runs')
|
||||||
expect(res.body).toContain('ros-7')
|
expect(res.body).toContain('ros-8')
|
||||||
expect(res.body).toContain(':local vtDaily "no"')
|
expect(res.body).toContain(':local vtDaily "no"')
|
||||||
expect(res.body).toContain('ipinfo.io')
|
expect(res.body).toContain('ipinfo.io')
|
||||||
expect(res.body).toContain('cloudflare cdn')
|
expect(res.body).toContain('Cloudflare CDN')
|
||||||
|
expect(res.body).toContain('YouTube CDN')
|
||||||
|
expect(res.body).toContain('YouTube')
|
||||||
|
expect(res.body).toContain('Netflix CDN')
|
||||||
expect(res.body).toContain('vt-srcIp')
|
expect(res.body).toContain('vt-srcIp')
|
||||||
expect(res.body).toContain(':global "vt-srcIp"')
|
expect(res.body).toContain(':global "vt-srcIp"')
|
||||||
expect(res.body).toContain('src-address=$srcIp')
|
expect(res.body).toContain('src-address=$srcIp')
|
||||||
|
|||||||
Reference in New Issue
Block a user