From 1bab82ab36db602d16f97c6ed933cd417ab4720d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Thu, 15 Feb 2024 12:01:18 +0100 Subject: [PATCH] mssql: socks proxy: use plugin-sdk (#82407) --- pkg/tsdb/mssql/mssql.go | 18 +++++++++----- pkg/tsdb/mssql/proxy.go | 12 +++------ pkg/tsdb/mssql/proxy_test.go | 48 +++++++++++++++++++++--------------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/pkg/tsdb/mssql/mssql.go b/pkg/tsdb/mssql/mssql.go index 9319c5f34de..068a5edccb6 100644 --- a/pkg/tsdb/mssql/mssql.go +++ b/pkg/tsdb/mssql/mssql.go @@ -16,7 +16,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" - sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" mssql "github.com/microsoft/go-mssqldb" @@ -26,7 +25,6 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb/mssql/utils" "github.com/grafana/grafana/pkg/tsdb/sqleng" - "github.com/grafana/grafana/pkg/tsdb/sqleng/proxyutil" "github.com/grafana/grafana/pkg/util" ) @@ -67,7 +65,7 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) } func newInstanceSettings(cfg *setting.Cfg, logger log.Logger) datasource.InstanceFactoryFunc { - return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { + return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { jsonData := sqleng.JsonData{ MaxOpenConns: cfg.SqlDatasourceMaxOpenConnsDefault, MaxIdleConns: cfg.SqlDatasourceMaxIdleConnsDefault, @@ -113,14 +111,22 @@ func newInstanceSettings(cfg *setting.Cfg, logger log.Logger) datasource.Instanc driverName = "azuresql" } + proxyClient, err := settings.ProxyClient(ctx) + if err != nil { + return nil, err + } + // register a new proxy driver if the secure socks proxy is enabled - proxyOpts := proxyutil.GetSQLProxyOptions(cfg.SecureSocksDSProxy, dsInfo, settings.Name, settings.Type) - if sdkproxy.New(proxyOpts).SecureSocksProxyEnabled() { + if proxyClient.SecureSocksProxyEnabled() { + dialer, err := proxyClient.NewSecureSocksProxyContextDialer() + if err != nil { + return nil, err + } URL, err := ParseURL(dsInfo.URL, logger) if err != nil { return nil, err } - driverName, err = createMSSQLProxyDriver(cnnstr, URL.Hostname(), proxyOpts) + driverName, err = createMSSQLProxyDriver(cnnstr, URL.Hostname(), dialer) if err != nil { return nil, err } diff --git a/pkg/tsdb/mssql/proxy.go b/pkg/tsdb/mssql/proxy.go index 84b20000baf..2518af15d44 100644 --- a/pkg/tsdb/mssql/proxy.go +++ b/pkg/tsdb/mssql/proxy.go @@ -10,14 +10,13 @@ import ( "net" "slices" - sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" mssql "github.com/microsoft/go-mssqldb" "golang.org/x/net/proxy" ) // createMSSQLProxyDriver creates and registers a new sql driver that uses a mssql connector and updates the dialer to // route connections through the secure socks proxy -func createMSSQLProxyDriver(cnnstr string, hostName string, opts *sdkproxy.Options) (string, error) { +func createMSSQLProxyDriver(cnnstr string, hostName string, dialer proxy.Dialer) (string, error) { // create a unique driver per connection string hash := fmt.Sprintf("%x", md5.Sum([]byte(cnnstr))) driverName := "mssql-proxy-" + hash @@ -29,7 +28,7 @@ func createMSSQLProxyDriver(cnnstr string, hostName string, opts *sdkproxy.Optio return "", err } - driver, err := newMSSQLProxyDriver(connector, hostName, opts) + driver, err := newMSSQLProxyDriver(connector, hostName, dialer) if err != nil { return "", err } @@ -62,12 +61,7 @@ var _ driver.DriverContext = (*mssqlProxyDriver)(nil) // newMSSQLProxyDriver updates the dialer for a mssql connector with a dialer that proxys connections through the secure socks proxy // and returns a new mssql driver to register -func newMSSQLProxyDriver(connector *mssql.Connector, hostName string, opts *sdkproxy.Options) (*mssqlProxyDriver, error) { - dialer, err := sdkproxy.New(opts).NewSecureSocksProxyContextDialer() - if err != nil { - return nil, err - } - +func newMSSQLProxyDriver(connector *mssql.Connector, hostName string, dialer proxy.Dialer) (*mssqlProxyDriver, error) { contextDialer, ok := dialer.(proxy.ContextDialer) if !ok { return nil, errors.New("unable to cast socks proxy dialer to context proxy dialer") diff --git a/pkg/tsdb/mssql/proxy_test.go b/pkg/tsdb/mssql/proxy_test.go index 9777e00e255..7a735c00ec0 100644 --- a/pkg/tsdb/mssql/proxy_test.go +++ b/pkg/tsdb/mssql/proxy_test.go @@ -3,38 +3,46 @@ package mssql import ( "context" "fmt" + "net" "testing" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/sqleng" - "github.com/grafana/grafana/pkg/tsdb/sqleng/proxyutil" mssql "github.com/microsoft/go-mssqldb" "github.com/stretchr/testify/require" + "golang.org/x/net/proxy" ) +type testDialer struct { +} + +func (d *testDialer) Dial(network, addr string) (c net.Conn, err error) { + return nil, fmt.Errorf("test-dialer: Dial is not functional") +} + +func (d *testDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return nil, fmt.Errorf("test-dialer: DialContext is not functional") +} + +var _ proxy.Dialer = (&testDialer{}) +var _ proxy.ContextDialer = (&testDialer{}) + +func newTestDialer() proxy.Dialer { + d := testDialer{} + return &d +} + func TestMSSQLProxyDriver(t *testing.T) { - settings := proxyutil.SetupTestSecureSocksProxySettings(t) - proxySettings := setting.SecureSocksDSProxySettings{ - Enabled: true, - ClientCert: settings.ClientCert, - ClientKey: settings.ClientKey, - RootCA: settings.RootCA, - ProxyAddress: settings.ProxyAddress, - ServerName: settings.ServerName, - } - opts := proxyutil.GetSQLProxyOptions(proxySettings, sqleng.DataSourceInfo{UID: "1", JsonData: sqleng.JsonData{SecureDSProxy: true}}, "mssql", "mssql") cnnstr := "server=127.0.0.1;port=1433;user id=sa;password=yourStrong(!)Password;database=db" - driverName, err := createMSSQLProxyDriver(cnnstr, "127.0.0.1", opts) + driverName, err := createMSSQLProxyDriver(cnnstr, "127.0.0.1", newTestDialer()) require.NoError(t, err) t.Run("Driver should not be registered more than once", func(t *testing.T) { - testDriver, err := createMSSQLProxyDriver(cnnstr, "127.0.0.1", opts) + testDriver, err := createMSSQLProxyDriver(cnnstr, "127.0.0.1", newTestDialer()) require.NoError(t, err) require.Equal(t, driverName, testDriver) }) t.Run("A new driver should be created for a new connection string", func(t *testing.T) { - testDriver, err := createMSSQLProxyDriver("server=localhost;user id=sa;password=yourStrong(!)Password;database=db2", "localhost", opts) + testDriver, err := createMSSQLProxyDriver("server=localhost;user id=sa;password=yourStrong(!)Password;database=db2", "localhost", newTestDialer()) require.NoError(t, err) require.NotEqual(t, driverName, testDriver) }) @@ -42,23 +50,23 @@ func TestMSSQLProxyDriver(t *testing.T) { t.Run("Connector should use dialer context that routes through the socks proxy to db", func(t *testing.T) { connector, err := mssql.NewConnector(cnnstr) require.NoError(t, err) - driver, err := newMSSQLProxyDriver(connector, "127.0.0.1", opts) + driver, err := newMSSQLProxyDriver(connector, "127.0.0.1", newTestDialer()) require.NoError(t, err) conn, err := driver.OpenConnector(cnnstr) require.NoError(t, err) _, err = conn.Connect(context.Background()) - require.Contains(t, err.Error(), fmt.Sprintf("socks connect tcp %s->127.0.0.1:1433", settings.ProxyAddress)) + require.Contains(t, err.Error(), "test-dialer: DialContext is not functional") }) t.Run("Open should use the connector that routes through the socks proxy to db", func(t *testing.T) { connector, err := mssql.NewConnector(cnnstr) require.NoError(t, err) - driver, err := newMSSQLProxyDriver(connector, "127.0.0.1", opts) + driver, err := newMSSQLProxyDriver(connector, "127.0.0.1", newTestDialer()) require.NoError(t, err) _, err = driver.Open(cnnstr) - require.Contains(t, err.Error(), fmt.Sprintf("socks connect tcp %s->127.0.0.1:1433", settings.ProxyAddress)) + require.Contains(t, err.Error(), "test-dialer: DialContext is not functional") }) }