Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32297d1bba
|
||
|
|
d37aa3eb6b
|
||
|
|
0c8577f149
|
@@ -50,7 +50,7 @@ A tool to assist in design of segregate/segment/split/subnet networks.
|
|||||||
**** If the `XDG_CACHE_HOME` environment variable is not present...
|
**** If the `XDG_CACHE_HOME` environment variable is not present...
|
||||||
***** On macOS, an explicit fallback of `~/Library/Caches/subnetter/` will be used. (To my knowledge/understanding, this is the standard user cache directory and cannot be changed.) This usually evaluates to `/Users/<username>/Library/Caches/subnetter/`.
|
***** On macOS, an explicit fallback of `~/Library/Caches/subnetter/` will be used. (To my knowledge/understanding, this is the standard user cache directory and cannot be changed.) This usually evaluates to `/Users/<username>/Library/Caches/subnetter/`.
|
||||||
***** On all others, an explicit fallback of `~/.cache/subnetter` will be used.
|
***** On all others, an explicit fallback of `~/.cache/subnetter` will be used.
|
||||||
****** On most non-macOS \*NIX-like systems , this is usually `/home/<username>/.cache/subetter/`, provided normal user homes. On http://p9f.org/[Plan9^] platforms (e.g. https://9p.io/plan9/index.html[Plan 9 4th Ed.^], https://9front.org/[9front^], http://9legacy.org/[9legacy^]), the `/env/home` environment variable (`$home`) will be used, the `./lib/` subdirectory under there (which typically/should already exist) will be appended to it, and that appended with `./cache/subnetter/` (this usually evaluates to `/usr/<username>/lib/cache/subnetter/`).
|
****** On most non-macOS/*NIX-like systems , this is usually `/home/<username>/.cache/subetter/`, provided normal user homes. On http://p9f.org/[Plan9^] platforms (e.g. https://9p.io/plan9/index.html[Plan 9 4th Ed.^], https://9front.org/[9front^], http://9legacy.org/[9legacy^]), the `/env/home` environment variable (`$home`) will be used, the `./lib/` subdirectory under there (which typically/should already exist) will be appended to it, and that appended with `./cache/subnetter/` (this usually evaluates to `/usr/<username>/lib/cache/subnetter/`).
|
||||||
*** For Windows systems...
|
*** For Windows systems...
|
||||||
**** If https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#constants[the `LOCALAPPDATA` environment variable^] is present, it will be `%LOCALAPPDATA%\Cache\subnetter\` (or `${env:LOCALAPPDATA}\Cache\subnetter\` in Powershell syntax). This usually evaluates to `C:\Users\<username>\AppData\Local\Cache\subnetter\`.
|
**** If https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid#constants[the `LOCALAPPDATA` environment variable^] is present, it will be `%LOCALAPPDATA%\Cache\subnetter\` (or `${env:LOCALAPPDATA}\Cache\subnetter\` in Powershell syntax). This usually evaluates to `C:\Users\<username>\AppData\Local\Cache\subnetter\`.
|
||||||
|
|
||||||
@@ -61,3 +61,5 @@ This program in general draws inspiration from `ipcalc` (http://jodies.de/ipcalc
|
|||||||
The `table` subcommand is inspired by `iptab` from https://metacpan.org/pod/Net::IP[Perl Net-IP^].
|
The `table` subcommand is inspired by `iptab` from https://metacpan.org/pod/Net::IP[Perl Net-IP^].
|
||||||
|
|
||||||
Additional notes for certain contexts are primarily taken from https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing[the Wikipedia article on _Classless Inter-Domain Routing_^] (as of _Jan 28, 2025_).
|
Additional notes for certain contexts are primarily taken from https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing[the Wikipedia article on _Classless Inter-Domain Routing_^] (as of _Jan 28, 2025_).
|
||||||
|
|
||||||
|
Reservations are pulled/cached directly from the IANA registries (https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml[IPv4^], https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml[IPv6^]).
|
||||||
4
TODO
4
TODO
@@ -1 +1,5 @@
|
|||||||
- add table rendering for reserved networks?
|
- add table rendering for reserved networks?
|
||||||
|
|
||||||
|
- when checking/rendering reserved networks, currently the footnotes aren't returned.
|
||||||
|
-- netsplit.IANARegistryFootnote
|
||||||
|
-- encapsulated in the IANARegistry.Footnotes
|
||||||
@@ -89,7 +89,10 @@ type XNetArgs struct {
|
|||||||
|
|
||||||
type VLSMArgs struct {
|
type VLSMArgs struct {
|
||||||
Asc bool `short:"A" long:"ascending" description:"If specified, place smaller networks (larger prefixes) at the beginning. You almost assuredly do not want to do this."`
|
Asc bool `short:"A" long:"ascending" description:"If specified, place smaller networks (larger prefixes) at the beginning. You almost assuredly do not want to do this."`
|
||||||
Sizes []uint8 `short:"s" long:"size" required:"true" description:"Prefix lengths. May be specified multiple times." validate:"required"`
|
Explicit bool `short:"O" long:"explicit-order" description:"If specified, ignore -A/--ascending and do no reordering of prefix sizes whatsoever, instead using the order given. This is EXTREMELY suboptimal and can lead to drastic addressing waste."`
|
||||||
|
// Custom type for now; see https://github.com/jessevdk/go-flags/issues/245
|
||||||
|
// Sizes []uint8 `short:"s" long:"size" required:"true" description:"Prefix lengths. May be specified multiple times." validate:"required"`
|
||||||
|
Sizes []vlsmSize `short:"s" long:"size" required:"true" description:"Prefix lengths. May be specified multiple times or as a comma-delimited list." validate:"required"`
|
||||||
splitArgs
|
splitArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
ErrBadFmt error = errors.New("unknown output format")
|
||||||
errBadNet error = errors.New("bad inet/addr family/version")
|
errBadNet error = errors.New("bad inet/addr family/version")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -471,7 +471,180 @@ func printNets(orig *netip.Prefix, origNet *net.IPNet, nets []*netip.Prefix, rem
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func printReserved(nets []*netip.Prefix, remaining *netipx.IPSet, args *common) (err error) {
|
func printReserved(records map[netip.Prefix]*netsplit.IANAAddrNetResRecord, origNet netip.Prefix, plain bool, fmtType string) (err error) {
|
||||||
|
|
||||||
|
var b []byte
|
||||||
|
var idx int
|
||||||
|
var pfx netip.Prefix
|
||||||
|
var rec *netsplit.IANAAddrNetResRecord
|
||||||
|
var sortedKeys []netip.Prefix
|
||||||
|
var sb = new(strings.Builder)
|
||||||
|
|
||||||
|
switch fmtType {
|
||||||
|
case "json":
|
||||||
|
if b, err = json.MarshalIndent(records, "", " "); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return
|
||||||
|
case "xml":
|
||||||
|
if b, err = xml.MarshalIndent(records, "", " "); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return
|
||||||
|
case "yml", "yaml":
|
||||||
|
if b, err = yaml.Marshal(records); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(b))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if fmtType != "pretty" {
|
||||||
|
err = ErrBadFmt
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if records == nil || len(records) == 0 {
|
||||||
|
fmt.Println("No IANA/IETF/RFC-reserved subnet(s) found.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedKeys = make([]netip.Prefix, len(records))
|
||||||
|
idx = 0
|
||||||
|
for pfx, _ = range records {
|
||||||
|
sortedKeys[idx] = pfx
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
sort.SliceStable(
|
||||||
|
sortedKeys,
|
||||||
|
func(i, j int) (isBefore bool) {
|
||||||
|
isBefore = (netipx.ComparePrefix(sortedKeys[i], sortedKeys[j])) <= 0
|
||||||
|
return
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Fprintf(sb, "= %s =\n", origNet.String())
|
||||||
|
for _, pfx = range sortedKeys {
|
||||||
|
rec = records[pfx]
|
||||||
|
fmt.Fprint(sb, sectFmts[plain][0]+"\n")
|
||||||
|
// Name
|
||||||
|
fmt.Fprintf(sb, "Reservation Name:\t%s\n", rec.Name)
|
||||||
|
fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Networks
|
||||||
|
fmt.Fprint(sb, "\tCanonical Reserved Networks:")
|
||||||
|
if rec.Networks != nil {
|
||||||
|
fmt.Fprint(sb, "\n")
|
||||||
|
for _, recPfx := range rec.Networks.Prefixes {
|
||||||
|
fmt.Fprint(sb, "\t\t"+sectFmts[plain][2]+"\n")
|
||||||
|
fmt.Fprintf(sb, "\t\t%s\n", recPfx.String())
|
||||||
|
// TODO: Print footnotes/refs!
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "\t(N/A)\n")
|
||||||
|
}
|
||||||
|
fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Reference/Specification
|
||||||
|
fmt.Fprint(sb, "\tSpecification:")
|
||||||
|
if rec.Spec != nil {
|
||||||
|
fmt.Fprint(sb, "\n")
|
||||||
|
for _, line := range strings.Split(rec.Spec.Text, "\n") {
|
||||||
|
fmt.Fprint(sb, "\t\t"+line+"\n")
|
||||||
|
}
|
||||||
|
if rec.Spec.References != nil {
|
||||||
|
fmt.Fprintf(sb, "\t\t%s\n", sectFmts[plain][2])
|
||||||
|
for rIdx, recref := range rec.Spec.References {
|
||||||
|
if recref != nil {
|
||||||
|
fmt.Fprintf(sb, "\t\t[%d] (%s) %s\n", rIdx, recref.Type, recref.Reference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "\t(None)\n")
|
||||||
|
}
|
||||||
|
fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Allocated (always present)
|
||||||
|
fmt.Fprintf(sb, "\tAllocated:\t%s\n", time.Time(rec.Allocation).String())
|
||||||
|
// fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Updated
|
||||||
|
fmt.Fprint(sb, "\tUpdated:\t")
|
||||||
|
if rec.Updated != nil {
|
||||||
|
fmt.Fprintf(sb, "%s\n", time.Time(*rec.Updated).String())
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
// fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Termination
|
||||||
|
fmt.Fprint(sb, "\tTerminated:\t")
|
||||||
|
if rec.Termination != nil {
|
||||||
|
fmt.Fprintf(sb, "%s\n", time.Time(*rec.Termination).String())
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Source
|
||||||
|
fmt.Fprint(sb, "\tValid Source:\t\t\t")
|
||||||
|
if rec.Source != nil {
|
||||||
|
if rec.Source.Applicable != nil && !bool(*rec.Source.Applicable) {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "%v\n", bool(*rec.Source.Evaluated))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
// fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Destination
|
||||||
|
fmt.Fprint(sb, "\tValid Destination:\t\t")
|
||||||
|
if rec.Dest != nil {
|
||||||
|
if rec.Dest.Applicable != nil && !bool(*rec.Dest.Applicable) {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "%v\n", bool(*rec.Dest.Evaluated))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
// fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Forwardable
|
||||||
|
fmt.Fprint(sb, "\tForwardable:\t\t\t")
|
||||||
|
if rec.Forwardable != nil {
|
||||||
|
if rec.Forwardable.Applicable != nil && !bool(*rec.Forwardable.Applicable) {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "%v\n", bool(*rec.Forwardable.Evaluated))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
// fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Globally reachable
|
||||||
|
fmt.Fprint(sb, "\tGlobally Routable/Reachable:\t")
|
||||||
|
if rec.GlobalReach != nil {
|
||||||
|
if rec.GlobalReach.Applicable != nil && !bool(*rec.GlobalReach.Applicable) {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "%v\n", bool(*rec.GlobalReach.Evaluated))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
// fmt.Fprint(sb, "\t"+sectFmts[plain][1]+"\n")
|
||||||
|
// Reserved by Protocol
|
||||||
|
fmt.Fprint(sb, "\tReserved by Protocol:\t\t")
|
||||||
|
if rec.ProtoReserved != nil {
|
||||||
|
if rec.ProtoReserved.Applicable != nil && !bool(*rec.ProtoReserved.Applicable) {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(sb, "%v\n", bool(*rec.ProtoReserved.Evaluated))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(sb, "(N/A)\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(sb.String())
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
26
cmd/subnetter/funcs_vlsmargs.go
Normal file
26
cmd/subnetter/funcs_vlsmargs.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/*
|
||||||
|
AllSizes returns a properly parsed and consolidated slice
|
||||||
|
of all specified sizes, as it takes two valid syntaxes (`-s 32 -s 32`, `-s 32,32`)
|
||||||
|
that can be mixed together.
|
||||||
|
*/
|
||||||
|
func (v *VLSMArgs) AllSizes() (sizes []uint8, err error) {
|
||||||
|
|
||||||
|
var sizeSlice []uint8
|
||||||
|
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v.Sizes == nil || len(v.Sizes) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, s := range v.Sizes {
|
||||||
|
if sizeSlice, err = s.Sizes(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sizes = append(sizes, sizeSlice...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
33
cmd/subnetter/funcs_vlsmsize.go
Normal file
33
cmd/subnetter/funcs_vlsmsize.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
`strconv`
|
||||||
|
`strings`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sizes returns a parsed/split slice of uint8s from a vlsmSize.
|
||||||
|
func (v *vlsmSize) Sizes() (sizes []uint8, err error) {
|
||||||
|
|
||||||
|
var s []string
|
||||||
|
var u uint64
|
||||||
|
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s = strings.Split(string(*v), ",")
|
||||||
|
for idx, i := range s {
|
||||||
|
s[idx] = strings.TrimSpace(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
sizes = make([]uint8, len(s))
|
||||||
|
|
||||||
|
// No validation is performed since we don't have access to the addr inet family; that's up to the parsers.
|
||||||
|
for idx, i := range s {
|
||||||
|
if u, err = strconv.ParseUint(i, 10, 8); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sizes[idx] = uint8(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ func main() {
|
|||||||
var pfx *net.IPNet
|
var pfx *net.IPNet
|
||||||
var resPfx *netip.Prefix
|
var resPfx *netip.Prefix
|
||||||
var origPfx netip.Prefix
|
var origPfx netip.Prefix
|
||||||
|
var vlsmSizes []uint8
|
||||||
var splitter netsplit.NetSplitter
|
var splitter netsplit.NetSplitter
|
||||||
var cmnArgs common
|
var cmnArgs common
|
||||||
var nets []*netip.Prefix
|
var nets []*netip.Prefix
|
||||||
@@ -34,6 +35,7 @@ func main() {
|
|||||||
var res *netsplit.StructuredResults
|
var res *netsplit.StructuredResults
|
||||||
var noStrict bool
|
var noStrict bool
|
||||||
var strictErr error
|
var strictErr error
|
||||||
|
var reservations map[netip.Prefix]*netsplit.IANAAddrNetResRecord
|
||||||
var splitErr *netsplit.SplitErr = new(netsplit.SplitErr)
|
var splitErr *netsplit.SplitErr = new(netsplit.SplitErr)
|
||||||
var parser *flags.Parser = flags.NewParser(args, flags.Default)
|
var parser *flags.Parser = flags.NewParser(args, flags.Default)
|
||||||
|
|
||||||
@@ -78,7 +80,25 @@ func main() {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
case "reserved":
|
case "reserved":
|
||||||
// TODO
|
if origPfx, err = netip.ParsePrefix(args.Check.Network.Network); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
nets = make([]*netip.Prefix, 1)
|
||||||
|
nets[0] = new(netip.Prefix)
|
||||||
|
*nets[0] = origPfx
|
||||||
|
if err = netsplit.SetCachePath(args.Check.CacheDir); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
if err = netsplit.EnableCache(args.Check.DoResCache); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
if reservations, err = netsplit.CheckReserved(nets, !args.Check.NoRevRecursive, !args.Check.NoRecursive, !args.Check.NoPrivate); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
if err = printReserved(reservations, origPfx, args.Check.Plain, args.Check.Fmt); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
case "table":
|
case "table":
|
||||||
// Account for a weird redundant CLI condition.
|
// Account for a weird redundant CLI condition.
|
||||||
if args.Table.NoIpv4 && args.Table.NoIpv6 {
|
if args.Table.NoIpv4 && args.Table.NoIpv6 {
|
||||||
@@ -170,9 +190,13 @@ func main() {
|
|||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
cmnArgs = args.VLSM.common
|
cmnArgs = args.VLSM.common
|
||||||
|
if vlsmSizes, err = args.VLSM.AllSizes(); err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
splitter = &netsplit.VLSMSplitter{
|
splitter = &netsplit.VLSMSplitter{
|
||||||
Ascending: args.VLSM.Asc,
|
Ascending: args.VLSM.Asc,
|
||||||
PrefixLengths: args.VLSM.Sizes,
|
Explicit: args.VLSM.Explicit,
|
||||||
|
PrefixLengths: vlsmSizes,
|
||||||
BaseSplitter: new(netsplit.BaseSplitter),
|
BaseSplitter: new(netsplit.BaseSplitter),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ type tableFormatter struct {
|
|||||||
NoBoldTitle bool
|
NoBoldTitle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// vlsmSize is a custom type to let us specify multiple sizes as a repeated or consolidated argument.
|
||||||
|
type vlsmSize string
|
||||||
|
|
||||||
type ReservedResults struct {
|
type ReservedResults struct {
|
||||||
Opts CheckArgs
|
Opts CheckArgs
|
||||||
Reserved map[netip.Prefix]*netsplit.IANAAddrNetResRecord
|
Reserved map[netip.Prefix]*netsplit.IANAAddrNetResRecord
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ func SetCachePath(cacheDirPath string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cacheDirPath != oldPath {
|
if cacheDirPath != oldPath {
|
||||||
|
cacheDir = cacheDirPath
|
||||||
if err = os.MkdirAll(cacheDir, cacheDirPerms); err != nil {
|
if err = os.MkdirAll(cacheDir, cacheDirPerms); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func (c *CIDRSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.PrefixLength > uint8(base.Bits()) {
|
if c.PrefixLength < uint8(base.Bits()) {
|
||||||
err = ErrBigPrefix
|
err = ErrBigPrefix
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -48,11 +48,11 @@ func (c *CIDRSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
// We just hit the end of the prefix.
|
// We just hit the end of the prefix.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
subPtr = new(netip.Prefix)
|
subPtr = new(netip.Prefix)
|
||||||
*subPtr = sub
|
*subPtr = sub
|
||||||
nets = append(nets, subPtr)
|
nets = append(nets, subPtr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package netsplit
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sort"
|
`sort`
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
@@ -42,6 +42,7 @@ func (v *VLSMSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !v.Explicit {
|
||||||
sort.SliceStable(
|
sort.SliceStable(
|
||||||
v.PrefixLengths,
|
v.PrefixLengths,
|
||||||
func(i, j int) (isBefore bool) { // We use a reverse sorting by default so we get larger prefixes at the beginning.
|
func(i, j int) (isBefore bool) { // We use a reverse sorting by default so we get larger prefixes at the beginning.
|
||||||
@@ -53,6 +54,7 @@ func (v *VLSMSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, e
|
|||||||
return
|
return
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pfxLen, _ = v.network.Mask.Size()
|
pfxLen, _ = v.network.Mask.Size()
|
||||||
pfxLen8 = uint8(pfxLen)
|
pfxLen8 = uint8(pfxLen)
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ type VLSMSplitter struct {
|
|||||||
You almost assuredly do not want to do this.
|
You almost assuredly do not want to do this.
|
||||||
*/
|
*/
|
||||||
Ascending bool
|
Ascending bool
|
||||||
|
/*
|
||||||
|
Explicit, if true, will ignore Ascending completely and split in the explicit order of PrefixLengths.
|
||||||
|
|
||||||
|
This has the potential to be *extremely* wasteful of addressing space as the resulting blocks are
|
||||||
|
VERY unoptimized.
|
||||||
|
*/
|
||||||
|
Explicit bool
|
||||||
// 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"`
|
||||||
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
*BaseSplitter `json:"net" xml:"net,omitempty" yaml:"network,omitempty"`
|
||||||
|
|||||||
Reference in New Issue
Block a user