Direkt VPN-tunnel mellan datorer genom NAT:er från leverantörer (utan VPS, med hjälp av STUN-server och Yandex.disk)

Förlängning Artikel om hur jag lyckades organisera en direkt VPN-tunnel mellan två datorer bakom NAT-leverantörer. Den tidigare artikeln beskrev processen att organisera en anslutning med hjälp av en tredje part - en mellanhand (en hyrd VPS som fungerar som något som en STUN-server och en noddatasändare för anslutningen). I den här artikeln kommer jag att berätta hur jag klarade mig utan VPS, men mellanhänderna fanns kvar och de var STUN-servern och Yandex.Disk...
Direkt VPN-tunnel mellan datorer genom leverantörens NAT:er (utan VPS, med hjälp av STUN-server och Yandex.disk)

Inledning

Efter att ha läst kommentarerna i det tidigare inlägget insåg jag att den största nackdelen med implementeringen var användningen av en mellanhand - en tredje part (VPS) som angav nodens nuvarande parametrar, var och hur man ansluter. Med tanke på rekommendationerna för att använda denna STUN (som det finns en hel del av) för att bestämma de aktuella anslutningsparametrarna. Först och främst bestämde jag mig för att använda TCPDump för att titta på innehållet i paketen när STUN-servern arbetade med klienter och fick helt oläsbart innehåll. Googlade på protokollet jag hittade artikel som beskriver protokollet. Jag insåg att jag inte kunde implementera en begäran till STUN-servern på egen hand och lade idén i en "avlägsen låda".

Теория

Nyligen var jag tvungen att installera STUN-servern på Debian från paketet

# apt install stun-server

och i beroenden såg jag stun-client-paketet, men på något sätt uppmärksammade jag det inte. Men senare kom jag ihåg om stun-client-paketet och bestämde mig för att ta reda på hur det fungerar, efter att ha googlat och sökt i Yandex fick jag:

# apt install stun-client
# stun stun.ekiga.net -p 21234 -v

Som svar fick jag:

STUN-klientversion 0.97
Öppnade port 21234 med fd 3
Öppnade port 21235 med fd 4
Kodning bedövande meddelande:
Encoding ChangeRequest: 0

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Mottaget bedövande meddelande: 92 byte
MappadAddress = <Min IP>:2885
Källadress = 216.93.246.18:3478
Ändrad adress = 216.93.246.17:3479
Okänt attribut: 32800
Servernamn = Vovida.org 0.98-CPC
Mottaget meddelande av typen 257 id=1
Kodning bedövande meddelande:
Encoding ChangeRequest: 0

Ska skicka meddelande från len 28 till 216.93.246.17:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 0

På väg att skicka meddelande från len 28 till <Min IP>:2885
Mottaget bedövande meddelande: 28 byte
ChangeRequest = 0
Mottaget meddelande av typen 1 id=11
Kodning bedövande meddelande:
Encoding ChangeRequest: 0

Ska skicka meddelande från len 28 till 216.93.246.17:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Mottaget bedövande meddelande: 92 byte
MappadAddress = <Min IP>:2885
Källadress = 216.93.246.17:3479
Ändrad adress = 216.93.246.18:3478
Okänt attribut: 32800
Servernamn = Vovida.org 0.98-CPC
Mottaget meddelande av typen 257 id=10
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 4

Ska skicka meddelande från len 28 till 216.93.246.18:3478
Kodning bedövande meddelande:
Encoding ChangeRequest: 2

Ska skicka meddelande från len 28 till 216.93.246.18:3478
test I = 1
test II = 0
test III = 0
test I(2) = 1
är nat = 1
mappad IP samma = 1
hårnål = 1
bevarandeport = 0
Primär: Oberoende mappning, portberoende filter, slumpmässig port, kommer att hårnåla
Returvärdet är 0x000006

Sträng med värde

MappadAddress = <Min IP>:2885

