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  }