- Simple way to create a tunnel from one local port to another?
- 8 Answers 8
- Проброс и перенаправление портов в iptables
- Проброс портов
- Рассмотрим пример
- Рассмотрим пример
- Рассмотрим пример
- Рассмотрим пример
- Перенаправление портов
- Iptables: немного о действии REDIRECT, его ограничениях и области применения
- Iptables и REDIRECT
- Кейс
- REDIRECT и удаленный клиент
- REDIRECT и локальный клиент
- REDIRECT и закрытый порт
- Полный набор правил
Simple way to create a tunnel from one local port to another?
I have a development server, which is only accessible from 127.0.0.1:8000, not 192.168.1.x:8000. As a quick hack, is there a way to set up something to listen on another port (say, 8001) so that from the local network I could connect 192.168.1.x:8001 and it would tunnel the traffic between the client and 127.0.0.1:8000?
Is there anything that can be run on an Android device? Or a limitation of Android that prevents such a solution?
8 Answers 8
socat tcp-listen:8001,reuseaddr,fork tcp:localhost:8000
By default, socat will listen on TCP port 8001 on any IPv4 or IPv6 address (if supported) on the machine. You can restrict it to IPv4/6 by replacing tcp-listen with tcp4-listen or tcp6-listen , or to a specific local address by adding a ,bind=that-address .
Same for the connecting socket you’re proxying to, you can use any address in place of localhost , and replace tcp with tcp4 or tcp6 if you want to restrict the address resolution to IPv4 or IPv6 addresses.
Note that for the server listening on port 8000, the connection will appear as coming from the proxy (in the case of localhost , that will be localhost ), not the original client. You’d need to use DNAT approaches (but which requires superuser privileges) for the server to be able to tell who’s the client.
@Phate, see Tell socat to listen to connections from a single IP address (and the range and tcpwrap options in the socat man page).
this solution better than nc.traditional solution below, this one didn’t disconnect after a few connections
Using ssh is the easiest solution.
ssh -g -L 8001:localhost:8000 -f -N user@remote-server.com
This forwards the local port 8001 on your workstation to the localhost address on remote-server.com port 8000.
-g means allow other clients on my network to connect to port 8001 on my workstation. Otherwise only local clients on your workstation can connect to the forwarded port.
-N means all I am doing is forwarding ports, don’t start a shell.
-f means fork into background after a successful SSH connection and log-in.
Port 8001 will stay open for many connections, until ssh dies or is killed. If you happen to be on Windows, the excellent SSH client PuTTY can do this as well. Use 8001 as the local port and localhost:8000 and the destination and add a local port forwarding in settings. You can add it after a successful connect with PuTTY.
Проброс и перенаправление портов в iptables
Чаще всего проброс трафика используется, если мы находимся в локальной сети и от внешнего мира отделены шлюзом. Для того, чтобы открыть доступ для локальных служб (ssh, web, ftp), нам необходимо пробросить порты. Поскольку в качестве шлюза мы будем использовать сервер на Linux, то осуществлять данные действия будем с помощью iptables.
Определимся с переменными, которые будут использоваться в статье:
$EXT_IP — внешний, реальный IP-адрес шлюза;
$INT_IP — внутренний IP-адрес шлюза, в локальной сети;
$LAN_IP — внутренний IP-адрес сервера, предоставляющего службы внешнему миру;
$SRV_PORT — порт службы. Для веб-сервера равен 80, для SMTP — 25 и т.д.;
eth0 — внешний интерфейс шлюза. Именно ему присвоен сетевой адрес $EXT_IP;
eth1 — внутренний интерфейс шлюза, с адресом $INT_IP;
Проброс портов
На шлюз приходит пакет, который мы должны перенаправить на нужный сервер в локальной сети перед принятием решения о маршрутизации, то есть — в цепочке PREROUTING таблицы nat.
iptables -t nat -A PREROUTING —dst $EXT_IP -p tcp —dport $SRV_PORT -j DNAT —to-destination $LAN_IP
Рассмотрим пример
iptables -t nat -A PREROUTING —dst 1.2.3.4 -p tcp —dport 80 -j DNAT —to-destination 192.168.1.50
Если входящий пакет пришёл извне на шлюз (1.2.3.4), но предназначен веб-серверу (порт 80), то адрес назначения подменяется на локальный адрес 192.168.1.50. И впоследствии маршрутизатор передаст пакет в локальную сеть.
Дальше принимается решение о маршрутизации. В результате пакет пойдёт по цепочке FORWARD таблицы filter, поэтому в неё надо добавить разрешающее правило. Оно может выглядеть, например, так:
iptables -I FORWARD 1 -i eth0 -o eth1 -d $LAN_IP -p tcp -m tcp —dport $SRV_PORT -j ACCEPT
Рассмотрим пример
iptables -I FORWARD 1 -i eth0 -o eth1 -d 192.168.0.22 -p tcp -m tcp —dport 80 -j ACCEPT
Пропустить пакет, который пришёл на внешний интерфейс, уходит с внутреннего интерфейса и предназначен веб-серверу (192.168.1.50:80) локальной сети.
С одной стороны, этих двух правил уже достаточно для того, чтобы любые клиенты за пределами локальной сети успешно подключались к внутреннему серверу. С другой — а что будет, если попытается подключиться клиент из локальной сети? Подключение просто не состоится: стороны не поймут друг друга.
Допустим, 192.168.1.31 — ip-адрес клиента внутри локальной сети.
- Пользователь вводит в адресную строку браузера адрес example.com;
- Сервер обращается к DNS и разрешает имя example.com в адрес 1.2.3.4;
- Маршрутизатор понимает, что это внешний адрес и отправляет пакет на шлюз;
- Шлюз, в соответствии с нашим правилом, подменяет в пакете адрес 1.2.3.4 на 192.168.1.50, после чего отправляет пакет серверу;
- Веб-сервер видит, что клиент находится в этой же локальной сети (обратный адрес пакета — 192.168.1.31) и пытается передать данные напрямую клиенту, в обход шлюза;
- Клиент игнорирует ответ, потому что он приходит не с 1.2.3.4, а с 192.168.1.50;
- Клиент и сервер ждут, но связи и обмена данными нет.
Есть два способа избежать данной ситуации.
Первый — разграничивать обращения к серверу изнутри и извне, для этого создать на локальном DNS-сервере А-запись для example.com указывающую на 192.168.1.50
Второй — с помощью того же iptables заменить обратный адрес пакета.
Правило должно быть добавлено после принятия решения о маршрутизации и перед непосредственной отсылкой пакета. То есть — в цепочке POSTROUTING таблицы nat.
iptables -t nat -A POSTROUTING —dst $LAN_IP -p tcp —dport $SRV_PORT -j SNAT —to-source $INT_IP
Рассмотрим пример
iptables -t nat -A POSTROUTING —dst 192.168.1.50 -p tcp —dport 80 -j SNAT —to-source 192.168.1.1
Если пакет предназначен веб-серверу, то обратный адрес клиента заменяется на внутренний адрес шлюза.
Этим мы гарантируем, что ответный пакет пойдёт через шлюз.
Надо дополнительно отметить, что это правило важно только для внутренних клиентов. Ответ внешним клиентам пойдёт через шлюз в любом случае.
Но, пока что, для нормальной работы этого недостаточно. Предположим, что в качестве клиента выступает сам шлюз.
В соответствии с нашими предыдущими правилами он будет гонять трафик от себя к себе и представлять исходящие пакеты транзитными.
iptables -t nat -A OUTPUT —dst $EXT_IP -p tcp —dport $SRV_PORT -j DNAT —to-destination $LAN_IP
Рассмотрим пример
iptables -t nat -A OUTPUT —dst 1.2.3.4 -p tcp —dport 80 -j DNAT —to-destination 192.168.1.50
Теперь для удобства запилим скрипт, чтобы не прописывать правила каждый раз вручную.
#!/bin/bash
EXT_IP=«xxx.xxx.xxx.xxx» # внешний, реальный IP-адрес шлюза;
INT_IP=«xxx.xxx.xxx.xxx» # См. выше.
EXT_IF=eth0 # Внешний и внутренний интерфейсы.
INT_IF=eth1 # Для шлюза они вряд ли изменятся, поэтому можно прописать вручную.
LAN_IP=$1 # Локальный адрес сервера передаём скрипту первым параметром,
SRV_PORT=$2 # а тип сервера, в смысле какой порт (или набор портов) открывать — вторым
# Здесь желательно сделать проверку ввода данных, потому что операции достаточно серьёзные.
iptables -t nat -A PREROUTING —dst $EXT_IP -p tcp —dport $SRV_PORT -j DNAT —to-destination $LAN_IP
iptables -t nat -A POSTROUTING —dst $LAN_IP -p tcp —dport $SRV_PORT -j SNAT —to-source $INT_IP
iptables -t nat -A OUTPUT —dst $EXT_IP -p tcp —dport $SRV_PORT -j DNAT —to-destination $LAN_IP
iptables -I FORWARD 1 -i $EXT_IF -o $INT_IF -d $LAN_IP -p tcp -m tcp —dport $SRV_PORT -j ACCEPT
Теперь, чтобы обеспечить доступ извне к локальному FTP по адресу 192.168.1.52, достаточно набрать в консоли от имени супер-пользователя:
Перенаправление портов
Перенаправление портов нужно в том случае, если мы хотим «замаскировать» внутреннюю службу, обеспечив к ней доступ извне не по стандартному, а совсем по другому порту.
Пусть $FAKE_PORT — обманный порт на внешнем интерфейсе шлюза, подключившись к которому мы должны попасть на адрес $LAN_IP и порт $SRV_PORT .
Набор правил для iptables будет отличаться несущественно, поэтому приведу сразу пример итогового скрипта для ленивых.
#!/bin/bash
EXT_IP=«xxx.xxx.xxx.xxx» # внешний, реальный IP-адрес шлюза;
INT_IP=«xxx.xxx.xxx.xxx» # См. выше.
EXT_IF=eth0 # Внешний и внутренний интерфейсы.
INT_IF=eth1 # Для шлюза они вряд ли изменятся, поэтому можно прописать вручную.
FAKE_PORT=$1 # Вначале передаём скрипту «неправильный» порт на внешнем интерфейсе,
LAN_IP=$2 # затем — локальный адрес сервера
SRV_PORT=$3 # и в конце — реальный порт для подключения к серверу
# Здесь опять надо сделать проверку ввода данных, потому что операции всё ещё серьёзные.
iptables -t nat -A PREROUTING -d $EXT_IP -p tcp -m tcp —dport $FAKE_PORT -j DNAT —to-destination $LAN_IP:$SRV_PORT
iptables -t nat -A POSTROUTING -d $LAN_IP -p tcp -m tcp —dport $SRV_PORT -j SNAT —to-source $INT_IP
iptables -t nat -A OUTPUT -d $EXT_IP -p tcp -m tcp —dport $SRV_PORT -j DNAT —to-destination $LAN_IP
iptables -I FORWARD 1 -i $EXT_IF -o $INT_IF -d $LAN_IP -p tcp -m tcp —dport $SRV_PORT -j ACCEPT
Iptables: немного о действии REDIRECT, его ограничениях и области применения
Данная заметка повествует о действии REDIRECT в iptables, его ограничениях и области применения.
Iptables и REDIRECT
Действие REDIRECT предназначено для перенаправления пакетов с одного набора портов на другой внутри одной системы, не выходя за пределы хоста.
Работает REDIRECT только в цепочках PREROUTING и OUTPUT таблицы nat. Таким образом, область применения сводится только к перенаправлению с одного порта на другой. Чаще всего это используется для прозрачного прокси, когда клиент из локальной сети коннектится на 80 порт, а шлюз редиректит пакеты на локальный порт прокси:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3128
Кейс
Допустим, надо сменить порт приложения только перенаправлением при помощи iptables, не трогая настроек демона. Пусть новый порт будет 5555, а порт приложения 22. Таким образом, надо сделать редирект с порта 5555 на 22.
REDIRECT и удаленный клиент
Первый шаг очевиден и будет таким же, что и в примере выше:
iptables -t nat -A PREROUTING -p tcp --dport 5555 -j REDIRECT --to-port 22
Однако, правило будет работать только для внешних клиентов и только при открытом порте приложения.
REDIRECT и локальный клиент
Предыдущее правило для самого хоста с iptables не сработает, т.к. пакеты с localhost не попадают в таблицу nat. Чтобы кейс сработал на локальной машине — надо добавить редирект в цепочку OUTPUT таблицы nat:
iptables -t nat -A OUTPUT -p tcp -s 127.0.0.1 --dport 5555 -j REDIRECT --to-ports 22
Теперь локальный клиент тоже может подключиться по 5555 порту.
REDIRECT и закрытый порт
Смысл кейса в том, чтобы использовать левый порт, а порт приложения держать закрытым, но если выполнить DROP правило в INPUT цепочке по 22 порту, то 5555 тоже перестанет отвечать. Собственно, хитрость в том, чтобы открыть порт приложения в INPUT цепочке, а дропать его в mangle:
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j DROP
Полный набор правил
Редирект с сетевым и локальным доступом при закрытом порте приложения:
iptables -t nat -A PREROUTING -p tcp --dport 5555 -j REDIRECT --to-port 22 iptables -t nat -A OUTPUT -p tcp -s 127.0.0.1 --dport 5555 -j REDIRECT --to-ports 22 iptables -A INPUT -p tcp --dport 5555 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -i lo -j ACCEPT iptables -t mangle -A PREROUTING -p tcp --dport 22 -j DROP iptables -P INPUT DROP