Бөгөттөөнү айланып өтүү үчүн BGP орнотуу же "Кантип мен коркпой калдым жана RKNди сүйүп калдым"

Ооба, макул, "сүйгөн" жөнүндө аша чапкандык. Тескерисинче, "менен бирге жашай алган".

Баарыңыздарга белгилүү болгондой, Роскомнадзор 16-жылдын 2018-апрелинен тарта Интернеттеги ресурстарга кирүү мүмкүнчүлүгүн өтө кеңири масштабда жаап, “Домендик аталыштардын бирдиктүү реестрине, Интернеттеги сайттардын барак индекстерине жана сайттарды аныктоого мүмкүндүк берген тармак даректерине” толуктоо киргизген. Интернетте” Россия Федерациясында жайылтууга тыюу салынган маалыматтарды камтыган” (текстинде – жөн гана реестр) /10 кээде. Натыйжада, Россия Федерациясынын жарандары жана ишканалар өздөрүнө зарыл болгон мыйзамдуу ресурстарды толук пайдалана албай кыйналып жатышат.

Мен Хабредеги макалалардын бирине комментарийлерде жабырлануучуларга айланып өтүү схемасын орнотууда жардам берүүгө даяр экенимди айтканымдан кийин, мага ушундай жардам сурап бир нече адам келишти. Баары алар үчүн иштегенде, алардын бири макалада техниканы сүрөттөп берүүнү сунуштады. Бир аз ойлонгондон кийин, мен сайтта унчукпай турганымды бузуп, бир жолу долбоор менен Facebook постунун ортосунда бир нерсени жазууга аракет кылууну чечтим, б.а. habrapost. Натыйжа сиздин алдыңызда.

баш тартуу

Россия Федерациясынын аймагында тыюу салынган маалыматка кирүүнү бөгөттөө жолдорун жарыялоо өтө мыйзамдуу болбогондуктан, бул макаланын максаты - бул жерде уруксат берилген ресурстарга жетүүнү автоматташтырууга мүмкүндүк берүүчү ыкма жөнүндө сөз кылуу. Россия Федерациясынын аймагында, бирок башка бирөөнүн аракеттеринен улам сиздин провайдериңиз аркылуу түздөн-түз жеткиликтүү эмес. Ал эми макаладагы аракеттердин натыйжасында алынган башка ресурстарга жетүү жагымсыз терс таасир болуп саналат жана макаланын максаты болуп саналбайт.

Ошондой эле, мен негизинен кесибим, кесибим жана жашоо жолу боюнча тармак архитектору болгондуктан, программалоо жана Linux менин күчтүү жактарым эмес. Ошондуктан, албетте, сценарийлерди жакшыраак жазса болот, VPSдеги коопсуздук маселелерин тереңирээк иштеп чыгууга болот ж.б.у.с. Сиздин сунуштарыңыз ыраазы болуу менен кабыл алынат, эгерде алар жетиштүү деталдаштырылган болсо - мен аларды макаланын текстине кошууга кубанычта болом.

TL; DR

Биз реестрдин көчүрмөсүн жана BGP протоколун колдонуп, учурдагы туннелиңиз аркылуу ресурстарга кирүү мүмкүнчүлүгүн автоматташтырабыз. Максаты туннелге бөгөттөлгөн ресурстарга багытталган бардык трафикти алып салуу. Минималдуу түшүндүрмөлөр, негизинен этап-этабы менен көрсөтмөлөр.

Бул үчүн сага эмне керек?

