mirror of
https://github.com/lwch/natpass.git
synced 2024-04-21 12:41:54 +00:00
140 lines
2.7 KiB
Go
140 lines
2.7 KiB
Go
package reverse
|
|
|
|
import (
|
|
"natpass/code/client/global"
|
|
"natpass/code/client/pool"
|
|
"natpass/code/client/tunnel"
|
|
"net"
|
|
"sync"
|
|
|
|
"github.com/lwch/logging"
|
|
"github.com/lwch/runtime"
|
|
)
|
|
|
|
// Tunnel tunnel object
|
|
type Tunnel struct {
|
|
sync.RWMutex
|
|
Name string
|
|
cfg global.Tunnel
|
|
links map[string]*Link
|
|
}
|
|
|
|
// New new tunnel
|
|
func New(cfg global.Tunnel) *Tunnel {
|
|
return &Tunnel{
|
|
Name: cfg.Name,
|
|
cfg: cfg,
|
|
links: make(map[string]*Link),
|
|
}
|
|
}
|
|
|
|
// NewLink new link
|
|
func (tn *Tunnel) NewLink(id, remote string, remoteIdx uint32, localConn net.Conn, remoteConn *pool.Conn) tunnel.Link {
|
|
remoteConn.AddLink(id)
|
|
logging.Info("create link %s for reverse %s on connection %d",
|
|
id, tn.Name, remoteConn.Idx)
|
|
link := &Link{
|
|
parent: tn,
|
|
id: id,
|
|
target: remote,
|
|
targetIdx: remoteIdx,
|
|
local: localConn,
|
|
remote: remoteConn,
|
|
OnWork: make(chan struct{}),
|
|
}
|
|
tn.Lock()
|
|
tn.links[link.id] = link
|
|
tn.Unlock()
|
|
return link
|
|
}
|
|
|
|
// GetName get reverse tunnel name
|
|
func (tn *Tunnel) GetName() string {
|
|
return tn.Name
|
|
}
|
|
|
|
// GetTypeName get reverse tunnel type name
|
|
func (tn *Tunnel) GetTypeName() string {
|
|
return "reverse"
|
|
}
|
|
|
|
// GetTarget get target of this tunnel
|
|
func (tn *Tunnel) GetTarget() string {
|
|
return tn.cfg.Target
|
|
}
|
|
|
|
// GetLinks get tunnel links
|
|
func (tn *Tunnel) GetLinks() []tunnel.Link {
|
|
ret := make([]tunnel.Link, 0, len(tn.links))
|
|
tn.RLock()
|
|
for _, link := range tn.links {
|
|
ret = append(ret, link)
|
|
}
|
|
tn.RUnlock()
|
|
return ret
|
|
}
|
|
|
|
// GetRemote get remote target name
|
|
func (tn *Tunnel) GetRemote() string {
|
|
return tn.cfg.Target
|
|
}
|
|
|
|
// GetPort get listen port
|
|
func (tn *Tunnel) GetPort() uint16 {
|
|
return tn.cfg.LocalPort
|
|
}
|
|
|
|
// Handle handle tunnel
|
|
func (tn *Tunnel) Handle(pool *pool.Pool) {
|
|
if tn.cfg.Type == "tcp" {
|
|
tn.handleTCP(pool)
|
|
} else {
|
|
// TODO
|
|
func() {}()
|
|
}
|
|
}
|
|
|
|
func (tn *Tunnel) handleTCP(pool *pool.Pool) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
logging.Error("close tcp tunnel: %s, err=%v", tn.cfg.Name, err)
|
|
}
|
|
}()
|
|
l, err := net.ListenTCP("tcp", &net.TCPAddr{
|
|
IP: net.ParseIP(tn.cfg.LocalAddr),
|
|
Port: int(tn.cfg.LocalPort),
|
|
})
|
|
runtime.Assert(err)
|
|
defer l.Close()
|
|
for {
|
|
conn, err := l.Accept()
|
|
if err != nil {
|
|
logging.Error("accept from %s tunnel, err=%v", tn.cfg.Name, err)
|
|
continue
|
|
}
|
|
|
|
id, err := runtime.UUID(16, "0123456789abcdef")
|
|
if err != nil {
|
|
conn.Close()
|
|
logging.Error("generate link id failed, err=%v", err)
|
|
continue
|
|
}
|
|
|
|
remote := pool.Get(id)
|
|
if remote == nil {
|
|
conn.Close()
|
|
logging.Error("no connection available")
|
|
continue
|
|
}
|
|
link := tn.NewLink(id, tn.cfg.Target, 0, conn, remote).(*Link)
|
|
remote.SendConnectReq(id, tn.cfg)
|
|
link.Forward()
|
|
}
|
|
}
|
|
|
|
func (tn *Tunnel) remove(id string) {
|
|
tn.Lock()
|
|
delete(tn.links, id)
|
|
tn.Unlock()
|
|
}
|