2 Commits

Author SHA1 Message Date
brent saner
c05f9c4d47 v0.2.4
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.
2025-04-13 03:52:43 -04:00
brent saner
4ab83c9069 v0.2.3
ADDED:
* Additional diagram under table subcommand for the IPv6 CIDR segments
2025-04-07 16:03:20 -04:00
5 changed files with 317 additions and 71 deletions

8
ACKNOWLEDGEMENTS Normal file
View File

@@ -0,0 +1,8 @@
The "IPv6 Segment Reference Diagram" output as rendered in the `table`
subcommand is from:
https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
as fetched on April 07, 2025.
It is licensed under Creative Commons "CC BY-SA 4.0";
see:
https://creativecommons.org/licenses/by-sa/4.0/
https://creativecommons.org/licenses/by-sa/4.0/legalcode.en)

View File

@@ -47,13 +47,268 @@ IPV4:
{{- end }}
{{- if not $opts.NoIpv6 }}
{{- if $opts.Plain }}
IPV6:
{{- else }}
{{ bold "IPv6:"}}
{{- end }}
{{- if not $opts.NoIpv6Seg }}
{{- if $opts.Plain }}
IPv6 Segment Reference Diagram:
{{- if $opts.VertSeg }}
Example: 2001:0db8:0123:4567:89ab:cdef:1234:5678
{{- if not $opts.VertInvert }}
2 4
0 8
0 12
1 16
:
0 20
d 24
b 28
8 32
:
0 36
1 40
2 44
3 48
:
4 52
5 56
6 60
7 64
:
8 68
9 72
a 76
b 80
:
c 84
d 88
e 92
f 96
:
1 100
2 104
3 108
4 112
:
5 116
6 120
7 124
8 127 or 128
{{- else }}
4 ____ 2
8 ____ 0
12 ___ 0
16 ___ 1
___ :
20 _____ 0
24 _____ d
28 _____ b
32 _____ 8
_____ :
36 _______ 0
40 _______ 1
44 _______ 2
48 _______ 3
_______ :
52 _________ 4
56 _________ 5
60 _________ 6
64 _________ 7
_________ :
68 ___________ 8
72 ___________ 9
76 ___________ a
80 ___________ b
___________ :
84 _____________ c
88 _____________ d
92 _____________ e
96 _____________ f
_____________ :
100 ______________ 1
104 ______________ 2
108 ______________ 3
112 ______________ 4
______________ :
116 ________________ 5
120 ________________ 6
124 ________________ 7
127 ________________ (8)
128 ________________ (8)
{{- end }}
{{- else }}
2001:0db8:0123:4567:89ab:cdef:1234:5678
|||| |||| |||| |||| |||| |||| |||| ||||
|||| |||| |||| |||| |||| |||| |||| |||128
|||| |||| |||| |||| |||| |||| |||| |||127
|||| |||| |||| |||| |||| |||| |||| ||124
|||| |||| |||| |||| |||| |||| |||| |120
|||| |||| |||| |||| |||| |||| |||| 116
|||| |||| |||| |||| |||| |||| |||112
|||| |||| |||| |||| |||| |||| ||108
|||| |||| |||| |||| |||| |||| |104
|||| |||| |||| |||| |||| |||| 100
|||| |||| |||| |||| |||| |||96
|||| |||| |||| |||| |||| ||92
|||| |||| |||| |||| |||| |88
|||| |||| |||| |||| |||| 84
|||| |||| |||| |||| |||80
|||| |||| |||| |||| ||76
|||| |||| |||| |||| |72
|||| |||| |||| |||| 68
|||| |||| |||| |||64
|||| |||| |||| ||60
|||| |||| |||| |56
|||| |||| |||| 52
|||| |||| |||48
|||| |||| ||44
|||| |||| |40
|||| |||| 36
|||| |||32
|||| ||28
|||| |24
|||| 20
|||16
||12
|8
4
{{- end }}
{{- else }}
{{ bold "IPv6 Segment Reference Diagram:" }}
{{- if $opts.VertSeg }}
{{ bold "Example:"}} 2001:0db8:0123:4567:89ab:cdef:1234:5678
{{- if not $opts.VertInvert }}
2 4
0 8
0 12
1 16
:
0 20
d 24
b 28
8 32
:
0 36
1 40
2 44
3 48
:
4 52
5 56
6 60
7 64
:
8 68
9 72
a 76
b 80
:
c 84
d 88
e 92
f 96
:
1 100
2 104
3 108
4 112
:
5 116
6 120
7 124
8 127 or 128
{{- else }}
4 ━━━━ 2
8 ━━━━ 0
12 ━━━ 0
16 ━━━ 1
━━━ :
20 ━━━━━ 0
24 ━━━━━ d
28 ━━━━━ b
32 ━━━━━ 8
━━━━━ :
36 ━━━━━━━ 0
40 ━━━━━━━ 1
44 ━━━━━━━ 2
48 ━━━━━━━ 3
━━━━━━━ :
52 ━━━━━━━━━ 4
56 ━━━━━━━━━ 5
60 ━━━━━━━━━ 6
64 ━━━━━━━━━ 7
━━━━━━━━━ :
68 ━━━━━━━━━━━ 8
72 ━━━━━━━━━━━ 9
76 ━━━━━━━━━━━ a
80 ━━━━━━━━━━━ b
━━━━━━━━━━━ :
84 ━━━━━━━━━━━━━ c
88 ━━━━━━━━━━━━━ d
92 ━━━━━━━━━━━━━ e
96 ━━━━━━━━━━━━━ f
━━━━━━━━━━━━━ :
100 ━━━━━━━━━━━━━━ 1
104 ━━━━━━━━━━━━━━ 2
108 ━━━━━━━━━━━━━━ 3
112 ━━━━━━━━━━━━━━ 4
━━━━━━━━━━━━━━ :
116 ━━━━━━━━━━━━━━━━ 5
120 ━━━━━━━━━━━━━━━━ 6
124 ━━━━━━━━━━━━━━━━ 7
127 ━━━━━━━━━━━━━━━━ (8)
128 ━━━━━━━━━━━━━━━━ (8)
{{- end }}
{{- else }}
{{ bold "2001:0db8:0123:4567:89ab:cdef:1234:5678" }}
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃128
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃127
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃124
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃120
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ 116
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃112
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃108
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃104
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ 100
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃96
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃92
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃88
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ 84
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃80
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃76
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃72
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃┃ 68
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃┃64
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃┃60
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ ┃56
┃┃┃┃ ┃┃┃┃ ┃┃┃┃ 52
┃┃┃┃ ┃┃┃┃ ┃┃┃48
┃┃┃┃ ┃┃┃┃ ┃┃44
┃┃┃┃ ┃┃┃┃ ┃40
┃┃┃┃ ┃┃┃┃ 36
┃┃┃┃ ┃┃┃32
┃┃┃┃ ┃┃28
┃┃┃┃ ┃24
┃┃┃┃ 20
┃┃┃16
┃┃12
┃8
4
{{- end }}
{{- end }}
{{- end }}
{{- if $opts.Plain }}
CIDR:
{{- else }}
{{ bold "CIDR:" }}

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
}
@@ -89,6 +89,9 @@ type TableArgs struct {
NoV4Mask bool `short:"M" long:"no-mask" description:"Do not include netmasks for IPv4."`
NoIpv6 bool `short:"4" long:"ipv4" description:"Only show IPv4 table(s)."`
NoIpv4 bool `short:"6" long:"ipv6" description:"Only show IPv6 table(s)."`
NoIpv6Seg bool `short:"D" long:"no-ipv6-seg" description:"Do not show the IPv6 Segment Reference Diagram (ignored if -4/--ipv4 is specified)."`
VertSeg bool `short:"V" long:"vert-ipv6-seg" description:"If specified, display the IPv6 Segment Reference Diagram vertically-aligned instead of horizontally."`
VertInvert bool `short:"I" long:"vert-invert" description:"When printing a vertical-aligned IPv6 Segment Reference Diagram, flip so the prefix length is on the left. This takes up less width and is recommended for smaller terminals, and may be easier to read in general."`
}
type CheckArgs struct {

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 {
return
}
// Previously, this used (github.com/projectdiscovery/mapcidr).SplitIPNetIntoN.
// It no longer does: https://github.com/projectdiscovery/mapcidr/issues/628
// I am Noticing.
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
// 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
}
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)
// Likewise.
if base.Addr().Is6() {
ok = pfxLen <= int(maxBitsv6)
} 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),
ok = pfxLen <= int(maxBitsv4)
}
}
ipsb.AddPrefix(sub)
} else {
subPtr = new(netip.Prefix)
*subPtr = sub
nets = append(nets, subPtr)
}
}
}
if remaining, err = ipsb.IPSet(); err != nil {
if !ok {
err = ErrBadPrefix
return
}
if len(nets) < int(s.NumberSubnets) {
err = &SplitErr{
Wrapped: ErrNoNetSpace,
Nets: nets,
Remaining: remaining,
// 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
}