Тилекке каршы, бул пост бардык адамдар үчүн эмес. Бул ыкманы колдонуу үчүн, бир нече элементтерди бириктирүү керек:

  1. Сизде бөгөттөө талаасынан тышкары жерде Linux сервери болушу керек. Же, жок эле дегенде, мындай серверге ээ болууну каалоо - бактыга жараша, анын баасы жылына 9 доллардан, жана балким, андан азыраак. Эгер сизде өзүнчө VPN туннели бар болсо, анда сервер бөгөттөө талаасынын ичинде жайгашса болот.
  2. Сиздин роутер жетиштүү акылдуу болушу керек
    • сизге жаккан каалаган VPN кардары (мен OpenVPN'ди жактырам, бирок ал PPTP, L2TP, GRE+IPSec же туннель интерфейсин түзгөн башка вариант болушу мүмкүн);
    • BGPv4 протоколу. Бул SOHO үчүн бул Mikrotik же OpenWRT/LEDE/ушуга окшош ыңгайлаштырылган микропрограммасы бар роутер болушу мүмкүн дегенди билдирет, ал сизге Quagga же Bird орнотууга мүмкүндүк берет. PC роутерин колдонуу да тыюу салынган эмес. Ишкана болсо, чек ара роутериңиздин документтеринен BGP колдоосун издеңиз.
  3. Linux колдонуу жана тармактык технологиялар, анын ичинде BGP протоколу жөнүндө түшүнүккө ээ болушуңуз керек. Же жок дегенде ушундай идеяны алгыңыз келет. Мен бул жолу чексиздикти кабыл алууга даяр болбогондуктан, сизге түшүнүксүз болгон кээ бир аспектилерди өз алдынча изилдөөгө туура келет. Бирок, мен, албетте, комментарийлерде конкреттүү суроолорго жооп берем жана мен жалгыз гана жооп бере албайм, андыктан суроодон тартынбаңыз.

Мисалда эмне колдонулат

  • Реестрдин көчүрмөсү - тартып https://github.com/zapret-info/z-i 
  • VPS - Ubuntu 16.04
  • Маршруттук кызмат - куш 1.6.3   
  • Маршрутизатор - Микротик hAP ac
  • Жумушчу папкалар - биз тамыр катары иштеп жаткандыктан, бардыгынын көбү тамырдын башкы папкасында жайгашат. Тиешелүүлүгүнө жараша:
    • /root/кара тизме - компиляция скрипти бар жумушчу папка
    • /root/zi - githubдан реестрдин көчүрмөсү
    • /etc/bird - канаттууларды тейлөө жөндөөлөрү үчүн стандарттык папка
  • Маршруттук сервер жана туннелди токтотуу чекити менен VPSтин тышкы IP дареги 194.165.22.146, ASN 64998; роутердин тышкы IP дареги - 81.177.103.94, ASN 64999
  • Туннелдин ичиндеги IP даректер тиешелүүлүгүнө жараша 172.30.1.1 жана 172.30.1.2.

Бөгөттөөнү айланып өтүү үчүн BGP орнотуу же "Кантип мен коркпой калдым жана RKNди сүйүп калдым"

Албетте, сиз башка роутерлерди, операциялык системаларды жана программалык өнүмдөрдү колдоно аласыз, алардын логикасына чечимди тууралоо.

Кыскача - чечүү логикасы

  1. Даярдык иш-аракеттери
    1. VPS алуу
    2. Роутерден VPSке туннелди көтөрүү
  2. Биз реестрдин көчүрмөсүн алып, үзгүлтүксүз жаңыртып турабыз
  3. Маршрутизация кызматын орнотуу жана конфигурациялоо
  4. Биз реестрдин негизинде маршруттоо кызматы үчүн статикалык маршруттардын тизмесин түзөбүз
  5. Биз роутерди кызматка туташтырабыз жана бардык трафикти туннель аркылуу жөнөтүүнү конфигурациялайбыз.

Чыныгы чечим

Даярдык иш-аракеттери

Интернетте өтө акылга сыярлык баада VPS камсыз кылган көптөгөн кызматтар бар. Азырынча мен $ 9 / жыл үчүн опцияны таптым жана колдонуп жатам, бирок сиз көп убараланбасаңыз да, ар бир бурчта 1E / ай үчүн көптөгөн варианттар бар. VPS тандоо маселеси бул макаланын алкагынан алыс, ошондуктан кимдир бирөө бул жөнүндө бир нерсени түшүнбөсө, комментарийлерден сураңыз.

Эгер сиз VPSти багыттоо кызматы үчүн гана эмес, андагы туннелди токтотуу үчүн да колдонсоңуз, анда бул туннелди көтөрүшүңүз керек жана, албетте, ал үчүн NAT конфигурациялооңуз керек. Интернетте бул аракеттер боюнча көптөгөн көрсөтмөлөр бар, мен аларды бул жерде кайталабайм. Мындай туннелдин негизги талабы, ал роутериңизде VPSке карай туннелди колдогон өзүнчө интерфейс түзүшү керек. Көпчүлүк колдонулган VPN технологиялары бул талапка жооп берет - мисалы, тун режиминде OpenVPN идеалдуу.

Реестрдин көчүрмөсүн алуу

Жабраил айткандай: «Бизге ким тоскоол болсо, ошол жардам берет». РКН тыюу салынган ресурстардын реестрин түзүп жаткандыктан, биздин көйгөйдү чечүү үчүн бул реестрди колдонбосок күнөө болот. Биз githubдан реестрдин көчүрмөсүн алабыз.

Биз сиздин Linux сервериңизге барып, түпкү контекстке киребиз (sudo su —) жана git орното элек болсо орнотуңуз.

apt install git

Үй каталогуңузга барып, реестрдин көчүрмөсүн чыгарыңыз.

cd ~ && git clone --depth=1 https://github.com/zapret-info/z-i 

Биз cron жаңыртуусун орноттук (мен 20 мүнөт сайын бир жолу жасайм, бирок сиз каалаган интервалды тандай аласыз). Бул үчүн биз ишке киргизебиз crontab -E жана ага төмөнкү сапты кошуңуз:

*/20 * * * * cd ~/z-i && git pull && git gc

Реестрди жаңырткандан кийин маршрутташтыруу кызматы үчүн файлдарды түзө турган илгичти туташтырабыз. Бул үчүн, файл түзүңүз /root/zi/.git/hooks/post-merge төмөнкү мазмун менен:

#!/usr/bin/env bash
changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
check_run() {
    echo "$changed_files" | grep --quiet "$1" && eval "$2"
}
check_run dump.csv "/root/blacklist/makebgp"

жана аны аткарыла турган кылууну унутпаңыз

chmod +x /root/z-i/.git/hooks/post-merge

Биз илгич айткан makebgp скриптин бир аз кийинчерээк түзөбүз.

Маршрутизация кызматын орнотуу жана конфигурациялоо

Канаттууларды орнотуу. Тилекке каршы, учурда Ubuntu репозиторийлеринде жайгаштырылган куштун версиясы жаңылыгы боюнча Archaeopteryx заңы менен салыштырууга болот, андыктан алгач системага программалык камсыздоону иштеп чыгуучулардын расмий PPAсын кошуубуз керек.

add-apt-repository ppa:cz.nic-labs/bird
apt update
apt install bird

Андан кийин биз IPv6 үчүн кушту дароо өчүрөбүз - бул орнотууда бизге кереги жок болот.

systemctl stop bird6
systemctl disable bird6

Төмөндө канаттуулардын минималисттик конфигурация файлы (/etc/bird/bird.conf), бул биз үчүн жетиштүү (жана дагы бир жолу эскертем, эч ким өз муктаждыктарыңызга ылайык идеяны иштеп чыгууга жана тууралоого тыюу салбайт)

log syslog all;
router id 172.30.1.1;

protocol kernel {
        scan time 60;
        import none;
#       export all;   # Actually insert routes into the kernel routing table
}

protocol device {
        scan time 60;
}

protocol direct {
        interface "venet*", "tun*"; # Restrict network interfaces it works with
}

protocol static static_bgp {
        import all;
        include "pfxlist.txt";
        #include "iplist.txt";
}

protocol bgp OurRouter {
        description "Our Router";
        neighbor 81.177.103.94 as 64999;
        import none;
        export where proto = "static_bgp";
        local as 64998;
        passive off;
        multihop;
}

роутердин идентификатору - роутердин идентификатору, ал визуалдык түрдө IPv4 дарегине окшош, бирок бир эмес. Биздин учурда, ал IPv32 дарек форматында каалаган 4 биттик сан болушу мүмкүн, бирок түзмөгүңүздүн IPv4 дарегин так көрсөтүү жакшы форма (бул учурда VPS).

протокол түз багыттоо процесси менен кайсы интерфейстер иштей турганын аныктайт. Мисал бир нече мисал атын берет, сиз башкаларды кошо аласыз. Сиз жөн гана сызыкты жок кылсаңыз болот, бул учурда сервер IPv4 дареги менен бардык жеткиликтүү интерфейстерди угат.

protocol static - бул префикстердин жана IP даректердин тизмелерин (албетте, алар /32 префикстер) кийинки жарыялоо үчүн файлдардан жүктөөчү сыйкырыбыз. Бул тизмелер кайдан алынганы төмөндө талкууланат. Көңүл буруңуз, IP даректерди жүктөө демейки боюнча түшүндүрүлөт, мунун себеби жүктөөнүн чоң көлөмү. Салыштыруу үчүн, жазуу учурунда, префикстердин тизмесинде 78 сап, ал эми IP даректеринин тизмесинде 85898. Мен префикстердин тизмесинен гана баштоону жана мүчүлүштүктөрдү оңдоону жана IP жүктөөнү иштетүү же иштетпөөнү сунуштайм. роутериңиз менен эксперимент кылгандан кийин, келечек сизден көз каранды. Алардын ар бири маршруттук таблицадагы 85 миң жазууну оңой сиңире албайт.

bgp протоколу, чындыгында, роутериңиз менен bgp пирингди орнотот. IP-адрес – роутердин тышкы интерфейсинин дареги (же роутер тарабындагы туннель интерфейсинин дареги), 64998 жана 64999 – автономдуу системалардын номерлери. Бул учурда, алар каалаган 16 биттик сандар түрүндө дайындалышы мүмкүн, бирок RFC6996 - 64512-65534 тарабынан аныкталган жеке диапазондогу AS номерлерин колдонуу жакшы практика болуп саналат (32 биттик ASN үчүн формат бар, бирок биздин учурда бул, албетте, ашыкча). Сүрөттөлгөн конфигурацияда eBGP пиринги колдонулат, мында маршрутизация кызматынын жана роутердин автономдуу тутумдарынын номерлери ар башка болушу керек.

Көрүнүп тургандай, кызмат роутердин IP дарегин билиши керек, андыктан динамикалык же багытталбаган жеке (RFC1918) же бөлүшүлгөн (RFC6598) дарегиңиз болсо, сизде тышкы перирингди көтөрүү мүмкүнчүлүгү жок. Interface, бирок кызмат дагы деле туннелдин ичинде иштей берет.

Ошондой эле бир кызматтан сиз бир нече ар кандай роутерлерге маршруттарды бере ала турганыңыз айдан ачык - протоколдун bgp бөлүмүн көчүрүп, кошунаңыздын IP дарегин өзгөртүү менен жөн гана алар үчүн орнотууларды кайталаңыз. Мына ошондуктан мисал туннелдин сыртына көз салуу үчүн эң универсалдуу параметрлерди көрсөтөт. Орнотуулардагы IP даректерди ошого жараша өзгөртүү менен аларды туннелге алып салуу оңой.

Маршрутизация кызматы үчүн реестрди иштетүү

Эми бизге, чындыгында, мурунку этапта статикалык протоколдо айтылган префикстердин жана IP даректердин тизмелерин түзүү керек. Бул үчүн, биз реестр файлын алып, андан керектүү файлдарды төмөнкү скрипттин жардамы менен жасайбыз, /root/blacklist/makebgp

#!/bin/bash
cut -d";" -f1 /root/z-i/dump.csv| tr '|' 'n' |  tr -d ' ' > /root/blacklist/tmpaddr.txt
cat /root/blacklist/tmpaddr.txt | grep / | sed 's_.*_route & reject;_' > /etc/bird/pfxlist.txt
cat /root/blacklist/tmpaddr.txt | sort | uniq | grep -Eo "([0-9]{1,3}[.]){3}[0-9]{1,3}" | sed 's_.*_route &/32 reject;_' > /etc/bird/iplist.txt
/etc/init.d/bird reload
logger 'bgp list compiled'

Аны аткарыла турган кылууну унутпаңыз

chmod +x /root/blacklist/makebgp

Эми сиз аны кол менен иштетип, /etc/bird ичиндеги файлдардын көрүнүшүн байкай аласыз.

Кыязы, куш учурда сиз үчүн иштебей жатат, анткени мурунку этапта сиз андан али жок файлдарды издөөнү сурангансыз. Ошондуктан, биз аны ишке киргизип, анын башталганын текшеребиз:

systemctl start bird
birdc show route

Экинчи буйруктун чыгышы болжол менен 80 жазууну көрсөтүшү керек (бул азыр, бирок сиз аны орнотуп жатканда, бардыгы RKNдин тармактарды блоктоодогу ынталуулугуна жараша болот) төмөнкүдөй:

54.160.0.0/12      unreachable [static_bgp 2018-04-19] * (200)

команда

birdc show protocol

кызматтын ичиндеги протоколдордун абалын көрсөтөт. Сиз роутерди конфигурациялаганга чейин (кийинки пунктту караңыз), OurRouter протоколу старт абалында болот (Туташуу же Активдүү фаза), ал эми ийгиликтүү туташуудан кийин ал жогору абалга өтөт (Түзүлгөн фаза). Мисалы, менин системамда бул буйруктун чыгышы төмөнкүдөй көрүнөт:

BIRD 1.6.3 ready.
name     proto    table    state  since       info
kernel1  Kernel   master   up     2018-04-19
device1  Device   master   up     2018-04-19
static_bgp Static   master   up     2018-04-19
direct1  Direct   master   up     2018-04-19
RXXXXXx1 BGP      master   up     13:10:22    Established
RXXXXXx2 BGP      master   up     2018-04-24  Established
RXXXXXx3 BGP      master   start  2018-04-22  Connect       Socket: Connection timed out
RXXXXXx4 BGP      master   up     2018-04-24  Established
RXXXXXx5 BGP      master   start  2018-04-24  Passive

Роутерди туташтыруу

Бул бут кийимди окуудан ар бир адам чарчаса керек, бирок көңүлүңүздү алыңыз - аягы жакындап калды. Мындан тышкары, бул бөлүмдө мен этап-этабы менен көрсөтмөлөрдү бере албайм - бул ар бир өндүрүүчү үчүн ар кандай болот.

Бирок, мен сизге бир нече мисалдарды көрсөтө алам. Негизги логика - бул BGP пирингин жогорулатуу жана биздин туннелди көрсөтүп (эгерде биз p2p интерфейси аркылуу трафик жөнөтүшүбүз керек болсо) же трафик Ethernetке кете турган болсо, nexthop IP дарегин көрсөтүп, бардык алынган префикстерге nexthop дайындоо.

Мисалы, RouterOSдогу Mikrotikте бул төмөнкүчө чечилет

/routing bgp instance set default as=64999 ignore-as-path-len=yes router-id=172.30.1.2
/routing bgp peer add in-filter=dynamic-in multihop=yes name=VPS remote-address=194.165.22.146 remote-as=64998 ttl=default
/routing filter add action=accept chain=dynamic-in protocol=bgp comment="Set nexthop" set-in-nexthop=172.30.1.1

жана Cisco IOSто - ушул сыяктуу

router bgp 64999
  neighbor 194.165.22.146 remote-as 64998
  neighbor 194.165.22.146 route-map BGP_NEXT_HOP in
  neighbor 194.165.22.146 ebgp-multihop 250
!
route-map BGP_NEXT_HOP permit 10
  set ip next-hop 172.30.1.1

Эгерде ошол эле туннель BGP пирингинде да, пайдалуу трафикти өткөрүү үчүн да колдонулса, анда кийинки баскычты коюунун кереги жок, ал протоколдун жардамы менен туура орнотулат. Бирок, эгер сиз аны кол менен орнотсоңуз, ал дагы начарлатпайт.

Башка платформаларда конфигурацияны өзүңүз чечишиңиз керек болот, бирок кандайдыр бир кыйынчылыктар болсо, комментарийге жазыңыз, мен жардам берүүгө аракет кылам.

Сиздин BGP сеансы башталгандан кийин, чоң тармактарга каттамдар келип, таблицага орнотулган, алардан даректерге трафик агылган жана бакыт жакын болгондон кийин, сиз куш кызматына кайтып келип, ал жердеги түйүндөрдү байланыштырган жазууну жокко чыгарууга аракет кылсаңыз болот. IP даректеринин тизмеси, андан кийин аткарыңыз

systemctl reload bird

жана роутериңиз бул 85 миң маршрутту кантип өткөрүп бергенин көрүңүз. Электр розеткасынан ажыратып, аны менен эмне кылууну ойлонууга даяр болуңуз :)

