v0.2.5
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:
parent
c05f9c4d47
commit
860ad5842b
2
TODO
2
TODO
@ -3,3 +3,5 @@
|
|||||||
- when checking/rendering reserved networks, currently the footnotes aren't returned.
|
- when checking/rendering reserved networks, currently the footnotes aren't returned.
|
||||||
-- netsplit.IANARegistryFootnote
|
-- netsplit.IANARegistryFootnote
|
||||||
-- encapsulated in the IANARegistry.Footnotes
|
-- encapsulated in the IANARegistry.Footnotes
|
||||||
|
|
||||||
|
- add new interface, Getter? different formatting?
|
@ -2,11 +2,13 @@ package main
|
|||||||
|
|
||||||
type Args struct {
|
type Args struct {
|
||||||
Version verArgs `command:"version" alias:"v" description:"Show version information." validate:"omitempty"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
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"`
|
||||||
@ -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."`
|
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 {
|
type NNetArgs struct {
|
||||||
Verbose bool `short:"v" long:"verbose" description:"Be verbose (more ideal for logging)."`
|
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)."`
|
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)."`
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/projectdiscovery/mapcidr"
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
"r00t2.io/subnetter/netsplit"
|
"r00t2.io/subnetter/netsplit"
|
||||||
"r00t2.io/subnetter/version"
|
"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, "%sBits:\t\t%d\n", pre2, pfx.Bits())
|
||||||
fmt.Fprintf(sb, "%sFirst:\t\t%s\n", pre2, first.String())
|
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, "%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, "%sAddresses:\t%d\n", pre2, netsplit.NumAddrsPfx(pfx.Masked(), true, true))
|
||||||
fmt.Fprintf(sb, "%sHosts:\t\t%d\n", pre2, mapcidr.CountIPsInCIDR(false, false, netipx.PrefixIPNet(pfx.Masked())))
|
fmt.Fprintf(sb, "%sHosts:\t\t%d\n", pre2, netsplit.NumAddrsPfx(pfx.Masked(), false, false))
|
||||||
if verb >= 2 {
|
if verb >= 2 {
|
||||||
fmt.Fprintf(sb, "%sExpanded:\t%s\n", pre2, netsplit.MaskExpand(mask, pfx.Addr().Is6()))
|
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())
|
fmt.Fprintf(sb, "%sHex:\t\t0x%s\n", pre2, mask.String())
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
`strings`
|
`strings`
|
||||||
|
|
||||||
`github.com/TwiN/go-color`
|
`github.com/TwiN/go-color`
|
||||||
`github.com/projectdiscovery/mapcidr`
|
|
||||||
`go4.org/netipx`
|
`go4.org/netipx`
|
||||||
`r00t2.io/subnetter/netsplit`
|
`r00t2.io/subnetter/netsplit`
|
||||||
)
|
)
|
||||||
@ -423,8 +422,8 @@ func tplTablePrefixes(ipVer uint8, indent string, plain bool) (out string, err e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
dummyNet = netipx.PrefixIPNet(rows[idx].NetPrefix.Masked())
|
dummyNet = netipx.PrefixIPNet(rows[idx].NetPrefix.Masked())
|
||||||
rows[idx].Addresses = mapcidr.CountIPsInCIDR(true, true, dummyNet)
|
rows[idx].Addresses = netsplit.NumAddrsNet(dummyNet, true, true)
|
||||||
rows[idx].Hosts = mapcidr.CountIPsInCIDR(false, false, dummyNet)
|
rows[idx].Hosts = netsplit.NumAddrsNet(dummyNet, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
colFields, colTitles, colSizes = sizeStructs(rows)
|
colFields, colTitles, colSizes = sizeStructs(rows)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
`math/big`
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
@ -34,6 +35,7 @@ func main() {
|
|||||||
var buf *bytes.Buffer
|
var buf *bytes.Buffer
|
||||||
var res *netsplit.StructuredResults
|
var res *netsplit.StructuredResults
|
||||||
var numNets uint
|
var numNets uint
|
||||||
|
var numAddrs *big.Int
|
||||||
var v6Only bool
|
var v6Only bool
|
||||||
var noStrict bool
|
var noStrict bool
|
||||||
var strictErr error
|
var strictErr error
|
||||||
@ -84,6 +86,18 @@ func main() {
|
|||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
return
|
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":
|
case "num-nets":
|
||||||
if err = validate.Struct(args.NumNets); err != nil {
|
if err = validate.Struct(args.NumNets); err != nil {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
@ -195,6 +209,18 @@ func main() {
|
|||||||
These are all handily-dandily enclosed in a `common` struct type.
|
These are all handily-dandily enclosed in a `common` struct type.
|
||||||
*/
|
*/
|
||||||
switch parser.Active.Name {
|
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":
|
case "split-hosts":
|
||||||
if err = validate.Struct(args.SplitHost); err != nil {
|
if err = validate.Struct(args.SplitHost); err != nil {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
|
9
go.mod
9
go.mod
@ -8,7 +8,6 @@ require (
|
|||||||
github.com/go-resty/resty/v2 v2.16.5
|
github.com/go-resty/resty/v2 v2.16.5
|
||||||
github.com/goccy/go-yaml v1.15.23
|
github.com/goccy/go-yaml v1.15.23
|
||||||
github.com/jessevdk/go-flags v1.6.1
|
github.com/jessevdk/go-flags v1.6.1
|
||||||
github.com/projectdiscovery/mapcidr v1.1.34
|
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/mod v0.24.0
|
golang.org/x/mod v0.24.0
|
||||||
r00t2.io/goutils v1.8.1
|
r00t2.io/goutils v1.8.1
|
||||||
@ -16,18 +15,12 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
|
||||||
github.com/djherbis/times v1.6.0 // indirect
|
github.com/djherbis/times v1.6.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/gorilla/css v1.0.1 // indirect
|
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/projectdiscovery/blackrock v0.0.1 // indirect
|
|
||||||
github.com/projectdiscovery/utils v0.4.14 // indirect
|
|
||||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
|
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/net v0.37.0 // indirect
|
golang.org/x/net v0.37.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
|
32
go.sum
32
go.sum
@ -1,7 +1,5 @@
|
|||||||
github.com/TwiN/go-color v1.4.1 h1:mqG0P/KBgHKVqmtL5ye7K0/Gr4l6hTksPgTgMk3mUzc=
|
github.com/TwiN/go-color v1.4.1 h1:mqG0P/KBgHKVqmtL5ye7K0/Gr4l6hTksPgTgMk3mUzc=
|
||||||
github.com/TwiN/go-color v1.4.1/go.mod h1:WcPf/jtiW95WBIsEeY1Lc/b8aaWoiqQpu5cf8WFxu+s=
|
github.com/TwiN/go-color v1.4.1/go.mod h1:WcPf/jtiW95WBIsEeY1Lc/b8aaWoiqQpu5cf8WFxu+s=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -22,58 +20,28 @@ github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ
|
|||||||
github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo=
|
github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo=
|
||||||
github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
|
||||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
|
||||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
|
||||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
|
||||||
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
|
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
|
||||||
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
|
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
|
|
||||||
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
|
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ=
|
|
||||||
github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss=
|
|
||||||
github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQtls1wmXN/kM=
|
|
||||||
github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ=
|
|
||||||
github.com/projectdiscovery/utils v0.0.85 h1:JpCVc9GJwJLNHy1MBPmAHJcE6rs7bRv72Trb3u84OHE=
|
|
||||||
github.com/projectdiscovery/utils v0.0.85/go.mod h1:ttiPgS2LmLFd+VRBUdgfLKMMdrF98zX7z5W+K71MX40=
|
|
||||||
github.com/projectdiscovery/utils v0.4.14 h1:BrEfO4f4P+Hu58jNfjho2aRt/Y4jxKhTVQqs2Ei4670=
|
|
||||||
github.com/projectdiscovery/utils v0.4.14/go.mod h1:y5gnpQn802iEWqf0djTRNskJlS62P5eqe1VS1+ah0tk=
|
|
||||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
|
||||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
|
||||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
|
||||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
|
||||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
|
||||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
`net/netip`
|
`net/netip`
|
||||||
`sync`
|
`sync`
|
||||||
|
|
||||||
|
`github.com/go-playground/validator/v10`
|
||||||
`github.com/go-resty/resty/v2`
|
`github.com/go-resty/resty/v2`
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,8 +40,12 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// TODO
|
// validate *validator.Validate = validator.New(validator.WithRequiredStructEnabled(), validator.WithPrivateFieldValidation())
|
||||||
cacheLock sync.RWMutex
|
validate *validator.Validate = validator.New(validator.WithRequiredStructEnabled())
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cacheLock sync.RWMutex // TODO
|
||||||
cacheClient *resty.Client
|
cacheClient *resty.Client
|
||||||
// IPv4: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml#iana-ipv4-special-registry-1
|
// IPv4: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml#iana-ipv4-special-registry-1
|
||||||
// IPv6: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
|
// IPv6: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
|
||||||
|
@ -11,4 +11,5 @@ var (
|
|||||||
ErrBadSplitter error = errors.New("invalid or unknown splitter when containing")
|
ErrBadSplitter error = errors.New("invalid or unknown splitter when containing")
|
||||||
ErrBigPrefix error = errors.New("prefix length exceeds remaining network space")
|
ErrBigPrefix error = errors.New("prefix length exceeds remaining network space")
|
||||||
ErrNoNetSpace error = errors.New("reached end of network space before splitting finished")
|
ErrNoNetSpace error = errors.New("reached end of network space before splitting finished")
|
||||||
|
ErrUnknownPos error = errors.New("unknown subnet position")
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package netsplit
|
package netsplit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
`bytes`
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -298,6 +299,113 @@ func Contain(origPfx *netip.Prefix, nets []*netip.Prefix, remaining *netipx.IPSe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
LastSubnetNet returns the last subnet of prefix length pfxLen from network pfx.
|
||||||
|
|
||||||
|
lastSubnet will be nil if pfx is nil or invalid.
|
||||||
|
*/
|
||||||
|
func LastSubnetNet(pfx *net.IPNet, pfxLen uint8) (lastSubnet *net.IPNet, err error) {
|
||||||
|
|
||||||
|
var nPfx netip.Prefix
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
if pfx == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if nPfx, ok = netipx.FromStdIPNet(pfx); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !nPfx.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if nPfx, err = LastSubnetPfx(nPfx, pfxLen); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !nPfx.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSubnet = netipx.PrefixIPNet(nPfx)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastSubnetPfx is exactly like LastSubnetNet but using netip.Prefix instead.
|
||||||
|
func LastSubnetPfx(pfx netip.Prefix, pfxLen uint8) (lastSubnet netip.Prefix, err error) {
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var pfxBytes []byte
|
||||||
|
var bitOffset uint
|
||||||
|
var offset *big.Int
|
||||||
|
var ipInt *big.Int
|
||||||
|
var ipBytes []byte
|
||||||
|
var byteLen int
|
||||||
|
var lastNet *net.IPNet
|
||||||
|
var maxBitLen uint8 = maxBitsv4
|
||||||
|
|
||||||
|
if !pfx.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pfx = pfx.Masked()
|
||||||
|
|
||||||
|
if pfx.Addr().Is6() || pfxLen > maxBitsv4 {
|
||||||
|
maxBitLen = maxBitsv6
|
||||||
|
}
|
||||||
|
if pfxLen > maxBitLen {
|
||||||
|
err = ErrBadPrefixLen
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pfxLen < uint8(pfx.Bits()) {
|
||||||
|
err = ErrBigPrefix
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if pfxBytes, err = pfx.Addr().MarshalBinary(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
byteLen = pfx.Addr().BitLen() / 8
|
||||||
|
bitOffset = uint(pfxLen - uint8(pfx.Bits()))
|
||||||
|
|
||||||
|
offset = new(big.Int).Lsh(big.NewInt(1), bitOffset)
|
||||||
|
offset.Sub(offset, big.NewInt(1))
|
||||||
|
|
||||||
|
// Cast the prefix (as represented as bytes) into a *big.Int for some number magic.
|
||||||
|
ipInt = new(big.Int).SetBytes(pfxBytes)
|
||||||
|
// Shift to the first "address" in the prefix/mask it.
|
||||||
|
offset.Lsh(offset, uint(pfx.Addr().BitLen()-int(pfxLen)))
|
||||||
|
// Now add the offset to the base network.
|
||||||
|
ipInt.Add(ipInt, offset)
|
||||||
|
|
||||||
|
// If the base address starts at the "0 address" (e.g. 0.0.0.0 or :: etc....),
|
||||||
|
// this can cause some strange behavior when casting the *big.Int to bytes.
|
||||||
|
// So it gets left-null-padded to the appropriate length for the inet family.
|
||||||
|
ipBytes = ipInt.Bytes()
|
||||||
|
if len(ipBytes) < byteLen {
|
||||||
|
ipBytes = append(
|
||||||
|
bytes.Repeat([]byte{0x00}, byteLen-len(ipBytes)),
|
||||||
|
ipBytes...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an explicit net.IPNet...
|
||||||
|
lastNet = &net.IPNet{
|
||||||
|
IP: net.IP(ipBytes),
|
||||||
|
Mask: net.CIDRMask(int(pfxLen), pfx.Addr().BitLen()),
|
||||||
|
}
|
||||||
|
// And then make it a netip.Prefix.
|
||||||
|
if lastSubnet, ok = netipx.FromStdIPNet(lastNet); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !lastSubnet.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MaskExpand expands a net.IPMask's string format.
|
MaskExpand expands a net.IPMask's string format.
|
||||||
Like AddrExpand but for netmasks.
|
Like AddrExpand but for netmasks.
|
||||||
@ -391,29 +499,29 @@ func MaskInvert(mask net.IPMask) (inverted net.IPMask) {
|
|||||||
Note that for the single-host prefix (/32 for IPv4, /128 for IPv6), numAddrs will *always* be 1.
|
Note that for the single-host prefix (/32 for IPv4, /128 for IPv6), numAddrs will *always* be 1.
|
||||||
For point-to-point prefix (IPv4 /31, IPv6 /127), numAddrs will *ALWAYS* be 2.
|
For point-to-point prefix (IPv4 /31, IPv6 /127), numAddrs will *ALWAYS* be 2.
|
||||||
*/
|
*/
|
||||||
func NumAddrsIn(prefixLen uint8, isIpv6, inclNet, inclBcast bool) (numAddrs *big.Int, err error) {
|
func NumAddrsIn(pfxLen uint8, isIpv6, inclNet, inclBcast bool) (numAddrs *big.Int, err error) {
|
||||||
|
|
||||||
var numBits uint
|
var numBits uint
|
||||||
var numRemoved int64
|
var numRemoved int64
|
||||||
var maxBitLen uint8 = maxBitsv4
|
var maxBitLen uint8 = maxBitsv4
|
||||||
|
|
||||||
if isIpv6 {
|
if isIpv6 || pfxLen > maxBitsv4 {
|
||||||
maxBitLen = maxBitsv6
|
maxBitLen = maxBitsv6
|
||||||
}
|
}
|
||||||
if prefixLen > maxBitLen {
|
if pfxLen > maxBitLen {
|
||||||
err = ErrBadPrefixLen
|
err = ErrBadPrefixLen
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if prefixLen == maxBitLen {
|
if pfxLen == maxBitLen {
|
||||||
numAddrs = big.NewInt(1)
|
numAddrs = big.NewInt(1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (prefixLen + 1) == maxBitLen {
|
if (pfxLen + 1) == maxBitLen {
|
||||||
numAddrs = big.NewInt(2)
|
numAddrs = big.NewInt(2)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
numBits = uint(maxBitLen - prefixLen)
|
numBits = uint(maxBitLen - pfxLen)
|
||||||
|
|
||||||
numAddrs = new(big.Int).Lsh(big.NewInt(1), numBits)
|
numAddrs = new(big.Int).Lsh(big.NewInt(1), numBits)
|
||||||
|
|
||||||
@ -451,6 +559,9 @@ func NumAddrsNet(pfx *net.IPNet, inclNet, inclBcast bool) (numAddrs *big.Int) {
|
|||||||
if nPfx, ok = netipx.FromStdIPNet(pfx); !ok {
|
if nPfx, ok = netipx.FromStdIPNet(pfx); !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !nPfx.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
numAddrs = NumAddrsPfx(nPfx, inclNet, inclBcast)
|
numAddrs = NumAddrsPfx(nPfx, inclNet, inclBcast)
|
||||||
|
|
||||||
@ -460,21 +571,16 @@ func NumAddrsNet(pfx *net.IPNet, inclNet, inclBcast bool) (numAddrs *big.Int) {
|
|||||||
// NumAddrsPfx is the exact same as NumAddrsNet but for a net/netip.Prefix instead.
|
// NumAddrsPfx is the exact same as NumAddrsNet but for a net/netip.Prefix instead.
|
||||||
func NumAddrsPfx(pfx netip.Prefix, inclNet, inclBcast bool) (numAddrs *big.Int) {
|
func NumAddrsPfx(pfx netip.Prefix, inclNet, inclBcast bool) (numAddrs *big.Int) {
|
||||||
|
|
||||||
var numBits uint
|
var err error
|
||||||
var numRemoved int64
|
|
||||||
|
|
||||||
numBits = uint(pfx.Addr().BitLen() - pfx.Bits())
|
if !pfx.IsValid() {
|
||||||
|
return
|
||||||
numAddrs = new(big.Int).Lsh(big.NewInt(1), numBits)
|
|
||||||
|
|
||||||
if !inclNet {
|
|
||||||
numRemoved++
|
|
||||||
}
|
}
|
||||||
if !inclBcast {
|
|
||||||
numRemoved++
|
// Since we're dealing with existing prefixes/networks, we should never get an error.
|
||||||
}
|
if numAddrs, err = NumAddrsIn(uint8(pfx.Bits()), pfx.Addr().Is6(), inclNet, inclBcast); err != nil {
|
||||||
if numRemoved > 0 {
|
// But *somehow* in case we do...
|
||||||
_ = numAddrs.Sub(numAddrs, big.NewInt(numRemoved))
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -22,6 +22,10 @@ func (c *CIDRSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = validate.Struct(c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if base, ok = netipx.FromStdIPNet(c.network); !ok {
|
if base, ok = netipx.FromStdIPNet(c.network); !ok {
|
||||||
err = ErrBadBoundary
|
err = ErrBadBoundary
|
||||||
return
|
return
|
||||||
@ -41,6 +45,15 @@ func (c *CIDRSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: This is *super* slow for tiny subnets in a large net.
|
||||||
|
For future optimzation, first off benchmark to make sure it makes a difference, but
|
||||||
|
chunk out the network (how to find appropriate length?) of n < x < y, where n is the network pfx len,
|
||||||
|
and goroutine each split into a channel.
|
||||||
|
Because this splits *on CIDR boundaries* and we aren't VLSM-ing, remaining never has to be considered-
|
||||||
|
it'll always be clean splitting.
|
||||||
|
See CIDRSplitter.LenSwitch.
|
||||||
|
*/
|
||||||
for {
|
for {
|
||||||
if sub, remaining, ok = remaining.RemoveFreePrefix(c.PrefixLength); !ok {
|
if sub, remaining, ok = remaining.RemoveFreePrefix(c.PrefixLength); !ok {
|
||||||
if !sub.IsValid() {
|
if !sub.IsValid() {
|
||||||
|
@ -28,6 +28,10 @@ func (h *HostSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = validate.Struct(h); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
pfx, _ = netipx.FromStdIPNet(h.network)
|
pfx, _ = netipx.FromStdIPNet(h.network)
|
||||||
tgt = new(big.Int)
|
tgt = new(big.Int)
|
||||||
tgt.SetUint64(uint64(h.NumberHosts))
|
tgt.SetUint64(uint64(h.NumberHosts))
|
||||||
|
102
netsplit/funcs_prefixgetter.go
Normal file
102
netsplit/funcs_prefixgetter.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package netsplit
|
||||||
|
|
||||||
|
import (
|
||||||
|
`fmt`
|
||||||
|
`net/netip`
|
||||||
|
|
||||||
|
`go4.org/netipx`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Split is to conform to a NetSplitter, though a PrefixGetter is *technically* not a splitter.
|
||||||
|
func (p *PrefixGetter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, err error) {
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var base netip.Prefix
|
||||||
|
var vlsmS *VLSMSplitter
|
||||||
|
var addr netip.Addr
|
||||||
|
var maxPfxLen uint8 = maxBitsv4
|
||||||
|
var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)
|
||||||
|
|
||||||
|
if p == nil || p.PrefixLength == 0 || p.BaseSplitter == nil || p.network == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = validate.Struct(p); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the position is "first", we can simply call a VLSM.
|
||||||
|
if p.Pos == "first" {
|
||||||
|
vlsmS = &VLSMSplitter{
|
||||||
|
Ascending: false,
|
||||||
|
Explicit: false,
|
||||||
|
PrefixLengths: []uint8{p.PrefixLength},
|
||||||
|
BaseSplitter: p.BaseSplitter,
|
||||||
|
}
|
||||||
|
if nets, remaining, err = vlsmS.Split(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Pos != "last" {
|
||||||
|
err = ErrUnknownPos
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise this gets... messy.
|
||||||
|
if base, ok = netipx.FromStdIPNet(p.network); !ok {
|
||||||
|
err = ErrBadBoundary
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !base.IsValid() {
|
||||||
|
err = ErrBadBoundary
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ipsb = new(netipx.IPSetBuilder)
|
||||||
|
ipsb.AddPrefix(base.Masked())
|
||||||
|
|
||||||
|
// First if it's a single host prefix, ezpz gg no re.
|
||||||
|
if base.Addr().Is6() {
|
||||||
|
maxPfxLen = maxBitsv6
|
||||||
|
}
|
||||||
|
if p.PrefixLength == maxPfxLen {
|
||||||
|
nets = make([]*netip.Prefix, 1)
|
||||||
|
nets[0] = new(netip.Prefix)
|
||||||
|
addr = netipx.PrefixLastIP(base)
|
||||||
|
fmt.Println(addr.String())
|
||||||
|
if *nets[0], err = addr.Prefix(int(p.PrefixLength)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ipsb.Remove(addr)
|
||||||
|
if remaining, err = ipsb.IPSet(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise this gets... interesting.
|
||||||
|
/*
|
||||||
|
For IPv4, performance NORMALLY would be "fine" on modern hardware with:
|
||||||
|
1. straight CIDR-splitting
|
||||||
|
2. grabbing the last prefix
|
||||||
|
3. condensing the leading prefixes to a new IPSet
|
||||||
|
But even this can take a long time (see CIDRSplitter.Split comments).
|
||||||
|
|
||||||
|
In almost all cases (unless subnetting like, n+12 prefix length),
|
||||||
|
IPv6 takes WAY too long.
|
||||||
|
|
||||||
|
So use the same function (LastSubnetPfx) for both cases.
|
||||||
|
*/
|
||||||
|
nets = make([]*netip.Prefix, 1)
|
||||||
|
nets[0] = new(netip.Prefix)
|
||||||
|
if *nets[0], err = LastSubnetPfx(base, p.PrefixLength); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ipsb.RemovePrefix(*nets[0])
|
||||||
|
if remaining, err = ipsb.IPSet(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -27,6 +27,10 @@ func (s *SubnetSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = validate.Struct(s); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if base, ok = netipx.FromStdIPNet(s.network); !ok {
|
if base, ok = netipx.FromStdIPNet(s.network); !ok {
|
||||||
err = ErrBadBoundary
|
err = ErrBadBoundary
|
||||||
return
|
return
|
||||||
|
@ -21,7 +21,15 @@ func (v *VLSMSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
var base netip.Prefix
|
var base netip.Prefix
|
||||||
var sub netip.Prefix
|
var sub netip.Prefix
|
||||||
var subPtr *netip.Prefix
|
var subPtr *netip.Prefix
|
||||||
var ipsb = new(netipx.IPSetBuilder)
|
var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)
|
||||||
|
|
||||||
|
if v == nil || v.PrefixLengths == nil || len(v.PrefixLengths) == 0 || v.BaseSplitter == nil || v.network == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = validate.Struct(v); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err = ValidateSizes(v.network, v.PrefixLengths...); err != nil {
|
if err = ValidateSizes(v.network, v.PrefixLengths...); err != nil {
|
||||||
return
|
return
|
||||||
@ -38,10 +46,6 @@ func (v *VLSMSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
But, as I expected, netipx ftw again.
|
But, as I expected, netipx ftw again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if v == nil || v.PrefixLengths == nil || len(v.PrefixLengths) == 0 || v.BaseSplitter == nil || v.network == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !v.Explicit {
|
if !v.Explicit {
|
||||||
sort.SliceStable(
|
sort.SliceStable(
|
||||||
v.PrefixLengths,
|
v.PrefixLengths,
|
||||||
|
@ -31,7 +31,16 @@ type NetSplitter interface {
|
|||||||
|
|
||||||
// BaseSplitter is used to encapsulate the "parent" network to be split.
|
// BaseSplitter is used to encapsulate the "parent" network to be split.
|
||||||
type BaseSplitter struct {
|
type BaseSplitter struct {
|
||||||
network *net.IPNet
|
network *net.IPNet `validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrefixGetter is a "pseudo-splitter"; it splits according to a given prefix but only returns a specfic subnet (either the first or the last).
|
||||||
|
type PrefixGetter struct {
|
||||||
|
// Pos is the position in BaseSplitter.network for the selected PrefixLength.
|
||||||
|
Pos string `json:"pos" xml:"pos,attr" yaml:"Position" validate:"required,oneof=first last"`
|
||||||
|
// PrefixLength specifies the CIDR/prefix length of the subnet.
|
||||||
|
PrefixLength uint8 `json:"prefix" xml:"prefix,attr" yaml:"network Prefix Length" validate:"required,lte=128"`
|
||||||
|
*BaseSplitter
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -40,7 +49,11 @@ It attemps to split the network into as many networks of size PrefixLength as cl
|
|||||||
*/
|
*/
|
||||||
type CIDRSplitter struct {
|
type CIDRSplitter struct {
|
||||||
// PrefixLength specifies the CIDR/prefix length of the subnets to split out.
|
// PrefixLength specifies the CIDR/prefix length of the subnets to split out.
|
||||||
PrefixLength uint8 `json:"prefix" xml:"prefix,attr" yaml:"network Prefix Length"`
|
PrefixLength uint8 `json:"prefix" xml:"prefix,attr" yaml:"network Prefix Length" validate:"required,lte=128"`
|
||||||
|
// TODO: See CIDRSplitter.Split for future optimization using this.
|
||||||
|
// LenSwitch specifies the threshold bit offset after which (inclusive) it switches from a repeated prefix removal to manual recursive binary split.
|
||||||
|
// If 0, 12 is the default.
|
||||||
|
// LenSwitch uint8 `json:"switch_at" xml:"switchAt,attr" yaml:"Switch Offset Threshold"`
|
||||||
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +63,7 @@ It attempts to evenly distribute addresses amoungs subnets.
|
|||||||
*/
|
*/
|
||||||
type HostSplitter struct {
|
type HostSplitter struct {
|
||||||
// NumberHosts is the number of hosts to be placed in each subnet to split out.
|
// NumberHosts is the number of hosts to be placed in each subnet to split out.
|
||||||
NumberHosts uint `json:"hosts" xml:"hosts,attr" yaml:"Number of Hosts Per Subnet"`
|
NumberHosts uint `json:"hosts" xml:"hosts,attr" yaml:"Number of Hosts Per Subnet" validate:"required"`
|
||||||
// InclNetAddr, if true, specifies that NumberHosts includes the network address.
|
// InclNetAddr, if true, specifies that NumberHosts includes the network address.
|
||||||
InclNetAddr bool `json:"net_addr" xml:"netAddr,attr,omitempty" yaml:"Network Address Included,omitempty"`
|
InclNetAddr bool `json:"net_addr" xml:"netAddr,attr,omitempty" yaml:"Network Address Included,omitempty"`
|
||||||
// InclBcastAddr, if true, specifies that NumberHosts includes the broadcast address.
|
// InclBcastAddr, if true, specifies that NumberHosts includes the broadcast address.
|
||||||
@ -66,7 +79,7 @@ as cleanly as poossible.
|
|||||||
*/
|
*/
|
||||||
type SubnetSplitter struct {
|
type SubnetSplitter struct {
|
||||||
// NumberSubnets indicates the number of subnets to split the network into.
|
// NumberSubnets indicates the number of subnets to split the network into.
|
||||||
NumberSubnets uint `json:"nets" xml:"nets,attr" yaml:"Number of Target Subnets"`
|
NumberSubnets uint `json:"nets" xml:"nets,attr" yaml:"Number of Target Subnets" validate:"required"`
|
||||||
// Strict, if true, will return an error from Split if the network sizes cannot split into equally-sized networks.
|
// Strict, if true, will return an error from Split if the network sizes cannot split into equally-sized networks.
|
||||||
Strict bool `json:"strict" xml:"strict,attr,omitempty" yaml:"Strictly Equal Subnet Sizes"`
|
Strict bool `json:"strict" xml:"strict,attr,omitempty" yaml:"Strictly Equal Subnet Sizes"`
|
||||||
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
||||||
@ -91,7 +104,7 @@ type VLSMSplitter struct {
|
|||||||
*/
|
*/
|
||||||
Explicit bool `json:"explicit,omitempty" xml:"explicit,attr,omitempty" yaml:"Explicit Ordering,omitempty"`
|
Explicit bool `json:"explicit,omitempty" xml:"explicit,attr,omitempty" yaml:"Explicit Ordering,omitempty"`
|
||||||
// PrefixLengths contains the prefix lengths of each subnet to split out from the network.
|
// PrefixLengths contains the prefix lengths of each subnet to split out from the network.
|
||||||
PrefixLengths []uint8 `json:"prefixes" xml:"prefixes>prefix" yaml:"Prefix Lengths"`
|
PrefixLengths []uint8 `json:"prefixes" xml:"prefixes>prefix" yaml:"Prefix Lengths" validate:"required,dive,lte=128"`
|
||||||
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user