DNSTap və BGP ilə ILV bloklanmasını keçin

DNSTap və BGP ilə ILV bloklanmasını keçin

Mövzu olduqca döyülüb, bilirəm. Məsələn, əla var məqalə, lakin orada blok siyahısının yalnız IP hissəsi nəzərə alınır. Domenləri də əlavə edəcəyik.

Məhkəmələr və RKN hər şeyi sağa və sola bloklayır və provayderlər Revizorro tərəfindən verilən cərimələrə düşməməyə çox çalışırlar, bununla əlaqədar bloklama itkiləri olduqca böyükdür. Və "qanuni" bloklanmış saytlar arasında çox faydalı olanlar var (salam, rutracker)

Mən RKN-nin yurisdiksiyasından kənarda yaşayıram, amma valideynlərim, qohumlarım və dostlarım evdə qaldılar. Beləliklə, İT-dən uzaq insanlar üçün blokdan yan keçmək üçün asan bir yol tapmaq qərara alındı, tercihen onların iştirakı olmadan.

Bu qeyddə mən əsas şəbəkə şeylərini addım-addım təsvir etməyəcəyəm, lakin bu sxemin necə həyata keçirilə biləcəyinin ümumi prinsiplərini təsvir edəcəyəm. Beləliklə, şəbəkənin ümumilikdə və xüsusən də Linux-da necə işlədiyinə dair biliklərə sahib olmaq lazımdır.

Kilidlərin növləri

Əvvəlcə bloklananlar haqqında yaddaşımızı təzələyək.

RKN-dən yüklənməmiş XML-də bir neçə növ kilid var:

  • IP
  • Domain Adı
  • URL

Sadəlik üçün onları ikiyə endirəcəyik: IP və domen və biz sadəcə domeni URL ilə bloklamaqdan çıxaracağıq (daha doğrusu, bunu bizim üçün artıq ediblər).

yaxşı insanlardan Roskomsvoboda gözəl bir şey başa düşdü API, bunun vasitəsilə biz lazım olanı əldə edə bilərik:

Bloklanmış saytlara giriş

Bunu etmək üçün bizə bir neçə kiçik xarici VPS lazımdır, tercihen limitsiz trafiklə - 3-5 dollara bunların çoxu var. Onu yaxın xaricə götürmək lazımdır ki, ping çox böyük olmasın, amma yenə də nəzərə alın ki, internet və coğrafiya həmişə üst-üstə düşmür. Və 5 dollar üçün SLA olmadığı üçün səhvlərə dözümlülük üçün müxtəlif provayderlərdən 2+ ədəd götürmək daha yaxşıdır.

Sonra, müştəri yönləndiricisindən VPS-ə şifrələnmiş tunel qurmalıyıq. Mən Wireguard-dan ən sürətli və ən asan quraşdırma kimi istifadə edirəm. Linux-a əsaslanan müştəri marşrutlaşdırıcılarım da var (APU2 və ya OpenWRT-də bir şey). Bəzi Mikrotik / Cisco vəziyyətində, OpenVPN və GRE-over-IPSEC kimi onlarda mövcud olan protokollardan istifadə edə bilərsiniz.

Maraqlı trafikin müəyyən edilməsi və yönləndirilməsi

Siz əlbəttə ki, xarici ölkələr vasitəsilə bütün internet trafikini söndürə bilərsiniz. Ancaq çox güman ki, yerli məzmunla işləmə sürəti bundan çox zərər çəkəcək. Üstəlik, VPS-də bant genişliyi tələbləri daha yüksək olacaq.

Buna görə də, biz hansısa şəkildə bloklanmış saytlara trafik ayırmalı və seçməli olaraq tunelə yönəltməliyik. Hətta "əlavə" trafikin bir hissəsi oraya çatsa belə, yenə də hər şeyi tuneldən keçirməkdən daha yaxşıdır.

Trafiki idarə etmək üçün biz BGP protokolundan istifadə edəcəyik və VPS-dən müştərilərə lazımi şəbəkələrə marşrutları elan edəcəyik. Ən funksional və rahat BGP demonlarından biri kimi BIRD-i götürək.

IP

