TCP forwardData copied plaintext after the handshake. Frame each chunk as uint32 length plus AES-GCM ciphertext in both client and server, both directions.
This commit is contained in:
+42
-12
@@ -28,6 +28,7 @@ type TeleportClient struct {
|
||||
cancel context.CancelFunc
|
||||
connectionPool chan net.Conn
|
||||
maxPoolSize int
|
||||
derivedKey []byte
|
||||
}
|
||||
|
||||
// NewTeleportClient creates a new teleport client
|
||||
@@ -49,6 +50,7 @@ func NewTeleportClient(config *config.Config) *TeleportClient {
|
||||
cancel: cancel,
|
||||
connectionPool: make(chan net.Conn, maxPoolSize),
|
||||
maxPoolSize: maxPoolSize,
|
||||
derivedKey: encryption.DeriveKey(config.EncryptionKey),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,23 +652,34 @@ func (tc *TeleportClient) handleTCPConnection(clientConn net.Conn, rule config.P
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
|
||||
// Forward data from client to server
|
||||
// Encrypt local plaintext onto the tunnel
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tc.forwardData(clientConn, serverConn)
|
||||
tc.forwardData(clientConn, serverConn, true)
|
||||
}()
|
||||
|
||||
// Forward data from server to client
|
||||
// Decrypt tunnel frames to the local connection
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tc.forwardData(serverConn, clientConn)
|
||||
tc.forwardData(serverConn, clientConn, false)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// forwardData forwards data from src to dst
|
||||
func (tc *TeleportClient) forwardData(src, dst net.Conn) {
|
||||
// forwardData copies between a local/plaintext conn and the tunnel.
|
||||
// When toTunnel is true, plaintext is AES-GCM encrypted and written as
|
||||
// uint32 length + ciphertext. When false, framed ciphertext is decrypted
|
||||
// and written as plaintext.
|
||||
func (tc *TeleportClient) forwardData(src, dst net.Conn, toTunnel bool) {
|
||||
if toTunnel {
|
||||
tc.forwardPlainToTunnel(src, dst)
|
||||
return
|
||||
}
|
||||
tc.forwardTunnelToPlain(src, dst)
|
||||
}
|
||||
|
||||
func (tc *TeleportClient) forwardPlainToTunnel(src, dst net.Conn) {
|
||||
buffer := make([]byte, 4096)
|
||||
for {
|
||||
select {
|
||||
@@ -675,14 +688,32 @@ func (tc *TeleportClient) forwardData(src, dst net.Conn) {
|
||||
default:
|
||||
n, err := src.Read(buffer)
|
||||
if err != nil {
|
||||
// Close the destination connection when source closes
|
||||
dst.Close()
|
||||
return
|
||||
}
|
||||
if n == 0 {
|
||||
continue
|
||||
}
|
||||
if err := encryption.WriteEncryptedFrame(dst, buffer[:n], tc.derivedKey); err != nil {
|
||||
src.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dst.Write(buffer[:n])
|
||||
func (tc *TeleportClient) forwardTunnelToPlain(src, dst net.Conn) {
|
||||
for {
|
||||
select {
|
||||
case <-tc.ctx.Done():
|
||||
return
|
||||
default:
|
||||
plain, err := encryption.ReadEncryptedFrame(src, tc.derivedKey)
|
||||
if err != nil {
|
||||
// Close the source connection when destination closes
|
||||
dst.Close()
|
||||
return
|
||||
}
|
||||
if _, err := dst.Write(plain); err != nil {
|
||||
src.Close()
|
||||
return
|
||||
}
|
||||
@@ -703,9 +734,8 @@ func (tc *TeleportClient) sendRequestToConnection(conn net.Conn, request types.P
|
||||
return err
|
||||
}
|
||||
|
||||
// Encrypt the data
|
||||
key := encryption.DeriveKey(tc.config.EncryptionKey)
|
||||
encryptedData, err := encryption.EncryptData(data, key)
|
||||
// Encrypt the data (key derived once at process start)
|
||||
encryptedData, err := encryption.EncryptData(data, tc.derivedKey)
|
||||
if err != nil {
|
||||
logger.WithFields(map[string]interface{}{
|
||||
"error": err,
|
||||
|
||||
Reference in New Issue
Block a user