diff --git a/go.mod b/go.mod index 119f6893..e9f4f5a8 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( github.com/xlab/treeprint v1.2.0 golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 golang.org/x/mod v0.23.0 + golang.org/x/net v0.34.0 golang.org/x/sync v0.11.0 golang.org/x/term v0.29.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f @@ -239,7 +240,6 @@ require ( go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.32.0 // indirect - golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.21.0 // indirect diff --git a/internal/client/client.go b/internal/client/client.go index 5cdc72d5..a5e93a0e 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -1,10 +1,15 @@ package client import ( + "context" "fmt" + "net" + "net/url" "os" "path/filepath" + "golang.org/x/net/proxy" + v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" "github.com/authzed/authzed-go/v1" "github.com/authzed/grpcutil" @@ -188,6 +193,24 @@ func DialOptsFromFlags(cmd *cobra.Command, token storage.Token) ([]grpc.DialOpti grpc.WithChainStreamInterceptor(zgrpcutil.StreamLogDispatchTrailers), } + proxyAddr := cobrautil.MustGetString(cmd, "proxy") + + if proxyAddr != "" { + addr, err := url.Parse(proxyAddr) + if err != nil { + return nil, fmt.Errorf("failed to parse socks5 proxy addr: %w", err) + } + + dialer, err := proxy.SOCKS5("tcp", addr.Host, nil, proxy.Direct) + if err != nil { + return nil, fmt.Errorf("failed to create socks5 proxy dialer: %w", err) + } + + opts = append(opts, grpc.WithContextDialer(func(_ context.Context, addr string) (net.Conn, error) { + return dialer.Dial("tcp", addr) + })) + } + if token.IsInsecure() { opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) opts = append(opts, grpcutil.WithInsecureBearerToken(token.APIToken)) diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 5ce1f6a5..79a3b206 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -75,6 +75,7 @@ func InitialiseRootCmd(zl *cobrazerolog.Builder) *cobra.Command { rootCmd.PersistentFlags().Bool("debug", false, "enable debug logging") rootCmd.PersistentFlags().String("request-id", "", "optional id to send along with SpiceDB requests for tracing") rootCmd.PersistentFlags().Int("max-message-size", 0, "maximum size *in bytes* (defaults to 4_194_304 bytes ~= 4MB) of a gRPC message that can be sent or received by zed") + rootCmd.PersistentFlags().String("proxy", "", "specify a SOCKS5 proxy address") _ = rootCmd.PersistentFlags().MarkHidden("debug") // This cannot return its error. versionCmd := &cobra.Command{