Update server and Client

Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
This commit is contained in:
Matheus Sampaio Queiroga 2024-06-16 01:30:10 -03:00
parent 24764ddd7f
commit 4f6c1af28b
Signed by: Sirherobrine23
GPG Key ID: 01CCABE2580AFEBC
17 changed files with 643 additions and 980 deletions

@ -1,261 +1,179 @@
package client
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net"
"net/netip"
"reflect"
"time"
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/pipe"
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
)
var (
ErrAgentUnathorized error = errors.New("cannot auth agent and controller not accepted")
ErrCannotConnect error = errors.New("cannot connect to controller")
)
type NewClient struct {
Client proto.Client
Writer net.Conn
}
type Client struct {
ControlAddr netip.AddrPort // Controller address
Conn net.Conn // Agent controller connection
Token proto.AgentAuth // Agent Token
ResponseBuffer uint64 // Agent Reponse Buffer size, Initial size from proto.DataSize
RequestBuffer uint64 // Controller send bytes, initial size from proto.DataSize
LastPong *time.Time // Last pong response
UDPClients map[string]net.Conn // UDP Clients
TCPClients map[string]net.Conn // TCP Clients
NewUDPClient chan net.Conn // Accepts new UDP Clients
NewTCPClient chan net.Conn // Accepts new TCP Clients
Token [36]byte
RemoteAdress []netip.AddrPort
clientsTCP map[string]net.Conn
clientsUDP map[string]net.Conn
NewClient chan NewClient
Conn *net.UDPConn
AgentInfo *proto.AgentInfo
}
func NewClient(ControlAddr netip.AddrPort, Token [36]byte) Client {
return Client{
ControlAddr: ControlAddr,
Conn: nil,
Token: Token,
ResponseBuffer: proto.DataSize,
RequestBuffer: proto.DataSize,
UDPClients: make(map[string]net.Conn),
TCPClients: make(map[string]net.Conn),
NewUDPClient: make(chan net.Conn),
NewTCPClient: make(chan net.Conn),
func CreateClient(Addres []netip.AddrPort, Token [36]byte) (*Client, error) {
cli := &Client{
Token: Token,
RemoteAdress: Addres,
clientsTCP: make(map[string]net.Conn),
clientsUDP: make(map[string]net.Conn),
NewClient: make(chan NewClient),
}
if err := cli.Setup(); err != nil {
return cli, err
}
return cli, nil
}
// Close client.Conn and Clients
func (client *Client) Close() error {
client.Conn.Close()
close(client.NewTCPClient)
close(client.NewUDPClient)
for addr, tunUDP := range client.UDPClients {
tunUDP.Close()
delete(client.UDPClients, addr)
}
for addr, tunTCP := range client.TCPClients {
tunTCP.Close()
delete(client.TCPClients, addr)
}
return nil
func (client *Client) Send(req proto.Request) error {
return proto.WriteRequest(client.Conn, req)
}
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
}
func (client *Client) Setup() error {
for _, addr := range client.RemoteAdress {
var err error
if client.Conn, err = net.DialUDP("udp", nil, net.UDPAddrFromAddrPort(addr)); err != nil {
continue
}
return
}
res = new(proto.Response)
if err = res.Reader(bytes.NewBuffer(recBuff[:n])); err != nil {
return
if client.Conn == nil {
return ErrCannotConnect
}
d,_:=json.Marshal(res)
log.Println(string(d))
return
}
func (client Client) Send(req proto.Request) error {
buff, err := req.Wbytes()
if err != nil {
return err
} else if _, err = client.Conn.Write(buff); err != nil {
return err
}
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
var auth = proto.AgentAuth(client.Token)
for {
if err = client.Send(proto.Request{AgentAuth: &client.Token}); err != nil {
client.Conn.Close()
return
} else if res, err = client.Recive(); err != nil {
client.Conn.Close()
return
}
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
client.Send(proto.Request{AgentAuth: &auth})
res, err := proto.ReaderResponse(client.Conn)
if err != nil {
panic(err) // TODO: Require fix to agent shutdown graced
} else if res.Unauthorized {
// Close tunnel and break loop-de-loop 🦔
client.Conn.Close()
err = ErrAgentUnathorized
return
return ErrCannotConnect
} else if res.AgentInfo == nil {
continue
}
client.AgentInfo = res.AgentInfo
break
}
return res.AgentInfo, nil
}
// 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) {
go func(){
for {
var current = time.Now()
client.Send(proto.Request{Ping: &current})
<-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
}
continue
}
if res.ResizeBuffer != nil {
client.ResponseBuffer = *res.ResizeBuffer
} else if res.Pong != nil {
client.LastPong = res.Pong
continue // Wait to next response
} else if res.BadRequest {
continue
} else if res.Unauthorized {
return ErrAgentUnathorized
} else if res.SendAuth {
if _, err := client.auth(); err != nil {
return err
}
} else if data := res.DataRX; data != nil {
if _, exist := client.TCPClients[data.Client.Client.String()]; !exist && data.Client.Proto == proto.ProtoTCP {
toAgent, toClient := pipe.CreatePipe(client.Conn.RemoteAddr(), net.TCPAddrFromAddrPort(data.Client.Client))
client.TCPClients[data.Client.Client.String()] = toClient
client.NewTCPClient <- toAgent // send to Accept
go func() {
for {
buff := make([]byte, client.RequestBuffer)
n, err := toClient.Read(buff)
if err != nil {
if err == io.EOF {
delete(client.TCPClients, data.Client.Client.String())
go client.Send(proto.Request{ClientClose: &data.Client})
go toClient.Close()
break
}
continue
} else {
if client.RequestBuffer-uint64(n) == 0 {
client.RequestBuffer += 500
var req proto.Request
req.ResizeBuffer = new(uint64)
*req.ResizeBuffer = client.RequestBuffer
client.Send(req)
<-time.After(time.Microsecond)
}
go client.Send(proto.Request{
DataTX: &proto.ClientData{
Client: data.Client,
Size: uint64(n),
Data: buff[:n],
},
})
}
}
}()
} else if _, exist := client.UDPClients[data.Client.Client.String()]; !exist && data.Client.Proto == proto.ProtoUDP {
toAgent, toClient := pipe.CreatePipe(client.Conn.RemoteAddr(), net.UDPAddrFromAddrPort(data.Client.Client))
client.UDPClients[data.Client.Client.String()] = toClient
client.NewUDPClient <- toAgent // send to Accept
go func() {
for {
buff := make([]byte, client.RequestBuffer)
n, err := toClient.Read(buff)
if err != nil {
if err == io.EOF {
delete(client.UDPClients, data.Client.Client.String())
go client.Send(proto.Request{ClientClose: &data.Client})
go toClient.Close()
break
}
continue
} else {
if client.RequestBuffer-uint64(n) == 0 {
var req proto.Request
req.ResizeBuffer = new(uint64)
*req.ResizeBuffer = uint64(n)
go client.Send(req)
}
go client.Send(proto.Request{
DataTX: &proto.ClientData{
Client: data.Client,
Size: uint64(n),
Data: buff[:n],
},
})
}
}
}()
}
if tcpConn, exist := client.TCPClients[data.Client.Client.String()]; exist && data.Client.Proto == proto.ProtoTCP {
go tcpConn.Write(data.Data)
} else if udpConn, exist := client.UDPClients[data.Client.Client.String()]; exist && data.Client.Proto == proto.ProtoUDP {
go udpConn.Write(data.Data)
}
} else if closeClient := res.CloseClient; closeClient != nil {
if tcpConn, exist := client.TCPClients[closeClient.Client.String()]; exist && closeClient.Proto == proto.ProtoTCP {
delete(client.TCPClients, closeClient.Client.String())
go tcpConn.Close()
} else if udpConn, exist := client.UDPClients[closeClient.Client.String()]; exist && closeClient.Proto == proto.ProtoUDP {
delete(client.UDPClients, closeClient.Client.String())
go udpConn.Close()
}
}
}
go client.handlers()
return nil
}
type toWr struct {
Proto uint8
To netip.AddrPort
tun *Client
}
func (t toWr) Write(w []byte) (int, error) {
err := t.tun.Send(proto.Request{
DataTX: &proto.ClientData{
Client: proto.Client{
Client: t.To,
Proto: t.Proto,
},
Size: uint64(len(w)),
Data: w[:],
},
})
if err == nil {
return len(w), nil
}
return 0, err
}
func (tun *Client) GetTargetWrite(Proto uint8, To netip.AddrPort) io.Writer {
return &toWr{Proto: Proto, To: To, tun: tun}
}
func (client *Client) handlers() {
for {
res, err := proto.ReaderResponse(client.Conn)
if err != nil {
panic(err) // TODO: Require fix to agent shutdown graced
} else if res.Unauthorized {
panic(fmt.Errorf("cannot recive requests")) // TODO: Require fix to agent shutdown graced
} else if res.SendAuth {
var auth = proto.AgentAuth(client.Token)
for {
client.Send(proto.Request{AgentAuth: &auth})
res, err := proto.ReaderResponse(client.Conn)
if err != nil {
panic(err) // TODO: Require fix to agent shutdown graced
} else if res.Unauthorized {
return
} else if res.AgentInfo == nil {
continue
}
client.AgentInfo = res.AgentInfo
break
}
} else if cl := *res.CloseClient; res.CloseClient != nil {
if cl.Proto == proto.ProtoTCP {
if tun, ok := client.clientsTCP[cl.Client.String()]; ok {
tun.Close()
}
} else if cl.Proto == proto.ProtoUDP {
if tun, ok := client.clientsUDP[cl.Client.String()]; ok {
tun.Close()
}
}
} else if data := *res.DataRX; res.DataRX != nil {
if data.Client.Proto == proto.ProtoTCP {
if _, ok := client.clientsTCP[data.Client.Client.String()]; !ok {
toClient, toAgent := pipe.CreatePipe(net.TCPAddrFromAddrPort(data.Client.Client), net.TCPAddrFromAddrPort(data.Client.Client))
client.NewClient <- NewClient{
Client: data.Client,
Writer: toClient,
}
client.clientsTCP[data.Client.Client.String()] = toAgent
go func() {
io.Copy(client.GetTargetWrite(proto.ProtoTCP, data.Client.Client), toAgent)
delete(client.clientsTCP, data.Client.Client.String())
}()
}
} else if data.Client.Proto == proto.ProtoUDP {
if _, ok := client.clientsUDP[data.Client.Client.String()]; !ok {
toClient, toAgent := pipe.CreatePipe(net.UDPAddrFromAddrPort(data.Client.Client), net.UDPAddrFromAddrPort(data.Client.Client))
client.NewClient <- NewClient{
Client: data.Client,
Writer: toClient,
}
client.clientsUDP[data.Client.Client.String()] = toAgent
go func() {
io.Copy(client.GetTargetWrite(proto.ProtoUDP, data.Client.Client), toAgent)
delete(client.clientsUDP, data.Client.Client.String())
}()
}
}
if data.Client.Proto == proto.ProtoTCP {
if tun, ok := client.clientsTCP[data.Client.Client.String()]; ok {
go tun.Write(data.Data)
}
} else if data.Client.Proto == proto.ProtoUDP {
if tun, ok := client.clientsUDP[data.Client.Client.String()]; ok {
go tun.Write(data.Data)
}
}
}
}
}

@ -13,21 +13,21 @@ import (
)
var CmdClient = cli.Command{
Name: "client",
Name: "client",
Aliases: []string{"c"},
Usage: "connect to controller server and bind new requests to local port",
Usage: "connect to controller server and bind new requests to local port",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "url",
Name: "url",
Required: true,
Aliases: []string{"host", "u"},
Usage: `host string to connect to controller, example: "example.com:5522"`,
Aliases: []string{"host", "u"},
Usage: `host string to connect to controller, example: "example.com:5522"`,
},
&cli.StringFlag{
Name: "token",
Name: "token",
Required: true,
Usage: "agent token",
Aliases: []string{"t"},
Usage: "agent token",
Aliases: []string{"t"},
Action: func(ctx *cli.Context, s string) error {
if _, err := uuid.Parse(s); err == nil {
return nil
@ -38,10 +38,10 @@ var CmdClient = cli.Command{
},
},
&cli.StringFlag{
Name: "dial",
Name: "dial",
Required: true,
Usage: `dial connection, default is "localhost:80"`,
Aliases: []string{"d"},
Usage: `dial connection, default is "localhost:80"`,
Aliases: []string{"d"},
},
},
Action: func(ctx *cli.Context) (err error) {
@ -49,28 +49,34 @@ var CmdClient = cli.Command{
if addr, err = netip.ParseAddrPort(ctx.String("url")); err != nil {
return
}
client := client.NewClient(addr, [36]byte([]byte(ctx.String("token"))))
var info *proto.AgentInfo
if info, err = client.Dial(); err != nil {
client, err := client.CreateClient([]netip.AddrPort{addr}, [36]byte([]byte(ctx.String("token"))))
if err != nil {
return err
}
fmt.Printf("Connected, Remote port: %d\n", info.LitenerPort)
fmt.Printf(" Remote address: %s\n", info.AddrPort.String())
fmt.Printf("Connected, Remote address: %s\n", client.AgentInfo.AddrPort.String())
if client.AgentInfo.Protocol == proto.ProtoUDP {
fmt.Printf(" Port: UDP %d\n", client.AgentInfo.UDPPort)
} else if client.AgentInfo.Protocol == proto.ProtoTCP {
fmt.Printf(" Port: TCP %d\n", client.AgentInfo.TCPPort)
} else if client.AgentInfo.Protocol == proto.ProtoBoth {
fmt.Printf(" Ports UDP %d and TCP %d\n", client.AgentInfo.UDPPort, client.AgentInfo.TCPPort)
}
localConnect := ctx.String("dial")
for {
var conn, dial net.Conn
select {
case conn = <-client.NewTCPClient:
client := <-client.NewClient
var dial net.Conn
if client.Client.Proto == proto.ProtoTCP {
if dial, err = net.Dial("tcp", localConnect); err != nil {
continue
}
case conn = <-client.NewUDPClient:
} else {
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)
go io.Copy(client.Writer, dial)
go io.Copy(dial, client.Writer)
}
},
}
}

@ -10,6 +10,7 @@ import (
)
var description string = `pproxit is a proxy that allows anyone to host a server without port forwarding. We use tunneling. Only the server needs to run the program, not every player!`
func main() {
app := cli.NewApp()
app.Name = "pproxit"

@ -1,33 +1,34 @@
package server
import (
"net/netip"
"github.com/urfave/cli/v2"
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
"sirherobrine23.org/Minecraft-Server/go-pproxit/server"
)
var CmdServer = cli.Command{
Name: "server",
Usage: "Create local server and open controller ports",
Name: "server",
Usage: "Create local server and open controller ports",
Aliases: []string{"s"},
Flags: []cli.Flag{
&cli.IntFlag{
Name: "port",
Value: 5522,
Name: "port",
Value: 5522,
Aliases: []string{"p"},
Usage: "Set controller port to watcher UDP requests",
Usage: "Set controller port to watcher UDP requests",
},
&cli.StringFlag{
Name: "log",
Value: "silence",
Name: "log",
Value: "silence",
Aliases: []string{"l"},
Usage: "set server log: silence, 0 or verbose, 2",
Usage: "set server log: silence, 0 or verbose, 2",
},
&cli.StringFlag{
Name: "db",
Value: "./pproxit.db",
Name: "db",
Value: "./pproxit.db",
Aliases: []string{"d"},
Usage: "sqlite file path",
Usage: "sqlite file path",
},
},
Action: func(ctx *cli.Context) error {
@ -35,8 +36,10 @@ var CmdServer = cli.Command{
if err != nil {
return err
}
pproxitServer := server.NewServer(calls)
pproxitServer.RequestBuffer = proto.PacketDataSize * 2 // More initial buffer request
return pproxitServer.Listen(uint16(ctx.Int("port")))
pproxitServer, err := server.NewController(calls, netip.AddrPortFrom(netip.IPv4Unspecified(), uint16(ctx.Int("port"))))
if err != nil {
return err
}
return <-pproxitServer.ProcessError
},
}
}

@ -1,6 +1,7 @@
package server
import (
"net/netip"
"time"
_ "modernc.org/sqlite"
@ -23,11 +24,12 @@ type User struct {
}
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
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
TPCListen uint16 // Port listen TCP agent
UDPListen uint16 // Port listen UDP agent
}
type Ping struct {
@ -51,35 +53,29 @@ func NewCall(DBConn string) (call *serverCalls, err error) {
return
}
func (call serverCalls) AgentInfo(Token [36]byte) (server.TunnelInfo, error) {
type TunCallbcks struct {
tunID int64
XormEngine *xorm.Engine
}
func (tun *TunCallbcks) BlockedAddr(AddrPort netip.Addr) bool { return false }
func (tun *TunCallbcks) AgentPing(agent, server time.Time) {}
func (tun *TunCallbcks) AgentShutdown(onTime time.Time) {}
func (tun *TunCallbcks) RegisterRX(client netip.AddrPort, Size int, Proto uint8) {}
func (tun *TunCallbcks) RegisterTX(client netip.AddrPort, Size int, Proto uint8) {}
func (caller *serverCalls) AgentAuthentication(Token [36]byte) (server.TunnelInfo, error) {
var tun = Tun{Token: Token}
if ok, err := call.XormEngine.Get(&tun); err != nil || !ok {
if ok, err := caller.XormEngine.Get(&tun); err != nil || !ok {
if !ok {
return server.TunnelInfo{}, server.ErrNoAgent
return server.TunnelInfo{}, server.ErrAuthAgentFail
}
return server.TunnelInfo{}, err
}
return server.TunnelInfo{
PortListen: tun.PortListen,
Proto: tun.Proto,
Proto: tun.Proto,
TCPPort: tun.TPCListen,
UDPPort: tun.UDPListen,
Callbacks: &TunCallbcks{tunID: tun.ID, XormEngine: caller.XormEngine},
}, 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
}

5
go.mod

@ -5,7 +5,7 @@ go 1.22.3
require (
github.com/google/uuid v1.6.0
github.com/urfave/cli/v2 v2.27.2
modernc.org/sqlite v1.30.0
modernc.org/sqlite v1.30.1
xorm.io/xorm v1.3.9
)
@ -24,10 +24,9 @@ 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
modernc.org/libc v1.52.1 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect

15
go.sum

@ -60,9 +60,8 @@ 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=
@ -84,16 +83,16 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs=
modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA=
modernc.org/ccgo/v4 v4.17.10 h1:6wrtRozgrhCxieCeJh85QsxkX/2FFrT9hdaWPlbn4Zo=
modernc.org/ccgo/v4 v4.17.10/go.mod h1:0NBHgsqTTpm9cA5z2ccErvGZmtntSM9qD2kFAs6pjXM=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.50.9 h1:hIWf1uz55lorXQhfoEoezdUHjxzuO6ceshET/yWjSjk=
modernc.org/libc v1.50.9/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE=
modernc.org/libc v1.52.1 h1:uau0VoiT5hnR+SpoWekCKbLqm7v6dhRL3hI+NQhgN3M=
modernc.org/libc v1.52.1/go.mod h1:HR4nVzFDSDizP620zcMCgjb1/8xk2lg5p/8yjfGv1IQ=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
@ -102,8 +101,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.30.0 h1:8YhPUs/HTnlEgErn/jSYQTwHN/ex8CjHHjg+K9iG7LM=
modernc.org/sqlite v1.30.0/go.mod h1:cgkTARJ9ugeXSNaLBPK3CqbOe7Ec7ZhWPoMFGldEYEw=
modernc.org/sqlite v1.30.1 h1:YFhPVfu2iIgUf9kuA1CR7iiHdcEEsI2i+yjRYHscyxk=
modernc.org/sqlite v1.30.1/go.mod h1:DUmsiWQDaAvU4abhc/N+djlom/L2o8f7gZ95RCvyoLU=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

@ -82,4 +82,4 @@ func ReadUint64(r io.Reader) (uint64, error) {
}
func WriteUint64(w io.Writer, value uint64) error {
return writeStream[uint64](w, value)
}
}

@ -117,7 +117,7 @@ func CreatePipe(LocalAddress, RemoteAddress net.Addr) (net.Conn, net.Conn) {
done2 := make(chan struct{})
p1 := &pipe{
localAddr: LocalAddress,
localAddr: LocalAddress,
remoteAddr: RemoteAddress,
rdRx: cb1, rdTx: cn1,
@ -127,7 +127,7 @@ func CreatePipe(LocalAddress, RemoteAddress net.Addr) (net.Conn, net.Conn) {
writeDeadline: makePipeDeadline(),
}
p2 := &pipe{
localAddr: LocalAddress,
localAddr: LocalAddress,
remoteAddr: RemoteAddress,
rdRx: cb2, rdTx: cn2,

@ -1,201 +1,64 @@
package udplisterner
import (
"bufio"
"io"
"net"
"os"
"sync"
"net/netip"
"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
type PipeConn struct {
root *net.UDPConn
to, localAddr netip.AddrPort
buff *bufio.ReadWriter
closed bool
closedChan chan struct{}
}
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
func NewConn(root *net.UDPConn, LocalAddr, to netip.AddrPort, buff *bufio.ReadWriter) net.Conn {
return &PipeConn{
root: root,
to: to,
localAddr: LocalAddr,
closedChan: make(chan struct{}),
closed: false,
buff: buff,
}
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{})
// Send close to channel
func (conn *PipeConn) Close() error {
conn.closedChan <- struct{}{}
conn.closed = true // end channel
conn.buff.Discard(conn.buff.Available())
conn.buff.Flush()
return nil
}
func (conn PipeConn) LocalAddr() net.Addr {
return net.UDPAddrFromAddrPort(conn.localAddr)
}
func (conn PipeConn) RemoteAddr() net.Addr {
return net.UDPAddrFromAddrPort(conn.to)
}
// Write direct to root UDP Connection
func (conn PipeConn) Write(w []byte) (int, error) {
return conn.root.WriteToUDPAddrPort(w, conn.to)
}
func (PipeConn) SetDeadline(time.Time) error { return nil }
func (PipeConn) SetWriteDeadline(time.Time) error { return nil }
func (PipeConn) SetReadDeadline(time.Time) error { return nil }
func (conn PipeConn) Read(r []byte) (int, error) {
for {
if conn.closed {
return 0, io.EOF
} else if conn.buff.Available() >= len(r) {
return conn.buff.Read(r)
}
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)
<-time.After(time.Millisecond) // wait 1ms
}
}
// 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
}

@ -1,111 +1,97 @@
/*
Lidar com pacotes de varios tamanhos
*/
package udplisterner
import (
"io"
"bufio"
"bytes"
"log"
"net"
"net/netip"
"sync"
)
type client struct {
ClientConn *pipe
rdRx, wrTx chan []byte
rdTx, wrRx chan int
localDone, remoteDone chan struct{}
type Udplisterner struct {
Log *log.Logger // Write request to Debug
conn *net.UDPConn // root listen connection
newClientErr chan error
newClient chan net.Conn
currentClients map[string]*bufio.ReadWriter
locker sync.RWMutex
}
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
func (list *Udplisterner) handle() {
defer list.conn.Close()
localAddr := list.conn.LocalAddr().String()
var readBuff int = 1024 * 8
for {
buff := make([]byte, readBuff)
list.Log.Printf("%s: Reading from %d bytes\n", localAddr, readBuff)
n, from, err := list.conn.ReadFromUDPAddrPort(buff)
if err != nil {
list.Log.Printf("closing readers, err: %s", err.Error())
list.newClientErr <- err
break
} else if n == readBuff {
readBuff += 1024 // Grow buffer size
list.Log.Printf("%s: Growing from %d to %d\n", localAddr, readBuff-1024, readBuff)
}
return rec.(net.Conn), nil
list.locker.RLock() // Read locker
if client, ok := list.currentClients[from.String()]; ok {
list.Log.Printf("%s: Caching %d bytes to %s\n", localAddr, n, from.String())
client.Write(buff[:n])
list.locker.RUnlock() // Unlocker
continue
}
list.Log.Printf("%s: New client %s\n", localAddr, from.String())
list.locker.RUnlock() // Unlocker
list.locker.Lock() // Locker map
bufferd := bufio.NewReadWriter(bufio.NewReader(bytes.NewReader(buff[:n])), &bufio.Writer{})
clientConn := NewConn(list.conn, netip.MustParseAddrPort(list.conn.LocalAddr().String()), from, bufferd)
list.currentClients[from.String()] = bufferd
list.locker.Unlock() // Unlocker map
go func() {
list.newClient <- clientConn
<-clientConn.(*PipeConn).closedChan
}()
}
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 {
func Listen(network string, laddr netip.AddrPort) (net.Listener, error) {
return Listener(network, net.UDPAddrFromAddrPort(laddr))
}
func Listener(network string, laddr *net.UDPAddr) (net.Listener, error) {
conn, err := net.ListenUDP(network, laddr)
if 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
}
}()
}
}()
listen := &Udplisterner{
conn: conn,
}
go listen.handle()
return listen, nil
}
func (c *Udplisterner) Addr() net.Addr { return c.conn.LocalAddr() }
func (c *Udplisterner) Close() error {
c.conn.Close()
c.locker.Lock()
defer c.locker.Unlock()
for key := range c.currentClients {
delete(c.currentClients, key)
}
return nil
}
func (c *Udplisterner) Accept() (net.Conn, error) {
select {
case client := <-c.newClient:
return client, nil
case err := <-c.newClientErr:
return nil, err
default:
return nil, net.ErrClosed
}
}

@ -3,18 +3,19 @@ package udplisterner
import (
"bytes"
"net"
"net/netip"
"testing"
"time"
)
func TestListen(t *testing.T) {
addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:0")
listen, err := Listen("udp", addr)
listen, err := Listener("udp", net.UDPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), 0)))
if err != nil {
t.Fatal(err)
}
defer listen.Close() // end test
go func(){
go func() {
t.Logf("Waiting to accept client ...\n")
conn, err := listen.Accept()
if err != nil {
@ -41,4 +42,4 @@ func TestListen(t *testing.T) {
defer conn.Close()
conn.Write([]byte{1, 9, 9, 1})
conn.Read(make([]byte, 4))
}
}

@ -14,7 +14,6 @@ const (
ReqPing uint64 = 2 // Time ping
ReqCloseClient uint64 = 3 // Close client
ReqClientData uint64 = 4 // Send data
ReqResize uint64 = 5 // Resize request buffer
)
var (
@ -45,6 +44,21 @@ type Request struct {
ResizeBuffer *uint64 // Resize request buffer
}
func ReaderRequest(r io.Reader) (*Request, error) {
res := &Request{}
if err := res.Reader(r); err != nil {
return nil, err
}
return res, nil
}
func WriteRequest(w io.Writer, res Request) error {
if err := res.Writer(w); err != nil {
return err
}
return nil
}
// Get Bytes from Request
func (req Request) Wbytes() ([]byte, error) {
buff := new(bytes.Buffer)
@ -75,11 +89,6 @@ func (req Request) Writer(w io.Writer) error {
return err
}
return data.Writer(w)
} else if req.ResizeBuffer != nil {
if err := bigendian.WriteUint64(w, ReqResize); err != nil {
return err
}
return bigendian.WriteUint64(w, *req.ResizeBuffer)
}
return ErrInvalidBody
}
@ -105,10 +114,6 @@ func (req *Request) Reader(r io.Reader) (err error) {
} else if reqID == ReqClientData {
req.DataTX = new(ClientData)
return req.DataTX.Reader(r)
} else if reqID == ReqResize {
req.ResizeBuffer = new(uint64)
*req.ResizeBuffer, err = bigendian.ReadUint64(r)
return
}
return ErrInvalidBody
}

@ -21,15 +21,17 @@ const (
)
type AgentInfo struct {
Protocol uint8 // Proto supported (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
LitenerPort uint16 // Controller port listened
AddrPort netip.AddrPort // request address and port
Protocol uint8 // Proto supported (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
UDPPort, TCPPort uint16 // Controller port listened
AddrPort netip.AddrPort // request address and port
}
func (agent AgentInfo) Writer(w io.Writer) error {
if err := bigendian.WriteUint8(w, agent.Protocol); err != nil {
return err
} else if err := bigendian.WriteUint16(w, agent.LitenerPort); err != nil {
} else if err := bigendian.WriteUint16(w, agent.UDPPort); err != nil {
return err
} else if err := bigendian.WriteUint16(w, agent.TCPPort); err != nil {
return err
}
addr := agent.AddrPort.Addr()
@ -54,7 +56,9 @@ func (agent AgentInfo) Writer(w io.Writer) error {
func (agent *AgentInfo) Reader(r io.Reader) (err error) {
if agent.Protocol, err = bigendian.ReadUint8(r); err != nil {
return
} else if agent.LitenerPort, err = bigendian.ReadUint16(r); err != nil {
} else if agent.UDPPort, err = bigendian.ReadUint16(r); err != nil {
return
} else if agent.TCPPort, err = bigendian.ReadUint16(r); err != nil {
return
}
var addrFamily uint8
@ -87,14 +91,28 @@ type Response struct {
BadRequest bool // Controller accepted packet so cannot process Request
SendAuth bool // Send Agent token
AgentInfo *AgentInfo // Agent Info
Pong *time.Time // ping response
ResizeBuffer *uint64 // Resize Agent response
AgentInfo *AgentInfo // Agent Info
Pong *time.Time // ping response
CloseClient *Client // Controller end client
DataRX *ClientData // Controller recive data from client
}
func ReaderResponse(r io.Reader) (*Response, error) {
res := &Response{}
if err := res.Reader(r); err != nil {
return nil, err
}
return res, nil
}
func WriteResponse(w io.Writer, res Response) error {
if err := res.Writer(w); err != nil {
return err
}
return nil
}
// Get Bytes from Response
func (req Response) Wbytes() ([]byte, error) {
buff := new(bytes.Buffer)
@ -131,11 +149,6 @@ func (res Response) Writer(w io.Writer) error {
return err
}
return info.Writer(w)
} else if res.ResizeBuffer != nil {
if err := bigendian.WriteUint64(w, ResResize); err != nil {
return err
}
return bigendian.WriteUint64(w, *res.ResizeBuffer)
}
return ErrInvalidBody
}
@ -171,13 +184,6 @@ func (res *Response) Reader(r io.Reader) error {
res.Pong = new(time.Time)
*res.Pong = time.UnixMilli(unixMil)
return nil
} else if resID == ResResize {
var err error
res.ResizeBuffer = new(uint64)
if *res.ResizeBuffer, err = bigendian.ReadUint64(r); err != nil {
return err
}
return nil
}
return ErrInvalidBody

@ -1,37 +0,0 @@
package server
import (
"net"
"time"
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
)
func getFreePort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
// Accept any agent in ramdom port
type DefaultCall struct{}
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 {
return TunnelInfo{
PortListen: uint16(port),
Proto: proto.ProtoBoth,
}, nil
}
return TunnelInfo{}, err
}

@ -1,354 +1,90 @@
package server
import (
"bytes"
"encoding/json"
"errors"
"io"
"log"
"net"
"net/netip"
"time"
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/udplisterner/v2"
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
)
var (
ErrNoAgent error = errors.New("agent not found")
ErrAuthAgentFail error = errors.New("cannot authenticate agent") // Send unathorized client and close new accepts from current port
)
type TunnelInfo struct {
PortListen uint16 // Port to listen Listeners
Proto uint8 // (proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth)
}
type Tunnel struct {
Token [36]byte // Agent Token
Authenticated bool // Agent Authenticated and avaible to recive/transmiter data
ResponseBuffer uint64 // Send Reponse size
UDPListener net.Listener // Accept connections from UDP Clients
TCPListener net.Listener // Accept connections from TCP Clients
UDPClients map[string]net.Conn // Current clients connected in UDP Socket
TCPClients map[string]net.Conn // Current clients connected in TCP Socket
SendToAgent chan proto.Response // Send data to agent
}
// Interface to server accept and reject agents sessions
type ServerCalls interface {
AgentInfo(Token [36]byte) (TunnelInfo, error)
RegisterPing(serverTime, clientTime time.Time, Token [36]byte) error
type ServerCall interface {
// Authenticate agents
AgentAuthentication(Token [36]byte) (TunnelInfo, 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
ControllConn net.Listener
ProcessError chan error
ControlCalls ServerCall
Agents map[string]*Tunnel
}
func (server Server) Send(to netip.AddrPort, res proto.Response) error {
buff, err := res.Wbytes()
func NewController(calls ServerCall, local netip.AddrPort) (*Server, error) {
conn, err := udplisterner.Listen("udp", local)
if err != nil {
return err
return nil, err
}
_, err = server.Conn.WriteToUDPAddrPort(buff, to)
return err
tuns := &Server{
ControllConn: conn,
ControlCalls: calls,
Agents: make(map[string]*Tunnel),
ProcessError: make(chan error),
}
go tuns.handler()
return tuns, nil
}
// Create new server struct
//
// if Calls is nil set DefaultCall and accept any new agent in random ports and TCP+UDP Proto
func NewServer(Calls ServerCalls) Server {
if Calls == nil {
Calls = DefaultCall{}
}
return Server{
RequestBuffer: proto.DataSize,
ServerCalls: Calls,
Tunnels: make(map[string]Tunnel),
}
}
// Close client and send dead to agent
func (tun *Tunnel) Close() {
tun.TCPListener.Close()
tun.UDPListener.Close()
for key, conn := range tun.UDPClients {
conn.Close() // End connection
delete(tun.UDPClients, key) // Delete from map
}
for key, conn := range tun.TCPClients {
conn.Close() // End connection
delete(tun.UDPClients, key) // Delete from map
}
close(tun.SendToAgent)
}
// Process UDP Connections from listerner
func (tun *Tunnel) UDPAccepts() {
func (controller *Server) handlerConn(conn net.Conn) {
defer conn.Close() // End agent accepts
var req *proto.Request
var tunnelInfo TunnelInfo
var err error
for {
conn, err := tun.UDPListener.Accept()
if err != nil {
time.Sleep(time.Second)
if req, err = proto.ReaderRequest(conn); err != nil {
break
} else if req.AgentAuth == nil {
proto.WriteResponse(conn, proto.Response{SendAuth: true})
continue
}
clientAddr := netip.MustParseAddrPort(conn.RemoteAddr().String())
tun.UDPClients[conn.RemoteAddr().String()] = conn
go func() {
for {
buff := make([]byte, tun.ResponseBuffer)
n, err := conn.Read(buff)
if err != nil {
go conn.Close()
tun.SendToAgent <- proto.Response{
CloseClient: &proto.Client{
Client: clientAddr,
Proto: proto.ProtoUDP,
},
}
break
}
if tun.ResponseBuffer-uint64(n) == 0 {
tun.ResponseBuffer += 500
res := proto.Response{}
res.ResizeBuffer = new(uint64)
*res.ResizeBuffer = tun.ResponseBuffer
tun.SendToAgent <- res
<-time.After(time.Microsecond)
}
tun.SendToAgent <- proto.Response{
DataRX: &proto.ClientData{
Size: uint64(n),
Data: buff[:n],
Client: proto.Client{
Client: clientAddr,
Proto: proto.ProtoUDP,
},
},
}
if tunnelInfo, err = controller.ControlCalls.AgentAuthentication([36]byte(req.AgentAuth[:])); err != nil {
if err == ErrAuthAgentFail {
proto.WriteResponse(conn, proto.Response{Unauthorized: true})
return
}
}()
proto.WriteResponse(conn, proto.Response{BadRequest: true})
continue
}
break
}
// Close current tunnel
if tun, ok := controller.Agents[string(req.AgentAuth[:])]; ok {
tun.Close() // Close connection
}
var tun = &Tunnel{
RootConn: conn,
TunInfo: tunnelInfo,
UDPClients: make(map[string]net.Conn),
TCPClients: make(map[string]net.Conn),
}
controller.Agents[string(req.AgentAuth[:])] = tun
go tun.Setup()
}
// Process TCP Connections from listerner
func (tun *Tunnel) TCPAccepts() {
func (controller *Server) handler() {
defer controller.ControllConn.Close()
for {
conn, err := tun.TCPListener.Accept()
conn, err := controller.ControllConn.Accept()
if err != nil {
time.Sleep(time.Second)
continue
break
}
clientAddr := netip.MustParseAddrPort(conn.RemoteAddr().String())
tun.TCPClients[conn.RemoteAddr().String()] = conn
go func() {
for {
buff := make([]byte, tun.ResponseBuffer)
n, err := conn.Read(buff)
if err != nil {
go conn.Close()
tun.SendToAgent <- proto.Response{
CloseClient: &proto.Client{
Client: clientAddr,
Proto: proto.ProtoTCP,
},
}
break
}
if tun.ResponseBuffer-uint64(n) == 0 {
tun.ResponseBuffer += 500
res := proto.Response{}
res.ResizeBuffer = new(uint64)
*res.ResizeBuffer = tun.ResponseBuffer
tun.SendToAgent <- res
<-time.After(time.Microsecond)
}
tun.SendToAgent <- proto.Response{
DataRX: &proto.ClientData{
Size: uint64(n),
Data: buff[:n],
Client: proto.Client{
Client: clientAddr,
Proto: proto.ProtoTCP,
},
},
}
}
}()
go controller.handlerConn(conn)
}
}
func (tun *Tunnel) Request(req proto.Request) {
if client := req.ClientClose; client != nil {
addrStr := client.Client.String()
if cl, exit := tun.TCPClients[addrStr]; exit && client.Proto == 1 {
cl.Close()
delete(tun.TCPClients, addrStr)
} else if cl, exit := tun.UDPClients[addrStr]; exit && client.Proto == 2 {
cl.Close()
delete(tun.TCPClients, addrStr)
}
return
} else if data := req.DataTX; data != nil {
var conn net.Conn = nil
var exist bool
if data.Client.Proto == proto.ProtoTCP {
if conn, exist = tun.TCPClients[data.Client.Client.String()]; !exist {
conn = nil
}
} else if data.Client.Proto == proto.ProtoUDP {
if conn, exist = tun.UDPClients[data.Client.Client.String()]; !exist {
conn = nil
}
}
if conn == nil {
tun.SendToAgent <- proto.Response{CloseClient: client}
return
}
if _, err := conn.Write(data.Data); err != nil {
conn.Close()
delete(tun.TCPClients, data.Client.Client.String())
tun.SendToAgent <- proto.Response{CloseClient: client}
}
return
}
}
// Listener controller and controller listener
func (server *Server) Listen(ControllerPort uint16) (err error) {
var conn *net.UDPConn
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 readSize int
var addr netip.AddrPort
log.Println("waiting to request")
buffer := make([]byte, proto.PacketSize+server.RequestBuffer)
if readSize, addr, err = conn.ReadFromUDPAddrPort(buffer); err != nil {
if err == io.EOF {
break // End controller
}
continue
}
if err := req.Reader(bytes.NewBuffer(buffer[:readSize])); err != nil {
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
}
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: &current})
continue
}
go tun.Request(req) // process request to tunnel
continue // Call next message
}
// Create tunnel
if _, exist := server.Tunnels[addr.String()]; !exist {
// Create new tunnel agent
server.Tunnels[addr.String()] = Tunnel{
Token: [36]byte{},
Authenticated: false,
UDPClients: make(map[string]net.Conn),
TCPClients: make(map[string]net.Conn),
SendToAgent: make(chan proto.Response),
}
go func() {
tun := server.Tunnels[addr.String()]
for {
if res, ok := <-tun.SendToAgent; ok {
data, err := res.Wbytes()
if err != nil {
continue
}
go conn.WriteToUDPAddrPort(data, addr) // send data to agent
continue
}
break
}
}()
}
if !server.Tunnels[addr.String()].Authenticated && req.AgentAuth == nil {
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
go server.Send(addr, proto.Response{Unauthorized: true})
} else {
// Cannot process request resend
go server.Send(addr, proto.Response{SendAuth: true})
}
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 {
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", 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()
}
go server.Send(addr, proto.Response{BadRequest: true})
continue
}
go tun.UDPAccepts() // Make accepts new requests
}
tun.Authenticated = true
server.Tunnels[addr.String()] = tun
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
}

181
server/tunnel.go Normal file

@ -0,0 +1,181 @@
package server
import (
"io"
"net"
"net/netip"
"time"
"sirherobrine23.org/Minecraft-Server/go-pproxit/internal/udplisterner/v2"
"sirherobrine23.org/Minecraft-Server/go-pproxit/proto"
)
type TunnelCall interface {
BlockedAddr(AddrPort netip.Addr) bool // Ignore request from this address
AgentPing(agent, server time.Time) // Register ping to Agent
AgentShutdown(onTime time.Time) // Agend end connection
RegisterRX(client netip.AddrPort, Size int, Proto uint8) // Register Recived data from client
RegisterTX(client netip.AddrPort, Size int, Proto uint8) // Register Transmitted data from client
}
type TunnelInfo struct {
Proto uint8 // Protocol listen tunnel, use proto.ProtoTCP, proto.ProtoUDP or proto.ProtoBoth
UDPPort, TCPPort uint16 // Port to Listen UDP and TCP listeners
Callbacks TunnelCall // Tunnel Callbacks
}
type Tunnel struct {
RootConn net.Conn // Current client connection
TunInfo TunnelInfo // Tunnel info
UDPClients map[string]net.Conn // Current clients connected
TCPClients map[string]net.Conn // Current clients connected
}
func (tun *Tunnel) Close() error {
// Stop TCP Clients
for k := range tun.TCPClients {
tun.TCPClients[k].Close()
delete(tun.TCPClients, k)
}
// Stop UDP Clients
for k := range tun.UDPClients {
tun.UDPClients[k].Close()
delete(tun.UDPClients, k)
}
tun.RootConn.Close() // End root conenction
tun.TunInfo.Callbacks.AgentShutdown(time.Now()) // Register shutdown
return nil
}
func (tun *Tunnel) send(res proto.Response) error {
return proto.WriteResponse(tun.RootConn, res)
}
type toWr struct {
Proto uint8
To netip.AddrPort
tun *Tunnel
}
func (t toWr) Write(w []byte) (int, error) {
go t.tun.TunInfo.Callbacks.RegisterRX(t.To, len(w), t.Proto)
err := t.tun.send(proto.Response{
DataRX: &proto.ClientData{
Client: proto.Client{
Proto: t.Proto,
Client: t.To,
},
Size: uint64(len(w)),
Data: w[:],
},
})
if err == nil {
return len(w), nil
}
return 0, err
}
func (tun *Tunnel) GetTargetWrite(Proto uint8, To netip.AddrPort) io.Writer {
return &toWr{Proto: Proto, To: To, tun: tun}
}
// Setup connections and maneger connections from agent
func (tun *Tunnel) Setup() {
defer tun.Close()
tun.send(proto.Response{
AgentInfo: &proto.AgentInfo{
Protocol: tun.TunInfo.Proto,
AddrPort: netip.MustParseAddrPort(tun.RootConn.RemoteAddr().String()),
UDPPort: tun.TunInfo.UDPPort,
TCPPort: tun.TunInfo.TCPPort,
},
})
if proto.ProtoBoth == tun.TunInfo.Proto || proto.ProtoTCP == tun.TunInfo.Proto {
go tun.TCP() // Setup TCP Listerner
}
if proto.ProtoBoth == tun.TunInfo.Proto || proto.ProtoUDP == tun.TunInfo.Proto {
go tun.UDP() // Setup UDP Listerner
}
for {
req, err := proto.ReaderRequest(tun.RootConn)
if err != nil {
break
} else if ping := *req.Ping; req.Ping != nil {
var now = time.Now()
tun.send(proto.Response{Pong: &now})
go tun.TunInfo.Callbacks.AgentPing(ping, now) // backgroud process
} else if clClose := *req.ClientClose; req.ClientClose != nil {
if clClose.Proto == proto.ProtoTCP {
if cl, ok := tun.TCPClients[clClose.Client.String()]; ok {
cl.Close()
}
} else if clClose.Proto == proto.ProtoUDP {
if cl, ok := tun.UDPClients[clClose.Client.String()]; ok {
cl.Close()
}
}
} else if data := *req.DataTX; req.DataTX != nil {
go tun.TunInfo.Callbacks.RegisterTX(data.Client.Client, int(data.Size), data.Client.Proto)
if data.Client.Proto == proto.ProtoTCP {
if cl, ok := tun.TCPClients[data.Client.Client.String()]; ok {
go cl.Write(data.Data) // Process in backgroud
}
} else if data.Client.Proto == proto.ProtoUDP {
if cl, ok := tun.UDPClients[data.Client.Client.String()]; ok {
go cl.Write(data.Data) // Process in backgroud
}
}
}
}
}
// Listen TCP
func (tun *Tunnel) TCP() {
dial, err := net.ListenTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), tun.TunInfo.TCPPort)))
if err != nil {
tun.send(proto.Response{BadRequest: true}) // TODO: require new option to shutdown agent
tun.Close() // End process listen
return
}
for {
conn, err := dial.AcceptTCP()
if err != nil {
panic(err) // TODO: fix accepts in future
}
remote := netip.MustParseAddrPort(conn.RemoteAddr().String())
if tun.TunInfo.Callbacks.BlockedAddr(remote.Addr()) {
conn.Close() // Close connection
continue
}
tun.TCPClients[remote.String()] = conn
go io.Copy(tun.GetTargetWrite(proto.ProtoTCP, remote), conn)
}
}
// Listen UDP
func (tun *Tunnel) UDP() {
dial, err := udplisterner.Listen("udp", netip.AddrPortFrom(netip.IPv4Unspecified(), tun.TunInfo.UDPPort))
if err != nil {
tun.send(proto.Response{BadRequest: true}) // TODO: require new option to shutdown agent
tun.Close() // End process listen
return
}
for {
conn, err := dial.Accept()
if err != nil {
panic(err) // TODO: fix accepts in future
}
remote := netip.MustParseAddrPort(conn.RemoteAddr().String())
if tun.TunInfo.Callbacks.BlockedAddr(remote.Addr()) {
conn.Close() // Close connection
continue
}
tun.UDPClients[remote.String()] = conn
go io.Copy(tun.GetTargetWrite(proto.ProtoUDP, remote), conn)
}
}