Pull to refresh

Настраиваем интернет шлюз с прозрачным обходом блокировок (а рекламу таки будем блокировать)

Reading time 9 min
Views 103K


У вас есть старенький (или не очень) компьютер с двумя сетевыми картами? Вам надоела реклама и лишние телодвижения для обхода блокировок? Вы не хотите с этим мириться? Тогда добро пожаловать под кат.

Цель


Настроить интернет шлюз таким образом, чтобы клиенты внутри локальной сети без дополнительных настроек работали с интернетом без ограничений. К заблокированным сайтам доступ будет осуществляться через тор, к остальным через обычное интернет соединение. К .onion ресурсам доступ из любого браузера как к обычным сайтам. В качестве бонуса, настроим блокировку рекламных доменов и доступ к условно заблокированным сайтам через тор (имеются в виду сайты, которые ограничивают функциональность для пользователей из РФ). Мой интернет провайдер чтоб тебе икнулось осуществляет перехват DNS запросов и подмену адресов (т.е. при резольвинге запрещенных сайтов возвращает адрес своей заглушки), поэтому все DNS запросы я отправляю в тор.

Предупреждение
Все что описано ниже помогает обойти блокировки, но НЕ ОБЕСПЕЧИВАЕТ анонимности. От слова совсем.

Идеи и способы реализации взял отсюда и отсюда. Авторам этих статей большое спасибо.

Итак поехали


Предполагается, что на начальном этапе у вас уже есть установленная ОС (в моем случае Ubuntu server 16.04) на компьютере с двумя сетевыми интерфейсами. Один из которых (у меня это ppp0) смотрит в сторону провайдера, а второй (у меня это enp7s0) в локалку. Внутренний IP шлюза 192.168.1.2. Локальная сеть 192.168.1.0/24.

Как подойти к этому этапу в данной статье не рассматривается, так как информации в сети более чем достаточно. Скажу только, что pppoe подключение к провайдеру удобно настраивать утилитой pppoeconf.

Подготовительный этап


Если вы, как и я, используете н{е|оу}тбук, то возможно вам захочется, чтобы он не засыпал при закрытии крышки.

sudo nano /etc/systemd/logind.conf

HandleLidSwitch=ignore

Разрешаем форвардинг в ядре. Я за одно отключил IPv6.

sudo nano /etc/sysctl.conf

net.ipv4.ip_forward=1
# IPv6 disabled
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Применим изменения без перезагрузки.

sudo sysctl -p

Настройка DHCP


Мы хотим, чтобы клиенты настраивались автоматически, поэтому без DHCP сервера не обойтись.


$ sudo apt install isc-dhcp-server
$ sudo nano /etc/dhcp/dhcpd.conf

Приводим файл примерно к такому виду.
default-lease-time 600;
max-lease-time 7200;

subnet 192.168.1.0 netmask 255.255.255.0 {
        range 192.168.1.100 192.168.1.200;
        option routers 192.168.1.2;
        option domain-name-servers 192.168.1.2, 8.8.8.8;
        option broadcast-address 192.168.1.255;
}

Пояснение
subnet 192.168.1.0 netmask 255.255.255.0 — определяет сеть и маску,
range 192.168.1.100 192.168.1.200; — диапазон адресов, который будет выдаваться сервером,
option routers 192.168.1.2; — адрес шлюза
option domain-name-servers 192.168.1.2, 8.8.8.8; — адреса DN серверов
option broadcast-address 192.168.1.255; — широковещательный адрес.

Перезапустим сервер

sudo /etc/init.d/isc-dhcp-server restart 

Настройка TOR


Устанавливаем и открываем настройки.


$ sudo apt install tor
$ sudo nano /etc/tor/torrc

Добавляем строки
#Определяем подсеть в которую тор будет разрешать имена onion
#такой диапазон достаточно жирный. Можно смело сокращать.
VirtualAddrNetworkIPv4 10.0.0.0/8
#Включаем DNS от луковицы
AutomapHostsOnResolve 1
#Определяем порты прозрачного прокси и DNS
TransPort 0.0.0.0:9040
DNSPort 0.0.0.0:5353
#Не пользуемся выходными узлами из этих стран
ExcludeExitNodes {RU}, {UA}, {BY}

Настройка DNS


