Skip to content

Commit

Permalink
Allow for adding multiple CIDRs to map to a single logical "network"
Browse files Browse the repository at this point in the history
  • Loading branch information
dekobon committed Sep 15, 2017
1 parent 5f69d57 commit 48f37d9
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.
This project aims to adhere to [Semantic Versioning](http://semver.org/).

## [0.3.0] - 2017-09-15
## Added
- Allow for adding multiple CIDRs to map to a single logical "network"

## [0.2.1] - 2017-09-12
### Fixed
- Fixes [Two NICs from the same network added to a single instance will trigger an alert](https://github.com/joyent/nic-audit/issues/1)
Expand Down
3 changes: 2 additions & 1 deletion example/nic-audit.json5
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* UUID that identifies the network, a CIDR that matches
* the network or the string 'public' which indicates any
* public network. */
"192.168.24.0/21", "e70b8c02-91b8-11e7-ae1f-9392cd8e4bf7"
"192.168.24.0/21,192.168.192.0/21", "e70b8c02-91b8-11e7-ae1f-9392cd8e4bf7"
],
"jpc-public-and-privileged-intranet" : [
"public", "e70b8c02-91b8-11e7-ae1f-9392cd8e4bf7"
Expand All @@ -61,6 +61,7 @@
"networks_to_remove" : [
// Format of network values is the same as the matching pattern
"192.168.24.0/21", // remove JPC-Private NIC
"192.168.192.0/21", // remove JPC-Private NIC
"public", // remove JPC-Public NIC
]
}
Expand Down
13 changes: 8 additions & 5 deletions src/github.com/joyent/nic-audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,17 @@ func countMatchingNetworkIds(instance compute.Instance, searchStrings []string,
}

// If our search string is a CIDR
_, ipNet, ipErr := net.ParseCIDR(search)
ipNets, ipErr := parseMultipleCIDRs(search)
if ipErr == nil {
for ip, networkId := range netToIps {
instanceIp := net.ParseIP(ip)
if ipNet.Contains(instanceIp) {
count += 1
delete(netToIps, ip)
deleteByValue(netToIps, networkId)

for _, ipNet := range ipNets {
if ipNet.Contains(instanceIp) {
count += 1
delete(netToIps, ip)
deleteByValue(netToIps, networkId)
}
}
}
continue
Expand Down
40 changes: 38 additions & 2 deletions src/github.com/joyent/nic-audit/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func TestCountOfMatchingNetworkIdsMatchesPublicAndCIDRShouldCountAsOne(t *testin
}
}

func TestCountOfMatchingNetworkIdsMatchesTwoCIDROutOfMantyShouldCountAsOne(t *testing.T) {
func TestCountOfMatchingNetworkIdsMatchesTwoCIDROutOfManyShouldCountAsOne(t *testing.T) {
instanceNetworks := []string{
"70294144-7680-43d2-9ed0-897ce1658f80",
"14323a83-b0e3-44e8-bd67-fc7078cc94ba",
Expand Down Expand Up @@ -254,4 +254,40 @@ func TestCountOfMatchingNetworkIdsMatchesTwoCIDRShouldCountAsOne(t *testing.T) {
t.Errorf("Expected 1 networks matched. Actually matched %v networks.",
count)
}
}
}

func TestCountOfMatchingNetworkIdsMatchesMultipleCIDRSearch(t *testing.T) {
instanceNetworks := []string{
"e8bc049e-9804-11e7-b5fa-43719e86e8fe",
"84eacf74-8310-4549-b297-96743e5fa947",
"a345f0a8-551c-4a33-8040-9bc76440f42c",
}

ips := []string{
"192.168.24.7", "105.160.112.196", "10.2.45.234",
}

instance := compute.Instance{
Networks: instanceNetworks,
IPs: ips,
}

search := []string{
// example of JPC-Private and a user network
"192.168.24.0/21, 192.168.192.0/21", "84eacf74-8310-4549-b297-96743e5fa947",
}

privateBlocks := []string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"105.160.112.0/22",
}

count := countMatchingNetworkIds(instance, search, privateBlocks)

if count != 2 {
t.Errorf("Expected 1 networks matched. Actually matched %v networks.",
count)
}
}
47 changes: 47 additions & 0 deletions src/github.com/joyent/nic-audit/ip_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"fmt"
"log"
"net"
"strings"
)

// isPrivateIP determines if the specified IP address is on a
Expand Down Expand Up @@ -38,3 +39,49 @@ func isPrivateIP(ip net.IP, privateBlocks []string) bool {
func isPublicIP(ip net.IP, privateBlocks []string) bool {
return !isPrivateIP(ip, privateBlocks)
}

// parseMultipleCIDRs parses a comma delimited list of CIDRs and returns an
// array containing all valid values.
func parseMultipleCIDRs(input string) ([]net.IPNet, error) {
if strings.Contains(input, ",") {
uniqueCidrs := make(map[string]bool)

elements := strings.Split(input, ",")

cidrs := make([]net.IPNet, len(elements))

count := 0
for _, element := range elements {
cidr := strings.TrimSpace(element)

if len(cidr) < 1 {
continue
}

_, ipNet, ipErr := net.ParseCIDR(strings.TrimSpace(cidr))

if ipErr != nil {
log.Printf("Invalid CIDR specified: %v\n", cidr)
continue
}

if uniqueCidrs[ipNet.String()] {
log.Printf("Duplicate CIDR specified: %v\n", cidr)
continue
}

cidrs[count] = *ipNet
uniqueCidrs[ipNet.String()] = true
count++
}

return cidrs[0:count], nil
}

_, ipNet, ipErr := net.ParseCIDR(strings.TrimSpace(input))
if ipErr != nil {
return nil, ipErr
} else {
return []net.IPNet{*ipNet}, nil
}
}
127 changes: 127 additions & 0 deletions src/github.com/joyent/nic-audit/ip_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2017, Joyent, Inc. All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package main

import (
"fmt"
"net"
"testing"
)

func TestParseMultipleCIDRsCanParseASingleValidCIDR(t *testing.T) {
cidr := "172.16.0.0/12"
_, expected, _ := net.ParseCIDR(cidr)

cidrs, err := parseMultipleCIDRs(cidr)

if err != nil {
t.Error(err)
}

if len(cidrs) != 1 {
t.Errorf("Too many elements returned. Expected 1. Actually: %v",
len(cidrs))
}

if cidrs[0].String() != expected.String() {
t.Errorf("Unexpected value: %v", cidrs[0])
}
}

func TestParseMultipleCIDRsWillErrorOnASingleInvalidCIDR(t *testing.T) {
cidr := "172.16.0.0/99"
_, err := parseMultipleCIDRs(cidr)

if err == nil {
t.Error("Expected error and none was thrown")
}
}

func TestParseMultipleCIDRsCanParseMultipleValidCIDRs(t *testing.T) {
input := "172.16.0.0/12,192.168.24.0/21,10.0.0.0/8"
expected := "[{172.16.0.0 fff00000} {192.168.24.0 fffff800} {10.0.0.0 ff000000}]"
cidrs, err := parseMultipleCIDRs(input)

if err != nil {
t.Error(err)
}

if len(cidrs) != 3 {
t.Errorf("Incorrect number of elements returned. Expected 3. Actually: %v",
len(cidrs))
}

cidrsAsString := fmt.Sprintf("%v", cidrs)

if cidrsAsString != expected {
t.Errorf("Unexpected value: %v\nExpected: %v", cidrsAsString, expected)
}
}

func TestParseMultipleCIDRsCanParseMultipleValidCIDRsWithWhitespace(t *testing.T) {
input := " 172.16.0.0/12, 192.168.24.0/21, 10.0.0.0/8"
expected := "[{172.16.0.0 fff00000} {192.168.24.0 fffff800} {10.0.0.0 ff000000}]"
cidrs, err := parseMultipleCIDRs(input)

if err != nil {
t.Error(err)
}

if len(cidrs) != 3 {
t.Errorf("Incorrect number of elements returned. Expected 3. Actually: %v",
len(cidrs))
}

cidrsAsString := fmt.Sprintf("%v", cidrs)

if cidrsAsString != expected {
t.Errorf("Unexpected value: %v\nExpected: %v", cidrsAsString, expected)
}
}

func TestParseMultipleCIDRsCanParseMultipleValidAndOneInvalidCIDRs(t *testing.T) {
input := " 172.16.0.0/12,192.168.24.0/99,10.0.0.0/8"
expected := "[{172.16.0.0 fff00000} {10.0.0.0 ff000000}]"
cidrs, err := parseMultipleCIDRs(input)

if err != nil {
t.Error(err)
}

if len(cidrs) != 2 {
t.Errorf("Incorrect number of elements returned. Expected 2. Actually: %v",
len(cidrs))
}

cidrsAsString := fmt.Sprintf("%v", cidrs)

if cidrsAsString != expected {
t.Errorf("Unexpected value: %v\nExpected: %v", cidrsAsString, expected)
}
}

func TestParseMultipleCIDRsCanParseMultipleValidCIDRsWithDuplicate(t *testing.T) {
input := "172.16.0.0/12,192.168.24.0/21,172.16.0.0/12"
expected := "[{172.16.0.0 fff00000} {192.168.24.0 fffff800}]"
cidrs, err := parseMultipleCIDRs(input)

if err != nil {
t.Error(err)
}

if len(cidrs) != 2 {
t.Errorf("Incorrect number of elements returned. Expected 2. Actually: %v",
len(cidrs))
}

cidrsAsString := fmt.Sprintf("%v", cidrs)

if cidrsAsString != expected {
t.Errorf("Unexpected value: %v\nExpected: %v", cidrsAsString, expected)
}
}

0 comments on commit 48f37d9

Please sign in to comment.