precis vad du behöver! Den visade aktuell status för anslutningen på den lokala UDP-porten 21234. Men detta är bara halva striden, frågan uppstod om hur man överför denna data till fjärrvärden och organiserar en VPN-anslutning. Använda e-postprotokollet, eller kanske Telegram?! Det finns många alternativ och jag bestämde mig för att använda Yandex.disk, eftersom jag kom över artikel om att arbeta med Curl via WebDav med Yandex.disk. Efter att ha funderat på implementeringen kom jag fram till följande schema:

  1. Signalera att noder är redo att upprätta en anslutning genom närvaron av en specifik fil med en tidsstämpel på Yandex.disk;
  2. Om noderna är klara, ta emot aktuella parametrar från STUN-servern;
  3. Ladda upp aktuella inställningar till Yandex.disk;
  4. Kontrollera närvaron och läs parametrarna för en fjärrnod från en fil på Yandex.disk;
  5. Upprätta en anslutning med en fjärrvärd med OpenVPN.

Praxis

Efter att ha funderat lite, med hänsyn till upplevelsen av den senaste artikeln, skrev jag snabbt ett manus. Vi kommer att behöva:

# apt install openvpn stun-client curl 

Själva skriptet:

original version

# cat vpn8.sh

#!/bin/bash
######################## Задаем цветной текст ###
WARN='33[37;1;41m'				#
END='33[0m'					#
RED='33[0;31m'         #  ${RED}		#
GREEN='33[0;32m'      #  ${GREEN}		#
#################################################
####################### Проверяем наличие необходымих приложений #########################################################
al="echo readlink dirname grep awk md5sum shuf nc curl sleep openvpn cat stun"
ch=0
for i in $al; do which $i > /dev/null || echo -e "${WARN}Для работы необходим $i ${END}"; which $i > /dev/null || ch=1; done
if (( $ch > 0 )); then echo -e "${WARN}Ой, отсутствуют необходимые для корректной работы приложения${END}"; exit; fi
#######################################################################################################################

if [[ $1 == '' ]]; then echo -e "${WARN}Введите идентификатор соединения (любое уникальное слово, должно быть одинаковое с двух сторон!) ${END} t
${GREEN}Для запуска в автоматическом режиме при включении компьютера можно прописать в /etc/rc.local строку nohup /<путь к файлу>/vpn8.sh  > /var/log/vpn8.log 2>/dev/hull & ${END}"; exit; fi
ABSOLUTE_FILENAME=`readlink -f "$0"`                                                    # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"`                                                      # каталог в котором лежит скрипт
############################### Проверка наличия секретного ключа ##################################
key="$DIR/secret.key"
if [ ! -f "$key" ]; then
				echo -e "${WARN}Секретный ключ VPN-соединения не найден, для генерации ключа выполните: 
openvpn --genkey --secret secret.key Внимание: ключ используется для авторизации и должен 
быть одинаковым с двух сторон!!!${END}
 # ls -l secret.key
 -rw------- 1 root root 637 ноя 27 11:12 secret.key
 # chmod 600 secret.key";
				exit;
				fi
########################################################################################################################

ABSOLUTE_FILENAME=`readlink -f "$0"`                                                    # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"`                                                      # каталог в котором лежит скрипт
name=$(uname -n | md5sum | awk '{print $1}')
vpn=$(echo $1 | md5sum | awk '{print $1}')
stun="stun.ekiga.net" 	# STUN сервер
username="Yandex"	# Логин от Яндекс.диска	
password="Password"	# Пароль от Яндекс.диска
localport=`shuf -i 20000-65000 -n 1`	# генерация локального порта

echo "$(date) Создаю папку на Яндекс.диске"
curl -X MKCOL --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn
echo "$(date) Очищаю папку от всякого мусора"
for i in `curl --silent --user "$username:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></n/g' | grep "d:displayname" | sed 's/d:displayname//g' | sed 's/>//g' | sed 's/<//' | sed 's////g' | grep -v $(date +%Y-%m-%d-%H-%M)`; do
	echo "$(date) Delete: $i"
	curl -X DELETE --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn/$i
	done