Если вам не нужна блокировка рекламы, то данный пункт можно не выполнять. Если вы хотите просто пользоваться DNS от тора, добавьте в файл /etc/tor/torrc строку DNSPort 0.0.0.0:53 и всё.

Но я буду резать рекламу, а значит устанавливаем и открываем настройки

$ sudo apt install bind9
$ sudo nano /etc/bind/named.conf.options

Приводим файл к следующему виду
options {
	directory "/var/cache/bind";
	forwarders {
		127.0.0.1 port 5353;
	};
	listen-on {
		192.168.1.2;
		127.0.0.1;
	};
	dnssec-validation auto;

	auth-nxdomain no;   
	listen-on-v6 { none; };
};

Если ваш провайдер не химичит с DNS запросами, можете направить трафик на другие днс серверы. Например на сервера гугла:
forwarders {
		8.8.8.8; 
                8.8.4.4;
	};

Теоретически должно работать по шустрее, чем через тор.
К дальнейшей настройке DNS вернемся чуть позже. Пока этого достаточно. А сейчас перезапустим службу.

sudo /etc/init.d/bind9 restart

Настройка iptables


Вся магия будет твориться именно здесь.

Суть идеи
  1. Формируем список IP адресов на которые мы хотим ходить через тор.
  2. Заворачиваем запросы к этим адресам на прозрачный прокси тора.
  3. Заворачиваем DNS запросы к ресурсам .onion на DNS тора
  4. Тор при резольвинге имен из зоны .onion возвращает IP адрес из подсети 10.0.0.0/8 (которую мы указали при настройке ТОР). Разумеется, эта зона не маршрутизируется в интернете и нам нужно завернуть обращения на эту подсеть на прозрачный прокси тора.


Лирическое отступление
Изначально я полагал, что можно обойтись без перенаправления DNS запросов к .onion в iptables. Что можно настроить bind таким образом, чтобы он перенаправлял запросы на тор DNS и возвращал адреса из 10-й зоны. У меня не получилось так настроить.

forwarders {
		127.0.0.1 port 5353;
	};

Не приводит к желаемому результату, так же как выделение отдельной зоны ".onion" с forwarders на 127.0.0.1 port 5353.
Если кто-нибудь знает почему так происходит и как это исправить, напишите в комментариях.

Полагаю, что iptables уже установлен. Устанавливаем ipset. С помощью этой утилиты мы сможем управлять списком заблокированных адресов и заворачивать пакеты в прозрачный прокси тора.

sudo apt install ipset

Далее последовательно из под рута выполняем команды по настройке iptables. Разумеется вам нужно заменить имена интерфейсов и адреса на свои. Я поместил эти команды в /etc/rc.local перед exit 0 и они выполняются каждый раз после загрузки.

Предлагаю и вам поступить аналогично.

#Создаем ipset для списка блокировок
ipset -exist create blacklist hash:ip

#Редирект запросов  DNS на TOR для доменов onion. Средствами bind9 такой редирект настроить не удалось
iptables -t nat -A PREROUTING -p udp --dport 53 -m string --hex-string "|056f6e696f6e00|" --algo bm -j REDIRECT --to-port 5353
iptables -t nat -A OUTPUT     -p udp --dport 53 -m string --hex-string "|056f6e696f6e00|" --algo bm -j REDIRECT --to-port 5353

#Редирект на ТОР IP адресов из списка блокировок
iptables -t nat -A PREROUTING -p tcp -m set --match-set blacklist dst -j REDIRECT --to-port 9040
iptables -t nat -A OUTPUT     -p tcp -m set --match-set blacklist dst -j REDIRECT --to-port 9040

#Редирект на тор для ресурсов разрезольвенных тором в локалку 10.0.0.0/8
#обычно это .onion
iptables -t nat -A PREROUTING -p tcp -d 10.0.0.0/8 -j REDIRECT --to-port 9040
iptables -t nat -A OUTPUT     -p tcp -d 10.0.0.0/8 -j REDIRECT --to-port 9040

###########################################
#Все что ниже относится к настройке самого шлюза, а не к обходу
#блокировок
###########################################
#Включаем NAT
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

# Рзрешаем пинги
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Отбрасываем неопознанные пакеты
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP

# Отбрасываем нулевые пакеты
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP

