diff --git a/cmd/in.go b/cmd/in.go index c146906..e615be0 100644 --- a/cmd/in.go +++ b/cmd/in.go @@ -10,7 +10,7 @@ import ( func newIn() *cli.Command { return &cli.Command{ Name: "in", - Usage: "Determine if an ip falls within a range", + Usage: "Determine if an ip or range falls within one or more ranges", Aliases: []string{"i"}, Action: func(_ context.Context, command *cli.Command) error { args := command.Args().Slice() @@ -19,6 +19,6 @@ func newIn() *cli.Command { return handler.Handle(args) }, - UsageText: "in [ip] [range1] [optional range2] [optional rangeN]", + UsageText: "in [ip or range] [range1] [optional range2] [optional rangeN]", } } diff --git a/internal/cidr/cidr_block.go b/internal/cidr/cidr_block.go index 67c4fd9..3c80ed1 100644 --- a/internal/cidr/cidr_block.go +++ b/internal/cidr/cidr_block.go @@ -15,8 +15,8 @@ const ( ) type CIDRBlock struct { - Network string - HostPortion int + Network string + Host int } func NewBlock(network string) *CIDRBlock { @@ -26,8 +26,8 @@ func NewBlock(network string) *CIDRBlock { hostPortion := networkAndHostPortion[1] return &CIDRBlock{ - Network: networkPortion, - HostPortion: must(strconv.Atoi(hostPortion)), + Network: networkPortion, + Host: must(strconv.Atoi(hostPortion)), } } @@ -41,10 +41,10 @@ func (b *CIDRBlock) Subnet(sizes []int) ([]string, error) { subnetBlock := NewBlock(fmt.Sprintf("%s/%v", next.Network, size)) if !b.Contains(subnetBlock.Network) { - return nil, fmt.Errorf("invalid configuration: subnet %s/%v is outside provided network range %s/%v", next.Network, size, b.Network, b.HostPortion) + return nil, fmt.Errorf("invalid configuration: subnet %s/%v is outside provided network range %s/%v", next.Network, size, b.Network, b.Host) } - subnets = append(subnets, fmt.Sprintf("%s/%v", subnetBlock.Network, subnetBlock.HostPortion)) + subnets = append(subnets, fmt.Sprintf("%s/%v", subnetBlock.Network, subnetBlock.Host)) next = NewBlock(fmt.Sprintf("%s/%v", subnetBlock.StartAddressOfNextBlock(), size)) } @@ -53,10 +53,12 @@ func (b *CIDRBlock) Subnet(sizes []int) ([]string, error) { } // https://stackoverflow.com/questions/9622967/how-to-see-if-an-ip-address-belongs-inside-of-a-range-of-ips-using-cidr-notation -func (b *CIDRBlock) Contains(ip string) bool { - IP_addr := ipToDecimal(ip) - CIDR_addr := ipToDecimal(b.Network) - CIDR_mask := -1 << (INT_SIZE - b.HostPortion) +func (outer *CIDRBlock) Contains(inner string) bool { + innerNetwork := strings.Split(inner, "/")[0] + + IP_addr := ipToDecimal(innerNetwork) + CIDR_addr := ipToDecimal(outer.Network) + CIDR_mask := -1 << (INT_SIZE - outer.Host) return (IP_addr & CIDR_mask) == (CIDR_addr & CIDR_mask) } @@ -88,9 +90,9 @@ func toBin(s string) string { return paddedBynaryString } -func (b *CIDRBlock) SubnetMask() string { - ones := strings.Repeat("1", b.HostPortion) - zeroes := strings.Repeat("0", INT_SIZE-b.HostPortion) +func (b *CIDRBlock) Mask() string { + ones := strings.Repeat("1", b.Host) + zeroes := strings.Repeat("0", INT_SIZE-b.Host) mask := ones + zeroes @@ -100,7 +102,7 @@ func (b *CIDRBlock) SubnetMask() string { } func (b *CIDRBlock) AvailableHosts() uint { - numAddresses := math.Pow(2, float64(INT_SIZE)-float64(b.HostPortion)) + numAddresses := math.Pow(2, float64(INT_SIZE)-float64(b.Host)) return uint(numAddresses) } @@ -131,9 +133,9 @@ func (b *CIDRBlock) StartAddressOfNextBlock() string { } func (b *CIDRBlock) NetworkAddress() string { - ipBin := strings.ReplaceAll(b.NetworkPortionBinary(), ".", "")[0:b.HostPortion] + ipBin := strings.ReplaceAll(b.NetworkPortionBinary(), ".", "")[0:b.Host] - broadcast := ipBin + strings.Repeat("0", INT_SIZE-b.HostPortion) + broadcast := ipBin + strings.Repeat("0", INT_SIZE-b.Host) octets := stringToOctets(broadcast) @@ -142,9 +144,9 @@ func (b *CIDRBlock) NetworkAddress() string { func (b *CIDRBlock) BroadcastAddress() string { // https://stackoverflow.com/questions/1470792/how-to-calculate-the-ip-range-when-the-ip-address-and-the-netmask-is-given - ipBin := strings.ReplaceAll(b.NetworkPortionBinary(), ".", "")[0:b.HostPortion] + ipBin := strings.ReplaceAll(b.NetworkPortionBinary(), ".", "")[0:b.Host] - broadcast := ipBin + strings.Repeat("1", INT_SIZE-b.HostPortion) + broadcast := ipBin + strings.Repeat("1", INT_SIZE-b.Host) octets := stringToOctets(broadcast) diff --git a/internal/cidr/cidr_block_test.go b/internal/cidr/cidr_block_test.go index f3ab114..299d8ea 100644 --- a/internal/cidr/cidr_block_test.go +++ b/internal/cidr/cidr_block_test.go @@ -57,8 +57,10 @@ func Test_Contains(t *testing.T) { ipRange *cidr.CIDRBlock expected bool }{ - "ip inside range": {ip: "10.50.30.7", ipRange: cidr.NewBlock("10.0.0.0/8"), expected: true}, - "ip outside range": {ip: "10.50.30.7", ipRange: cidr.NewBlock("10.0.0.0/28"), expected: false}, + "ip inside range": {ip: "10.0.0.5", ipRange: cidr.NewBlock("10.0.0.0/28"), expected: true}, + "ip outside range": {ip: "10.0.0.17", ipRange: cidr.NewBlock("10.0.0.0/28"), expected: false}, + "range inside range": {ip: "10.0.0.4/30", ipRange: cidr.NewBlock("10.0.0.0/28"), expected: true}, + "range outside range": {ip: "10.0.0.16/29", ipRange: cidr.NewBlock("10.0.0.0/28"), expected: false}, } for name, test := range tests { @@ -97,7 +99,7 @@ func Test_NetworkPortionBinary(t *testing.T) { } } -func Test_SubnetMask(t *testing.T) { +func Test_Mask(t *testing.T) { tests := map[string]struct { input *cidr.CIDRBlock expected string @@ -141,10 +143,10 @@ func Test_SubnetMask(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - actual := test.input.SubnetMask() + actual := test.input.Mask() if actual != test.expected { - t.Fatalf("%s returns correct subnet mask: got %v expected %v", name, actual, test.expected) + t.Fatalf("%s returns correct mask: got %v expected %v", name, actual, test.expected) } }) } diff --git a/internal/commands/in/command.go b/internal/commands/in/command.go index 7f87c4d..22abb6a 100644 --- a/internal/commands/in/command.go +++ b/internal/commands/in/command.go @@ -17,23 +17,23 @@ func (h *handler) Handle(args []string) error { return fmt.Errorf("command expects at least 2 arguments") } - ip := args[0] - ranges := list.Map(args[1:], func(i string) *cidr.CIDRBlock { return cidr.NewBlock(i) }) + ipOrRange := args[0] + blocksInRange := list.Filter(ranges, func(cidr *cidr.CIDRBlock) bool { - return cidr.Contains(ip) + return cidr.Contains(ipOrRange) }) if len(blocksInRange) == 0 { - fmt.Printf("%s is not in any of the provided ranges\n", ip) + fmt.Printf("%s is not in any of the provided ranges\n", ipOrRange) return nil } for _, block := range blocksInRange { - fmt.Printf("%s/%d\n", block.Network, block.HostPortion) + fmt.Printf("%s/%d\n", block.Network, block.Host) } return nil diff --git a/internal/commands/info/command.go b/internal/commands/info/command.go index f05b0fe..fb211a1 100644 --- a/internal/commands/info/command.go +++ b/internal/commands/info/command.go @@ -30,7 +30,7 @@ func (h *handler) Handle(args []string) error { entries := []pair{ {item1: "Address range", item2: fmt.Sprintf("%s - %s", block.NetworkAddress(), block.BroadcastAddress())}, {item1: "Start of next block", item2: block.StartAddressOfNextBlock()}, - {item1: "Mask", item2: fmt.Sprintf("%s (%s)", fmt.Sprintf("/%v", block.HostPortion), block.SubnetMask())}, + {item1: "Mask", item2: fmt.Sprintf("%s (%s)", fmt.Sprintf("/%v", block.Host), block.Mask())}, {item1: "Addresses", item2: fmt.Sprintf("%v", block.AvailableHosts())}, {item1: "Azure addresses", item2: block.AvailableAzureHosts()}, } diff --git a/internal/commands/ranges/command.go b/internal/commands/ranges/command.go index 3aed70c..4541134 100644 --- a/internal/commands/ranges/command.go +++ b/internal/commands/ranges/command.go @@ -62,9 +62,9 @@ func defaultCidrBlockFromHostPortion(hostPortion int) *cidr.CIDRBlock { func printCidrBlocks(blocks []*cidr.CIDRBlock) error { w := tabwriter.NewWriter(os.Stdout, 2, 4, 1, ' ', 0) - fmt.Fprint(w, "Cidr\tSubnet mask\tAddresses\tAzure addresses\n") + fmt.Fprint(w, "Cidr\tMask\tAddresses\tAzure addresses\n") for _, block := range blocks { - fmt.Fprintf(w, "/%v\t%s\t%v\t%s\n", block.HostPortion, block.SubnetMask(), block.AvailableHosts(), block.AvailableAzureHosts()) + fmt.Fprintf(w, "/%v\t%s\t%v\t%s\n", block.Host, block.Mask(), block.AvailableHosts(), block.AvailableAzureHosts()) } return w.Flush()