diff --git a/agent/config.go b/agent/config.go index 5e0d6e86b6..3a21adbc3a 100644 --- a/agent/config.go +++ b/agent/config.go @@ -25,6 +25,14 @@ import ( "github.com/mitchellh/mapstructure" ) +const ( + // SegmentLimit is the maximum number of network segments that may be declared. + SegmentLimit = 64 + + // SegmentNameLimit is the maximum segment name length. + SegmentNameLimit = 64 +) + // Ports is used to simplify the configuration by // providing default ports, and allowing the addresses // to only be specified once @@ -1453,9 +1461,36 @@ func DecodeConfig(r io.Reader) (*Config, error) { return nil, fmt.Errorf("Failed to parse node metadata: %v", err) } + // Validate segment config + if err := ValidateSegments(&result); err != nil { + return nil, err + } + return &result, nil } +func ValidateSegments(conf *Config) error { + if conf.Server && conf.Segment != "" { + return fmt.Errorf("Segment option can only be set on clients") + } + + if !conf.Server && len(conf.Segments) > 0 { + return fmt.Errorf("Cannot define segments on clients") + } + + if len(conf.Segments) > SegmentLimit { + return fmt.Errorf("Cannot exceed network segment limit of %d", SegmentLimit) + } + + for _, segment := range conf.Segments { + if len(segment.Name) > SegmentNameLimit { + return fmt.Errorf("Segment name %q exceeds maximum length of %d", segment.Name, SegmentNameLimit) + } + } + + return nil +} + // DecodeServiceDefinition is used to decode a service definition func DecodeServiceDefinition(raw interface{}) (*structs.ServiceDefinition, error) { rawMap, ok := raw.(map[string]interface{}) diff --git a/agent/config_test.go b/agent/config_test.go index 3494dcd891..a6ad9af43e 100644 --- a/agent/config_test.go +++ b/agent/config_test.go @@ -1309,6 +1309,37 @@ func TestDecodeConfig_VerifyUniqueListeners(t *testing.T) { } } +func TestDecodeConfig_ValidateSegments(t *testing.T) { + t.Parallel() + serverWithSegment := &Config{Segment: "asfd", Server: true} + if err := ValidateSegments(serverWithSegment); !strings.Contains(err.Error(), "can only be set on clients") { + t.Fatalf("bad: %v", err) + } + + clientWithSegments := &Config{ + Segments: []NetworkSegment{{Name: "asdf"}}, + } + if err := ValidateSegments(clientWithSegments); !strings.Contains(err.Error(), "Cannot define segments on clients") { + t.Fatalf("bad: %v", err) + } + + tooManySegments := &Config{Server: true} + for i := 0; i < SegmentLimit+1; i++ { + tooManySegments.Segments = append(tooManySegments.Segments, NetworkSegment{}) + } + if err := ValidateSegments(tooManySegments); !strings.Contains(err.Error(), "Cannot exceed network segment limit") { + t.Fatalf("bad: %v", err) + } + + segmentNameTooLong := &Config{ + Segments: []NetworkSegment{{Name: strings.Repeat("a", SegmentNameLimit+1)}}, + Server: true, + } + if err := ValidateSegments(segmentNameTooLong); !strings.Contains(err.Error(), "exceeds maximum length") { + t.Fatalf("bad: %v", err) + } +} + func TestDefaultConfig(t *testing.T) { t.Parallel()