Files
threshold/internal/daemon/worker/proxy/tcp/tcp.go
T
Todd b58dada40d Move the server daemons into their own package (#2061)
* Move the server daemons into their own package

With this change the internal/server package now is dedicated to the server domain (workers and controllers) and not to the server daemons.
The hope is that this will make it easier to keep the daemons decoupled from the representation of the servers in the database.
2022-05-09 12:45:10 -07:00

89 lines
2.5 KiB
Go

package tcp
import (
"context"
"fmt"
"io"
"net"
"net/url"
"sync"
"github.com/hashicorp/boundary/internal/daemon/worker/proxy"
"github.com/hashicorp/boundary/internal/daemon/worker/session"
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
"nhooyr.io/websocket"
)
func init() {
err := proxy.RegisterHandler("tcp", handleProxy)
if err != nil {
panic(err)
}
}
// handleProxy creates a tcp proxy between the incoming websocket conn and the
// connection it creates with the remote endpoint. handleTcpProxyV1 sets the connectionId
// as connected in the repository.
//
// handleProxy blocks until an error (EOF on happy path) is received on either
// connection.
//
// All options are ignored.
func handleProxy(ctx context.Context, conf proxy.Config, _ ...proxy.Option) error {
conn := conf.ClientConn
sessionUrl, err := url.Parse(conf.RemoteEndpoint)
if err != nil {
return fmt.Errorf("error parsing endpoint information: %w", err)
}
if sessionUrl.Scheme != "tcp" {
return fmt.Errorf("invalid scheme for tcp proxy: %v", sessionUrl.Scheme)
}
remoteConn, err := net.Dial("tcp", sessionUrl.Host)
if err != nil {
return fmt.Errorf("error dialing endpoint: %w", err)
}
// Assert this for better Go 1.11 splice support
tcpRemoteConn := remoteConn.(*net.TCPConn)
endpointAddr := tcpRemoteConn.RemoteAddr().(*net.TCPAddr)
connectionInfo := &pbs.ConnectConnectionRequest{
ConnectionId: conf.ConnectionId,
ClientTcpAddress: conf.ClientAddress.IP.String(),
ClientTcpPort: uint32(conf.ClientAddress.Port),
EndpointTcpAddress: endpointAddr.IP.String(),
EndpointTcpPort: uint32(endpointAddr.Port),
Type: "tcp",
UserClientIp: conf.UserClientIp.String(),
}
connStatus, err := session.ConnectConnection(ctx, conf.SessionClient, connectionInfo)
if err != nil {
return fmt.Errorf("error marking connection as connected: %w", err)
}
// Update connection info to set connection status
conf.SessionInfo.Lock()
conf.SessionInfo.ConnInfoMap[conf.ConnectionId].Status = connStatus
conf.SessionInfo.Unlock()
// Get a wrapped net.Conn so we can use io.Copy
netConn := websocket.NetConn(ctx, conn, websocket.MessageBinary)
connWg := new(sync.WaitGroup)
connWg.Add(2)
go func() {
defer connWg.Done()
_, _ = io.Copy(netConn, tcpRemoteConn)
_ = netConn.Close()
_ = tcpRemoteConn.Close()
}()
go func() {
defer connWg.Done()
_, _ = io.Copy(tcpRemoteConn, netConn)
_ = tcpRemoteConn.Close()
_ = netConn.Close()
}()
connWg.Wait()
return nil
}