IP ilə bloklama ilə hər şey aydındır: biz sadəcə olaraq bütün bloklanmış IP-ləri VPS ilə elan edirik. Problem ondadır ki, siyahıda API-nin qaytardığı təxminən 600 min alt şəbəkə var və onların böyük əksəriyyəti /32 hostdur. Bu sayda marşrutlar zəif müştəri marşrutlaşdırıcılarını çaşdıra bilər.

Buna görə də, siyahını işləyərkən, 24 və ya daha çox host varsa, şəbəkə / 2-ə qədər ümumiləşdirmək qərara alındı. Beləliklə, marşrutların sayı ~100 minə endirildi. Bunun üçün skript gələcək.

Domains

Bu daha mürəkkəbdir və bir neçə yol var. Məsələn, hər bir müştəri yönləndiricisinə şəffaf Squid quraşdıra və orada HTTP ələ keçirə və birinci halda tələb olunan URL-i, ikinci halda isə SNI-dən domeni əldə etmək üçün TLS əl sıxmasına nəzər sala bilərsiniz.

Lakin hər cür yeni açılmış TLS1.3 + eSNI sayəsində HTTPS təhlili hər gün daha az reallaşır. Bəli və müştəri tərəfindəki infrastruktur getdikcə mürəkkəbləşir - ən azı OpenWRT-dən istifadə etməli olacaqsınız.

Buna görə də DNS sorğularına cavabların tutulması yolunu tutmağa qərar verdim. Burada da TLS/HTTPS üzərindən istənilən DNS başınızın üstündə gəzməyə başlayır, lakin biz (hazırda) müştərinin bu hissəsinə nəzarət edə bilərik - ya onu söndürün, ya da DoT/DoH üçün öz serverinizdən istifadə edin.

DNS-ə necə müdaxilə etmək olar?

Burada da bir neçə yanaşma ola bilər.

  • PCAP və ya NFLOG vasitəsilə DNS trafikinin tutulması
    Bu tutma üsullarının hər ikisi kommunal proqramda həyata keçirilir sidmat. Ancaq uzun müddət dəstəklənmir və funksionallıq çox primitivdir, buna görə də hələ də bunun üçün bir qoşqu yazmalısınız.
  • DNS server qeydlərinin təhlili
    Təəssüf ki, mənə məlum olan rekursorlar cavabları deyil, yalnız sorğuları qeyd edə bilirlər. Prinsipcə, bu məntiqlidir, çünki sorğulardan fərqli olaraq cavablar mürəkkəb bir quruluşa malikdir və onları mətn şəklində yazmaq çətindir.
  • DNSTap
    Xoşbəxtlikdən, onların çoxu bu məqsədlə artıq DNSTap-ı dəstəkləyir.

DNSTap nədir?

DNSTap və BGP ilə ILV bloklanmasını keçin

Bu, DNS serverindən strukturlaşdırılmış DNS sorğuları və cavablarının kollektoruna köçürmək üçün Protokol Buferləri və Çərçivə Axınlarına əsaslanan müştəri-server protokoludur. Əsasən, DNS server sorğu və cavab metadatalarını (mesajın növü, müştəri/server IP və s.) üstəgəl tam DNS mesajlarını şəbəkə üzərindən onlarla işlədiyi (ikili) formada ötürür.

DNSTap paradiqmasında DNS serverinin müştəri, kollektorun isə server kimi çıxış etdiyini başa düşmək vacibdir. Yəni DNS server kollektora qoşulur, əksinə deyil.

Bu gün DNSTap bütün məşhur DNS serverlərində dəstəklənir. Lakin, məsələn, bir çox distribütorlarda (Ubuntu LTS kimi) BIND tez-tez nədənsə onun dəstəyi olmadan qurulur. Beləliklə, yenidən montajla narahat olmayaq, lakin daha yüngül və daha sürətli bir rekursor götürək - Unbound.

DNSTap-ı necə tutmaq olar?

Yoxdur bəziləri nömrə DNSTap hadisələrinin axını ilə işləmək üçün CLI utilitləri, lakin problemimizi həll etmək üçün uyğun deyil. Buna görə də, lazım olan hər şeyi edəcək öz velosipedimi icad etmək qərarına gəldim: dnstap-bgp

