mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-05-12 00:56:34 +00:00

To use cloudflared as a socks proxy, add an ingress on the server side with your desired rules. Rules are matched in the order they are added. If there are no rules, it is an implicit allow. If there are rules, but no rule matches match, the connection is denied. ingress: - hostname: socks.example.com service: socks-proxy originRequest: ipRules: - prefix: 1.1.1.1/24 ports: [80, 443] allow: true - prefix: 0.0.0.0/0 allow: false On the client, run using tcp mode: cloudflared access tcp --hostname socks.example.com --url 127.0.0.1:8080 Set your socks proxy as 127.0.0.1:8080 and you will now be proxying all connections to the remote machine.
126 lines
3.5 KiB
Go
126 lines
3.5 KiB
Go
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() {
|
|
}
|