
FIXED: * IPv6 split-nets splitter didn't work. It does not. https://github.com/projectdiscovery/mapcidr/issues/628 Noticed. As such, this library/program has *completely removed* ALL use of the mapcidr library as it cannot be expected to be accurate.
86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
package netsplit
|
|
|
|
import (
|
|
`math`
|
|
"net/netip"
|
|
|
|
"go4.org/netipx"
|
|
)
|
|
|
|
/*
|
|
Split splits the network defined in a SubnetSplitter alongside its configuration and performs the subnetting.
|
|
This strategy allows for splitting a network into exactly evenly sized specified number of subnets.
|
|
|
|
remaining may or may not be nil depending on if the specified number of subnets fit cleanly into the network boundaries.
|
|
|
|
An ErrNoNetSpace error will be returned if subnetting size exhaustion occurs before the specified number of subnets is reached
|
|
(but nets will be populated and remaining will contain any left over subnets).
|
|
*/
|
|
func (s *SubnetSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, err error) {
|
|
|
|
var ok bool
|
|
var pfxLen int
|
|
var base netip.Prefix
|
|
var vlsm *VLSMSplitter
|
|
|
|
if s == nil || s.BaseSplitter == nil || s.network == nil || s.NumberSubnets == 0 {
|
|
return
|
|
}
|
|
|
|
if base, ok = netipx.FromStdIPNet(s.network); !ok {
|
|
err = ErrBadBoundary
|
|
return
|
|
}
|
|
if !base.IsValid() {
|
|
err = ErrBadBoundary
|
|
return
|
|
}
|
|
|
|
// Previously, this used (github.com/projectdiscovery/mapcidr).SplitIPNetIntoN.
|
|
// It no longer does: https://github.com/projectdiscovery/mapcidr/issues/628
|
|
// I am Noticing.
|
|
|
|
// First the number of bits needed is calculated.
|
|
pfxLen = int(math.Ceil(math.Log2(float64(s.NumberSubnets))))
|
|
// And this is then added to the original prefix length to get the new prefix size.
|
|
pfxLen = pfxLen + base.Bits()
|
|
// I don't know how this would happen, but it'd be bad if it did.
|
|
if pfxLen < base.Bits() {
|
|
err = ErrBigPrefix
|
|
return
|
|
}
|
|
// Likewise.
|
|
if base.Addr().Is6() {
|
|
ok = pfxLen <= int(maxBitsv6)
|
|
} else {
|
|
ok = pfxLen <= int(maxBitsv4)
|
|
}
|
|
if !ok {
|
|
err = ErrBadPrefix
|
|
return
|
|
}
|
|
|
|
// We can now VLSM.
|
|
vlsm = &VLSMSplitter{
|
|
// Ascenting and Explicit are pointless to set as all defined sizes are the same.
|
|
Ascending: false,
|
|
Explicit: false,
|
|
PrefixLengths: make([]uint8, s.NumberSubnets),
|
|
BaseSplitter: s.BaseSplitter,
|
|
}
|
|
for i := 0; i < int(s.NumberSubnets); i++ {
|
|
vlsm.PrefixLengths[i] = uint8(pfxLen)
|
|
}
|
|
|
|
if nets, remaining, err = vlsm.Split(); err != nil {
|
|
return
|
|
}
|
|
|
|
if s.Strict && remaining != nil && remaining.Prefixes() != nil && len(remaining.Prefixes()) > 0 {
|
|
err = ErrBadNumNets
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|