Əməliyyat alqoritmi:

  • Başladıqda, o, mətn faylından domenlərin siyahısını yükləyir, onları tərsinə çevirir (habr.com -> com.habr), qırıq sətirləri, dublikatları və alt domenləri istisna edir (yəni siyahıda habr.com və www.habr.com varsa, yalnız birincisi yüklənəcək) və bu siyahıda sürətli axtarış üçün prefiks ağacı qurur
  • DNSTap serveri kimi fəaliyyət göstərərək, DNS serverindən əlaqə gözləyir. Prinsipcə, o, həm UNIX, həm də TCP soketlərini dəstəkləyir, lakin mənim bildiyim DNS serverləri yalnız UNIX yuvalarından istifadə edə bilər.
  • Daxil olan DNSTap paketləri əvvəlcə Protobuf strukturunda sıradan çıxarılır, sonra isə Protobuf sahələrindən birində yerləşən ikili DNS mesajının özü DNS RR qeydləri səviyyəsinə təhlil edilir.
  • Tələb olunan hostun (və ya onun əsas domeninin) yüklənmiş siyahıda olub-olmaması yoxlanılır, əks halda cavab nəzərə alınmır.
  • Cavabdan yalnız A/AAAA/CNAME RR-ləri seçilir və onlardan müvafiq IPv4/IPv6 ünvanları çıxarılır.
  • IP ünvanları konfiqurasiya edilə bilən TTL ilə yaddaşda saxlanılır və bütün konfiqurasiya edilmiş BGP həmyaşıdlarına elan edilir
  • Artıq keşlənmiş IP-yə işarə edən cavab aldıqda, onun TTL-i yenilənir
  • TTL müddəti başa çatdıqdan sonra giriş keşdən və BGP elanlarından silinir

Əlavə funksionallıq:

  • SIGHUP tərəfindən domenlərin siyahısı yenidən oxunur
  • Keşin digər nümunələrlə sinxronlaşdırılması dnstap-bgp HTTP/JSON vasitəsilə
  • Yenidən başladıqdan sonra məzmununu bərpa etmək üçün diskdəki önbelleği (BoltDB verilənlər bazasında) dublikat edin
  • Fərqli şəbəkə ad sahəsinə keçid üçün dəstək (bunun nə üçün lazım olduğu aşağıda təsvir olunacaq)
  • IPv6 dəstəyi

Məhdudiyyətlər:

  • IDN domenləri hələ dəstəklənmir
  • Bir neçə BGP parametrləri

yığdım RPM və DEB asan quraşdırma üçün paketlər. systemd ilə bütün nisbətən yeni OS-lərdə işləməlidir. onların heç bir asılılığı yoxdur.

Sxem

Beləliklə, bütün komponentləri birlikdə yığmağa başlayaq. Nəticədə bu şəbəkə topologiyası kimi bir şey almalıyıq:
DNSTap və BGP ilə ILV bloklanmasını keçin

İşin məntiqi, məncə, diaqramdan aydın görünür:

  • Müştəri bizim serverimizi DNS kimi konfiqurasiya edib və DNS sorğuları da VPN üzərindən keçməlidir. Bu, provayderin bloklamaq üçün DNS müdaxiləsindən istifadə edə bilməməsi üçün lazımdır.
  • Saytı açarkən müştəri “xxx.org-un İP-ləri nədir” kimi DNS sorğusu göndərir.
  • cilovsuz xxx.org-u həll edir (və ya onu keşdən götürür) və müştəriyə “xxx.org-da belə və belə IP var” cavabını DNSTap vasitəsilə paralel olaraq təkrarlayır.
  • dnstap-bgp bu ünvanları elan edir Quş domen bloklanmış siyahıdadırsa, BGP vasitəsilə
  • Quş ilə bu IP-lərə marşrutu reklam edir next-hop self müştəri yönləndiricisi
  • Müştəridən bu IP-lərə sonrakı paketlər tuneldən keçir

Serverdə bloklanmış saytlara marşrutlar üçün mən BIRD daxilində ayrıca cədvəldən istifadə edirəm və heç bir şəkildə ƏS ilə kəsişmir.

Bu sxemin bir çatışmazlığı var: müştəridən ilk SYN paketi, çox güman ki, yerli provayder vasitəsilə ayrılmağa vaxt tapacaq. marşrut dərhal elan edilmir. Və burada provayderin bloklamanı necə etməsindən asılı olaraq seçimlər mümkündür. O, sadəcə olaraq trafiki azaldırsa, deməli problem yoxdur. Və onu bəzi DPI-yə yönləndirirsə, (nəzəri olaraq) xüsusi effektlər mümkündür.