until [ $c ];do

	until [[ $b ]]; do
		echo "$(date) Проверяю папку"
		date=`date +%Y-%m-%d-%H-%M`
		mydata=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep $name | grep $date | grep "d:displayname"`
		if [[ -z $mydata ]]; 	then
						echo "$(date) Файл готовности создан"
					        echo "$date" > "/tmp/$date-$name-ready.txt"
					        curl -T "/tmp/$date-$name-ready.txt" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$date-$name-ready.txt
					else
						echo "$(date) Файл готовности уже существует - $date"
					fi
		remote=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep -v $name | grep $date | grep "d:displayname"`
		if [[ -z $remote ]];	then
						echo -e "$(date) ${RED} Удаленный узел не готов ${END}"
						echo "$(date) Жду"
						sleep 20
					else
						echo -e "$(date) ${GREEN} Удаленный узел готов ${END}"
						b=1
						a=''
					fi
	done

	until [ $a ]; do
		echo "$(date) Подключение и получение данных от STUN сервера: $stun"
                mydata=`stun $stun -p $localport -v 2>&1 | grep MappedAddress | sort | uniq`
                echo -e "$(date) ${GREEN}Мои данные соединения: $mydata${END}"
                echo "$mydata" > "$DIR/mydata"
                echo "$(date) Загрузка данных на Яндекс.диск"
                curl -T "$DIR/mydata" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$name.txt
		echo "$(date) Получение файла данных удаленного узла"
		filename=$(curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></n/g' | grep "d:displayname>" | grep "txt" | grep -v "$name" | grep -v "ready" | sed 's|.*d:displayname>||' | sed 's/</ /g' | awk '{print $1}')
		echo "$(date) Чтение файла данных удаленного узла: $filename"
		address=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$filename | sort | uniq | head -n1 | sed 's/:/ /g')
		echo "$(date) Определение IP-адреса и порта"
		ip=$(echo "$address" | awk '{print $3}')
		port=$(echo "$address" | awk '{print $4}')
		if [[ -n "$ip" && -n "$port" ]]; then
			echo -e "$(date) ${GREEN} Соединение $ip $port ${END}"
       		 	openvpn --remote $ip --rport $port --lport $localport 
	       	 	    --proto udp --dev tap --float --auth-nocache --verb 3 --mute 20 
	       	 	    --ifconfig 10.45.54.2 255.255.255.252 
	       		    --secret "$DIR/secret.key" 
	       		    --auth SHA256 --cipher AES-256-CBC 
	        	    --ncp-disable --ping 10  --ping-exit 30 
	        	    --comp-lzo yes
			echo -e "$(date) ${WARN} Соединение разорвано${END}"
			a=1
			b=''
			else
			a=1
			b=''
			fi
	done
done

För att skriptet ska fungera behöver du:

  1. Kopiera till urklipp och klistra in i editorn, till exempel:
    # nano vpn8.sh 
  2. ange användarnamn och lösenord för Yandex.disk.
  3. i fältet "—ifconfig 10.45.54.(1 eller 2) 255.255.255.252" ange den interna IP-adressen för gränssnittet
  4. skapa hemlig nyckel genom kommando:
    # openvpn --genkey --secret secret.key 
  5. gör skriptet körbart:
    # chmod +x vpn8.sh
  6. kör skriptet:
    # ./vpn8.sh nZbVGBuX5dtturD

    där nZbVGBuX5dtturD är det genererade anslutnings-ID här

På fjärrnoden, gör allt på samma sätt förutom att generera secret.key och anslutnings-ID, de måste vara identiska.

Uppdaterad version (tiden måste synkroniseras för korrekt funktion):

cat vpn10.sh