жалпы

Таза теориялык жактан алганда, жогоруда сүрөттөлгөн кадамдарды аткаргандан кийин, сизде азыр чыпкалоо тутумунан өткөн Россия Федерациясында тыюу салынган IP даректерге трафикти автоматтык түрдө багыттоочу кызмат бар.

Аны, албетте, жакшыртууга болот. Мисалы, perl же python чечимдерин колдонуп IP даректеринин тизмесин жалпылоо оңой. Муну Net::CIDR::Lite аркылуу жасаган жөнөкөй Perl скрипти 85 миң префиксти 60 (миң эмес) кылып түзөт, бирок, албетте, блоктолгондон алда канча чоң даректер диапазонун камтыйт.

Кызмат ISO/OSI моделинин үчүнчү деңгээлинде иштегендиктен, реестрде жазылгандай туура эмес дарекке кайрылса, сайтты/баракты бөгөттөөдөн куткара албайт. Бирок реестр менен бирге nxdomain.txt файлы githubдан келет, ал скрипттин бир нече штрихтери менен оңой эле даректердин булагына айланат, мисалы, Chrome'догу SwitchyOmega плагини.

Эгер сиз жөн гана Интернет колдонуучусу болбосоңуз, ошондой эле кээ бир ресурстарды өз алдынча жарыяласаңыз (мисалы, веб-сайт же почта сервери ушул туташууда иштейт) чечим кошумча тактоону талап кылаарын да белгилей кетүү керек. Маршрутизатордун каражаттарын колдонуу менен бул кызматтан чыгуучу трафикти сиздин жалпыга ачык дарегиңизге катуу туташтыруу керек, антпесе роутер алган префикстердин тизмегинде камтылган ресурстар менен байланышты жоготуп аласыз.