Müştərilərin DNS TTL möcüzələrinə hörmət etməməsi də mümkündür ki, bu da müştərinin Unbound sorğusu əvəzinə çürük keşindən bəzi köhnə girişlərdən istifadə etməsinə səbəb ola bilər.

Praktikada nə birinci, nə də ikinci mənim üçün problem yaratmadı, ancaq yürüşünüz fərqli ola bilər.

Server Sazlama

Yuvarlanma asanlığı üçün yazdım Ansible üçün rol. O, həm serverləri, həm də müştəriləri Linux əsasında konfiqurasiya edə bilər (deb əsaslı paylamalar üçün nəzərdə tutulmuşdur). Bütün parametrlər olduqca aydındır və quraşdırılmışdır inventar.yml. Bu rol mənim böyük oyun kitabımdan kəsilib, ona görə də səhvlər ola bilər - istəkləri çəkin xoş gəldiniz 🙂

Əsas komponentləri nəzərdən keçirək.

Bgp

Eyni hostda iki BGP demonunun işlədilməsinin əsas problemi var: BIRD localhost (və ya hər hansı yerli interfeys) ilə BGP peering qurmaq istəmir. Sözdən ümumiyyətlə. Googling və poçt siyahılarını oxumaq kömək etmədi, onlar bunun dizaynla olduğunu iddia edirlər. Bəlkə bir yol var, amma tapmadım.

Başqa bir BGP demonunu sınaya bilərsiniz, amma mən BIRD-ı bəyənirəm və o, mənim tərəfimdən hər yerdə istifadə olunur, mən obyektlər istehsal etmək istəmirəm.

Buna görə də, mən dnstap-bgp-ni veth interfeysi vasitəsilə kökə qoşulan şəbəkə ad məkanında gizlətdim: bu, ucları müxtəlif ad məkanlarında çıxan boruya bənzəyir. Bu uçların hər birində biz hostdan kənara çıxmayan şəxsi p2p IP ünvanlarını asırıq, buna görə də onlar hər hansı bir şey ola bilər. Bu, daxili proseslərə daxil olmaq üçün istifadə edilən eyni mexanizmdir hamı tərəfindən sevilir Docker və digər konteynerlər.

Bunun üçün yazılmışdır ssenari və yuxarıda təsvir edilmiş, özünüzü başqa ad sahəsinə sürükləmək üçün funksiya dnstap-bgp-ə əlavə edildi. Buna görə də, o, kök kimi işə salınmalı və ya setcap əmri ilə CAP_SYS_ADMIN binarına verilməlidir.

Ad sahəsi yaratmaq üçün nümunə skript

#!/bin/bash

NS="dtap"

IP="/sbin/ip"
IPNS="$IP netns exec $NS $IP"

IF_R="veth-$NS-r"
IF_NS="veth-$NS-ns"

IP_R="192.168.149.1"
IP_NS="192.168.149.2"

/bin/systemctl stop dnstap-bgp || true

$IP netns del $NS > /dev/null 2>&1
$IP netns add $NS

$IP link add $IF_R type veth peer name $IF_NS
$IP link set $IF_NS netns $NS

$IP addr add $IP_R remote $IP_NS dev $IF_R
$IP link set $IF_R up

$IPNS addr add $IP_NS remote $IP_R dev $IF_NS
$IPNS link set $IF_NS up

/bin/systemctl start dnstap-bgp

dnstap-bgp.conf

namespace = "dtap"
domains = "/var/cache/rkn_domains.txt"
ttl = "168h"

[dnstap]
listen = "/tmp/dnstap.sock"
perm = "0666"

[bgp]
as = 65000
routerid = "192.168.149.2"

peers = [
    "192.168.149.1",
]

bird.conf

router id 192.168.1.1;

table rkn;

# Clients
protocol bgp bgp_client1 {
    table rkn;
    local as 65000;
    neighbor 192.168.1.2 as 65000;
    direct;
    bfd on;
    next hop self;
    graceful restart;
    graceful restart time 60;
    export all;
    import none;
}

# DNSTap-BGP
protocol bgp bgp_dnstap {
    table rkn;
    local as 65000;
    neighbor 192.168.149.2 as 65000;
    direct;
    passive on;
    rr client;
    import all;
    export none;
}

