FastNetMon

Monday, 18 October 2010

Редирект с localhost:3306 на удаленный сервер MySQL средствами iptables

Задача: требуется все коннекты на localhost (127.0.0.1:3306) отправлять на удаленный сервер и корректно возвращать его ответ запросившему клиенту.

Переброс MySQL с одного порта на другой, в пределах одной машины

Итак, для начала попробуем сделать локальный проброс, то есть, чтобы при подключении к порту 33060 нам в реальности откликался 3306 порт, по которому работает MySQL.

Для тестов нам понадобится telnet:
apt-get install -y telnet

Итак, убедимся, что MySQL работает на 3306 порту:
netstat -lnpt | grep 3306
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 4667/mysqld

Попробуем подключиться к MySQL посредством telnet:
telnet 127.0.0.1 3306
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
?
5.0.51a-24+lenny4,X!6,zD$',5se"tHHp|?bSC

Теперь подключим к фаерволлу вот такое правило, которое перебросит все запросы с 33060 порта на 3306 посредством цели REDIRECT (которая делает примерно следующее - "It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface"):
iptables -t nat -I OUTPUT --src 0/0 --dst 127.0.0.1 -p tcp --dport 33060 -j REDIRECT --to-ports 3306

Теперь проверим телнетом:
telnet 127.0.0.1 33060Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
?
5.0.51a-24+lenny4-KDSV4@(C,WoGTPv"@\/sv

Визуально, все работает, но будет ли работать mysql клиент?

Еще как будет, смотрим:
mysql --host=127.0.0.1 -uroot -pyour_password --port 33060 -e 'show databases;;'
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
+--------------------+

Переброс запросов к локалхосту на 3306 порт на удаленный сервер

Итак, теперь нам для тестов нужна еще одна машина с mysql клиентов и telnet:
apt-get install -y telnet

На первой же машине (с MySQL) нужно открыть MySQL наружу, чтобы он слушал внешний интерфейс:
vi /etc/mysql/my.cnf

И в блоке mysqld сделать следующую правку:
bind-address = 0.0.0.0

И перезаупстить сервер:
/etc/init.d/mysql restart

Теперь на второй машине-клиенте забрасываем весь трафик выходящий с интерфейса localhost на внешний сервер:

iptables -t nat -A OUTPUT -p tcp --dport 3306 -j DNAT --to ext.ernal.ip.addr:3306

После часов извращений (убрав -o lo и подключаясь не к локалхосту, а к внешнему IP клиент машину) я добился того, что:
telnet ext.ernal.ip.addr
Trying ext.ernal.ip.addr...
Connected to ext.ernal.ip.addr.
Escape character is '^]'.
dHost 'xxxx' is not allowed to connect to this MySQL serverConnection closed by foreign host.


Но команда, которая может завернуть обращения к localhost наружу по-прежнему упорно не работает:
iptables -t nat -A OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to ip_of_server_with_mysql:3306

У кого есть идеи? Все машины Debian Lenny 5, а также тестил на 2.6.33.

Update:

Работать это не будет принципиально, вот такой вот iptables!

По материалам:

1. http://forums.cpanel.net/f5/iptables-redirect-internal-port-remote-mysql-98333.html (рекомендуют NAT)
2. http://ubuntuforums.org/showthread.php?t=1436579 (попытки применить NAT)
3. http://www.linuxquestions.org/questions/showthread.php?p=3909624#post3909624 (еще немного по iptables)
4. http://forum.slicehost.com/comments.php?DiscussionID=4647 (готовое решение!)
5. http://wiki.debian.org/Firewalls-local-port-redirection (примеры порт редиректа! готовые!)
6. http://www.linuxquestions.org/questions/linux-networking-3/iptables-how-to-redirect-locally-generated-packets-to-a-remote-server-797173/
7. http://www.experts-exchange.com/Networking/Linux_Networking/Q_22862486.html (проблема DNAT + loopback)
8. http://lists.netfilter.org/pipermail/netfilter/2005-April/059765.html (пару слов про необходимость CONFIG_IP_NF_NAT_LOCAL)
9. Ссылка на "как это сделать через iproute2": http://www.listware.net/201007/debian-user/27927-iptables-localhost-redirect.html

8 comments :

  1. http://highloaded.blogspot.com/2010/02/mysql-socketa-localhost-tcp.html

    ReplyDelete
  2. Вариант, но число патчей на хостинге уже стремится к страшным числам, еще один я не хочу :)

    ReplyDelete
  3. а по другому никак =)

    ReplyDelete
  4. Спосибо товарищ за ваш пост. А то я чуть с ума не сошел. Сижу тут больной, с температурой 38, и поставили мне ту же задачу.
    Пробую очевидное - не получается. Ничего понять не могу... и так пробовал, и эдтак. И на другом серваке попробовал.. нифига.
    Стал гуглить и наткнулся на ваш пост.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Приветствую, вот может Вам поможет, мне лично помогло для решения своей задачи.
    http://www.geekzone.co.nz/forums.asp?forumid=46&topicid=87441

    YourIP=127.0.0.1
    YourExternalIP=192.168.10.10
    YourPort=12345
    TargetIP=203.97.30.147
    TargetPort=80

    iptables -t nat -F
    iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT --to-destination $TargetIP:$TargetPort
    iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT --to-source $YourExternalIP
    iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT --to-destination $TargetIP:$TargetPort

    P.S Не забудьте выполнить sysctl -w net.ipv4.conf.all.route_localnet=1. Проверял на Centos 7.

    ReplyDelete
    Replies
    1. Крутейше!!! Спасибо что поделились!

      Delete

Note: only a member of this blog may post a comment.