123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- package ingress
- import (
- "context"
- "crypto/tls"
- "io"
- "net"
- "net/http"
- "github.com/cloudflare/cloudflared/ipaccess"
- "github.com/cloudflare/cloudflared/socks"
- "github.com/cloudflare/cloudflared/websocket"
- gws "github.com/gorilla/websocket"
- "github.com/rs/zerolog"
- )
- // OriginConnection is a way to stream to a service running on the user's origin.
- // Different concrete implementations will stream different protocols as long as they are io.ReadWriters.
- type OriginConnection interface {
- // Stream should generally be implemented as a bidirectional io.Copy.
- Stream(ctx context.Context, tunnelConn io.ReadWriter, log *zerolog.Logger)
- Close()
- }
- type streamHandlerFunc func(originConn io.ReadWriter, remoteConn net.Conn, log *zerolog.Logger)
- // Stream copies copy data to & from provided io.ReadWriters.
- func Stream(conn, backendConn io.ReadWriter, log *zerolog.Logger) {
- proxyDone := make(chan struct{}, 2)
- go func() {
- _, err := io.Copy(conn, backendConn)
- if err != nil {
- log.Debug().Msgf("conn to backendConn copy: %v", err)
- }
- proxyDone <- struct{}{}
- }()
- go func() {
- _, err := io.Copy(backendConn, conn)
- if err != nil {
- log.Debug().Msgf("backendConn to conn copy: %v", err)
- }
- proxyDone <- struct{}{}
- }()
- // If one side is done, we are done.
- <-proxyDone
- }
- // DefaultStreamHandler is an implementation of streamHandlerFunc that
- // performs a two way io.Copy between originConn and remoteConn.
- func DefaultStreamHandler(originConn io.ReadWriter, remoteConn net.Conn, log *zerolog.Logger) {
- Stream(originConn, remoteConn, log)
- }
- // tcpConnection is an OriginConnection that directly streams to raw TCP.
- type tcpConnection struct {
- conn net.Conn
- }
- func (tc *tcpConnection) Stream(ctx context.Context, tunnelConn io.ReadWriter, log *zerolog.Logger) {
- Stream(tunnelConn, tc.conn, log)
- }
- func (tc *tcpConnection) Close() {
- tc.conn.Close()
- }
- // tcpOverWSConnection is an OriginConnection that streams to TCP over WS.
- type tcpOverWSConnection struct {
- conn net.Conn
- streamHandler streamHandlerFunc
- }
- func (wc *tcpOverWSConnection) Stream(ctx context.Context, tunnelConn io.ReadWriter, log *zerolog.Logger) {
- wc.streamHandler(websocket.NewConn(ctx, tunnelConn, log), wc.conn, log)
- }
- func (wc *tcpOverWSConnection) Close() {
- wc.conn.Close()
- }
- // wsConnection is an OriginConnection that streams WS between eyeball and origin.
- type wsConnection struct {
- wsConn *gws.Conn
- resp *http.Response
- }
- func (wsc *wsConnection) Stream(ctx context.Context, tunnelConn io.ReadWriter, log *zerolog.Logger) {
- Stream(tunnelConn, wsc.wsConn.UnderlyingConn(), log)
- }
- func (wsc *wsConnection) Close() {
- wsc.resp.Body.Close()
- wsc.wsConn.Close()
- }
- func newWSConnection(clientTLSConfig *tls.Config, r *http.Request) (OriginConnection, *http.Response, error) {
- d := &gws.Dialer{
- TLSClientConfig: clientTLSConfig,
- }
- wsConn, resp, err := websocket.ClientConnect(r, d)
- if err != nil {
- return nil, nil, err
- }
- return &wsConnection{
- wsConn,
- resp,
- }, resp, nil
- }
- // socksProxyOverWSConnection is an OriginConnection that streams SOCKS connections over WS.
- // The connection to the origin happens inside the SOCKS code as the client specifies the origin
- // details in the packet.
- type socksProxyOverWSConnection struct {
- accessPolicy *ipaccess.Policy
- }
- func (sp *socksProxyOverWSConnection) Stream(ctx context.Context, tunnelConn io.ReadWriter, log *zerolog.Logger) {
- socks.StreamNetHandler(websocket.NewConn(ctx, tunnelConn, log), sp.accessPolicy, log)
- }
- func (sp *socksProxyOverWSConnection) Close() {
- }
|