出于测试目的,我想构建一个服务器来监听某个接口(例如eth0)上每个端口(或至少在大多数端口上)的TCP连接。服务器通过SSH访问eth1,所以没问题。 (我不关心UDP或其他协议)
我想做一种特殊的中间盒检测/分析,因此我需要能够完全建立连接。拥有HTTP连接将是最好的,因为"客户端"可以在浏览器中实现为JS。
我从一个简单的jetty服务器开始,但必须意识到jetty需要至少在它正在侦听的每个端口的线程上生成。当我想听几千个端口时,这会导致问题。 或者有办法吗?
我的下一次尝试是使用iptables
:
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp -j DNAT --to-destination 127.0.0.1:8080`
似乎有效。它允许在每个端口上连接,并且流量被路由到jetty侦听的本地端口8080。但现在我不再知道客户端使用了哪个端口。因为jetty认为连接是通过端口8080建立的。有没有办法从jetty确定真正的输入端口?我可以将端口作为HTTP请求的一部分发送,但是如果客户端试图联系端口1234 ..和一个中间件将其重定向到端口5678 ..我无法知道使用了什么端口。
我也试过像socat
这样的用户态解决方案。问题比以前更糟糕。因为现在jetty也看到远程IP为127.0.0.1。
或者,还有其他方法可以实现这一目标吗?
哦,顺便说一下:我完全控制了机器。所以我可以改变内核或任何需要的东西。现在我使用的是Ubuntu 14.04 LTS,但如果解决方案需要别的东西,我可以继续使用它。
答案 0 :(得分:6)
NB :这是一个Python解决方案,因为我了解Python,但您可以使用任何语言完成相同的事情,从而暴露底层C库getsockopt
调用。
如果您使用DNAT
规则替换REDIRECT
规则,则可以
使用getsockopt
和SO_ORIGINAL_DST
选项来检索。{
REDIRECT
- ed连接的原始地址。
请考虑以下代码:
#!/usr/bin/python
import socket
import struct
SO_ORIGINAL_DST = 80
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 2000))
s.listen(10)
while True:
csock, caddr = s.accept()
orig_dst = csock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, 16)
orig_port = struct.unpack('>H', orig_dst[2:4])
orig_addr = socket.inet_ntoa(orig_dst[4:8])
print 'connection from', caddr
print 'connection to', (orig_addr, orig_port)
print
如果我的iptables规则如下:
# iptables -t nat -A PREROUTING -p tcp --dport 1500:1600 \
-j REDIRECT --to-port 2000
当上面的Python代码正在运行时,我从另一个连接
主持人到my_ip_address:1500
,我明白了:
connection from ('192.168.1.20', 35790)
connection to ('192.168.1.75', (1500,))
如果我连接到1550端口,我会看到:
connection from ('192.168.1.20', 42054)
connection to ('192.168.1.75', (1550,))
我认为这正是你所要求的。请注意,据我所知,这仅适用于TCP连接;还有其他解决方案(可能涉及TPROXY
iptables目标)也可以与UDP连接一起使用。