2025-01-31 17:18:35 -05:00

162 lines
4.0 KiB
Go

package main
import (
"bytes"
"errors"
"go4.org/netipx"
"io"
"log"
"net"
"net/netip"
"os"
"strings"
"subnetter/netsplit"
"github.com/jessevdk/go-flags"
"r00t2.io/sysutils/paths"
)
func main() {
var err error
var b []byte
var pfx *net.IPNet
var resPfx *netip.Prefix
var origPfx netip.Prefix
var splitter netsplit.NetSplitter
var cmnArgs common
var nets []*netip.Prefix
var remaining *netipx.IPSet
var buf *bytes.Buffer
var res *netsplit.StructuredResults
var splitErr *netsplit.SplitErr = new(netsplit.SplitErr)
var parser *flags.Parser = flags.NewParser(args, flags.Default)
if _, err = parser.Parse(); err != nil {
switch flagsErr := err.(type) {
case *flags.Error:
switch flagsErr.Type {
case flags.ErrHelp, flags.ErrCommandRequired, flags.ErrRequired: // These print their relevant messages by themselves.
return
default:
log.Panicln(err)
}
default:
log.Panicln(err)
}
}
switch parser.Active.Name {
case "table":
// TODO: print table and exit
return
case "parse":
// TODO: parse file/bytes, unmarshal, and render with new options then exit
if strings.TrimSpace(args.Parse.InFile) == "-" {
buf = new(bytes.Buffer)
if _, err = io.Copy(buf, os.Stdin); err != nil {
log.Panicln(err)
}
b = buf.Bytes()
} else {
if err = paths.RealPath(&args.Parse.InFile); err != nil {
log.Panicln(err)
}
if b, err = os.ReadFile(args.Parse.InFile); err != nil {
log.Panicln(err)
}
}
if res, err = netsplit.Parse(b); err != nil {
log.Panicln(err)
}
if resPfx, nets, remaining, splitter, err = res.Uncontain(); err != nil {
log.Panicln(err)
}
if resPfx != nil {
origPfx = *resPfx
}
pfx = netipx.PrefixIPNet(origPfx.Masked())
cmnArgs = common{
outputOpts: args.Parse.outputOpts,
AllowReserved: args.Parse.AllowReserved,
AllowHostNet: args.Parse.AllowHostNet,
}
if err = printNets(&origPfx, pfx, nets, remaining, &cmnArgs, res.GetSplitter()); err != nil {
log.Panicln(err)
}
return
default:
// Actually subnet (and print results).
/*
A netsplit.NetSplitter is needed, along with:
* prefix
* verbosity
* disable showing remaining
* formatter
These are all handily-dandily enclosed in a `common` struct type.
*/
switch parser.Active.Name {
case "split-hosts":
if err = validate.Struct(args.SplitHost); err != nil {
log.Panicln(err)
}
cmnArgs = args.SplitHost.common
splitter = &netsplit.HostSplitter{
BaseSplitter: new(netsplit.BaseSplitter),
NumberHosts: args.SplitHost.Hosts,
}
case "split-nets":
if err = validate.Struct(args.SplitSubnets); err != nil {
log.Panicln(err)
}
cmnArgs = args.SplitSubnets.common
splitter = &netsplit.SubnetSplitter{
BaseSplitter: new(netsplit.BaseSplitter),
NumberSubnets: args.SplitSubnets.NumNets,
}
case "split-cidr":
if err = validate.Struct(args.SplitCIDR); err != nil {
log.Panicln(err)
}
cmnArgs = args.SplitCIDR.common
splitter = &netsplit.CIDRSplitter{
BaseSplitter: new(netsplit.BaseSplitter),
PrefixLength: args.SplitCIDR.Prefix,
}
case "vlsm":
if err = validate.Struct(args.VLSM); err != nil {
log.Panicln(err)
}
cmnArgs = args.VLSM.common
splitter = &netsplit.VLSMSplitter{
BaseSplitter: new(netsplit.BaseSplitter),
Ascending: args.VLSM.Asc,
PrefixLengths: args.VLSM.Sizes,
}
}
if origPfx, err = netip.ParsePrefix(cmnArgs.Network.Network); err != nil {
log.Panicln(err)
}
// This can be a direct conversion. We have to make sure we mask off the host bits to avoid errors, though.
/*
if _, pfx, err = net.ParseCIDR(cmnArgs.network.network); err != nil {
log.Panicln(err)
}
*/
pfx = netipx.PrefixIPNet(origPfx.Masked())
splitter.SetParent(*pfx)
if nets, remaining, err = splitter.Split(); err != nil {
if errors.As(err, &splitErr) {
printSplitErr(splitErr)
os.Exit(1)
} else {
log.Panicln(err)
}
}
if err = printNets(&origPfx, pfx, nets, remaining, &cmnArgs, splitter); err != nil {
log.Panicln(err)
}
}
}