ADDED:
* num-addrs subcommand, to get the number of hosts/addresses in a given
  prefix length
* get-net subcommand, to more easily get a single subnet from either the
  beginning or the end of a prefix. (MUCH FASTER than CIDR-splitting!)
This commit is contained in:
brent saner
2025-04-13 18:25:32 -04:00
parent c05f9c4d47
commit 860ad5842b
16 changed files with 334 additions and 78 deletions

View File

@@ -2,11 +2,13 @@ package main
type Args struct {
Version verArgs `command:"version" alias:"v" description:"Show version information." validate:"omitempty"`
SplitCIDR SplitCIDRArgs `command:"split-cidr" alias:"sc" description:"Split a network into as many equal subnets of prefix size N as possible." validate:"omitempty"`
GetPfx GetPfxArgs `command:"get-net" alias:"gn" description:"Get a single subnet from a network at either the beginning or end. (You'll probably want to enable -r/--no-remaining.)" validate:"omitempty"`
SplitCIDR SplitCIDRArgs `command:"split-cidr" alias:"sc" description:"Split a network into as many equal subnets of prefix size N as possible. (This may have issues/take a very long time if you are splitting a very large network into many very small subnets.)" 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." 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:"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" alias:"net" description:"Print information about an explicit network address." validate:"omitempty"`
NumAddrs NAddrArgs `command:"num-addrs" alias:"na" alias:"addrs" description:"Return the number of addresses/hosts in a given network size. (This saves needing to lookup from the table subcommand.)" 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"`
Table TableArgs `command:"table" alias:"t" alias:"tab" alias:"tbl" description:"Show prefix summaries (by default both IPv4 and IPv6)." validate:"omitempty"`
@@ -49,6 +51,21 @@ type cacheArgs struct {
DoResCache bool `short:"c" long:"cache-reservations" env:"SBNTR_RSVCACHE" description:"Enable caching/cache lookup for reservation data."`
}
type GetPfxArgs struct {
Position string `short:"P" long:"position" choice:"first" choice:"last" default:"first" description:"The position of the subnet within the network." validate:"required,oneof=first last"`
Prefix uint8 `short:"s" long:"size" required:"true" description:"Prefix length/network size in bits (as CIDR number)." validate:"required"`
splitArgs
}
type NAddrArgs struct {
Isv6 bool `short:"6" long:"v6" description:"If the prefix given is <=32, specify this flag to indicate that it is an IPv6 prefix and not IPv4. (If it is >32, it is automatically treated as an IPv6 prefix for obvious reasons.)"`
InclNetAddr bool `short:"N" long:"incl-net" description:"If specified, include the network address in the count."`
InclBcastAddr bool `short:"B" long:"incl-bcast" description:"If specified, include the broadcast/reserved broadcast address in the count."`
Size struct {
PrefixSize uint8 `positional-arg-name:"<prefix length>" required:"1" validate:"lte=128"`
} `positional-args:"yes" required:"1" validate:"required"`
}
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)."`

View File

@@ -15,7 +15,6 @@ import (
"time"
"github.com/goccy/go-yaml"
"github.com/projectdiscovery/mapcidr"
"go4.org/netipx"
"r00t2.io/subnetter/netsplit"
"r00t2.io/subnetter/version"
@@ -159,8 +158,8 @@ func printMask(label string, pfx netip.Prefix, verb, indent int, indentStr strin
fmt.Fprintf(sb, "%sBits:\t\t%d\n", pre2, pfx.Bits())
fmt.Fprintf(sb, "%sFirst:\t\t%s\n", pre2, first.String())
fmt.Fprintf(sb, "%sLast:\t\t%s\n", pre2, last.String())
fmt.Fprintf(sb, "%sAddresses:\t%d\n", pre2, mapcidr.CountIPsInCIDR(true, true, netipx.PrefixIPNet(pfx.Masked())))
fmt.Fprintf(sb, "%sHosts:\t\t%d\n", pre2, mapcidr.CountIPsInCIDR(false, false, netipx.PrefixIPNet(pfx.Masked())))
fmt.Fprintf(sb, "%sAddresses:\t%d\n", pre2, netsplit.NumAddrsPfx(pfx.Masked(), true, true))
fmt.Fprintf(sb, "%sHosts:\t\t%d\n", pre2, netsplit.NumAddrsPfx(pfx.Masked(), false, false))
if verb >= 2 {
fmt.Fprintf(sb, "%sExpanded:\t%s\n", pre2, netsplit.MaskExpand(mask, pfx.Addr().Is6()))
fmt.Fprintf(sb, "%sHex:\t\t0x%s\n", pre2, mask.String())

View File

@@ -10,7 +10,6 @@ import (
`strings`
`github.com/TwiN/go-color`
`github.com/projectdiscovery/mapcidr`
`go4.org/netipx`
`r00t2.io/subnetter/netsplit`
)
@@ -423,8 +422,8 @@ func tplTablePrefixes(ipVer uint8, indent string, plain bool) (out string, err e
return
}
dummyNet = netipx.PrefixIPNet(rows[idx].NetPrefix.Masked())
rows[idx].Addresses = mapcidr.CountIPsInCIDR(true, true, dummyNet)
rows[idx].Hosts = mapcidr.CountIPsInCIDR(false, false, dummyNet)
rows[idx].Addresses = netsplit.NumAddrsNet(dummyNet, true, true)
rows[idx].Hosts = netsplit.NumAddrsNet(dummyNet, false, false)
}
colFields, colTitles, colSizes = sizeStructs(rows)

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"log"
`math/big`
"net"
"net/netip"
"os"
@@ -34,6 +35,7 @@ func main() {
var buf *bytes.Buffer
var res *netsplit.StructuredResults
var numNets uint
var numAddrs *big.Int
var v6Only bool
var noStrict bool
var strictErr error
@@ -84,6 +86,18 @@ func main() {
log.Panicln(err)
}
return
case "num-addrs":
if err = validate.Struct(args.NumAddrs); err != nil {
log.Panicln(err)
}
if args.NumAddrs.Size.PrefixSize > 32 {
args.NumAddrs.Isv6 = true
}
if numAddrs, err = netsplit.NumAddrsIn(args.NumAddrs.Size.PrefixSize, args.NumAddrs.Isv6, args.NumAddrs.InclNetAddr, args.NumAddrs.InclBcastAddr); err != nil {
log.Panicln(err)
}
fmt.Println(numAddrs.String())
return
case "num-nets":
if err = validate.Struct(args.NumNets); err != nil {
log.Panicln(err)
@@ -195,6 +209,18 @@ func main() {
These are all handily-dandily enclosed in a `common` struct type.
*/
switch parser.Active.Name {
case "get-net": // Not a *true* splitter, per se; splitting is required but only for functional reasons.
if err = validate.Struct(args.GetPfx); err != nil {
log.Panicln(err)
}
cmnArgs = args.GetPfx.common
splitter = &netsplit.PrefixGetter{
Pos: args.GetPfx.Position,
PrefixLength: args.GetPfx.Prefix,
BaseSplitter: new(netsplit.BaseSplitter),
}
noStrict = false
strictErr = netsplit.ErrBadNumHosts // dummy
case "split-hosts":
if err = validate.Struct(args.SplitHost); err != nil {
log.Panicln(err)