#!/bin/bash
stuns="stun.sipnet.ru stun.ekiga.net"   		# Список STUN серверов через пробел
username=" Login "		# Логин от Яндекс.диска
password=" Password "   	# Пароль от Яндекс.диска
intip="10.23.22.1"		# IP-адрес внутреннего интерфейса
WARN='33[37;1;41m'
END='33[0m'
RED='33[0;31m'
GREEN='33[0;32m'
al="ip echo readlink dirname grep awk md5sum openssl sha256sum shuf curl sleep openvpn cat stun"
ch=0
for i in $al; do which $i > /dev/null || echo -e "${WARN}Для работы необходим $i ${END}"; which $i > /dev/null || ch=1; done
if (( $ch > 0 )); then echo -e "${WARN}Ой, отсутствуют необходимые для корректной работы приложения${END}"; exit; fi
if [[ $1 == '' ]];
then
echo -e "${WARN}Введите идентификатор соединения (любое уникальное слово, должно быть одинаковое с двух сторон!) ${END} t
${GREEN}Для запуска в автоматическом режиме при включении компьютера можно прописать в /etc/rc.local строку nohup /<путь к файлу>/vpn10.sh  > /var/log/vpn10.log 2>/dev/hull & ${END}"
exit
fi
ABSOLUTE_FILENAME=`readlink -f "$0"`                                                    # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"`                                                      # каталог в котором лежит скрипт
key="$DIR/secret.key"
until [[ -n "$iftosrv" ]]
do
echo "$(date) Определяю сетевой интерфейс"; iftosrv=`ip route get 8.8.8.8 | head -n 1 | sed 's|.*dev ||' | awk '{print $1}'`
sleep 5
done
timedatectl
name=$(uname -n | md5sum | awk '{print $1}')
vpn=$(echo $1 | md5sum | awk '{print $1}')
echo "$(date) Создаю папку на Яндекс.диске"
curl -X MKCOL --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn
echo "$(date) ID на диске: $vpn"
until [ $c ];do
echo "$(date) Очищаю папку от всякого мусора"
for i in `curl --silent --user "$username:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></n/g' | grep "d:displayname" | sed 's/d:displayname//g' | sed 's/>//g' | sed 's/<//' | sed 's////g' | grep -v $(date +%Y-%m-%d-%H-%M)`
do
echo -e "$(date)${RED} Удаляю старый файл: $i${END}"
curl -X DELETE --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn/$i
done
echo "$(date) ID на диске: $vpn"
openvpn --genkey --secret "$key"
passwd=`echo "$vpn-tt" | sha256sum | awk '{print $1}'`
openssl AES-256-CBC -e -in "$key" -out "$DIR/file.enc" -k "$passwd" -base64
curl -T "$DIR/file.enc" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/key.enc
rm "$DIR"/file.enc
echo -e "$(date) ${GREEN}Фаза 1 - Получение готовности удаленного узла${END}"
go=3
localport=`shuf -i 20000-65000 -n 1`    # генерация локального порта
start=''
remote=''
timeout1=''
nextcheck=''
timestart=''
until [[ $b ]]
do
echo "$(date) Проверяю папку"
date=`date +%s`
timeout1=60
echo "$(date) Создание файла готовности $date"
echo "$date" > "/tmp/ready-$date-$name.txt"
curl -T "/tmp/ready-$date-$name.txt" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/ready-$name.txt
readyfile=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep -v $name | grep "ready" | grep "d:displayname" | sed 's/<d:displayname>//g' | sed 's/</d:displayname>//g'`
if [[ -z $readyfile ]]
then
echo -e "$(date) ${RED} Удаленный узел не готов ${END}"
echo "$(date) Жду 60 секунд"
sleep $timeout1
else
remote=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$readyfile)
echo -e "$(date) ${GREEN} Удаленный узел готов ${END}"
start=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep "start" | grep "d:displayname" | sed 's/-/ /g' | awk '{print $2}'`
if [[ -z $start ]]
then
let nextcheck=$timeout1-$date+$remote
let timestart=$date+$timeout1-$nextcheck
go=$nextcheck
echo "$timestart" > "/tmp/start-$date-$name.txt"
curl -T "/tmp/start-$date-$name.txt" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/start-$date-$name.txt
else
echo "$(date) жду $go секунд"
sleep $go
b=1
a=''
fi
fi
done
echo -e "$(date) ${GREEN}Фаза 2 - Обмен данными и установка соединения${END}"
mydata=''
filename=''
address=''
myip=''
ip=''
port=''
ex=0
until [ $a ]; do
until [[ -n "$mydata" ]]; do
k=`echo "$stuns" | wc -w`
x=1
z=`shuf -i 1-$k -n 1`
for st in $stuns; do
if [[ $x == $z ]]; then
stun=$st;
fi;
(( x++ ));
done
echo "$(date) Подключение и получение данных от STUN сервера: $stun"
sleep 5 && for pid in $(ps xa | grep "stun "$stun" 1 -p "$localport" -v" | grep -v grep | awk '{print $1}'); do kill $pid; done &
mydata=`stun "$stun" 1 -p "$localport" -v 2>&1 | grep "MappedAddress" | sort | uniq`
done
echo -e "$(date) ${GREEN}Мои данные соединения: $mydata${END}"
echo "$(date) Загрузка данных на Яндекс.диск"
echo "$mydata" > "$DIR/mydata"
echo "IntIP $intip" >> "$DIR/mydata"
curl -T "$DIR/mydata" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$name-ipport.txt
rm "$DIR/mydata"
sleep 5
echo "$(date) Получение файла данных удаленного узла"
filename=$(curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></n/g' | grep "d:displayname>" | grep "ipport" | grep -v "$name" |  sed 's|.*d:displayname>||' | sed 's/</ /g' | awk '{print $1}')
if [[ -n "$filename" ]]
then
echo "$(date) Чтение файла данных удаленного узла: $filename"
address=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$filename | grep "MappedAddress" | head -n1 | sed 's/:/ /g')
intip2=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$filename | grep "IntIP" | head -n1 | awk '{print $2}')
echo "$(date) Определение IP-адреса и порта: $address $sesid2 $tunid2"
ip=$(echo "$address" | awk '{print $3}')
port=$(echo "$address" | awk '{print $4}')
myip=`ip route get "$ip" | head -n 1 | sed 's|.*src ||' | awk '{print $1}'`
if [[ -n "$ip" && -n "$port" && -n "$myip" && -n "$localport" ]];
then
echo -e "$(date) ${GREEN} Соединение $ip $port ${END}"
echo -e  "`date` ${GREEN} $myip:$localport -> $ip:$port ${END}"
curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/key.enc > "$DIR/secret.enc"
openssl AES-256-CBC -d -in "$DIR/secret.enc" -out "$key" -k "$passwd" -base64
chmod 600 "$key"
rm "$DIR/secret.enc"
openvpn --remote $ip --rport $port --lport $localport 
--proto udp --dev tun --float --auth-nocache --verb 3 --mute 20 
--ifconfig "$intip" "$intip2" 
--secret "$key" 
--auth SHA256 --cipher AES-256-CBC 
--ncp-disable --ping 10 --ping-exit 20 
--comp-lzo yes
a=1
b=''
fi
else
if (( $ex >= 5 ))
then
echo "$(date) Сброс"
a=1
b=''
fi
(( ex++ ))
sleep 5
fi
done
done

