69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
package netsplit
|
|
|
|
import (
|
|
`math/big`
|
|
`net`
|
|
"net/netip"
|
|
|
|
`github.com/projectdiscovery/mapcidr`
|
|
"go4.org/netipx"
|
|
)
|
|
|
|
/*
|
|
Split splits the network defined in a HostSplitter alongside its configuration and performs the subnetting.
|
|
This strategy attempts to split the network into subnets of equal number of hosts.
|
|
|
|
remaining may or may not be nil depending on if the number of hosts can fit cleanly within equal network sizes on boundaries.
|
|
|
|
An ErrBadNumHosts will be returned if the number of hosts does not match the *addressable* range in a prefix.
|
|
*/
|
|
func (h *HostSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, err error) {
|
|
|
|
var tgt *big.Int
|
|
var hosts *big.Int
|
|
var sub netip.Prefix
|
|
var subPtr *netip.Prefix
|
|
var split []*net.IPNet
|
|
var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)
|
|
|
|
if h == nil || h.NumberHosts == 0 || h.BaseSplitter == nil || h.network == nil {
|
|
return
|
|
}
|
|
|
|
if split, err = mapcidr.SplitIPNetByNumber(h.network, int(h.NumberHosts)); err != nil {
|
|
return
|
|
}
|
|
|
|
tgt = big.NewInt(0)
|
|
tgt.SetUint64(uint64(h.NumberHosts))
|
|
|
|
nets = make([]*netip.Prefix, len(split))
|
|
for idx, n := range split {
|
|
sub, _ = netipx.FromStdIPNet(n)
|
|
hosts = mapcidr.CountIPsInCIDR(false, false, n)
|
|
if hosts == nil || tgt.Cmp(hosts) != 0 {
|
|
err = &SplitErr{
|
|
Wrapped: ErrBadNumHosts,
|
|
Nets: nets,
|
|
Remaining: remaining,
|
|
LastSubnet: &sub,
|
|
RequestedPrefixLen: uint8(sub.Bits()),
|
|
}
|
|
ipsb.AddPrefix(sub)
|
|
} else {
|
|
subPtr = new(netip.Prefix)
|
|
*subPtr = sub
|
|
nets = append(nets, subPtr)
|
|
}
|
|
|
|
nets[idx] = new(netip.Prefix)
|
|
*nets[idx] = sub
|
|
}
|
|
|
|
if remaining, err = ipsb.IPSet(); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|