# Static routes list
protocol static static_rkn {
    table rkn;
    include "rkn_routes.list";
    import all;
    export none;
}

rkn_routes.list

route 3.226.79.85/32 via "ens3";
route 18.236.189.0/24 via "ens3";
route 3.224.21.0/24 via "ens3";
...

DNS

Varsayılan olaraq, Ubuntu-da Unbound binar proqramı hər cür DNSTap yuvalarına qoşulmağı qadağan edən AppArmor profili tərəfindən sıxılır. Siz ya bu profili silə və ya söndürə bilərsiniz:

# cd /etc/apparmor.d/disable && ln -s ../usr.sbin.unbound .
# apparmor_parser -R /etc/apparmor.d/usr.sbin.unbound

Bu, yəqin ki, oyun kitabına əlavə edilməlidir. Profili düzəltmək və lazımi hüquqları vermək, əlbəttə ki, idealdır, amma çox tənbəl idim.

unbound.conf

server:
    chroot: ""
    port: 53
    interface: 0.0.0.0
    root-hints: "/var/lib/unbound/named.root"
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
    access-control: 192.168.0.0/16 allow

remote-control:
    control-enable: yes
    control-use-cert: no

dnstap:
    dnstap-enable: yes
    dnstap-socket-path: "/tmp/dnstap.sock"
    dnstap-send-identity: no
    dnstap-send-version: no

    dnstap-log-client-response-messages: yes

Siyahıların yüklənməsi və işlənməsi

IP ünvanlarının siyahısını yükləmək və emal etmək üçün skript
Siyahını yükləyir, prefiksə yekunlaşdırır pfx. Ilə əlavə etmə и ümumiləşdirməyin İP-lərə və şəbəkələrə ötürməyi və ya ümumiləşdirməməyi söyləyə bilərsiniz. Mənə lazım idi. VPS-in alt şəbəkəsi blok siyahısında idi 🙂

Gülməli odur ki, RosKomSvoboda API standart Python istifadəçi agenti ilə sorğuları bloklayır. Deyəsən, skript-uşaq bunu anladı. Buna görə də onu Ognelis olaraq dəyişdiririk.

Hələlik o, yalnız IPv4 ilə işləyir. IPv6-nın payı kiçikdir, lakin onu düzəltmək asan olacaq. Bird6-dan da istifadə etməli olmadıqda.

rkn.py

#!/usr/bin/python3

import json, urllib.request, ipaddress as ipa

url = 'https://api.reserve-rbl.ru/api/v2/ips/json'
pfx = '24'

dont_summarize = {
    # ipa.IPv4Network('1.1.1.0/24'),
}

dont_add = {
    # ipa.IPv4Address('1.1.1.1'),
}

req = urllib.request.Request(
    url,
    data=None, 
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
    }
)

f = urllib.request.urlopen(req)
ips = json.loads(f.read().decode('utf-8'))

prefix32 = ipa.IPv4Address('255.255.255.255')

r = {}
for i in ips:
    ip = ipa.ip_network(i)
    if not isinstance(ip, ipa.IPv4Network):
        continue

    addr = ip.network_address

    if addr in dont_add:
        continue

    m = ip.netmask
    if m != prefix32:
        r[m] = [addr, 1]
        continue

    sn = ipa.IPv4Network(str(addr) + '/' + pfx, strict=False)

    if sn in dont_summarize:
        tgt = addr
    else:
        tgt = sn

    if not sn in r:
        r[tgt] = [addr, 1]
    else:
        r[tgt][1] += 1

o = []
for n, v in r.items():
    if v[1] == 1:
        o.append(str(v[0]) + '/32')
    else:
        o.append(n)

for k in o:
    print(k)

Yeniləmək üçün skript
Gündə bir dəfə tacın üstündə gəzdirirəm, bəlkə də hər 4 saatdan bir çəkməyə dəyər. bu, mənim fikrimcə, RKN-nin provayderlərdən tələb etdiyi yenilənmə dövrüdür. Üstəlik, onların daha tez çata biləcək başqa super-təcili bloklamaları var.

Aşağıdakıları edir:

  • İlk skripti işlədir və marşrutların siyahısını yeniləyir (rkn_routes.list) BIRD üçün
  • BIRD-ı yenidən yükləyin
  • dnstap-bgp üçün domenlərin siyahısını yeniləyir və təmizləyir
  • dnstap-bgp-ni yenidən yükləyin

