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 }