Суроолоруңуз болсо бериңиз, мен жооп берүүгө даярмын.

UPD. Рахмат navion и TerAnYu жүктөө көлөмүн кыскартууга мүмкүндүк берген git параметрлери үчүн.

UPD2. Кесиптештер, макалага VPS менен роутердин ортосунда туннелди орнотуу боюнча инструкцияларды кошпой, ката кетирдим окшойт. Ушундан улам көптөгөн суроолор жаралууда.
Болгондо да, мен дагы бир жолу белгилей кетейин, бул колдонмону баштоодон мурун, сиз VPN туннелин керектүү багытта конфигурациялап, анын иштешин текшерип алгансыз (мисалы, трафикти демейки же статикалык түрдө бул жакка буруп). Эгер сиз бул этапты аягына чыгара элек болсоңуз, анда макаладагы кадамдарды аткаруунун мааниси жок. Бул боюнча менин жеке текстим жок, бирок Google'да VPSде орнотулган операциялык системанын аталышы менен "OpenVPN серверин орнотуу" жана роутериңиздин аталышы менен "OpenVPN кардарын орнотуу" деп жазсаңыз , сиз бул тема боюнча бир катар макалаларды таба аласыз, анын ичинде Habré.

UPD3. Курмандык кылынбаган Мен dump.csv файлын IP даректеринин кошумча жалпылоосу менен канаттуулар үчүн файлга айланткан код жаздым. Ошондуктан, "Маршруттоо кызматы үчүн реестрди иштетүү" бөлүмүн анын программасын чакыруу менен алмаштырууга болот. https://habr.com/post/354282/#comment_10782712

