SSH Tunnel for UDP
UDP port forwarding is a bit more complicated. We will need to convert the packets from UDP to TCP on the SSH client side, tunnel it over the SSH connection and convert it back from TCP to UDP on the SSH server side.
由于业务需要,要实现内网一个服务器的udp服务对外暴露,并且外网需要访问该服务,但是该机器没有公网IP,也不能做NAT。所以实现基于ssh隧道的端口转发,拓扑图和原理如下:

根据以上原理,配置如下:
server01:xxx.xxx.xxx.xxx
server02:10.21.17.15
server03:172.18.153.13
1.配置ssh隧道和socat的udp/tcp端口转发:
在server02(10.21.17.15)上执行
# autossh -p 22 -M 6777 -NfR '*:8899:127.0.0.1:8899' root@94.191.109.129 或者 # ssh -R 8899:127.0.0.1:8899 xxx.xxx.xxx.xxx "vmstat 30"
# socat tcp4-listen:8899,reuseaddr,fork udp:172.18.153.13:9999 或者使用管道来实现 # mkfifo /tmp/fifo && nc -l -p 8899 < /tmp/fifo | nc -u 172.18.153.13 9999 > /tmp/fifo
在server01(94.191.109.129)上执行
# socat udp4-listen:9999,reuseaddr,fork tcp:localhost:8899 或者使用管道来实现 # mkfifo /tmp/fifo && nc -l -u -p 9999 < /tmp/fifo | nc localhost 8899 > /tmp/fifo
*其中udp4-listen:改成udp4-recvfrom也是可以的。
2.在server03上启动python进程:
# -*- coding: utf-8 -*-
import socket
'''
使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。
虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。
我们来看看如何通过UDP协议传输数据。和TCP类似,使用UDP的通信双方也分为客户端和服务器。服务器首先需要绑定端口
绑定端口和TCP一样,但是不需要调用listen()方法,而是直接接收来自任何客户端的数据
'''
# ipv4 SOCK_DGRAM指定了这个Socket的类型是UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定 客户端口和地址:
s.bind(('172.18.153.13', 9999))
print 'Bind UDP on 9999...'
while True:
# 接收数据 自动阻塞 等待客户端请求:
data, addr = s.recvfrom(1024)
print 'Received from %s:%s.' % addr
s.sendto('Hello, %s!' % data, addr)
3.在测试机器上做如下测试:
测试一:只有一个进程连接传输数据
1)持续写数据到临时文件中:
# while true;do echo test >> /tmp/socat.tmp;sleep 0.05;done
2)从临时文件中读取数据并使用socat发送udp数据:
# tail -f /tmp/socat.tmp | socat - udp-connect:xxx.xxx.xxx.xxx:9999
测试二:不断使用新端口连接传输数据
# while true;do echo test | socat - udp-connect:xxx.xxx.xxx.xxx:9999;sleep 0.05;done
4.socat进程在会话完成之后会自动断开,需要写脚本自动拉起:
#!/bin/bash while : do pid=`ps -ef|grep socat|grep listen|awk '{print $2}' | wc -l` sleep 10 { if [ "$pid" -le 8 ] then socat tcp4-listen:9010,reuseaddr,fork udp:172.18.171.15:43010 >> 9010.log 2>&1 & socat tcp4-listen:9011,reuseaddr,fork udp:172.18.171.15:43011 >> 9011.log 2>&1 & socat tcp4-listen:9012,reuseaddr,fork udp:172.18.171.15:43012 >> 9012.log 2>&1 & socat tcp4-listen:9013,reuseaddr,fork udp:172.18.171.15:43013 >> 9013.log 2>&1 & socat tcp4-listen:9014,reuseaddr,fork udp:172.18.171.15:43014 >> 9014.log 2>&1 & socat tcp4-listen:9015,reuseaddr,fork udp:172.18.171.15:43015 >> 9015.log 2>&1 & socat tcp4-listen:9016,reuseaddr,fork udp:172.18.171.15:43016 >> 9016.log 2>&1 & socat tcp4-listen:9017,reuseaddr,fork udp:172.18.171.15:43017 >> 9017.log 2>&1 & fi }||{ if [ "$pid" -le 8 ] then ps -ef|grep socat|grep listen|awk '{print $2}'|xargs kill -9 sleep 5 socat tcp4-listen:9010,reuseaddr,fork udp:172.18.171.15:43010 >> 9010.log 2>&1 & socat tcp4-listen:9011,reuseaddr,fork udp:172.18.171.15:43011 >> 9011.log 2>&1 & socat tcp4-listen:9012,reuseaddr,fork udp:172.18.171.15:43012 >> 9012.log 2>&1 & socat tcp4-listen:9013,reuseaddr,fork udp:172.18.171.15:43013 >> 9013.log 2>&1 & socat tcp4-listen:9014,reuseaddr,fork udp:172.18.171.15:43014 >> 9014.log 2>&1 & socat tcp4-listen:9015,reuseaddr,fork udp:172.18.171.15:43015 >> 9015.log 2>&1 & socat tcp4-listen:9016,reuseaddr,fork udp:172.18.171.15:43016 >> 9016.log 2>&1 & socat tcp4-listen:9017,reuseaddr,fork udp:172.18.171.15:43017 >> 9017.log 2>&1 & fi } done
总结:
1.配置完成之后,隧道,socat端口转发和数据的传输正常,稳定,测试过程中没有出现断线,丢包的问题。
2.socat工具强大,主要特点就是在两个数据流之间建立通道,且支持众多协议和链接方式。如 IP、TCP、 UDP、IPv6、PIPE、EXEC、System、Open、Proxy、Openssl、Socket等。更多功能待验证和熟悉。