rkn_update.sh

#!/bin/bash

ROUTES="/etc/bird/rkn_routes.list"
DOMAINS="/var/cache/rkn_domains.txt"

# Get & summarize routes
/opt/rkn.py | sed 's/(.*)/route 1 via "ens3";/' > $ROUTES.new

if [ $? -ne 0 ]; then
    rm -f $ROUTES.new
    echo "Unable to download RKN routes"
    exit 1
fi

if [ -e $ROUTES ]; then
    mv $ROUTES $ROUTES.old
fi

mv $ROUTES.new $ROUTES

/bin/systemctl try-reload-or-restart bird

# Get domains
curl -s https://api.reserve-rbl.ru/api/v2/domains/json -o - | jq -r '.[]' | sed 's/^*.//' | sort | uniq > $DOMAINS.new

if [ $? -ne 0 ]; then
    rm -f $DOMAINS.new
    echo "Unable to download RKN domains"
    exit 1
fi

if [ -e $DOMAINS ]; then
    mv $DOMAINS $DOMAINS.old
fi

mv $DOMAINS.new $DOMAINS

/bin/systemctl try-reload-or-restart dnstap-bgp

Onlar çox düşünmədən yazılmışdır, buna görə də yaxşılaşdırıla bilən bir şey görürsənsə, get.

Müştəri quraşdırması

Burada Linux marşrutlaşdırıcıları üçün nümunələr verəcəyəm, lakin Mikrotik / Cisco vəziyyətində daha da asan olmalıdır.

Əvvəlcə BIRD-ı quraşdırırıq:

bird.conf

router id 192.168.1.2;
table rkn;

protocol device {
    scan time 10;
};

# Servers
protocol bgp bgp_server1 {
    table rkn;
    local as 65000;
    neighbor 192.168.1.1 as 65000;
    direct;
    bfd on;
    next hop self;
    graceful restart;
    graceful restart time 60;
    rr client;
    export none;
    import all;
}

protocol kernel {
    table rkn;
    kernel table 222;
    scan time 10;
    export all;
    import none;
}

Beləliklə, BGP-dən alınan marşrutları 222 nömrəli nüvə marşrutlaşdırma cədvəli ilə sinxronlaşdıracağıq.

Bundan sonra, standart birinə baxmadan əvvəl nüvədən bu lövhəyə baxmağı xahiş etmək kifayətdir:

# ip rule add from all pref 256 lookup 222
# ip rule
0:  from all lookup local
256:    from all lookup 222
32766:  from all lookup main
32767:  from all lookup default

Hər şey, serverin tunel IP ünvanını DNS olaraq yaymaq üçün marşrutlaşdırıcıda DHCP-ni konfiqurasiya etmək qalır və sxem hazırdır.

Məhdudiyyətlər

Domenlərin siyahısını yaratmaq və emal etmək üçün mövcud alqoritmlə o, digər şeylər arasında, youtube.com və onun CDN-ləri.

Və bu, bütün videoların VPN-dən keçəcəyinə gətirib çıxarır ki, bu da bütün kanalı bağlaya bilər. Yəqin ki, hazırda RKN-ni bloklayan məşhur domenlərin - istisnaların siyahısını tərtib etməyə dəyər, bağırsaqlar nazikdir. Və təhlil edərkən onları keçin.

Nəticə

Təsvir edilən üsul, provayderlərin hazırda tətbiq etdiyi demək olar ki, hər hansı bir blokdan keçməyə imkan verir.

Prinsipcə, dnstap-bgp domen adına əsaslanaraq müəyyən səviyyəli trafikə nəzarətin lazım olduğu hər hansı digər məqsəd üçün istifadə edilə bilər. Unutmayın ki, bizim dövrümüzdə min sayt eyni IP ünvanında (məsələn, bəzi Cloudflare-in arxasında) asılı ola bilər, buna görə də bu metod kifayət qədər aşağı dəqiqliyə malikdir.

Ancaq kilidləri keçmək ehtiyacları üçün bu kifayətdir.

Əlavələr, redaktələr, sorğular - xoş gəlmisiniz!

Mənbə: www.habr.com

Добавить комментарий