UPD4. Каталар боюнча бир аз иш (мен аларды текстке кошкон жокмун):
1) ордуна systemctl кайра жүктөө куш команданы колдонуунун мааниси бар birdc конфигурациялоо.
2) Microtik роутеринде, туннелдин экинчи капталынын IP-ке кийинкисин өзгөртүүнүн ордуна /маршруттук фильтр кошуу аракети=кабыл алуу чынжыр=динамикалык-протокол=bgp comment=»Nexthop орнотуу» set-in-nexthop=172.30.1.1 дарексиз, туннелдин интерфейсине түз маршрутту көрсөтүү мааниси бар /маршруттук фильтр кошуу аракети=кабыл алуу чынжыр=динамикалык-протокол=bgp comment=»Nexthop орнотуу» set-in-nexthop-direct=<интерфейс аты>

UPD5. Жаңы кызмат пайда болду https://antifilter.download, бул жерден сиз IP даректеринин даяр тизмесин ала аласыз. Ар бир жарым саат сайын жаңыртылып турат. кардар тарабында, бардык тиешелүү "маршрут ... четке кагуу" менен жазууларды алкак үчүн калат.
Бул учурда, балким, чоң энеңизди чүпүрөктөп, макаланы жаңыртуу жетиштүү.

UPD6. Аны түшүнгүсү келбегендер, бирок баштоону каалагандар үчүн макаланын оңдолгон версиясы - бул жерде.

Source: www.habr.com

Комментарий кошуу