mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
143 lines
3.6 KiB
Go
143 lines
3.6 KiB
Go
package gateway
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/quic-go/quic-go"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func handleConnection(ctx context.Context, quicConn quic.Connection) {
|
|
log.Info().Msgf("New connection from: %s", quicConn.RemoteAddr().String())
|
|
// Use WaitGroup to track all streams
|
|
var wg sync.WaitGroup
|
|
for {
|
|
// Accept the first stream, which we'll use for commands
|
|
stream, err := quicConn.AcceptStream(ctx)
|
|
if err != nil {
|
|
log.Printf("Failed to accept QUIC stream: %v", err)
|
|
break
|
|
}
|
|
wg.Add(1)
|
|
go func(stream quic.Stream) {
|
|
defer wg.Done()
|
|
defer stream.Close()
|
|
|
|
handleStream(stream, quicConn)
|
|
}(stream)
|
|
}
|
|
|
|
wg.Wait()
|
|
log.Printf("All streams closed for connection: %s", quicConn.RemoteAddr().String())
|
|
}
|
|
|
|
func handleStream(stream quic.Stream, quicConn quic.Connection) {
|
|
streamID := stream.StreamID()
|
|
log.Printf("New stream %d from: %s", streamID, quicConn.RemoteAddr().String())
|
|
|
|
// Use buffered reader for better handling of fragmented data
|
|
reader := bufio.NewReader(stream)
|
|
defer stream.Close()
|
|
|
|
for {
|
|
msg, err := reader.ReadBytes('\n')
|
|
if err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
return
|
|
}
|
|
log.Error().Msgf("Error reading command: %s", err)
|
|
return
|
|
}
|
|
|
|
cmd := bytes.ToUpper(bytes.TrimSpace(bytes.Split(msg, []byte(" "))[0]))
|
|
args := bytes.TrimSpace(bytes.TrimPrefix(msg, cmd))
|
|
|
|
switch string(cmd) {
|
|
case "FORWARD-TCP":
|
|
proxyAddress := string(bytes.Split(args, []byte(" "))[0])
|
|
destTarget, err := net.Dial("tcp", proxyAddress)
|
|
if err != nil {
|
|
log.Error().Msgf("Failed to connect to target: %v", err)
|
|
return
|
|
}
|
|
defer destTarget.Close()
|
|
log.Info().Msgf("Starting secure transmission between %s->%s", quicConn.LocalAddr().String(), destTarget.LocalAddr().String())
|
|
|
|
// Handle buffered data
|
|
buffered := reader.Buffered()
|
|
if buffered > 0 {
|
|
bufferedData := make([]byte, buffered)
|
|
_, err := reader.Read(bufferedData)
|
|
if err != nil {
|
|
log.Error().Msgf("Error reading buffered data: %v", err)
|
|
return
|
|
}
|
|
|
|
if _, err = destTarget.Write(bufferedData); err != nil {
|
|
log.Error().Msgf("Error writing buffered data: %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
CopyDataFromQuicToTcp(stream, destTarget)
|
|
log.Info().Msgf("Ending secure transmission between %s->%s", quicConn.LocalAddr().String(), destTarget.LocalAddr().String())
|
|
return
|
|
case "PING":
|
|
if _, err := stream.Write([]byte("PONG\n")); err != nil {
|
|
log.Error().Msgf("Error writing PONG response: %v", err)
|
|
}
|
|
return
|
|
default:
|
|
log.Error().Msgf("Unknown command: %s", string(cmd))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
type CloseWrite interface {
|
|
CloseWrite() error
|
|
}
|
|
|
|
func CopyDataFromQuicToTcp(quicStream quic.Stream, tcpConn net.Conn) {
|
|
// Create a WaitGroup to wait for both copy operations
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
// Start copying from QUIC stream to TCP
|
|
go func() {
|
|
defer wg.Done()
|
|
if _, err := io.Copy(tcpConn, quicStream); err != nil {
|
|
log.Error().Msgf("Error copying quic->postgres: %v", err)
|
|
}
|
|
|
|
if e, ok := tcpConn.(CloseWrite); ok {
|
|
log.Debug().Msg("Closing TCP write end")
|
|
e.CloseWrite()
|
|
} else {
|
|
log.Debug().Msg("TCP connection does not support CloseWrite")
|
|
}
|
|
}()
|
|
|
|
// Start copying from TCP to QUIC stream
|
|
go func() {
|
|
defer wg.Done()
|
|
if _, err := io.Copy(quicStream, tcpConn); err != nil {
|
|
log.Debug().Msgf("Error copying postgres->quic: %v", err)
|
|
}
|
|
// Close the write side of the QUIC stream
|
|
if err := quicStream.Close(); err != nil && !strings.Contains(err.Error(), "close called for canceled stream") {
|
|
log.Error().Msgf("Error closing QUIC stream write: %v", err)
|
|
}
|
|
}()
|
|
|
|
// Wait for both copies to complete
|
|
wg.Wait()
|
|
}
|