Зачем?
Обратился однажды ко мне мой старый товарищ с проблемой, что вот некие буржуйские ресурсы не пущают советского человека к заморским радостям. При этом не помогают в борьбе с супостатом не VPN не анонимайзеры не прочие руны и мантры. Как оказывается, стали нынче блокировать уже не только по IP и его расовой принадлежности, но и заглядывать гораздо глубже, вплоть до MTU! Ситуация была критической и нужно было с этим что то делать…
Задача
Стояла достаточно понятная задача, перенести десктоп пользователя де-юре в страну, в которой проживает ресурс «жадина» и прикинуться местным аборигеном. В свете используемых ухищрений со стороны супостата, решение было только одно — прозрачный тоннель с человеческим MTU и дефолтным маршрутом на десктопе. В связи с тем, что товарищ был «православным» и юзал во весь рост линь, решение стало очевидным.
Рецепт
Для реализации поставленной задачи, в искомой стране арендуется VPS сервер с минимальными требованиями ну и естественно белым и пушистым IP адресом для организации маршрутизатора. На стороне клиента тоже должен быть выделенный IP, иначе GRE не работает.
Далее на клиенте и на роутере необходимо запустить из произвольной директории соответствующие скрипты (естественно от root’a), которые приведены ниже и сконфигурировать тоннель. Для запуска скриптов, необходимо скопировать контент в файл и сделать его исполняемым. Скрипты писались и проверялись под Debian, соответственно работоспособность на иных осях не гарантирую.
1 2 3 4 5 6 7 8 | # Создаём файл. grevm$ touch grerouter.sh # Открываем на редактирование и вставляем скопированный скрипт. Сохраняем, выходим. grevm$ nano grerouter.sh # Делаем файл исполняемым. grevm$ chmod +x grerouter.sh # Выполняем скрипт. grevm$ sh grerouter.sh |
1 2 3 4 5 6 7 8 | # Создаём файл. grecl$ touch greclient.sh # Открываем на редактирование и вставляем скопированный скрипт. Сохраняем, выходим. grecl$ nano greclient.sh # Делаем файл исполняемым. grecl$ chmod +x greclient.sh # Выполняем скрипт. grecl$ sh greclient.sh |
Настройка маршрутизатора
После выполнения скрипта, на нашем маршрутизаторе появляется конфигурационный файл /etc/grerouter/grerouter.conf
, который нам необходимо заполнить.
1 2 3 4 5 6 7 | # Здесь перечисляем через пробел или запятую IP адреса всех клиентов, которые будут подключаться к нашему роутеру. REMOTE="x.x.x.x x.x.x.x" # Если ВМ имеет несколько адресов, то указываем с какого отправлять трафик. PUBLIC="" # Указываем на каких портах пускать SSH и VNC. RSSH="22" RVNC="5901" |
Теперь сохраняем файл и запускаем маршрутизатор любым из перечисленных ниже способов.
1 | grevm$ service grerouter start |
1 | grevm$ /etc/init.d/grerouter start |
После успешного старта переходим к конфигурации клиентов.
Настройка клиента
После выполнения скрипта, на нашем клиенте появляется конфигурационный файл /etc/greclient/greclient.conf
, который нам необходимо заполнить.
1 2 3 4 5 6 7 8 9 | # Здесь указываем IP адрес нашего роутера. REMOTE="x.x.x.x" # Указываем желаемый адрес для клиента. Если клиент является первым из списка перечисленных в роутере, # то его сеть 192.168.0.x, если вторым, то 192.168.1.х и так далее. LOCALIP="192.168.x.2" # Адрес маршрутизатора из той-же сети. Он всегда первый. LOCALGW="192.168.x.1" # Указание конкретного интерфейса через который ходить (не обязательно). IFNM="" |
Теперь сохраняем файл и запускаем клиент любым из перечисленных ниже способов.
1 | grecl$ service greclient start |
1 | grecl$ /etc/init.d/greclient start |
После всех манипуляций можно сделать на клиенте трассировку и убедится что всё работает корректно. Вот собственно и всё! Управление происходит стандартными командами start|stop|restart|status
1 2 3 4 | grecl$ /etc/init.d/greclient start grecl$ /etc/init.d/greclient stop grecl$ /etc/init.d/greclient restart grecl$ /etc/init.d/greclient status |
или
1 2 3 4 | grevm$ service grerouter start grevm$ service grerouter stop grevm$ service grerouter restart grevm$ service grerouter status |
Как понять что всё работает?
В этой задаче поможет команда status
1 2 3 4 5 6 7 8 9 10 | grevm$ service grerouter status ● grerouter.service - LSB: Start daemon at boot time Loaded: loaded (/etc/init.d/grerouter) Active: active (exited) since Сб 2017-10-14 17:05:23 MSK; 1min 12s ago Process: 12445 ExecStart=/etc/init.d/grerouter start (code=exited, status=0/SUCCESS) окт 14 17:05:23 grevm systemd[1]: Started LSB: Start daemon at boot time. окт 14 17:05:23 grevm grerouter[12445]: start grerouter at eth0:0 - xxx.xxx.xxx.xxx compleate окт 14 17:05:23 grevm grerouter[12445]: Now running: окт 14 17:05:23 grevm grerouter[12445]: 192.168.0.0 * 255.255.255.0 U 0 0 0 grel0 |
или
1 2 3 4 | grevm$ /etc/init.d/grerouter status status grerouter at eth0:0 - xxx.xxx.xxx.xxx Now running: 192.168.0.0 * 255.255.255.0 U 0 0 0 grel0 |
Возможные «грабли»
1) Я писал это давно, и в момент изложения этой статьи что-то забыл;
2) У вашего домашнего провайдера или у хостера зарезан GRE трафик. Такое бывает, нужно позвонить ТП и провести разъяснительную беседу;
3) У вас на одной из сторон IP не выделенный а общественный, просто это тщательно скрывает ваш провайдер. Такое тоже бывает, нужно позвонить ТП и провести разъяснительную беседу с применением специальных «скриптов», возможно даже запрещённых.
З.Ы. Оставляйте свои комментарии по этому поводу, будем общаться 😉
Клиент
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | #! /bin/bash # /etc/init.d/ ### BEGIN INIT INFO # Provides: greclient # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO GSD=${0} GSN=${0##*/} CST=true COM="compleate" if [ ! -f /bin/sh ]; then ln -sf /bin/bash /bin/sh fi if [ ! -f /etc/init.d/greclient ]; then mkdir -p /etc/greclient touch /etc/greclient/greclient.conf echo -e "REMOTE=\"x.x.x.x\"\nLOCALIP=\"192.168.0.2\"\nLOCALGW=\"192.168.0.1\"\nIFNM=\"\"" > /etc/greclient/greclient.conf mv $GSD /etc/init.d/greclient chmod +x /etc/init.d/greclient update-rc.d greclient defaults fi source /etc/greclient/greclient.conf if [ -z "$IFNM" ]; then DAR=$(ls /sys/class/net|awk '!/lo/&&!/gre/{print $0;exit}') else DAR=$IFNM fi if [ -z "$REMOTE" ]; then echo "No REMOTE set" exit 1 fi GIP=$(ifconfig $DAR | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1') echo "$1 $GSN at $DAR - $GIP" itf(){ iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT } stt(){ if [ ! -f /var/lock/$GSN ] && [ -z $(route|grep gre)]; then CST=true else CST=false fi } sta(){ stt echo "$1 $GSN at $DAR - $GIP $2" if [ "$CST" = true ]; then echo -e "\033[1;31mNow stopped\033[0m" else echo -e "\033[1mNow running:\033[0m \n\033[0;36m`route|grep gre`\033[0m" fi } srt(){ stt if [ "$CST" = true ]; then GDR=$(route -n | grep 'UG[ \t]' | awk '{print $2}') ip tunnel add grel0 mode gre remote $REMOTE local $GIP ip addr add $LOCALIP/24 dev grel0 ip link set grel0 up mtu 1500 ip route add $REMOTE via $GDR ip route change default via $LOCALGW ip route flush table 200 ip route show table main | grep -Ev ^default | while read ROUTE ; do ip route add table 200 $ROUTE ; done ip route add table 200 default via $LOCALGW ip rule add fwmark 200 table 200 ip route flush cache $(itf) iptables -t mangle -A OUTPUT -o $DAR -p tcp --dport 0:49999 -s $GIP -j MARK --set-mark 200 iptables -t mangle -A OUTPUT -o $DAR -p udp --dport 0:49999 -s $GIP -j MARK --set-mark 200 iptables -t mangle -A OUTPUT -o $DAR -p tcp --dport 50000:65535 -s $GIP -j MARK --set-mark 200 iptables -t mangle -A OUTPUT -o $DAR -p udp --dport 50000:65535 -s $GIP -j MARK --set-mark 200 iptables -A PREROUTING -t nat -i grel0 -p tcp --sport 0:49999 -j DNAT --to $GIP iptables -A PREROUTING -t nat -i grel0 -p udp --sport 0:49999 -j DNAT --to $GIP iptables -A PREROUTING -t nat -i grel0 -p tcp --sport 50000:65535 -j DNAT --to $GIP iptables -A PREROUTING -t nat -i grel0 -p udp --sport 50000:65535 -j DNAT --to $GIP iptables -t nat -A POSTROUTING -o grel0 -j SNAT --to-source $LOCALIP iptables -A INPUT -i $DAR -p tcp --dport 0:49999 -j DROP iptables -A INPUT -i $DAR -p tcp --dport 50000:65535 -j DROP iptables -A INPUT -i $DAR -p udp --dport 0:49999 -j DROP iptables -A INPUT -i $DAR -p udp --dport 50000:65535 -j DROP iptables -A INPUT -p icmp --icmp-type echo-request -j REJECT iptables -A OUTPUT -p icmp --icmp-type echo-request -j REJECT iptables -A INPUT -p icmp --icmp-type echo-reply -j REJECT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j REJECT iptables -A INPUT -p icmp --icmp-type 8 -j REJECT iptables -A OUTPUT -p icmp --icmp-type 8 -j REJECT iptables -I INPUT -p gre -s $REMOTE -j ACCEPT for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/route/flush echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all touch /var/lock/$GSN else exit 1 fi sta $1 $2 } stp(){ stt if [ "$CST" = true ]; then exit 1 else $(itf) GPR=$(route -n | grep 'UGH[ \t]' | awk '{print $2}') ip route change default via $GPR ip route delete $REMOTE via $GPR ip route flush table 200 ip route flush cache ip link set grel0 down ip tunnel delete grel0 echo 0 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all rm /var/lock/$GSN fi sta $1 $2 } rst(){ echo -e "\033[1mRestarting $GSN...\033[0m" stt if [ "$CST" = true ]; then echo -e "\033[1mAlready stopped. Now starting...\033[0m" srt "Starting" $2 else echo -e "\033[1mStopping $GSN...\033[0m" while [ "$CST" = false ]; do stp "Stopping" $2 echo -e "\033[1mWait a moment..\033[0m" sleep 1 stt if [ "$CST" = true ]; then echo -e "\033[1mStopped successful. Now starting...\033[0m" srt "Starting" $2 exit 0 fi done fi } case "$1" in start) srt $1 $COM ;; stop) stp $1 $COM ;; restart) rst $1 $COM ;; status) sta $1 ;; *) echo "Usage: /etc/init.d/$GSN {start|stop|restart|status}" exit 1 ;; esac exit 0 |
Маршрутизатор
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | #! /bin/bash # /etc/init.d/ ### BEGIN INIT INFO # Provides: grerouter # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO GSD=${0} GSN=${0##*/} CST=true COM="compleate" if [ ! -f /bin/sh ]; then ln -sf /bin/bash /bin/sh fi if [ ! -f /etc/init.d/grerouter ]; then mkdir -p /etc/grerouter touch /etc/grerouter/grerouter.conf echo -e "REMOTE=\"x.x.x.x x.x.x.x\"\nPUBLIC=\"\"\nSUBNET=\"172.20\"\nRSSH=\"22\"\nRVNC=\"5901\"" > /etc/grerouter/grerouter.conf mv $GSD /etc/init.d/grerouter chmod +x /etc/init.d/grerouter update-rc.d grerouter defaults fi source /etc/grerouter/grerouter.conf IFS=',|| ' read -ra arr <<< "$REMOTE" if [ -z "$PUBLIC" ]; then DAR=$(ls /sys/class/net|awk '!/lo/&&!/gre/&&!/erspan/{print $0;exit}') GIP=$(ifconfig $DAR|grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*'|grep -Eo '([0-9]*\.){3}[0-9]*'|grep -v '127.0.0.1') else GIP=$PUBLIC DAR=$(netstat -ie|grep -B1 "$GIP"|head -n1|awk '{print $1}'|sed 's/:$//') fi if [ -z "$REMOTE" ]; then echo "No REMOTE set" exit 1 fi if [ -z "$SUBNET" ]; then SUBNET="172.20" fi itf(){ iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT } stt(){ if [ ! -f /var/lock/$GSN ] && [ -z $(route|grep gre)]; then CST=true else CST=false fi } sta(){ stt echo "$1 $GSN at $DAR - $GIP $2" if [ "$CST" = true ]; then echo -e "\033[1;31mNow stopped\033[0m" else echo -e "\033[1mNow running:\033[0m \n\033[0;36m`route|grep gre`\033[0m" fi } srt(){ stt if [ "$CST" = true ]; then $(itf) iptables -t nat -A POSTROUTING -o ${DAR} -j SNAT --to-source $GIP echo 1 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all for i in $(seq ${#arr[@]}); do p=$((i-1)) if [ "$p" -lt "9" ]; then g="0$p" if [ "$p" -lt "99" ]; then g="0$g" fi fi iptables -I INPUT -p gre -s ${arr[$p]} -j ACCEPT iptables -t nat -A PREROUTING -p tcp --dport 5"$g"0 -j DNAT --to $SUBNET.$p.2:$RSSH iptables -t nat -A PREROUTING -p tcp --dport 5"$g"1 -j DNAT --to $SUBNET.$p.2:$RVNC ip tunnel add grel$p mode gre remote ${arr[$p]} local $GIP ip addr add $SUBNET.$p.1/24 dev grel$p ip link set grel$p up mtu 1500 ip route add 172.16.0.0/24 via $SUBNET.$p.2 metric $p ip route add 172.19.0.0/24 via $SUBNET.$p.2 metric $p ip route add 192.168.0.0/24 via $SUBNET.$p.2 metric $p done touch /var/lock/$GSN else exit 1 fi sta $1 $2 } stp(){ stt if [ "$CST" = true ]; then exit 1 else $(itf) echo 0 > /proc/sys/net/ipv4/ip_forward echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all for i in $(seq ${#arr[@]}); do p=$((i-1)) ip link set grel$p down ip tunnel delete grel$p done rm /var/lock/$GSN fi sta $1 $2 } rst(){ echo -e "\033[1mRestarting $GSN...\033[0m" stt if [ "$CST" = true ]; then echo -e "\033[1mAlready stopped. Now starting...\033[0m" srt "Starting" $2 else echo -e "\033[1mStopping $GSN...\033[0m" while [ "$CST" = false ]; do stp "Stopping" $2 echo -e "\033[1mWait a moment..\033[0m" sleep 1 stt if [ "$CST" = true ]; then echo -e "\033[1mStopped successful. Now starting...\033[0m" srt "Starting" $2 exit 0 fi done fi } case "$1" in start) srt $1 $COM ;; stop) stp $1 $COM ;; restart) rst $1 $COM ;; status) sta $1 ;; *) echo "Usage: /etc/init.d/$GSN {start|stop|restart|status}" exit 1 ;; esac exit 0 |