TCP/UDP 端口转发(Google Voice 可用)
2020-11-26 21:03:34 +0000 UTC
Art
自己写的tcp/udp 转发工具,附部分源码。原先使用haproxy转发流量,提供的功能很强大,性能也很好,后来用Google Volce的时候发现用不了,不支持udp流量转发,于是自己动手写一个简易转发工具,自测可用。
1.TCP部分源码
func handle(client net.Conn, server string, output string) {
if client == nil {
return
}
log.Println("TCP handle new connection.")
defer client.Close()
destConn, err := net.DialTimeout("tcp", server+output, time.Second*3)
if err != nil {
log.Println(err)
return
}
defer destConn.Close()
//将客户端的请求转发至服务端,将服务端的响应转发给客户端。io.Copy为阻塞函数,文件描述符不关闭就不停止
relay(client, destConn)
log.Println("TCP handle close connection.")
}
// relay copies between left and right bidirectionally
func relay(left, right net.Conn) error {
var err, err1 error
var wg sync.WaitGroup
var wait = 5 * time.Second
wg.Add(1)
go func() {
defer wg.Done()
_, err1 = io.Copy(right, left)
right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right
}()
_, err = io.Copy(left, right)
left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left
wg.Wait()
if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+
return err1
}
if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
return err
}
return nil
}
2.UDP部分源码
type UDPCap struct {
ClientAddr *net.UDPAddr // Address of the client
ServerConn *net.UDPConn // UDP connection to server
}
type UDPCapsLock struct {
UDPCaps map[string]*UDPCap
Lock sync.Mutex
}
// Generate a new connection by opening a UDP connection to the server
func NewConnection(srvAddr, cliAddr *net.UDPAddr) *UDPCap {
conn := new(UDPCap)
conn.ClientAddr = cliAddr
srvudp, err := net.DialUDP("udp", nil, srvAddr)
if checkreport(1, err) {
return nil
}
conn.ServerConn = srvudp
return conn
}
func setup(hostport string, port int) {
// Set up Proxy
saddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
if checkreport(1, err) {
}
localConn, err := net.ListenUDP("udp", saddr)
if checkreport(1, err) {
}
logf("UDP Proxy serving on port %d\n", port)
// Get server address
ServerAddr, err := net.ResolveUDPAddr("udp", hostport)
if checkreport(1, err) {
}
logf("UDP Connected to server at %s\n", hostport)
RunProxy(localConn, ServerAddr)
}
// Go routine which manages connection from server to single client
func RunConnection(conn *UDPCap, udpcapsLock UDPCapsLock, localConn *net.UDPConn) {
var buffer [1500]byte
for {
// Read from server
conn.ServerConn.SetReadDeadline(time.Now().Add(time.Minute * 5))
n, err := conn.ServerConn.Read(buffer[0:])
if checkreport2(1, err) == 1 {
//删除
log.Println("udp delete timeout router")
udpcapsLock.Lock.Lock()
conn.ServerConn.Close()
delete(udpcapsLock.UDPCaps, conn.ClientAddr.String())
udpcapsLock.Lock.Unlock()
break
}
// Relay it to client
_, err = localConn.WriteToUDP(buffer[0:n], conn.ClientAddr)
}
}
// Routine to handle inputs to Proxy port
func RunProxy(localConn *net.UDPConn, ServerAddr *net.UDPAddr) {
var buffer [1500]byte
log.Println("UDP start")
var uncapsLock UDPCapsLock
uncapsLock.UDPCaps = map[string]*UDPCap{}
for {
n, cliaddr, err := localConn.ReadFromUDP(buffer[0:])
if checkreport(1, err) {
continue
}
//Vlogf(3, "UDP Read sth. from client %s, routers length %d \n", cliaddr.String(), len(uncapsLock.UDPCaps))
saddr := cliaddr.String()
udpcap, found := uncapsLock.UDPCaps[saddr]
if !found {
udpcap = NewConnection(ServerAddr, cliaddr)
if udpcap == nil {
continue
}
uncapsLock.Lock.Lock()
uncapsLock.UDPCaps[saddr] = udpcap
uncapsLock.Lock.Unlock()
logf("UDP Created new connection for client %s routers length %d \n", saddr, len(uncapsLock.UDPCaps))
// Fire up routine to manage new connection
go RunConnection(udpcap, uncapsLock, localConn)
}
// Relay to server
_, err = udpcap.ServerConn.Write(buffer[0:n])
if checkreport(1, err) {
continue
}
}
}
提取码: zus5 复制这段内容后打开百度网盘手机App,操作更方便哦
4.configs.json
[
{
"inport": 13531,
"outport": 13531,
"server": "127.0.0.1"
},
{
"inport": 13532,
"outport": 13532,
"server": "127.0.0.1"
},
{
"inport": 13533,
"outport": 13533,
"server": "127.0.0.1"
}
]
5.打开方式
./forward ./configs.json &