200 lines
4.2 KiB
Go
200 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
_ "encoding/csv"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/jszwec/csvutil"
|
|
|
|
"r00t2.io/sysutils/net/ports"
|
|
"r00t2.io/sysutils/net/protos"
|
|
"r00t2.io/sysutils/paths"
|
|
)
|
|
|
|
// I really don't get all the slobbering over interfaces. They seem... pointless.
|
|
// Because now I have to write multiple parsers with largely duplicate code.
|
|
// Massive code duplication is, apparently, Idiomatic Go(TM).
|
|
// I miss python.
|
|
func parsePort(src *[]byte, dst []ports.IPPort, outBytes *[]byte) (err error) {
|
|
|
|
var tName string
|
|
var varName string
|
|
var s string
|
|
var buf bytes.Buffer
|
|
var allports []string
|
|
|
|
buf.Write([]byte("package ports\n\n"))
|
|
|
|
if err = csvutil.Unmarshal(*src, &dst); err != nil {
|
|
return
|
|
}
|
|
|
|
buf.Write([]byte("var (\n"))
|
|
|
|
for _, i := range dst {
|
|
|
|
// tName = fmt.Sprintf("%v", i.ServiceName)
|
|
tName = strings.ToLower(i.ServiceName)
|
|
varName = fmt.Sprintf("RegisteredPort_%v%v", tName, int(i.Number))
|
|
|
|
s = fmt.Sprintf("\t%v := %#v\n", varName, &i)
|
|
buf.Write([]byte(s))
|
|
}
|
|
|
|
buf.Write([]byte(")\n\n"))
|
|
|
|
// Write the easy collections.
|
|
buf.Write([]byte("var (\n"))
|
|
buf.Write([]byte("\tAllRegisteredPorts []*IPPort = {\n"))
|
|
for _, i := range allports {
|
|
buf.Write([]byte(fmt.Sprintf("\t\t%v,\n", i)))
|
|
}
|
|
buf.Write([]byte(")\n\n)\n"))
|
|
|
|
*outBytes = buf.Bytes()
|
|
|
|
return
|
|
}
|
|
|
|
func parseProto(src *[]byte, dst []protos.IPProto, outBytes *[]byte) (err error) {
|
|
|
|
var tName string
|
|
var varName string
|
|
var s string
|
|
var buf bytes.Buffer
|
|
var allprotos []string
|
|
|
|
buf.Write([]byte("package protos\n\n"))
|
|
|
|
if err = csvutil.Unmarshal(*src, &dst); err != nil {
|
|
return
|
|
}
|
|
|
|
buf.Write([]byte("var (\n"))
|
|
|
|
for _, i := range dst {
|
|
|
|
tName = fmt.Sprintf("%v", i.Name)
|
|
varName = fmt.Sprintf("RegisteredProto%v%v", tName, strconv.Itoa(int(i.Number)))
|
|
|
|
allprotos = append(allprotos, varName)
|
|
|
|
s = fmt.Sprintf("\t%v := %#v\n", varName, &i)
|
|
buf.Write([]byte(s))
|
|
}
|
|
|
|
buf.Write([]byte(")\n\n"))
|
|
|
|
// Write the easy collections.
|
|
buf.Write([]byte("var (\n"))
|
|
buf.Write([]byte("\tAllRegisteredProtos []*IPProto = {\n"))
|
|
for _, i := range allprotos {
|
|
buf.Write([]byte(fmt.Sprintf("\t\t%v,\n", i)))
|
|
}
|
|
buf.Write([]byte(")\n\n)\n"))
|
|
|
|
*outBytes = buf.Bytes()
|
|
|
|
return
|
|
}
|
|
|
|
func write(path string, b []byte) (err error) {
|
|
|
|
if err = paths.RealPath(&path); err != nil {
|
|
return
|
|
}
|
|
if err = os.WriteFile(path, b, 0644); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func main() {
|
|
|
|
var dlbytes *[]byte // This is the raw downloaded CSV.
|
|
// var rows [][]string // This is the parsed CSV.
|
|
var err error
|
|
|
|
urls := map[string]map[string]string{
|
|
// Protos needs to be first so ports can reference them.
|
|
// TODO.
|
|
"protos": {
|
|
"url": protosUrl,
|
|
"file": protosFile,
|
|
},
|
|
"ports": {
|
|
"url": portsUrl,
|
|
"file": portsFile,
|
|
},
|
|
}
|
|
|
|
rendered := map[string]*[]byte{
|
|
"protos": &[]byte{},
|
|
"ports": &[]byte{},
|
|
}
|
|
|
|
for t, d := range urls {
|
|
|
|
var url string
|
|
var fpath string
|
|
var ok bool
|
|
|
|
if url, ok = d["url"]; !ok {
|
|
fmt.Printf("URL does not exist for %v; skipping.\n", t)
|
|
continue
|
|
}
|
|
if fpath, ok = d["file"]; !ok {
|
|
fmt.Printf("File path does not exist for %v; skipping.\n", t)
|
|
continue
|
|
} else {
|
|
if err = paths.RealPath(&fpath); err != nil {
|
|
fmt.Printf("Cannot resolve file path for %v; skipping.\n", t)
|
|
continue
|
|
}
|
|
}
|
|
|
|
if dlbytes, err = download(url); err != nil {
|
|
fmt.Printf("Could not download '%v' for %v (skipping):\n", url, t)
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
|
|
// I *could* set up a variable that refers to the proper func and set that func in an if block above...
|
|
// But then I'd have to use reflection and it gets gross and hacky. This is a lot more performant even though it's a lot
|
|
// more verbose. Write it once, run it many times...
|
|
if t == "ports" {
|
|
|
|
var objs []ports.IPPort
|
|
|
|
if err = parsePort(dlbytes, objs, rendered[t]); err != nil {
|
|
fmt.Printf("Could not parse %v (skipping):\n", t)
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
|
|
} else { // t == "proto"
|
|
|
|
var objs []protos.IPProto
|
|
|
|
if err = parseProto(dlbytes, objs, rendered[t]); err != nil {
|
|
fmt.Printf("Could not parse %v (skipping):\n", t)
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
|
|
}
|
|
|
|
if err = write(fpath, *rendered[t]); err != nil {
|
|
fmt.Printf("Could not write to '%v' for %v (skipping):\n", fpath, t)
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
|
|
}
|
|
}
|