Clients dynamic TX/RX sizes #1
@ -8,6 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/pipe"
|
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/pipe"
|
||||||
@ -67,6 +68,13 @@ func (client Client) Recive() (res *proto.Response, err error) {
|
|||||||
recBuff := make([]byte, client.ResponseBuffer+proto.PacketSize)
|
recBuff := make([]byte, client.ResponseBuffer+proto.PacketSize)
|
||||||
var n int
|
var n int
|
||||||
if n, err = client.Conn.Read(recBuff); err != nil {
|
if n, err = client.Conn.Read(recBuff); err != nil {
|
||||||
|
if opErr, isOp := err.(*net.OpError); isOp {
|
||||||
|
log.Println()
|
||||||
|
err = opErr.Err
|
||||||
|
if reflect.TypeOf(opErr.Err).String() == "poll.errNetClosing" {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +97,9 @@ func (client Client) Send(req proto.Request) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send token to controller to connect to tunnel
|
||||||
func (client *Client) auth() (info *proto.AgentInfo, err error) {
|
func (client *Client) auth() (info *proto.AgentInfo, err error) {
|
||||||
|
attemps := 0
|
||||||
var res *proto.Response
|
var res *proto.Response
|
||||||
for {
|
for {
|
||||||
if err = client.Send(proto.Request{AgentAuth: &client.Token}); err != nil {
|
if err = client.Send(proto.Request{AgentAuth: &client.Token}); err != nil {
|
||||||
@ -103,6 +113,10 @@ func (client *Client) auth() (info *proto.AgentInfo, err error) {
|
|||||||
if res.BadRequest || res.SendAuth {
|
if res.BadRequest || res.SendAuth {
|
||||||
// Wait seconds to resend token
|
// Wait seconds to resend token
|
||||||
<-time.After(time.Second * 3)
|
<-time.After(time.Second * 3)
|
||||||
|
if attemps++; attemps >= 25 {
|
||||||
|
err = ErrAgentUnathorized // Cannot auth
|
||||||
|
return
|
||||||
|
}
|
||||||
continue // Reload auth
|
continue // Reload auth
|
||||||
} else if res.Unauthorized {
|
} else if res.Unauthorized {
|
||||||
// Close tunnel and break loop-de-loop 🦔
|
// Close tunnel and break loop-de-loop 🦔
|
||||||
@ -115,19 +129,29 @@ func (client *Client) auth() (info *proto.AgentInfo, err error) {
|
|||||||
return res.AgentInfo, nil
|
return res.AgentInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial and Auth agent before require call in new gorotine client.Backgroud()
|
// Dial to controller and auto accept new responses from controller
|
||||||
func (client *Client) Dial() (info *proto.AgentInfo, err error) {
|
func (client *Client) Dial() (info *proto.AgentInfo, err error) {
|
||||||
if client.Conn, err = net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(client.ControlAddr)); err != nil {
|
if client.Conn, err = net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(client.ControlAddr)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
go client.backgroud()
|
||||||
return client.auth()
|
return client.auth()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watcher response from controller
|
// Watcher response from controller
|
||||||
func (client *Client) Backgroud() (err error) {
|
func (client *Client) backgroud() (err error) {
|
||||||
|
go func(){
|
||||||
|
for {
|
||||||
|
var current = time.Now()
|
||||||
|
client.Send(proto.Request{Ping: ¤t})
|
||||||
|
<-time.After(time.Second * 5)
|
||||||
|
}
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
|
log.Println("waiting response from controller")
|
||||||
var res *proto.Response
|
var res *proto.Response
|
||||||
if res, err = client.Recive(); err != nil {
|
if res, err = client.Recive(); err != nil {
|
||||||
|
log.Println(err.Error())
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -56,30 +56,21 @@ var CmdClient = cli.Command{
|
|||||||
}
|
}
|
||||||
fmt.Printf("Connected, Remote port: %d\n", info.LitenerPort)
|
fmt.Printf("Connected, Remote port: %d\n", info.LitenerPort)
|
||||||
fmt.Printf(" Remote address: %s\n", info.AddrPort.String())
|
fmt.Printf(" Remote address: %s\n", info.AddrPort.String())
|
||||||
go client.Backgroud()
|
|
||||||
|
|
||||||
localConnect := ctx.String("dial")
|
localConnect := ctx.String("dial")
|
||||||
for {
|
for {
|
||||||
|
var conn, dial net.Conn
|
||||||
select {
|
select {
|
||||||
case tcp := <-client.NewTCPClient:
|
case conn = <-client.NewTCPClient:
|
||||||
go func() {
|
if dial, err = net.Dial("tcp", localConnect); err != nil {
|
||||||
conn, err := net.Dial("tcp", localConnect)
|
continue
|
||||||
if err != nil {
|
}
|
||||||
return
|
case conn = <-client.NewUDPClient:
|
||||||
}
|
if dial, err = net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(netip.MustParseAddrPort(localConnect))); err != nil {
|
||||||
go io.Copy(conn, tcp)
|
continue
|
||||||
go io.Copy(tcp, conn)
|
}
|
||||||
}()
|
|
||||||
case udp := <-client.NewUDPClient:
|
|
||||||
go func () {
|
|
||||||
conn, err := net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(netip.MustParseAddrPort(localConnect)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go io.Copy(conn, udp)
|
|
||||||
go io.Copy(udp, conn)
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
go io.Copy(conn, dial)
|
||||||
|
go io.Copy(dial, conn)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
@ -13,14 +13,6 @@ type serverCalls struct {
|
|||||||
XormEngine *xorm.Engine
|
XormEngine *xorm.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tun struct {
|
|
||||||
ID int64 `xorm:"pk"` // Tunnel ID
|
|
||||||
User int64 // Agent ID
|
|
||||||
Token [36]byte // Tunnel Token
|
|
||||||
Proto uint8 // Proto accept
|
|
||||||
PortListen uint16 // Port listen agent
|
|
||||||
}
|
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int64 `xorm:"pk"` // Client ID
|
ID int64 `xorm:"pk"` // Client ID
|
||||||
Username string `xorm:"varchar(32) notnull unique 'user'"` // Username
|
Username string `xorm:"varchar(32) notnull unique 'user'"` // Username
|
||||||
@ -30,18 +22,35 @@ type User struct {
|
|||||||
UpdateAt time.Time `xorm:"updated"` // Update date
|
UpdateAt time.Time `xorm:"updated"` // Update date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Tun struct {
|
||||||
|
ID int64 `xorm:"pk"` // Tunnel ID
|
||||||
|
User int64 `xorm:"notnull"` // Agent ID
|
||||||
|
Token [36]byte `xorm:"blob notnull unique"` // Tunnel Token
|
||||||
|
Proto uint8 `xorm:"default 3"` // Proto accept
|
||||||
|
PortListen uint16 // Port listen agent
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ping struct {
|
||||||
|
ID int64 `json:"-" xorm:"pk"` // Tunnel ID
|
||||||
|
TunID int64 `json:"-"`
|
||||||
|
ServerTime time.Time `json:"server" xorm:"datetime notnull"`
|
||||||
|
AgentTime time.Time `json:"agent" xorm:"datetime notnull"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewCall(DBConn string) (call *serverCalls, err error) {
|
func NewCall(DBConn string) (call *serverCalls, err error) {
|
||||||
call = new(serverCalls)
|
call = new(serverCalls)
|
||||||
if call.XormEngine, err = xorm.NewEngine("sqlite", DBConn); err != nil {
|
if call.XormEngine, err = xorm.NewEngine("sqlite", DBConn); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
call.XormEngine.SetMapper(names.SameMapper{})
|
call.XormEngine.SetMapper(names.SameMapper{})
|
||||||
call.XormEngine.CreateTables(Tun{}, User{})
|
session := call.XormEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
session.CreateTable(User{})
|
||||||
|
session.CreateTable(Tun{})
|
||||||
|
session.CreateTable(Ping{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (call serverCalls) AgentShutdown(Token [36]byte) (err error) { return } // Ignore
|
|
||||||
|
|
||||||
func (call serverCalls) AgentInfo(Token [36]byte) (server.TunnelInfo, error) {
|
func (call serverCalls) AgentInfo(Token [36]byte) (server.TunnelInfo, error) {
|
||||||
var tun = Tun{Token: Token}
|
var tun = Tun{Token: Token}
|
||||||
if ok, err := call.XormEngine.Get(&tun); err != nil || !ok {
|
if ok, err := call.XormEngine.Get(&tun); err != nil || !ok {
|
||||||
@ -55,3 +64,22 @@ func (call serverCalls) AgentInfo(Token [36]byte) (server.TunnelInfo, error) {
|
|||||||
Proto: tun.Proto,
|
Proto: tun.Proto,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (call serverCalls) RegisterPing(serverTime, clientTime time.Time, Token [36]byte) error {
|
||||||
|
var tun = Tun{Token: Token}
|
||||||
|
if ok, err := call.XormEngine.Get(&tun); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !ok {
|
||||||
|
return server.ErrNoAgent
|
||||||
|
}
|
||||||
|
|
||||||
|
ping := new(Ping)
|
||||||
|
ping.TunID = tun.ID
|
||||||
|
ping.ServerTime = serverTime
|
||||||
|
ping.AgentTime = clientTime
|
||||||
|
_, err := call.XormEngine.InsertOne(ping)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -24,6 +24,7 @@ require (
|
|||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
|
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
|
||||||
|
golang.org/x/net v0.14.0 // indirect
|
||||||
golang.org/x/sys v0.19.0 // indirect
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
|
||||||
modernc.org/libc v1.50.9 // indirect
|
modernc.org/libc v1.50.9 // indirect
|
||||||
|
3
go.sum
3
go.sum
@ -60,8 +60,9 @@ github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe
|
|||||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
|
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
|
||||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||||
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
201
internal/udplisterner/v2/pipe.go
Normal file
201
internal/udplisterner/v2/pipe.go
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
package udplisterner
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pipeDeadline is an abstraction for handling timeouts.
|
||||||
|
type pipeDeadline struct {
|
||||||
|
mu sync.Mutex // Guards timer and cancel
|
||||||
|
timer *time.Timer
|
||||||
|
cancel chan struct{} // Must be non-nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makePipeDeadline() pipeDeadline {
|
||||||
|
return pipeDeadline{cancel: make(chan struct{})}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set sets the point in time when the deadline will time out.
|
||||||
|
// A timeout event is signaled by closing the channel returned by waiter.
|
||||||
|
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
||||||
|
// t value in the future.
|
||||||
|
//
|
||||||
|
// A zero value for t prevents timeout.
|
||||||
|
func (d *pipeDeadline) set(t time.Time) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
if d.timer != nil && !d.timer.Stop() {
|
||||||
|
<-d.cancel // Wait for the timer callback to finish and close cancel
|
||||||
|
}
|
||||||
|
d.timer = nil
|
||||||
|
|
||||||
|
// Time is zero, then there is no deadline.
|
||||||
|
closed := isClosedChan(d.cancel)
|
||||||
|
if t.IsZero() {
|
||||||
|
if closed {
|
||||||
|
d.cancel = make(chan struct{})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time in the future, setup a timer to cancel in the future.
|
||||||
|
if dur := time.Until(t); dur > 0 {
|
||||||
|
if closed {
|
||||||
|
d.cancel = make(chan struct{})
|
||||||
|
}
|
||||||
|
d.timer = time.AfterFunc(dur, func() {
|
||||||
|
close(d.cancel)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time in the past, so close immediately.
|
||||||
|
if !closed {
|
||||||
|
close(d.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait returns a channel that is closed when the deadline is exceeded.
|
||||||
|
func (d *pipeDeadline) wait() chan struct{} {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
return d.cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
func isClosedChan(c <-chan struct{}) bool {
|
||||||
|
select {
|
||||||
|
case <-c:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipe struct {
|
||||||
|
localAddr, remoteAddr net.Addr
|
||||||
|
|
||||||
|
wrMu sync.Mutex // Serialize Write operations
|
||||||
|
|
||||||
|
// Used by local Read to interact with remote Write.
|
||||||
|
// Successful receive on rdRx is always followed by send on rdTx.
|
||||||
|
rdRx <-chan []byte
|
||||||
|
rdTx chan<- int
|
||||||
|
|
||||||
|
// Used by local Write to interact with remote Read.
|
||||||
|
// Successful send on wrTx is always followed by receive on wrRx.
|
||||||
|
wrTx chan<- []byte
|
||||||
|
wrRx <-chan int
|
||||||
|
|
||||||
|
once sync.Once // Protects closing localDone
|
||||||
|
localDone chan struct{}
|
||||||
|
remoteDone <-chan struct{}
|
||||||
|
|
||||||
|
readDeadline pipeDeadline
|
||||||
|
writeDeadline pipeDeadline
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) LocalAddr() net.Addr { return p.localAddr }
|
||||||
|
func (p *pipe) RemoteAddr() net.Addr { return p.remoteAddr }
|
||||||
|
|
||||||
|
func (p *pipe) Read(b []byte) (int, error) {
|
||||||
|
n, err := p.read(b)
|
||||||
|
if err != nil && err != io.EOF && err != io.ErrClosedPipe {
|
||||||
|
err = &net.OpError{Op: "read", Net: "pipe", Err: err}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) read(b []byte) (n int, err error) {
|
||||||
|
switch {
|
||||||
|
case isClosedChan(p.localDone):
|
||||||
|
return 0, io.ErrClosedPipe
|
||||||
|
case isClosedChan(p.remoteDone):
|
||||||
|
return 0, io.EOF
|
||||||
|
case isClosedChan(p.readDeadline.wait()):
|
||||||
|
return 0, os.ErrDeadlineExceeded
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case bw := <-p.rdRx:
|
||||||
|
nr := copy(b, bw)
|
||||||
|
p.rdTx <- nr
|
||||||
|
return nr, nil
|
||||||
|
case <-p.localDone:
|
||||||
|
return 0, io.ErrClosedPipe
|
||||||
|
case <-p.remoteDone:
|
||||||
|
return 0, io.EOF
|
||||||
|
case <-p.readDeadline.wait():
|
||||||
|
return 0, os.ErrDeadlineExceeded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) Write(b []byte) (int, error) {
|
||||||
|
n, err := p.write(b)
|
||||||
|
if err != nil && err != io.ErrClosedPipe {
|
||||||
|
err = &net.OpError{Op: "write", Net: "pipe", Err: err}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) write(b []byte) (n int, err error) {
|
||||||
|
switch {
|
||||||
|
case isClosedChan(p.localDone):
|
||||||
|
return 0, io.ErrClosedPipe
|
||||||
|
case isClosedChan(p.remoteDone):
|
||||||
|
return 0, io.ErrClosedPipe
|
||||||
|
case isClosedChan(p.writeDeadline.wait()):
|
||||||
|
return 0, os.ErrDeadlineExceeded
|
||||||
|
}
|
||||||
|
|
||||||
|
p.wrMu.Lock() // Ensure entirety of b is written together
|
||||||
|
defer p.wrMu.Unlock()
|
||||||
|
for once := true; once || len(b) > 0; once = false {
|
||||||
|
select {
|
||||||
|
case p.wrTx <- b:
|
||||||
|
nw := <-p.wrRx
|
||||||
|
b = b[nw:]
|
||||||
|
n += nw
|
||||||
|
case <-p.localDone:
|
||||||
|
return n, io.ErrClosedPipe
|
||||||
|
case <-p.remoteDone:
|
||||||
|
return n, io.ErrClosedPipe
|
||||||
|
case <-p.writeDeadline.wait():
|
||||||
|
return n, os.ErrDeadlineExceeded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) SetDeadline(t time.Time) error {
|
||||||
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
|
return io.ErrClosedPipe
|
||||||
|
}
|
||||||
|
p.readDeadline.set(t)
|
||||||
|
p.writeDeadline.set(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) SetReadDeadline(t time.Time) error {
|
||||||
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
|
return io.ErrClosedPipe
|
||||||
|
}
|
||||||
|
p.readDeadline.set(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) SetWriteDeadline(t time.Time) error {
|
||||||
|
if isClosedChan(p.localDone) || isClosedChan(p.remoteDone) {
|
||||||
|
return io.ErrClosedPipe
|
||||||
|
}
|
||||||
|
p.writeDeadline.set(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) Close() error {
|
||||||
|
p.once.Do(func() { close(p.localDone) })
|
||||||
|
return nil
|
||||||
|
}
|
111
internal/udplisterner/v2/v2.go
Normal file
111
internal/udplisterner/v2/v2.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package udplisterner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
ClientConn *pipe
|
||||||
|
rdRx, wrTx chan []byte
|
||||||
|
rdTx, wrRx chan int
|
||||||
|
localDone, remoteDone chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPListener struct {
|
||||||
|
conn *net.UDPConn // Root listener
|
||||||
|
toAccept chan any // Return accept connections
|
||||||
|
clients map[string]client // Clients
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get address from UDP Listener
|
||||||
|
func (lis UDPListener) Addr() net.Addr {
|
||||||
|
return lis.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lis *UDPListener) Close() error {
|
||||||
|
for _, client := range lis.clients {
|
||||||
|
client.localDone <- struct{}{} // Close and wait response, ignoraing errors
|
||||||
|
}
|
||||||
|
close(lis.toAccept) // end channel
|
||||||
|
return lis.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lis UDPListener) Accept() (net.Conn, error) {
|
||||||
|
if rec, ok := <-lis.toAccept; ok {
|
||||||
|
if err, isErr := rec.(error); isErr {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rec.(net.Conn), nil
|
||||||
|
}
|
||||||
|
return nil, io.ErrClosedPipe
|
||||||
|
}
|
||||||
|
|
||||||
|
func Listen(network string, address *net.UDPAddr) (net.Listener, error) {
|
||||||
|
var conn *net.UDPConn
|
||||||
|
var err error
|
||||||
|
if conn, err = net.ListenUDP(network, address); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
accepts := make(chan any)
|
||||||
|
listen := &UDPListener{conn, accepts, make(map[string]client)}
|
||||||
|
go func() {
|
||||||
|
var maxSize int = 1024
|
||||||
|
for {
|
||||||
|
log.Println("waiting request")
|
||||||
|
buff := make([]byte, maxSize)
|
||||||
|
n, from, err := conn.ReadFromUDPAddrPort(buff)
|
||||||
|
if err != nil {
|
||||||
|
break // end loop-de-loop
|
||||||
|
}
|
||||||
|
log.Printf("Request from: %s", from.String())
|
||||||
|
if tun, ok := listen.clients[from.String()]; ok {
|
||||||
|
tun.wrTx <- buff[:n]
|
||||||
|
<-tun.rdTx // but ignore
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
rdRx := make(chan []byte)
|
||||||
|
wrTx := make(chan []byte)
|
||||||
|
rdTx := make(chan int)
|
||||||
|
wrRx := make(chan int)
|
||||||
|
localDone := make(chan struct{})
|
||||||
|
remoteDone := make(chan struct{})
|
||||||
|
newClient := client{
|
||||||
|
rdRx: rdRx, rdTx: rdTx,
|
||||||
|
wrTx: wrTx, wrRx: wrRx,
|
||||||
|
localDone: localDone, remoteDone: remoteDone,
|
||||||
|
ClientConn: &pipe{
|
||||||
|
localAddr: conn.LocalAddr(),
|
||||||
|
remoteAddr: net.UDPAddrFromAddrPort(from),
|
||||||
|
|
||||||
|
rdRx: wrTx, rdTx: wrRx,
|
||||||
|
wrTx: rdRx, wrRx: rdTx,
|
||||||
|
localDone: remoteDone, remoteDone: localDone,
|
||||||
|
readDeadline: makePipeDeadline(),
|
||||||
|
writeDeadline: makePipeDeadline(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
listen.clients[from.String()] = newClient // Set to clients map
|
||||||
|
listen.toAccept <- newClient.ClientConn // Send to accept
|
||||||
|
newClient.wrTx <- buff[:n]
|
||||||
|
<-newClient.rdTx // but ignore
|
||||||
|
for {
|
||||||
|
if data, ok := <-rdRx; ok {
|
||||||
|
n, err := conn.WriteToUDPAddrPort(data, from)
|
||||||
|
if err != nil {
|
||||||
|
localDone <- struct{}{}
|
||||||
|
<-remoteDone // wait remote
|
||||||
|
break // end
|
||||||
|
}
|
||||||
|
wrRx <- n // send write data
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return listen, nil
|
||||||
|
}
|
44
internal/udplisterner/v2/v2_test.go
Normal file
44
internal/udplisterner/v2/v2_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package udplisterner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListen(t *testing.T) {
|
||||||
|
addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||||
|
listen, err := Listen("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer listen.Close() // end test
|
||||||
|
go func(){
|
||||||
|
t.Logf("Waiting to accept client ...\n")
|
||||||
|
conn, err := listen.Accept()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
buff := make([]byte, 4)
|
||||||
|
if _, err := conn.Read(buff); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if bytes.Compare(buff, []byte{1, 9, 9, 1}) != 0 {
|
||||||
|
t.Fatalf("cannot get same buffer bytes")
|
||||||
|
}
|
||||||
|
conn.Write(buff)
|
||||||
|
}()
|
||||||
|
|
||||||
|
time.Sleep(time.Microsecond)
|
||||||
|
t.Logf("Connecting to %s\n", listen.Addr().String())
|
||||||
|
addr, _ = net.ResolveUDPAddr("udp", listen.Addr().String())
|
||||||
|
conn, err := net.DialUDP("udp", nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
conn.Write([]byte{1, 9, 9, 1})
|
||||||
|
conn.Read(make([]byte, 4))
|
||||||
|
}
|
@ -85,7 +85,7 @@ func (close *Client) Reader(r io.Reader) (err error) {
|
|||||||
type ClientData struct {
|
type ClientData struct {
|
||||||
Client Client // Client Destination
|
Client Client // Client Destination
|
||||||
Size uint64 // Data size
|
Size uint64 // Data size
|
||||||
Data []byte // Bytes to send
|
Data []byte `json:"-"` // Bytes to send
|
||||||
}
|
}
|
||||||
|
|
||||||
func (data ClientData) Writer(w io.Writer) error {
|
func (data ClientData) Writer(w io.Writer) error {
|
||||||
|
@ -177,6 +177,7 @@ func (res *Response) Reader(r io.Reader) error {
|
|||||||
if *res.ResizeBuffer, err = bigendian.ReadUint64(r); err != nil {
|
if *res.ResizeBuffer, err = bigendian.ReadUint64(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrInvalidBody
|
return ErrInvalidBody
|
||||||
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
||||||
)
|
)
|
||||||
@ -23,7 +24,7 @@ func getFreePort() (int, error) {
|
|||||||
// Accept any agent in ramdom port
|
// Accept any agent in ramdom port
|
||||||
type DefaultCall struct{}
|
type DefaultCall struct{}
|
||||||
|
|
||||||
func (DefaultCall) AgentShutdown(Token [36]byte) error { return nil }
|
func (DefaultCall) RegisterPing(serverTime, clientTime time.Time, Token [36]byte) error { return nil }
|
||||||
func (d DefaultCall) AgentInfo(Token [36]byte) (TunnelInfo, error) {
|
func (d DefaultCall) AgentInfo(Token [36]byte) (TunnelInfo, error) {
|
||||||
port, err := getFreePort()
|
port, err := getFreePort()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -2,15 +2,15 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/udplisterner"
|
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/udplisterner/v2"
|
||||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,15 +37,25 @@ type Tunnel struct {
|
|||||||
// Interface to server accept and reject agents sessions
|
// Interface to server accept and reject agents sessions
|
||||||
type ServerCalls interface {
|
type ServerCalls interface {
|
||||||
AgentInfo(Token [36]byte) (TunnelInfo, error)
|
AgentInfo(Token [36]byte) (TunnelInfo, error)
|
||||||
AgentShutdown(Token [36]byte) error
|
RegisterPing(serverTime, clientTime time.Time, Token [36]byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
Conn *net.UDPConn // Local listen
|
||||||
RequestBuffer uint64 // Request Buffer
|
RequestBuffer uint64 // Request Buffer
|
||||||
Tunnels map[string]Tunnel // Tunnels listened
|
Tunnels map[string]Tunnel // Tunnels listened
|
||||||
ServerCalls ServerCalls // Server call to auth and more
|
ServerCalls ServerCalls // Server call to auth and more
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (server Server) Send(to netip.AddrPort, res proto.Response) error {
|
||||||
|
buff, err := res.Wbytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = server.Conn.WriteToUDPAddrPort(buff, to)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Create new server struct
|
// Create new server struct
|
||||||
//
|
//
|
||||||
// if Calls is nil set DefaultCall and accept any new agent in random ports and TCP+UDP Proto
|
// if Calls is nil set DefaultCall and accept any new agent in random ports and TCP+UDP Proto
|
||||||
@ -62,12 +72,8 @@ func NewServer(Calls ServerCalls) Server {
|
|||||||
|
|
||||||
// Close client and send dead to agent
|
// Close client and send dead to agent
|
||||||
func (tun *Tunnel) Close() {
|
func (tun *Tunnel) Close() {
|
||||||
if tun.TCPListener != nil {
|
tun.TCPListener.Close()
|
||||||
tun.TCPListener.Close()
|
tun.UDPListener.Close()
|
||||||
}
|
|
||||||
if tun.UDPListener != nil {
|
|
||||||
tun.UDPListener.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, conn := range tun.UDPClients {
|
for key, conn := range tun.UDPClients {
|
||||||
conn.Close() // End connection
|
conn.Close() // End connection
|
||||||
@ -218,11 +224,11 @@ func (server *Server) Listen(ControllerPort uint16) (err error) {
|
|||||||
if conn, err = net.ListenUDP("udp", net.UDPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), ControllerPort))); err != nil {
|
if conn, err = net.ListenUDP("udp", net.UDPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), ControllerPort))); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
server.Conn = conn
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var err error
|
var err error
|
||||||
var req proto.Request
|
var req proto.Request
|
||||||
var res proto.Response
|
|
||||||
var readSize int
|
var readSize int
|
||||||
var addr netip.AddrPort
|
var addr netip.AddrPort
|
||||||
log.Println("waiting to request")
|
log.Println("waiting to request")
|
||||||
@ -235,24 +241,22 @@ func (server *Server) Listen(ControllerPort uint16) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := req.Reader(bytes.NewBuffer(buffer[:readSize])); err != nil {
|
if err := req.Reader(bytes.NewBuffer(buffer[:readSize])); err != nil {
|
||||||
res.BadRequest = true
|
log.Printf("From %s, cannot reader buffer: %s", addr.String(), err.Error())
|
||||||
if buffer, err = res.Wbytes(); err != nil {
|
go server.Send(addr, proto.Response{BadRequest: true}) // Send bad request to agent
|
||||||
continue // not send bad request to agent
|
|
||||||
}
|
|
||||||
conn.WriteToUDPAddrPort(buffer, addr) // Send bad request to agent
|
|
||||||
continue // Continue parsing new requests
|
continue // Continue parsing new requests
|
||||||
}
|
}
|
||||||
|
|
||||||
if ping := req.Ping; ping != nil {
|
d,_ := json.Marshal(req)
|
||||||
res.Pong = new(time.Time)
|
log.Printf("From %s: %s", addr.String(), string(d))
|
||||||
*res.Pong = time.Now()
|
|
||||||
data, _ := res.Wbytes()
|
|
||||||
conn.WriteToUDPAddrPort(data, addr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process request if tunnel is authenticated
|
// Process request if tunnel is authenticated
|
||||||
if tun, exist := server.Tunnels[addr.String()]; exist && tun.Authenticated {
|
if tun, exist := server.Tunnels[addr.String()]; exist && tun.Authenticated {
|
||||||
|
if ping := req.Ping; ping != nil {
|
||||||
|
current := time.Now()
|
||||||
|
go server.ServerCalls.RegisterPing(current, *req.Ping, tun.Token)
|
||||||
|
go server.Send(addr, proto.Response{Pong: ¤t})
|
||||||
|
continue
|
||||||
|
}
|
||||||
go tun.Request(req) // process request to tunnel
|
go tun.Request(req) // process request to tunnel
|
||||||
continue // Call next message
|
continue // Call next message
|
||||||
}
|
}
|
||||||
@ -285,45 +289,53 @@ func (server *Server) Listen(ControllerPort uint16) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !server.Tunnels[addr.String()].Authenticated && req.AgentAuth == nil {
|
if !server.Tunnels[addr.String()].Authenticated && req.AgentAuth == nil {
|
||||||
res.SendAuth = true
|
go server.Send(addr, proto.Response{SendAuth: true})
|
||||||
data, _ := res.Wbytes()
|
|
||||||
conn.WriteToUDPAddrPort(data, addr)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := server.ServerCalls.AgentInfo([36]byte(req.AgentAuth[:]))
|
info, err := server.ServerCalls.AgentInfo([36]byte(req.AgentAuth[:]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrNoAgent {
|
if err == ErrNoAgent {
|
||||||
// Client not found
|
// Client not found
|
||||||
res.Unauthorized = true
|
go server.Send(addr, proto.Response{Unauthorized: true})
|
||||||
} else {
|
} else {
|
||||||
// Cannot process request resend
|
// Cannot process request resend
|
||||||
res.SendAuth = true
|
go server.Send(addr, proto.Response{SendAuth: true})
|
||||||
}
|
}
|
||||||
data, _ := res.Wbytes()
|
|
||||||
conn.WriteToUDPAddrPort(data, addr)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close tunnels tokens listened
|
||||||
|
for ared, tun := range server.Tunnels {
|
||||||
|
if ared == addr.String() {
|
||||||
|
continue
|
||||||
|
} else if bytes.Equal(tun.Token[:], req.AgentAuth[:]) {
|
||||||
|
log.Printf("Closing agent %s", ared)
|
||||||
|
tun.Close()
|
||||||
|
delete(server.Tunnels, ared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tun := server.Tunnels[addr.String()]
|
tun := server.Tunnels[addr.String()]
|
||||||
|
tun.Token = *req.AgentAuth // Set token to tunnel
|
||||||
|
|
||||||
if info.Proto == 3 || info.Proto == 1 {
|
if info.Proto == 3 || info.Proto == 1 {
|
||||||
tun.TCPListener, err = net.ListenTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), info.PortListen)))
|
tun.TCPListener, err = net.ListenTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), info.PortListen)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.BadRequest = true
|
log.Printf("TCP Listener from %s: %s", addr.String(), err.Error())
|
||||||
data, _ := res.Wbytes()
|
go server.Send(addr, proto.Response{BadRequest: true})
|
||||||
conn.WriteToUDPAddrPort(data, addr)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go tun.TCPAccepts() // Make accepts new requests
|
go tun.TCPAccepts() // Make accepts new requests
|
||||||
}
|
}
|
||||||
if info.Proto == 3 || info.Proto == 2 {
|
if info.Proto == 3 || info.Proto == 2 {
|
||||||
tun.UDPListener, err = udplisterner.Listen("udp", fmt.Sprintf("0.0.0.0:%d", info.PortListen))
|
tun.UDPListener, err = udplisterner.Listen("udp", net.UDPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), info.PortListen)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("UDP Listener from %s: %s", addr.String(), err.Error())
|
||||||
if tun.TCPListener != nil {
|
if tun.TCPListener != nil {
|
||||||
tun.TCPListener.Close()
|
tun.TCPListener.Close()
|
||||||
}
|
}
|
||||||
res.BadRequest = true
|
go server.Send(addr, proto.Response{BadRequest: true})
|
||||||
data, _ := res.Wbytes()
|
|
||||||
conn.WriteToUDPAddrPort(data, addr)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go tun.UDPAccepts() // Make accepts new requests
|
go tun.UDPAccepts() // Make accepts new requests
|
||||||
@ -331,13 +343,11 @@ func (server *Server) Listen(ControllerPort uint16) (err error) {
|
|||||||
tun.Authenticated = true
|
tun.Authenticated = true
|
||||||
server.Tunnels[addr.String()] = tun
|
server.Tunnels[addr.String()] = tun
|
||||||
|
|
||||||
res.AgentInfo = new(proto.AgentInfo)
|
AgentInfo := new(proto.AgentInfo)
|
||||||
res.AgentInfo.Protocol = info.Proto
|
AgentInfo.Protocol = info.Proto
|
||||||
res.AgentInfo.LitenerPort = info.PortListen
|
AgentInfo.LitenerPort = info.PortListen
|
||||||
res.AgentInfo.AddrPort = addr
|
AgentInfo.AddrPort = addr
|
||||||
|
go server.Send(addr, proto.Response{AgentInfo: AgentInfo})
|
||||||
data, _ := res.Wbytes()
|
|
||||||
conn.WriteToUDPAddrPort(data, addr)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
Reference in New Issue
Block a user