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.
This commit is contained in:
brent saner 2025-04-13 03:36:47 -04:00
parent 4ab83c9069
commit c05f9c4d47
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
3 changed files with 38 additions and 58 deletions

View File

@ -77,7 +77,7 @@ type SplitHostArgs struct {
}

type SplitSubnetArgs struct {
Strict bool `short:"t" long:"strict" description:"If specified, an error will occur if the number of possible equally-sized subnets is not exactly -n/--num-nets."`
Strict bool `short:"t" long:"strict" description:"If specified, an error will occur if the number of subnets is not exactly -n/--num-nets."`
NumNets uint `short:"n" long:"num-nets" required:"true" description:"Number of networks." validate:"required"`
splitArgs
}

View File

@ -5,6 +5,7 @@ import "errors"
var (
ErrBadBoundary error = errors.New("subnet does not align on bit boundary")
ErrBadNumHosts error = errors.New("bad number of hosts; cannot split into prefix exactly")
ErrBadNumNets error = errors.New("bad number of nets; cannot split into prefix exactly")
ErrBadPrefix error = errors.New("prefix is invalid")
ErrBadPrefixLen error = errors.New("prefix length exceeds maximum possible for prefix's inet family")
ErrBadSplitter error = errors.New("invalid or unknown splitter when containing")

View File

@ -1,10 +1,9 @@
package netsplit

import (
`net`
`math`
"net/netip"

`github.com/projectdiscovery/mapcidr`
"go4.org/netipx"
)

@ -22,10 +21,7 @@ func (s *SubnetSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet,
var ok bool
var pfxLen int
var base netip.Prefix
var sub netip.Prefix
var subPtr *netip.Prefix
var split []*net.IPNet
var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)
var vlsm *VLSMSplitter

if s == nil || s.BaseSplitter == nil || s.network == nil || s.NumberSubnets == 0 {
return
@ -40,65 +36,48 @@ func (s *SubnetSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet,
return
}

if split, err = mapcidr.SplitIPNetIntoN(s.network, int(s.NumberSubnets)); err != nil {
// 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
}

for _, n := range split {
if sub, ok = netipx.FromStdIPNet(n); !ok {
// We bail early on this error.
err = &SplitErr{
Wrapped: ErrBadBoundary,
Nets: nets,
Remaining: remaining,
LastSubnet: subPtr,
RequestedPrefixLen: 0,
}
err = ErrBadBoundary
return
}
if sub.String() == base.String() {
continue
}
if pfxLen == 0 {
pfxLen = sub.Bits()
if nets == nil {
nets = make([]*netip.Prefix, 0)
}
subPtr = new(netip.Prefix)
*subPtr = sub
nets = append(nets, subPtr)
} else {
if sub.Bits() != pfxLen {
if err == nil {
// Return this err but don't return early; wait for the populate.
err = &SplitErr{
Wrapped: ErrNoNetSpace,
Nets: nets,
Remaining: remaining,
LastSubnet: subPtr,
RequestedPrefixLen: uint8(pfxLen),
}
}
ipsb.AddPrefix(sub)
} else {
subPtr = new(netip.Prefix)
*subPtr = sub
nets = append(nets, subPtr)
}
}
// 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 remaining, err = ipsb.IPSet(); err != nil {
if nets, remaining, err = vlsm.Split(); err != nil {
return
}

if len(nets) < int(s.NumberSubnets) {
err = &SplitErr{
Wrapped: ErrNoNetSpace,
Nets: nets,
Remaining: remaining,
}
if s.Strict && remaining != nil && remaining.Prefixes() != nil && len(remaining.Prefixes()) > 0 {
err = ErrBadNumNets
return
}