WIP: backend udp
This commit is contained in:
223
bounce.go
223
bounce.go
@@ -17,18 +17,32 @@ package netbounce
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"gitea.suyono.dev/suyono/netbounce/abstract"
|
||||
"gitea.suyono.dev/suyono/netbounce/config"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func Bounce() error {
|
||||
const (
|
||||
CONNECTION = "connection"
|
||||
DIRECTION = "direction"
|
||||
CLIENT_TO_BACKEND = "client-to-backend"
|
||||
BACKEND_TO_CLIENT = "backend-to-client"
|
||||
BUF_SIZE = 4096
|
||||
)
|
||||
|
||||
func Bounce(ctx context.Context) error {
|
||||
var (
|
||||
names []string
|
||||
err error
|
||||
cc abstract.ConnectionConfig
|
||||
)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
if names, err = config.ListConnection(); err != nil {
|
||||
return fmt.Errorf("bounce: connection list: %w", err)
|
||||
}
|
||||
@@ -37,20 +51,219 @@ func Bounce() error {
|
||||
return fmt.Errorf("bounce: connection get %s: %w", name, err)
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
if cc.Type() == abstract.TCP {
|
||||
go RunTCP(cc.AsTCP())
|
||||
go RunTCP(wg, ctx, cc.AsTCP())
|
||||
} else {
|
||||
go RunUDP(cc.AsUDP())
|
||||
go RunUDP(wg, ctx, cc.AsUDP())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RunTCP(cfg abstract.TCPConnectionConfig) {
|
||||
func RunTCP(wg *sync.WaitGroup, ctx context.Context, cfg abstract.TCPConnectionConfig) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
err error
|
||||
l net.Listener
|
||||
accepted chan net.Conn
|
||||
)
|
||||
|
||||
if l, err = net.Listen("tcp", cfg.Listen()); err != nil {
|
||||
panic(fmt.Errorf("failed to listen tcp: %w", err))
|
||||
}
|
||||
|
||||
accepted = make(chan net.Conn)
|
||||
go func(ctx context.Context, cfg abstract.TCPConnectionConfig, listener net.Listener, acceptChan chan<- net.Conn) {
|
||||
defer log.Info().Msgf("go routine for accepting connection quited: %s", cfg.Name())
|
||||
var (
|
||||
err error
|
||||
c net.Conn
|
||||
)
|
||||
|
||||
acceptIncoming:
|
||||
for {
|
||||
if c, err = listener.Accept(); err != nil {
|
||||
log.Error().Err(err).Msg("accept TCP connection")
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case acceptChan <- c:
|
||||
case <-ctx.Done():
|
||||
break acceptIncoming
|
||||
}
|
||||
}
|
||||
}(ctx, cfg, l, accepted)
|
||||
|
||||
connStarter:
|
||||
for {
|
||||
select {
|
||||
case c := <-accepted:
|
||||
wg.Add(1)
|
||||
go makeTCPConnection(wg, ctx, cfg, c)
|
||||
case <-ctx.Done():
|
||||
break connStarter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RunUDP(cfg abstract.UDPConnectionConfig) {
|
||||
func makeTCPConnection(wg *sync.WaitGroup, ctx context.Context, cfg abstract.TCPConnectionConfig, conn net.Conn) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
backend net.Conn
|
||||
err error
|
||||
)
|
||||
|
||||
if backend, err = net.Dial("tcp", cfg.Backend()); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Msg("connection to backend failed")
|
||||
return
|
||||
}
|
||||
|
||||
ctxConn, cancelConn := context.WithCancel(ctx)
|
||||
|
||||
wg.Add(1)
|
||||
go tcpClient2Backend(wg, ctxConn, cfg, cancelConn, conn, backend)
|
||||
|
||||
wg.Add(1)
|
||||
go tcpBackend2Client(wg, ctxConn, cfg, cancelConn, backend, conn)
|
||||
|
||||
<-ctxConn.Done()
|
||||
_ = backend.Close()
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
func tcpBackend2Client(wg *sync.WaitGroup, ctx context.Context, cfg abstract.TCPConnectionConfig, cf context.CancelFunc, backend, client net.Conn) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
buf []byte
|
||||
n, wn int
|
||||
cancel context.CancelFunc
|
||||
err error
|
||||
)
|
||||
|
||||
cancel = cf
|
||||
buf = make([]byte, BUF_SIZE)
|
||||
backendRead:
|
||||
for {
|
||||
if n, err = backend.Read(buf); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Str(DIRECTION, BACKEND_TO_CLIENT).Msg("tcp read error")
|
||||
cancel()
|
||||
break backendRead
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break backendRead
|
||||
default:
|
||||
}
|
||||
|
||||
if wn, err = client.Write(buf[:n]); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Str(DIRECTION, BACKEND_TO_CLIENT).Msg("tcp read error")
|
||||
cancel()
|
||||
break backendRead
|
||||
}
|
||||
|
||||
if wn != n {
|
||||
log.Error().Err(fmt.Errorf("mismatch length between read and write")).Str(CONNECTION, cfg.Name()).Str(DIRECTION, BACKEND_TO_CLIENT).Msg("tcp read problem")
|
||||
cancel()
|
||||
break backendRead
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break backendRead
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tcpClient2Backend(wg *sync.WaitGroup, ctx context.Context, cfg abstract.TCPConnectionConfig, cf context.CancelFunc, client, backend net.Conn) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
buf []byte
|
||||
n, wn int
|
||||
cancel context.CancelFunc
|
||||
err error
|
||||
)
|
||||
|
||||
cancel = cf
|
||||
buf = make([]byte, BUF_SIZE)
|
||||
clientRead:
|
||||
for {
|
||||
if n, err = client.Read(buf); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Str(DIRECTION, CLIENT_TO_BACKEND).Msg("tcp read error")
|
||||
cancel()
|
||||
break clientRead
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break clientRead
|
||||
default:
|
||||
}
|
||||
|
||||
if wn, err = backend.Write(buf[:n]); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Str(DIRECTION, CLIENT_TO_BACKEND).Msg("tcp write error")
|
||||
cancel()
|
||||
break clientRead
|
||||
}
|
||||
|
||||
if wn != n {
|
||||
log.Error().Err(fmt.Errorf("mismatch length between read and write")).Str(CONNECTION, cfg.Name()).Str(DIRECTION, CLIENT_TO_BACKEND).Msg("tcp write problem")
|
||||
cancel()
|
||||
break clientRead
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break clientRead
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RunUDP(wg *sync.WaitGroup, ctx context.Context, cfg abstract.UDPConnectionConfig) {
|
||||
defer wg.Done()
|
||||
|
||||
var (
|
||||
client net.PacketConn
|
||||
buf []byte
|
||||
addr net.Addr
|
||||
err error
|
||||
n int
|
||||
backend *backendUDP
|
||||
)
|
||||
|
||||
if client, err = net.ListenPacket("udp", cfg.Listen()); err != nil {
|
||||
panic(fmt.Errorf("failed to bind for UDP %s: %w", cfg.Name(), err))
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
backend = initUDP(wg, ctx, cfg, client)
|
||||
buf = make([]byte, BUF_SIZE)
|
||||
|
||||
udpReadLoop:
|
||||
for {
|
||||
if n, addr, err = client.ReadFrom(buf); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Str(DIRECTION, CLIENT_TO_BACKEND).Msg("udp read error")
|
||||
continue udpReadLoop
|
||||
}
|
||||
|
||||
if err = backend.Send(ctx, addr.String(), buf[:n]); err != nil {
|
||||
log.Error().Err(err).Str(CONNECTION, cfg.Name()).Str(DIRECTION, CLIENT_TO_BACKEND).Msg("send udp message")
|
||||
continue udpReadLoop
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break udpReadLoop
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user