# Закрываемся от syn-flood атак
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
iptables -A OUTPUT -p tcp ! --syn -m state --state NEW -j DROP

#Разрешаем входящие из локалки и  локальной петли, и все уже установленные соединения
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i enp7s0 -j ACCEPT
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#Остальные входящие запрещаем
iptables -P INPUT DROP

#Разрешаем форвардинг изнутри локалки.
iptables -A FORWARD -i enp7s0 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#Остальной форвардинг запрещаем
iptables -P FORWARD DROP


После перезагрузки мы должны получить шлюз, который:

  • Выдает IP адреса и настройки сети клиентам.
  • Раздает интернет.
  • Резольвит имена через тор DNS.
  • Резольвит имена .onion и позволяет посещать эти ресурсы через обычный браузер.
  • Закрывает нас от входящих подключений.

Обхода блокировок пока нет, так как несмотря на то, что мы создали blacklist и настроили маршрутизацию, сам blacklist пока пустой. Настало время это исправить.

Заполняем blacklist


Создаем каталог в котором будет лежать скрипт.

# mkdir -p /var/local/blacklist

Создаем скрипт

# nano /var/local/blacklist/blacklist-update.sh

со следующим содержимым
#! /bin/bash
#Переходим в каталог скрипта
cd $(dirname $0)
#Скачиваем с github репозиторий со списком заблокированных ресурсов
git pull -q || git clone https://github.com/zapret-info/z-i.git .
#Обрабатываем dump.csv так чтобы получился файл blacklist.txt с IP адресами заблокированных ресурсов
cat dump.csv | cut -f1 -d\; |  grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort | uniq  > blacklist.txt
#Обрабатываем файл my-blacklist c именами доменов, которые не под блокировкой
#но на которые мы хотим ходить через тор. Дополняем blacklist.txt
dig +short -f my-blacklist >> blacklist.txt
#Очищаем ipset
ipset flush blacklist
#Запиcываем новые данные
cat  blacklist.txt | xargs -n1 ipset add blacklist


Делаем скрипт исполняемым

# chmod +x /var/local/blacklist/blacklist-update.sh

создаем файл my-blacklist, который в дальнейшем будем наполнять вручную теми ресурсами, на которые хотим ходить через тор.
# echo lostfilm.tv > /var/local/blacklist/my-blacklist

Выполняем скрипт
# /var/local/blacklist/blacklist-update.sh

Скрипт работает долго, будь пациентом be patient. Теперь должна открываться флибуста должны работать заблокированные сайты. Добавляем в конец файла /etc/rc.local, но перед exit 0
#Ждем минуту чтобы тор полностью загрузился, подключился,
#заработал тор DNS
sleep 60
#Заполняем список запрещенных сайтов. Длительная операция.
/var/local/blacklist/blacklist-update.sh

Настраиваем фильтр рекламы


Суть идеи
  1. Устанавливаем и запускаем микро HTTP сервер, который слушает 80 порт и на любой запрос возвращает картинку png с одним прозрачным пикселем.
  2. Получаем список рекламных доменов.
  3. Настраиваем bind как авторитативный сервер для них.
  4. Заворачиваем все запросы на рекламные домены на наш HTTP сервер с чудесной картинкой.


Приступим. Займемся севером. Создаем файл

# nano /usr/local/bin/pixelserv

с содержимым
#! /usr/bin/perl -Tw

use IO::Socket::INET;

$crlf="\015\012";
$pixel=pack("C*",qw(71 73 70 56 57 97 1 0 1 0 128 0 0 255 255 255 0 0 0 33 249 4 1 0 0 0 0 44 0 0 0 0 1 0 1 0 0 2 2 68 1 0 59));

$sock = new IO::Socket::INET (  LocalHost => '0.0.0.0',
                                LocalPort => '80',
                                Proto => 'tcp',
                                Listen => 30,
                                Reuse => 1);

if (!defined($sock)) {
        print "error : cannot bind : $! exit\n";
        exit(1);
}

while ($new_sock = $sock->accept()) {
	while (<$new_sock>) {
		chop;chop;
#		print "$_\n";
		if ($_ eq '') { last; }
	}
        print $new_sock "HTTP/1.1 200 OK$crlf";
        print $new_sock "Content-type: image/gif$crlf";
        print $new_sock "Accept-ranges: bytes$crlf";
        print $new_sock "Content-length: 43$crlf$crlf";
	print $new_sock $pixel;
        shutdown($new_sock,2);
	undef($new_sock);
}

