Test ports are covered by firewall

This commit is contained in:
Nick Sardo
2018-02-05 13:54:27 -08:00
parent 1105751cc7
commit dd462ceb94
3 changed files with 151 additions and 3 deletions

View File

@@ -302,6 +302,83 @@ func PackProtocolsPortsFromFirewall(alloweds []*compute.FirewallAllowed) []strin
return protocolPorts
}
type portRange struct {
protocol string
min, max int
}
func toPortRange(s string) (pr portRange, err error) {
protoPorts := strings.Split(s, "/")
// Set protocol
pr.protocol = strings.ToUpper(protoPorts[0])
if len(protoPorts) != 2 {
return pr, fmt.Errorf("expected a single '/' in %q", s)
}
ports := strings.Split(protoPorts[1], "-")
switch len(ports) {
case 1:
v, err := strconv.Atoi(ports[0])
if err != nil {
return pr, err
}
pr.min, pr.max = v, v
case 2:
start, err := strconv.Atoi(ports[0])
if err != nil {
return pr, err
}
end, err := strconv.Atoi(ports[1])
if err != nil {
return pr, err
}
pr.min, pr.max = start, end
default:
return pr, fmt.Errorf("unexpected range value %q", protoPorts[1])
}
return pr, nil
}
// isPortsSubset asserts that the "requiredPorts" are covered by the "coverage" ports.
// requiredPorts - must be single-port, examples: 'tcp/50', 'udp/80'.
// coverage - single or port-range values, example: 'tcp/50', 'udp/80-1000'.
// Returns true if every requiredPort exists in the list of coverage rules.
func isPortsSubset(requiredPorts, coverage []string) error {
for _, reqPort := range requiredPorts {
rRange, err := toPortRange(reqPort)
if err != nil {
return err
}
if rRange.min != rRange.max {
return fmt.Errorf("requiring a range is not supported: %q", reqPort)
}
var covered bool
for _, c := range coverage {
cRange, err := toPortRange(c)
if err != nil {
return err
}
if rRange.protocol != cRange.protocol {
continue
}
if rRange.min >= cRange.min && rRange.min <= cRange.max {
covered = true
break
}
}
if !covered {
return fmt.Errorf("%q is not covered by %v", reqPort, coverage)
}
}
return nil
}
// SameStringArray verifies whether two string arrays have the same strings, return error if not.
// Order does not matter.
// When `include` is set to true, verifies whether result includes all elements from expected.
@@ -334,10 +411,19 @@ func VerifyFirewallRule(res, exp *compute.Firewall, network string, portsSubset
if !strings.HasSuffix(res.Network, "/"+network) {
return fmt.Errorf("incorrect network: %v, expected ends with: %v", res.Network, "/"+network)
}
if err := SameStringArray(PackProtocolsPortsFromFirewall(res.Allowed),
PackProtocolsPortsFromFirewall(exp.Allowed), portsSubset); err != nil {
return fmt.Errorf("incorrect allowed protocols ports: %v", err)
actualPorts := PackProtocolsPortsFromFirewall(res.Allowed)
expPorts := PackProtocolsPortsFromFirewall(exp.Allowed)
if portsSubset {
if err := isPortsSubset(expPorts, actualPorts); err != nil {
return fmt.Errorf("incorrect allowed protocol ports: %v", err)
}
} else {
if err := SameStringArray(actualPorts, expPorts, false); err != nil {
return fmt.Errorf("incorrect allowed protocols ports: %v", err)
}
}
if err := SameStringArray(res.SourceRanges, exp.SourceRanges, false); err != nil {
return fmt.Errorf("incorrect source ranges %v, expected %v: %v", res.SourceRanges, exp.SourceRanges, err)
}