79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package tunnel
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/koding/logging"
|
|
"git.xeserv.us/xena/route/lib/tunnel/proto"
|
|
)
|
|
|
|
var (
|
|
tpcLog = logging.NewLogger("tcp")
|
|
)
|
|
|
|
// TCPProxy forwards TCP streams.
|
|
//
|
|
// If port-based routing is used, LocalAddr or FetchLocalAddr field is required
|
|
// for tunneling to function properly.
|
|
// Otherwise you'll be forwarding traffic to random ports and this is usually not desired.
|
|
//
|
|
// If IP-based routing is used then tunnel server connection request is
|
|
// proxied to 127.0.0.1:incomingPort where incomingPort is control message LocalPort.
|
|
// Usually this is tunnel server's public exposed Port.
|
|
// This behaviour can be changed by setting LocalAddr or FetchLocalAddr.
|
|
// FetchLocalAddr takes precedence over LocalAddr.
|
|
type TCPProxy struct {
|
|
// LocalAddr defines the TCP address of the local server.
|
|
// This is optional if you want to specify a single TCP address.
|
|
LocalAddr string
|
|
// FetchLocalAddr is used for looking up TCP address of the server.
|
|
// This is optional if you want to specify a dynamic TCP address based on incommig port.
|
|
FetchLocalAddr func(port int) (string, error)
|
|
// Log is a custom logger that can be used for the proxy.
|
|
// If not set a "tcp" logger is used.
|
|
Log logging.Logger
|
|
}
|
|
|
|
// Proxy is a ProxyFunc.
|
|
func (p *TCPProxy) Proxy(remote net.Conn, msg *proto.ControlMessage) {
|
|
if msg.Protocol != proto.TCP {
|
|
panic("Proxy mismatch")
|
|
}
|
|
|
|
var log = p.log()
|
|
|
|
var port = msg.LocalPort
|
|
if port == 0 {
|
|
log.Warning("TCP proxy to port 0")
|
|
}
|
|
|
|
var localAddr = fmt.Sprintf("127.0.0.1:%d", port)
|
|
if p.LocalAddr != "" {
|
|
localAddr = p.LocalAddr
|
|
} else if p.FetchLocalAddr != nil {
|
|
l, err := p.FetchLocalAddr(msg.LocalPort)
|
|
if err != nil {
|
|
log.Warning("Failed to get custom local address: %s", err)
|
|
return
|
|
}
|
|
localAddr = l
|
|
}
|
|
|
|
log.Debug("Dialing local server: %q", localAddr)
|
|
local, err := net.DialTimeout("tcp", localAddr, defaultTimeout)
|
|
if err != nil {
|
|
log.Error("Dialing local server %q failed: %s", localAddr, err)
|
|
return
|
|
}
|
|
|
|
Join(local, remote, log)
|
|
}
|
|
|
|
func (p *TCPProxy) log() logging.Logger {
|
|
if p.Log != nil {
|
|
return p.Log
|
|
}
|
|
return tpcLog
|
|
}
|