Clients dynamic TX/RX sizes #1
@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"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)
|
||||
var n int
|
||||
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
|
||||
}
|
||||
|
||||
@ -89,7 +97,9 @@ func (client Client) Send(req proto.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send token to controller to connect to tunnel
|
||||
func (client *Client) auth() (info *proto.AgentInfo, err error) {
|
||||
attemps := 0
|
||||
var res *proto.Response
|
||||
for {
|
||||
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 {
|
||||
// Wait seconds to resend token
|
||||
<-time.After(time.Second * 3)
|
||||
if attemps++; attemps >= 25 {
|
||||
err = ErrAgentUnathorized // Cannot auth
|
||||
return
|
||||
}
|
||||
continue // Reload auth
|
||||
} else if res.Unauthorized {
|
||||
// Close tunnel and break loop-de-loop 🦔
|
||||
@ -115,19 +129,29 @@ func (client *Client) auth() (info *proto.AgentInfo, err error) {
|
||||
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) {
|
||||
if client.Conn, err = net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(client.ControlAddr)); err != nil {
|
||||
return
|
||||
}
|
||||
go client.backgroud()
|
||||
return client.auth()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
log.Println("waiting response from controller")
|
||||
var res *proto.Response
|
||||
if res, err = client.Recive(); err != nil {
|
||||
log.Println(err.Error())
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
@ -56,30 +56,21 @@ var CmdClient = cli.Command{
|
||||
}
|
||||
fmt.Printf("Connected, Remote port: %d\n", info.LitenerPort)
|
||||
fmt.Printf(" Remote address: %s\n", info.AddrPort.String())
|
||||
go client.Backgroud()
|
||||
|
||||
localConnect := ctx.String("dial")
|
||||
for {
|
||||
var conn, dial net.Conn
|
||||
select {
|
||||
case tcp := <-client.NewTCPClient:
|
||||
go func() {
|
||||
conn, err := net.Dial("tcp", localConnect)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go io.Copy(conn, tcp)
|
||||
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)
|
||||
}()
|
||||
case conn = <-client.NewTCPClient:
|
||||
if dial, err = net.Dial("tcp", localConnect); err != nil {
|
||||
continue
|
||||
}
|
||||
case conn = <-client.NewUDPClient:
|
||||
if dial, err = net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(netip.MustParseAddrPort(localConnect))); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
go io.Copy(conn, dial)
|
||||
go io.Copy(dial, conn)
|
||||
}
|
||||
},
|
||||
}
|
@ -13,14 +13,6 @@ type serverCalls struct {
|
||||
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 {
|
||||
ID int64 `xorm:"pk"` // Client ID
|
||||
Username string `xorm:"varchar(32) notnull unique 'user'"` // Username
|
||||
@ -30,18 +22,35 @@ type User struct {
|
||||
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) {
|
||||
call = new(serverCalls)
|
||||
if call.XormEngine, err = xorm.NewEngine("sqlite", DBConn); err != nil {
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (call serverCalls) AgentShutdown(Token [36]byte) (err error) { return } // Ignore
|
||||
|
||||
func (call serverCalls) AgentInfo(Token [36]byte) (server.TunnelInfo, error) {
|
||||
var tun = Tun{Token: Token}
|
||||
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,
|
||||
}, 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/syndtr/goleveldb v1.0.0 // 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
|
||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // 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=
|
||||
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/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.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/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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 {
|
||||
Client Client // Client Destination
|
||||
Size uint64 // Data size
|
||||
Data []byte // Bytes to send
|
||||
Data []byte `json:"-"` // Bytes to send
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrInvalidBody
|
||||
|
@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
|
||||
)
|
||||
@ -23,7 +24,7 @@ func getFreePort() (int, error) {
|
||||
// Accept any agent in ramdom port
|
||||
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) {
|
||||
port, err := getFreePort()
|
||||
if err == nil {
|
||||
|
@ -2,15 +2,15 @@ package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -37,15 +37,25 @@ type Tunnel struct {
|
||||
// Interface to server accept and reject agents sessions
|
||||
type ServerCalls interface {
|
||||
AgentInfo(Token [36]byte) (TunnelInfo, error)
|
||||
AgentShutdown(Token [36]byte) error
|
||||
RegisterPing(serverTime, clientTime time.Time, Token [36]byte) error
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Conn *net.UDPConn // Local listen
|
||||
RequestBuffer uint64 // Request Buffer
|
||||
Tunnels map[string]Tunnel // Tunnels listened
|
||||
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
|
||||
//
|
||||
// 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
|
||||
func (tun *Tunnel) Close() {
|
||||
if tun.TCPListener != nil {
|
||||
tun.TCPListener.Close()
|
||||
}
|
||||
if tun.UDPListener != nil {
|
||||
tun.UDPListener.Close()
|
||||
}
|
||||
tun.TCPListener.Close()
|
||||
tun.UDPListener.Close()
|
||||
|
||||
for key, conn := range tun.UDPClients {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
server.Conn = conn
|
||||
|
||||
for {
|
||||
var err error
|
||||
var req proto.Request
|
||||
var res proto.Response
|
||||
var readSize int
|
||||
var addr netip.AddrPort
|
||||
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 {
|
||||
res.BadRequest = true
|
||||
if buffer, err = res.Wbytes(); err != nil {
|
||||
continue // not send bad request to agent
|
||||
}
|
||||
conn.WriteToUDPAddrPort(buffer, addr) // Send bad request to agent
|
||||
log.Printf("From %s, cannot reader buffer: %s", addr.String(), err.Error())
|
||||
go server.Send(addr, proto.Response{BadRequest: true}) // Send bad request to agent
|
||||
continue // Continue parsing new requests
|
||||
}
|
||||
|
||||
if ping := req.Ping; ping != nil {
|
||||
res.Pong = new(time.Time)
|
||||
*res.Pong = time.Now()
|
||||
data, _ := res.Wbytes()
|
||||
conn.WriteToUDPAddrPort(data, addr)
|
||||
continue
|
||||
}
|
||||
d,_ := json.Marshal(req)
|
||||
log.Printf("From %s: %s", addr.String(), string(d))
|
||||
|
||||
// Process request if tunnel is 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
|
||||
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 {
|
||||
res.SendAuth = true
|
||||
data, _ := res.Wbytes()
|
||||
conn.WriteToUDPAddrPort(data, addr)
|
||||
go server.Send(addr, proto.Response{SendAuth: true})
|
||||
continue
|
||||
}
|
||||
|
||||
info, err := server.ServerCalls.AgentInfo([36]byte(req.AgentAuth[:]))
|
||||
if err != nil {
|
||||
if err == ErrNoAgent {
|
||||
// Client not found
|
||||
res.Unauthorized = true
|
||||
go server.Send(addr, proto.Response{Unauthorized: true})
|
||||
} else {
|
||||
// Cannot process request resend
|
||||
res.SendAuth = true
|
||||
go server.Send(addr, proto.Response{SendAuth: true})
|
||||
}
|
||||
data, _ := res.Wbytes()
|
||||
conn.WriteToUDPAddrPort(data, addr)
|
||||
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.Token = *req.AgentAuth // Set token to tunnel
|
||||
|
||||
if info.Proto == 3 || info.Proto == 1 {
|
||||
tun.TCPListener, err = net.ListenTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), info.PortListen)))
|
||||
if err != nil {
|
||||
res.BadRequest = true
|
||||
data, _ := res.Wbytes()
|
||||
conn.WriteToUDPAddrPort(data, addr)
|
||||
log.Printf("TCP Listener from %s: %s", addr.String(), err.Error())
|
||||
go server.Send(addr, proto.Response{BadRequest: true})
|
||||
continue
|
||||
}
|
||||
go tun.TCPAccepts() // Make accepts new requests
|
||||
}
|
||||
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 {
|
||||
log.Printf("UDP Listener from %s: %s", addr.String(), err.Error())
|
||||
if tun.TCPListener != nil {
|
||||
tun.TCPListener.Close()
|
||||
}
|
||||
res.BadRequest = true
|
||||
data, _ := res.Wbytes()
|
||||
conn.WriteToUDPAddrPort(data, addr)
|
||||
go server.Send(addr, proto.Response{BadRequest: true})
|
||||
continue
|
||||
}
|
||||
go tun.UDPAccepts() // Make accepts new requests
|
||||
@ -331,13 +343,11 @@ func (server *Server) Listen(ControllerPort uint16) (err error) {
|
||||
tun.Authenticated = true
|
||||
server.Tunnels[addr.String()] = tun
|
||||
|
||||
res.AgentInfo = new(proto.AgentInfo)
|
||||
res.AgentInfo.Protocol = info.Proto
|
||||
res.AgentInfo.LitenerPort = info.PortListen
|
||||
res.AgentInfo.AddrPort = addr
|
||||
|
||||
data, _ := res.Wbytes()
|
||||
conn.WriteToUDPAddrPort(data, addr)
|
||||
AgentInfo := new(proto.AgentInfo)
|
||||
AgentInfo.Protocol = info.Proto
|
||||
AgentInfo.LitenerPort = info.PortListen
|
||||
AgentInfo.AddrPort = addr
|
||||
go server.Send(addr, proto.Response{AgentInfo: AgentInfo})
|
||||
continue
|
||||
}
|
||||
return
|
||||
|
Reference in New Issue
Block a user