close($sock);
exit(0);


делаем его исполняемым

# chmod +x /usr/local/bin/pixelserv

Создаем файл инициализации сервера

# nano /etc/init.d/pixelserv

с содержимым
#! /bin/sh
# /etc/init.d/pixelserv
#
# Carry out specific functions when asked to by the system
case "$1" in
start)
echo "Starting pixelserv "
/usr/local/bin/pixelserv &
;;
stop)
echo "Stopping script pixelserv"
killall pixelserv
;;
*)
echo "Usage: /etc/init.d/pixelserv {start|stop}"
exit 1
;;
esac

exit 0


Делаем его исполняемым, регистрируем сервис, запускаем http сервер

# chmod +x /etc/init.d/pixelserv
# update-rc.d pixelserv defaults
# /etc/init.d/pixelserv start 

Теперь создаем скрипт обновления рекламных доменов

# nano var/local/blacklist/ad-update.sh

с содержимым

#! /bin/bash
cd /etc/bind/
curl "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=bindconfig&showintro=0&mimetype=plaintext" | sed 's/null.zone.file/\/etc\/bind\/db.adzone/g' > named.ad.conf
rndc reload

Делаем его исполняемым

# chmod +x /var/local/blacklist/ad-update.sh

и выполняем

# /var/local/blacklist/ad-update.sh

Создаем файл зоны

# nano /etc/bind/db.adzone

со следующим содержимымсервис

$TTL    86400   ; one day  
@       IN      SOA     ads.example.com. hostmaster.example.com. (
               2014090102
                    28800
                     7200
                   864000
                    86400 )          
                NS      my.dns.server.org          
                A       192.168.1.2
@       IN      A       192.168.1.2
*       IN      A       192.168.1.2

Добавляем в файл

# nano /etc/bind/named.conf

строку

include "/etc/bind/named.ad.conf";

Применяем изменения

rndc reload

Настраиваем обновление списка доменов при загрузке. Для этого открываем файл /etc/rc.local и добавляем после sleep 60

/var/local/blacklist/ad-update.sh

Последние штрихи


Для периодического обновления списков, создадим файл

# nano /etc/cron.daily/blacklist-update

Со следующим содержимым

#!/bin/bash
#Загружаем свежий список рекламных доменов для фильтрации
/var/local/blacklist/ad-update.sh
#Заполняем список запрещенных сайтов. Длительная операция.
/var/local/blacklist/blacklist-update.sh

Делаем его исполняемым

# chmod +x  /etc/cron.daily/blacklist-update
.

Замечание для пользователей десктопных версий Ubuntu


Несмотря на то, что целью было создать шлюз, который не требует настроек клиентов, в моем случае получилось не совсем так. В качестве рабочей операционной системы я использую десктопную Ubuntu 16.04. Для настройки сети в ней используется утилита NetworkManager, которая по умолчанию настроена таким образом, что адрес DN сервера берется не с DHCP сервера, а устанавливается как 127.0.1.1:53. На этом порту висит dnsmasq и только по ему известным правилам резольвит имена. В обычной жизни это никак не мешает, а в нашем случае делает совершенно неработоспособной зону .onion

Чтобы это исправить нужно в файле /etc/NetworkManager/NetworkManager.conf закоментировать строку

dns=dnsmasq

вот так

#dns=dnsmasq

После перезагрузки все работает.

Заключение лишь бы не под стражу


Клиенты на андроид работают нормально без дополнительных настроек.
Windows не проверял, так как не использую, но думаю, проблем возникнуть не должно.
Ограничения для firefox и iOs описаны здесь

Прошу прощения за сумбурное изложение. Дополнения, исправления, замечания приветствуются.
Спасибо за внимание.

Дополнение от 03.09.2017
По просьбам трудящихся выложил свои настройки на github.
Настройки даны как справочная информация. Из коробки они вам не подойдут с вероятностью близкой к 100%. Требуется подгонка под себя.
Tags:
Hubs:
+65
Comments 97
Comments Comments 97

Articles