v0.2.0
ADDED: * num-nets subcommand' this is MUCH much faster than actually splitting if you're trying to figure out how many times a given subnet fits into a network.
This commit is contained in:
parent
701b598b1c
commit
3c239a4d09
@ -5,8 +5,9 @@ type Args struct {
|
|||||||
SplitCIDR SplitCIDRArgs `command:"split-cidr" alias:"se" description:"Split a network into as many equal subnets of prefix size N as possible." validate:"omitempty"`
|
SplitCIDR SplitCIDRArgs `command:"split-cidr" alias:"se" description:"Split a network into as many equal subnets of prefix size N as possible." validate:"omitempty"`
|
||||||
SplitHost SplitHostArgs `command:"split-hosts" alias:"sh" description:"Split a network into N total number of hosts *per subnet* as cleanly/evenly as possible. (VERY easy to run out of memory for IPv6 prefixes; be sure to specify very small network!)" validate:"omitempty"`
|
SplitHost SplitHostArgs `command:"split-hosts" alias:"sh" description:"Split a network into N total number of hosts *per subnet* as cleanly/evenly as possible. (VERY easy to run out of memory for IPv6 prefixes; be sure to specify very small network!)" validate:"omitempty"`
|
||||||
SplitSubnets SplitSubnetArgs `command:"split-nets" alias:"sn" description:"Split a network into N number of subnets as cleanly as possible." validate:"omitempty"`
|
SplitSubnets SplitSubnetArgs `command:"split-nets" alias:"sn" description:"Split a network into N number of subnets as cleanly as possible." validate:"omitempty"`
|
||||||
VLSM VLSMArgs `command:"vlsm" alias:"sv" description:"Use VLSM (Variable-Length Subnet Masks) to split a network into differently sized subnets." validate:"omitempty"`
|
VLSM VLSMArgs `command:"split-vlsm" alias:"sv" alias:"vlsm" description:"Use VLSM (Variable-Length Subnet Masks) to split a network into differently sized subnets." validate:"omitempty"`
|
||||||
ExplicitNetwork XNetArgs `command:"net" alias:"xn" description:"Print information about an explicit network address." validate:"omitempty"`
|
ExplicitNetwork XNetArgs `command:"net" alias:"xn" alias:"net" description:"Print information about an explicit network address." validate:"omitempty"`
|
||||||
|
NumNets NNetArgs `command:"num-nets" alias:"nn" alias:"nets" description:"Return the number of subnets of a given size that can fit into a given network size. This is MUCH, MUCH FASTER than splitting (if you do not need addressing)." validate:"omitempty"`
|
||||||
Parse ParseArgs `command:"parse" alias:"p" alias:"read" alias:"convert" description:"Parse/convert output from a previous subnetter run." validate:"omitempty"`
|
Parse ParseArgs `command:"parse" alias:"p" alias:"read" alias:"convert" description:"Parse/convert output from a previous subnetter run." validate:"omitempty"`
|
||||||
Table TableArgs `command:"table" alias:"t" alias:"tab" alias:"tbl" description:"Show prefix summaries (by default both IPv4 and IPv6)." validate:"omitempty"`
|
Table TableArgs `command:"table" alias:"t" alias:"tab" alias:"tbl" description:"Show prefix summaries (by default both IPv4 and IPv6)." validate:"omitempty"`
|
||||||
Check CheckArgs `command:"reserved" alias:"r" description:"Check if a subnet is reserved per IANA/RFC." validate:"omitempty"`
|
Check CheckArgs `command:"reserved" alias:"r" description:"Check if a subnet is reserved per IANA/RFC." validate:"omitempty"`
|
||||||
@ -16,7 +17,7 @@ type verArgs struct {
|
|||||||
DetailVersion bool `short:"V" long:"detail" description:"Print detailed version info and exit."`
|
DetailVersion bool `short:"V" long:"detail" description:"Print detailed version info and exit."`
|
||||||
}
|
}
|
||||||
|
|
||||||
type common struct {
|
type commonBase struct {
|
||||||
cacheArgs
|
cacheArgs
|
||||||
SuppressRemaining bool `short:"r" long:"no-remaining" description:"Don't show leftover/unallocated/remaining space."`
|
SuppressRemaining bool `short:"r" long:"no-remaining" description:"Don't show leftover/unallocated/remaining space."`
|
||||||
Plain bool `short:"p" long:"plain" description:"Show plain output instead of unicode (only used if -f/--format=pretty)."`
|
Plain bool `short:"p" long:"plain" description:"Show plain output instead of unicode (only used if -f/--format=pretty)."`
|
||||||
@ -26,7 +27,11 @@ type common struct {
|
|||||||
AllowReserved bool `short:"R" long:"allow-reserved" description:"If specified, do not warn about reserved IP addresses/networks."`
|
AllowReserved bool `short:"R" long:"allow-reserved" description:"If specified, do not warn about reserved IP addresses/networks."`
|
||||||
reservedArgs
|
reservedArgs
|
||||||
AllowHostNet bool `short:"H" long:"allow-host" description:"If specified, do not warn about host bits. Host bits are always removed for subnetting (as otherwise there would be errors); this is only used only for output."`
|
AllowHostNet bool `short:"H" long:"allow-host" description:"If specified, do not warn about host bits. Host bits are always removed for subnetting (as otherwise there would be errors); this is only used only for output."`
|
||||||
Network Net `positional-args:"yes" required:"true" description:"The network/parent prefix to operate on." validate:"required"`
|
}
|
||||||
|
|
||||||
|
type common struct {
|
||||||
|
commonBase
|
||||||
|
Network Net `positional-args:"yes" required:"true" description:"The network/parent prefix to operate on." validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type reservedArgs struct {
|
type reservedArgs struct {
|
||||||
@ -44,8 +49,17 @@ type cacheArgs struct {
|
|||||||
DoResCache bool `short:"c" long:"cache-reservations" env:"SBNTR_RSVCACHE" description:"Enable caching/cache lookup for reservation data."`
|
DoResCache bool `short:"c" long:"cache-reservations" env:"SBNTR_RSVCACHE" description:"Enable caching/cache lookup for reservation data."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NNetArgs struct {
|
||||||
|
Verbose bool `short:"v" long:"verbose" description:"Be verbose (more ideal for logging)."`
|
||||||
|
NoV6Check bool `short:"6" long:"no-v6" description:"If specified, do not indicate if the subnetting is IPv6 only (true) or not (false; dual-stack/IPv4 supported)."`
|
||||||
|
Sizes struct {
|
||||||
|
SubnetSize uint8 `required:"1" validate:"required,le=128,gtefield=NetworkSize"`
|
||||||
|
NetworkSize uint8 `required:"1" validate:"required,le=128,ltefield=SubnetSize"`
|
||||||
|
} `positional-args:"yes" required:"2" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type ParseArgs struct {
|
type ParseArgs struct {
|
||||||
splitArgs
|
commonBase
|
||||||
InFile string `short:"i" long:"input" default:"-" description:"Input file to parse. Default is '-' (for STDIN)." required:"true" validate:"required,filepath|eq=-"`
|
InFile string `short:"i" long:"input" default:"-" description:"Input file to parse. Default is '-' (for STDIN)." required:"true" validate:"required,filepath|eq=-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,9 @@ func printNets(orig *netip.Prefix, origNet *net.IPNet, nets []*netip.Prefix, rem
|
|||||||
|
|
||||||
if args == nil {
|
if args == nil {
|
||||||
args = &common{
|
args = &common{
|
||||||
Separator: "\n",
|
commonBase: commonBase{
|
||||||
|
Separator: "\n",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmts = sectFmts[args.Plain]
|
fmts = sectFmts[args.Plain]
|
||||||
|
@ -33,6 +33,8 @@ func main() {
|
|||||||
var remaining *netipx.IPSet
|
var remaining *netipx.IPSet
|
||||||
var buf *bytes.Buffer
|
var buf *bytes.Buffer
|
||||||
var res *netsplit.StructuredResults
|
var res *netsplit.StructuredResults
|
||||||
|
var numNets uint
|
||||||
|
var v6Only bool
|
||||||
var noStrict bool
|
var noStrict bool
|
||||||
var strictErr error
|
var strictErr error
|
||||||
var reservations map[netip.Prefix]*netsplit.IANAAddrNetResRecord
|
var reservations map[netip.Prefix]*netsplit.IANAAddrNetResRecord
|
||||||
@ -79,6 +81,27 @@ func main() {
|
|||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
case "num-nets":
|
||||||
|
if numNets, v6Only, err = netsplit.NumNets(
|
||||||
|
args.NumNets.Sizes.SubnetSize,
|
||||||
|
args.NumNets.Sizes.NetworkSize,
|
||||||
|
); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
if !args.NumNets.Verbose {
|
||||||
|
fmt.Printf("%d\n", numNets)
|
||||||
|
if !args.NumNets.NoV6Check {
|
||||||
|
fmt.Println(v6Only)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Network Size:\t\t\t%d\n", args.NumNets.Sizes.NetworkSize)
|
||||||
|
fmt.Printf("Subnet Size:\t\t\t%d\n", args.NumNets.Sizes.SubnetSize)
|
||||||
|
fmt.Printf("Number of Subnets:\t\t%d\n", numNets)
|
||||||
|
if !args.NumNets.NoV6Check {
|
||||||
|
fmt.Printf("Subnetting is IPv6-Only:\t%v\n", v6Only)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
case "reserved":
|
case "reserved":
|
||||||
if origPfx, err = netip.ParsePrefix(args.Check.Network.Network); err != nil {
|
if origPfx, err = netip.ParsePrefix(args.Check.Network.Network); err != nil {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
@ -136,7 +159,12 @@ func main() {
|
|||||||
origPfx = *resPfx
|
origPfx = *resPfx
|
||||||
}
|
}
|
||||||
pfx = netipx.PrefixIPNet(origPfx.Masked())
|
pfx = netipx.PrefixIPNet(origPfx.Masked())
|
||||||
cmnArgs = args.Parse.common
|
cmnArgs = common{
|
||||||
|
commonBase: args.Parse.commonBase,
|
||||||
|
Network: Net{
|
||||||
|
Network: res.Original.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
if err = printNets(&origPfx, pfx, nets, remaining, &cmnArgs, res.GetSplitter()); err != nil {
|
if err = printNets(&origPfx, pfx, nets, remaining, &cmnArgs, res.GetSplitter()); err != nil {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
@ -185,7 +213,7 @@ func main() {
|
|||||||
PrefixLength: args.SplitCIDR.Prefix,
|
PrefixLength: args.SplitCIDR.Prefix,
|
||||||
BaseSplitter: new(netsplit.BaseSplitter),
|
BaseSplitter: new(netsplit.BaseSplitter),
|
||||||
}
|
}
|
||||||
case "vlsm":
|
case "split-vlsm":
|
||||||
if err = validate.Struct(args.VLSM); err != nil {
|
if err = validate.Struct(args.VLSM); err != nil {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,12 @@ import (
|
|||||||
`github.com/go-resty/resty/v2`
|
`github.com/go-resty/resty/v2`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxBitsv4 uint8 = 32
|
||||||
|
maxBitsv6 uint8 = 128
|
||||||
|
maxBits uint8 = maxBitsv6
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cachedirEnvName string = "SBNTR_RSVCACHE_DIR"
|
cachedirEnvName string = "SBNTR_RSVCACHE_DIR"
|
||||||
// https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
|
// https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
`math`
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
@ -375,6 +376,38 @@ func MaskInvert(mask net.IPMask) (inverted net.IPMask) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NumNets returns the number of times prefix size subnet fits into prefix size network.
|
||||||
|
|
||||||
|
It will error if network is larger than 128 or if subnet is smaller than network.
|
||||||
|
|
||||||
|
This is MUCH more performant than splitting out an actual network into explicit subnets,
|
||||||
|
and does not require an actual network.
|
||||||
|
*/
|
||||||
|
func NumNets(subnet, network uint8) (numNets uint, ipv6Only bool, err error) {
|
||||||
|
|
||||||
|
var x float64
|
||||||
|
|
||||||
|
// network cannot be higher than 128, as that's the maximum for IPv6.
|
||||||
|
if network > maxBits {
|
||||||
|
err = ErrBadPrefixLen
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if subnet < network {
|
||||||
|
err = ErrBigPrefix
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if network > maxBitsv4 {
|
||||||
|
ipv6Only = true
|
||||||
|
}
|
||||||
|
|
||||||
|
x = float64(subnet - network)
|
||||||
|
|
||||||
|
numNets = uint(math.Pow(2, x))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Parse parses b for JSON/XML/YAML and tries to return a StructuredResults from it.
|
// Parse parses b for JSON/XML/YAML and tries to return a StructuredResults from it.
|
||||||
func Parse(b []byte) (s *StructuredResults, err error) {
|
func Parse(b []byte) (s *StructuredResults, err error) {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user