För att skriptet ska fungera behöver du:

  1. Kopiera till urklipp och klistra in i editorn, till exempel:
    # nano vpn10.sh 
  2. ange inloggning (2:a raden) och lösenord för Yandex.disk (3:e raden).
  3. ange den interna IP-adressen för tunneln (4:e raden).
  4. gör skriptet körbart:
    # chmod +x vpn10.sh
  5. kör skriptet:
    # ./vpn10.sh nZbVGBuX5dtturD

    där nZbVGBuX5dtturD är det genererade anslutnings-ID här

Gör samma sak på fjärrnoden, ange motsvarande interna IP-adress för tunneln och anslutnings-ID.

För att köra skriptet automatiskt när det är aktiverat använder jag kommandot “nohup /<sökväg till skriptet>/vpn10.sh nZbVGBuX5dtturD > /var/log/vpn10.log 2>/dev/null &” som finns i filen /etc/ rc.local

Slutsats

Skriptet fungerar, testat på Ubuntu (18.04, 19.10, 20.04) och Debian 9. Du kan använda vilken annan tjänst som helst som sändare, men för erfarenheten använde jag Yandex.disk.
Under experimenten upptäcktes att vissa typer av NAT-leverantörer inte tillåter upprättande av en anslutning. Främst från mobiloperatörer där torrenter är blockerade.

Jag planerar att förbättra mig när det gäller:

  • Automatisk generering av secret.key varje gång du startar, kryptera och kopiera till Yandex.disk för överföring till en fjärrnod (med hänsyn till den uppdaterade versionen)
  • Automatisk tilldelning av IP-adresser för gränssnitt
  • Kryptera data innan överföring till Yandex.disk
  • Kodoptimering

Låt det finnas IPv6 i alla hem!

Uppdaterad! Senaste filerna och DEB-paketet här - yandex.disk

Källa: will.com

Lägg en kommentar