mirror of
https://github.com/luscis/openlan.git
synced 2025-10-05 16:47:11 +08:00
120 lines
2.2 KiB
Go
Executable File
120 lines
2.2 KiB
Go
Executable File
package proxy
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/luscis/openlan/pkg/config"
|
|
"github.com/luscis/openlan/pkg/libol"
|
|
)
|
|
|
|
type TcpProxy struct {
|
|
listen string
|
|
target []string
|
|
listener net.Listener
|
|
out *libol.SubLogger
|
|
rr uint64
|
|
}
|
|
|
|
func NewTcpProxy(cfg *config.TcpProxy) *TcpProxy {
|
|
return &TcpProxy{
|
|
listen: cfg.Listen,
|
|
target: cfg.Target,
|
|
out: libol.NewSubLogger(cfg.Listen),
|
|
}
|
|
}
|
|
|
|
func (t *TcpProxy) Initialize() {
|
|
}
|
|
|
|
func (t *TcpProxy) tunnel(src net.Conn, dst net.Conn) {
|
|
defer dst.Close()
|
|
defer src.Close()
|
|
t.out.Info("TcpProxy.tunnel %s -> %s", src.RemoteAddr(), dst.RemoteAddr())
|
|
wait := libol.NewWaitOne(2)
|
|
libol.Go(func() {
|
|
defer wait.Done()
|
|
if _, err := io.Copy(dst, src); err != nil {
|
|
t.out.Debug("TcpProxy.tunnel from ws %s", err)
|
|
}
|
|
})
|
|
libol.Go(func() {
|
|
defer wait.Done()
|
|
if _, err := io.Copy(src, dst); err != nil {
|
|
t.out.Debug("TcpProxy.tunnel from target %s", err)
|
|
}
|
|
})
|
|
wait.Wait()
|
|
t.out.Debug("TcpProxy.tunnel %s exit", dst.RemoteAddr())
|
|
}
|
|
|
|
func (t *TcpProxy) loadBalance(fail int) string {
|
|
size := len(t.target)
|
|
if fail < size {
|
|
i := t.rr % uint64(size)
|
|
t.rr++
|
|
return t.target[i]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (t *TcpProxy) Start() {
|
|
var listen net.Listener
|
|
promise := &libol.Promise{
|
|
First: time.Second * 2,
|
|
MaxInt: time.Minute,
|
|
MinInt: time.Second * 10,
|
|
}
|
|
promise.Do(func() error {
|
|
var err error
|
|
listen, err = net.Listen("tcp", t.listen)
|
|
if err != nil {
|
|
t.out.Warn("TcpProxy.Start %s", err)
|
|
}
|
|
return err
|
|
})
|
|
t.listener = listen
|
|
t.out.Info("TcpProxy.Start: %s", t.target)
|
|
libol.Go(func() {
|
|
defer listen.Close()
|
|
for {
|
|
conn, err := listen.Accept()
|
|
if err != nil {
|
|
t.out.Error("TcpServer.Accept: %s", err)
|
|
break
|
|
}
|
|
// connect target and pipe it.
|
|
fail := 0
|
|
for {
|
|
backend := t.loadBalance(fail)
|
|
if backend == "" {
|
|
break
|
|
}
|
|
target, err := net.Dial("tcp", backend)
|
|
if err != nil {
|
|
t.out.Error("TcpProxy.Accept %s", err)
|
|
fail++
|
|
continue
|
|
}
|
|
libol.Go(func() {
|
|
t.tunnel(conn, target)
|
|
})
|
|
break
|
|
}
|
|
}
|
|
})
|
|
return
|
|
}
|
|
|
|
func (t *TcpProxy) Stop() {
|
|
if t.listener != nil {
|
|
t.listener.Close()
|
|
t.listener = nil
|
|
}
|
|
t.out.Info("TcpProxy.Stop")
|
|
}
|
|
|
|
func (t *TcpProxy) Save() {
|
|
}
|