Clients dynamic TX/RX sizes #1

Merged
Sirherobrine23 merged 3 commits from dynamic-size into main 2024-06-11 21:24:33 +00:00
17 changed files with 1086 additions and 277 deletions
Showing only changes of commit 24764ddd7f - Show all commits

View File

@ -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: &current})
<-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
} }

View File

@ -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)
} }
}, },
} }

View File

@ -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
View File

@ -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
View File

@ -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=

View 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
}

View 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
}

View 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))
}

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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: &current})
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