Skip to content

Commit e2bbbe0

Browse files
committed
refactor: add toggle for internal network access validation
1 parent f960d09 commit e2bbbe0

5 files changed

Lines changed: 33 additions & 14 deletions

File tree

configs/mcp-gateway.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ forward:
149149

150150
tool_access:
151151
internal_network:
152+
# Enable/disable internal network access validation. Defaults to true.
153+
enabled: ${INTERNAL_NETWORK_VALIDATION_ENABLED:false}
152154
# Allowlist of internal targets (CIDR/IP/hostname). Empty means internal access is blocked.
153155
allowlist: "${INTERNAL_NETWORK_ALLOWLIST:127.0.0.1/32,localhost}"
154156
# allowlist: "internal.service.local,192.168.1.1"

internal/common/config/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ type (
6767

6868
// InternalNetworkAccessConfig defines allowlist for internal network targets.
6969
InternalNetworkAccessConfig struct {
70+
// Enabled controls whether internal network access validation is enabled.
71+
Enabled *bool `yaml:"enabled"`
7072
Allowlist StringList `yaml:"allowlist"`
7173
}
7274

internal/core/internal_network.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ func isInternalAddr(addr netip.Addr) bool {
103103
}
104104

105105
func (s *Server) validateToolEndpoint(ctx context.Context, endpoint *url.URL) error {
106+
// Skip validation if internal network access check is disabled
107+
if !s.internalNetEnabled {
108+
return nil
109+
}
110+
106111
if endpoint == nil {
107112
return fmt.Errorf("tool endpoint is empty")
108113
}

internal/core/internal_network_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
func TestValidateToolEndpoint_InternalBlocked(t *testing.T) {
12-
s := &Server{}
12+
s := &Server{internalNetEnabled: true}
1313
u, err := url.Parse("http://127.0.0.1:8080")
1414
assert.NoError(t, err)
1515
assert.Error(t, s.validateToolEndpoint(context.Background(), u))
@@ -19,7 +19,7 @@ func TestValidateToolEndpoint_InternalAllowlistedCIDR(t *testing.T) {
1919
allowlist, invalid := parseInternalNetworkAllowlist([]string{"127.0.0.0/8"})
2020
assert.Empty(t, invalid)
2121

22-
s := &Server{internalNetACL: allowlist}
22+
s := &Server{internalNetEnabled: true, internalNetACL: allowlist}
2323
u, err := url.Parse("http://127.0.0.1:8080")
2424
assert.NoError(t, err)
2525
assert.NoError(t, s.validateToolEndpoint(context.Background(), u))
@@ -29,15 +29,23 @@ func TestValidateToolEndpoint_InternalAllowlistedHost(t *testing.T) {
2929
allowlist, invalid := parseInternalNetworkAllowlist([]string{"internal.local"})
3030
assert.Empty(t, invalid)
3131

32-
s := &Server{internalNetACL: allowlist}
32+
s := &Server{internalNetEnabled: true, internalNetACL: allowlist}
3333
u, err := url.Parse("http://internal.local/health")
3434
assert.NoError(t, err)
3535
assert.NoError(t, s.validateToolEndpoint(context.Background(), u))
3636
}
3737

3838
func TestValidateToolEndpoint_PublicIPAllowed(t *testing.T) {
39-
s := &Server{}
39+
s := &Server{internalNetEnabled: true}
4040
u, err := url.Parse("http://8.8.8.8")
4141
assert.NoError(t, err)
4242
assert.NoError(t, s.validateToolEndpoint(context.Background(), u))
4343
}
44+
45+
func TestValidateToolEndpoint_Disabled(t *testing.T) {
46+
s := &Server{internalNetEnabled: false}
47+
u, err := url.Parse("http://127.0.0.1:8080")
48+
assert.NoError(t, err)
49+
// When disabled, internal addresses should be allowed
50+
assert.NoError(t, s.validateToolEndpoint(context.Background(), u))
51+
}

internal/core/server.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,17 @@ type (
6161
// shutdownCh is used to signal shutdown to all SSE connections
6262
shutdownCh chan struct{}
6363
// toolRespHandler is a chain of response handlers
64-
toolRespHandler ResponseHandler
65-
lastUpdateTime time.Time
66-
auth auth.Auth
67-
forwardConfig config.ForwardConfig
68-
traceCapture apptrace.CaptureConfig
69-
tracingService string // OTel service name for tracing
70-
metrics *metrics.Metrics
71-
metricsPath string
72-
toolAccess config.ToolAccessConfig
73-
internalNetACL internalNetworkAllowlist
64+
toolRespHandler ResponseHandler
65+
lastUpdateTime time.Time
66+
auth auth.Auth
67+
forwardConfig config.ForwardConfig
68+
traceCapture apptrace.CaptureConfig
69+
tracingService string // OTel service name for tracing
70+
metrics *metrics.Metrics
71+
metricsPath string
72+
toolAccess config.ToolAccessConfig
73+
internalNetACL internalNetworkAllowlist
74+
internalNetEnabled bool
7475
// Pre-parsed header lists for efficient lookup
7576
ignoreHeaders []string
7677
allowHeaders []string
@@ -165,6 +166,7 @@ func (s *Server) applyForwardConfig(cfg config.ForwardConfig) {
165166
// applyToolAccessConfig sets tool access config and parses internal allowlists.
166167
func (s *Server) applyToolAccessConfig(cfg config.ToolAccessConfig) {
167168
s.toolAccess = cfg
169+
s.internalNetEnabled = cfg.InternalNetwork.Enabled == nil || *cfg.InternalNetwork.Enabled
168170
allowlist, invalid := parseInternalNetworkAllowlist(cfg.InternalNetwork.Allowlist)
169171
if len(invalid) > 0 {
170172
s.logger.Warn("invalid internal network allowlist entries",

0 commit comments

Comments
 (0)