求问关于 iptables 端口映射的问题,求对网络比较熟的人帮忙

2014-08-22 17:04:05 +08:00
 lsylsy2
目标:想要在公网做端口映射,用iptables实现,功能有些类似“haproxy的TCP转发”。
网络环境:(IP替换过)
服务器A:Azure,公网IP 8.8.8.1,内网IP 10.8.8.1;
服务器B:某VPS,网卡直接绑定公网IP 8.8.8.2;
在AB之间利用openvpn建立了隧道,Azure端IP 10.0.0.1,VPS端IP 10.0.0.2,测试通过这对IP ping wget均正常。
目标:访问http://8.8.8.1/,请求能够被发送到服务器B

目前iptables用的是这两条规则:
-A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
-A POSTROUTING -o eth0 -j MASQUERADE

从我的个人电脑(IP 8.8.8.3)进行了telnet 8.8.8.1 80
并且tcpdump抓包测试,结果如下:
1、服务器A上,8.8.8.3->10.8.8.1 SYN包,这是正常的外网连接Azure;
2、服务器A上,8.8.8.3->10.0.0.2 SYN包,这是第一个包经过iptables转换,目标地址变成了服务器B;
3、服务器B上,8.8.8.3->10.0.0.2 SYN包,这个SYN包被成功的发送了过来;
4、服务器B上,10.0.0.2->8.8.8.3 SYN-ACK包,进行TCP三步握手;

然后包4就丢失了……至少看起来是丢失了,#服务器A并没有收到这个ACK#,后面有几个重发的SYN与SYN-ACK包,但是都是1234中的某一个。求问这是哪里设置的问题么?
3422 次点击
所在节点    问与答
11 条回复
tmqhliu
2014-08-22 19:37:13 +08:00
建议你直接用 nginx 之类的反向代理就行,应用层的需求可以用应用层的方式来解决,不要什么都想着用 iptables

如果你用 DNAT 把包交给 Server B ,Server B 在返回时也要有相应的路由。不能只有去的路,没有回来的路。
lsylsy2
2014-08-22 19:50:17 +08:00
@tmqhliu 现在的问题就是应用层直接读取的TCP对方IP,闭源软件无法修改……
回来和去走一条路不行么?假如我的电脑插了两根网线,分别是电信联通,难道有一边无法使用么?
tmqhliu
2014-08-22 20:12:18 +08:00
如果软件读 8.8.8.1 ,你在8.8.8.1 上配置一个 http透明代理,把请求转交给实际的服务器B不行么?


你没理解我的话。走一条路当然可以,但这事需要配置,并不是你一厢情愿就可以的
lsylsy2
2014-08-22 20:15:12 +08:00
@tmqhliu 走的并不是HTTP协议,是一个裸的TCP协议,内部内容我无法修改,直接TCP转发会导致无法获取用户IP从而影响功能
我的问题是,像“站群VPS”那样,一台Linux上绑着很多个IP,那么一个用户只能访问一个IP上的网站么?
tmqhliu
2014-08-22 20:27:31 +08:00
哦 原来是原生 TCP 那就没法搞代理了

站群那样配了很多个 IP,但可能只有一个网关,返回的数据包下一跳就是这个网关地址。而你的服务器B,是在两个接口上配了两个不同的ip,如果数据包是从 tun 接口进来的,返回的包却从 eth 公网接口出去,很可能是目的地址不可达(没有相应的路由)所以就收不到返回的数据包了,自然 TCP 连接也无从谈起。

建议你在 服务器 B 上 traceroute 一下客户端的 IP (比如主贴中你的pc地址)看一下是否是畅通的。
tmqhliu
2014-08-22 21:11:04 +08:00
“难道不应该是默认哪里来哪里去么?” 这个还真不是,你看看 2006 年就有人提这个问题了:
《多线路服务器如何让访问数据包从哪条线路进就从哪条出》
http://www.linuxsir.org/bbs/thread277992.html

你的问题是,数据包是在服务器 A 上由 iptables 经 DNAT 之后通过 VPN 隧道发给服务器 B,服务器 B 在收到连接请求后,发送 SYN+ACK,但是从公网接口发送出去的。公网上的路由器在收到一个源地址为 10 开头的包,很可能就会扔掉了,因为这种私有地址的包不应该出现在公网上。
tmqhliu
2014-08-22 21:13:06 +08:00
解决方案: 在服务器B上添加策略路由,指定源地址为 10.0.0.2 的包从接口 tun 发出去。
lsylsy2
2014-08-22 21:34:39 +08:00
@tmqhliu 十分感谢!
jerry74
2014-08-22 22:38:14 +08:00
试试看吧
iptables -t nat -I PREROUTING -d 8.8.8.1 -p tcp -m tcp --dport 80 -j DNAT --to-destination 8.8.8.2
lsylsy2
2014-08-23 00:17:27 +08:00
-A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
@jerry74 我现在用的是这个,没有问题的;
你想说公网是么,那个不好使……
lsylsy2
2014-08-24 02:36:46 +08:00
@jerry74
@tmqhliu
成功了!测试了可以通过服务器A的2222端口连接服务器B的SSH(通过2222转发到22),然后服务器B上netstat能获取我客户端的IP。
最后服务器B修改iptables无效,而是用iprouter2解决的,具体的我明天睡醒了再整理写博客好了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/129352

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX