go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/cmd/cidr/main.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package main 9 10 import ( 11 "fmt" 12 "net" 13 "os" 14 15 "github.com/urfave/cli/v2" 16 17 "go.charczuk.com/sdk/cliutil" 18 "go.charczuk.com/sdk/netutil" 19 ) 20 21 func main() { 22 app := &cli.App{ 23 Name: "cidr", 24 Usage: "helper utilities for dealing with cidr ranges", 25 Commands: []*cli.Command{ 26 increment, 27 addressRange, 28 contains, 29 overlaps, 30 }, 31 } 32 if err := app.Run(os.Args); err != nil { 33 cliutil.Fatal(err) 34 } 35 } 36 37 var increment = &cli.Command{ 38 Name: "increment", 39 Usage: "increment a range to the next, non-overlapping range", 40 Aliases: []string{"next", "incr", "n", "i"}, 41 Action: func(ctx *cli.Context) error { 42 _, parsed, err := netutil.ParseCIDR(ctx.Args().First()) 43 if err != nil { 44 return err 45 } 46 47 next, ok := parsed.Next() 48 if !ok { 49 return fmt.Errorf("cannot increment cidr") 50 } 51 fmt.Fprintln(os.Stdout, next.String()) 52 return nil 53 }, 54 } 55 56 var addressRange = &cli.Command{ 57 Name: "range", 58 Usage: "print the first and last address of a given cidr", 59 Action: func(ctx *cli.Context) error { 60 _, parsed, err := netutil.ParseCIDR(ctx.Args().First()) 61 if err != nil { 62 return err 63 } 64 65 begin, end := parsed.Range() 66 fmt.Fprintln(os.Stdout, begin.String()) 67 fmt.Fprintln(os.Stdout, end.String()) 68 return nil 69 }, 70 } 71 72 var contains = &cli.Command{ 73 Name: "contains", 74 Usage: "test if an address is contained in a cidr", 75 Action: func(ctx *cli.Context) error { 76 _, parsed, err := netutil.ParseCIDR(ctx.Args().First()) 77 if err != nil { 78 return err 79 } 80 testAddr := net.ParseIP(ctx.Args().Get(1)) 81 if parsed.Contains(testAddr) { 82 return nil 83 } 84 return fmt.Errorf("%s does not contain %v", parsed, testAddr) 85 }, 86 } 87 88 var overlaps = &cli.Command{ 89 Name: "overlaps", 90 Usage: "test if an cidr overlaps with another cidr", 91 Action: func(ctx *cli.Context) error { 92 // parse all the subnets from the args 93 var subnets []*netutil.IPNet 94 for _, arg := range ctx.Args().Slice() { 95 _, parsed, err := netutil.ParseCIDR(arg) 96 if err != nil { 97 return fmt.Errorf("cannot parse cidr; %w", err) 98 } 99 subnets = append(subnets, parsed) 100 } 101 for i, first := range subnets { 102 for j := 0; j < len(subnets); j++ { 103 if i == j { 104 continue 105 } 106 second := subnets[j] 107 if first.Overlaps(second) { 108 return fmt.Errorf("%s overlaps with %s", first, second) 109 } 110 } 111 } 112 return nil 113 }, 114 }