From 517dabc2b4acda13a228e19ee5d39a0b73433eec Mon Sep 17 00:00:00 2001 From: Leon Fernandez Date: Mon, 28 Oct 2024 10:05:01 +0100 Subject: [PATCH 1/2] Moved command declarations to central tapir lib Removed commands that shouldn't be in tapir-cli --- cmd/command.go | 148 ------- cmd/dawg.go | 204 --------- cmd/debugcmd.go | 439 ------------------- cmd/keyupload.go | 156 ------- cmd/mqtt.go | 1053 ---------------------------------------------- cmd/ping_cmd.go | 65 --- cmd/root.go | 9 +- cmd/rpz.go | 139 ------ cmd/slogger.go | 219 ---------- 9 files changed, 7 insertions(+), 2425 deletions(-) delete mode 100644 cmd/command.go delete mode 100644 cmd/dawg.go delete mode 100644 cmd/debugcmd.go delete mode 100644 cmd/keyupload.go delete mode 100644 cmd/mqtt.go delete mode 100644 cmd/ping_cmd.go delete mode 100644 cmd/rpz.go delete mode 100644 cmd/slogger.go diff --git a/cmd/command.go b/cmd/command.go deleted file mode 100644 index 668689e..0000000 --- a/cmd/command.go +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ - -package cmd - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - - "github.com/dnstapir/tapir" - "github.com/miekg/dns" - "github.com/ryanuber/columnize" - "github.com/spf13/cobra" -) - -var BumpCmd = &cobra.Command{ - Use: "bump", - Short: "Instruct TAPIR-POP to bump the SOA serial of the RPZ zone", - Run: func(cmd *cobra.Command, args []string) { - resp := SendCommandCmd(tapir.CommandPost{ - Command: "bump", - Zone: dns.Fqdn(tapir.GlobalCF.Zone), - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -var PopCmd = &cobra.Command{ - Use: "pop", - Short: "Prefix command, only usable via sub-commands", -} - -var PopMqttCmd = &cobra.Command{ - Use: "mqtt", - Short: "Prefix command, only usable via sub-commands", -} - -var PopStatusCmd = &cobra.Command{ - Use: "status", - Short: "Get the status of TAPIR-POP", - Run: func(cmd *cobra.Command, args []string) { - resp := SendCommandCmd(tapir.CommandPost{ - Command: "status", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - - if len(resp.TapirFunctionStatus.ComponentStatus) != 0 { - tfs := resp.TapirFunctionStatus - fmt.Printf("TAPIR-POP Status. Reported components: %d Total errors (since last start): %d\n", len(tfs.ComponentStatus), tfs.NumFailures) - var out = []string{"Component|Status|Error msg|# Fails|# Warns|LastFailure|LastSuccess"} - for k, v := range tfs.ComponentStatus { - out = append(out, fmt.Sprintf("%s|%s|%s|%d|%d|%v|%v", k, tapir.StatusToString[v.Status], v.ErrorMsg, v.NumFails, v.NumWarnings, v.LastFail.Format(tapir.TimeLayout), v.LastSuccess.Format(tapir.TimeLayout))) - } - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - } - }, -} - -var PopStopCmd = &cobra.Command{ - Use: "stop", - Short: "Instruct TAPIR-POP to stop", - Run: func(cmd *cobra.Command, args []string) { - resp := SendCommandCmd(tapir.CommandPost{ - Command: "stop", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -var PopMqttStartCmd = &cobra.Command{ - Use: "start", - Short: "Instruct TAPIR-POP MQTT Engine to start", - Run: func(cmd *cobra.Command, args []string) { - resp := SendCommandCmd(tapir.CommandPost{ - Command: "mqtt-start", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -var PopMqttStopCmd = &cobra.Command{ - Use: "stop", - Short: "Instruct TAPIR-POP MQTT Engine to stop", - Run: func(cmd *cobra.Command, args []string) { - resp := SendCommandCmd(tapir.CommandPost{ - Command: "mqtt-stop", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -var PopMqttRestartCmd = &cobra.Command{ - Use: "restart", - Short: "Instruct TAPIR-POP MQTT Engine to restart", - Run: func(cmd *cobra.Command, args []string) { - resp := SendCommandCmd(tapir.CommandPost{ - Command: "mqtt-restart", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -func init() { - rootCmd.AddCommand(BumpCmd, PopCmd) - PopCmd.AddCommand(PopStatusCmd, PopStopCmd, PopMqttCmd) - PopMqttCmd.AddCommand(PopMqttStartCmd, PopMqttStopCmd, PopMqttRestartCmd) - - BumpCmd.Flags().StringVarP(&tapir.GlobalCF.Zone, "zone", "z", "", "Zone name") -} - -func SendCommandCmd(data tapir.CommandPost) tapir.CommandResponse { - _, buf, _ := api.RequestNG(http.MethodPost, "/command", data, true) - - var cr tapir.CommandResponse - - err := json.Unmarshal(buf, &cr) - if err != nil { - log.Fatalf("Error from json.Unmarshal: %v\n", err) - } - return cr -} diff --git a/cmd/dawg.go b/cmd/dawg.go deleted file mode 100644 index 048d994..0000000 --- a/cmd/dawg.go +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ - -package cmd - -import ( - "errors" - "fmt" - "os" - - "github.com/dnstapir/tapir" - "github.com/miekg/dns" - "github.com/smhanov/dawg" - "github.com/spf13/cobra" -) - -var srcformat, srcfile, dawgfile, dawgname string - -var dawgCmd = &cobra.Command{ - Use: "dawg", - Short: "Generate or interact with data stored in a DAWG file; only useable via sub-commands", -} - -var dawgCompileCmd = &cobra.Command{ - Use: "compile", - Short: "Compile a new DAWG file from either a text or a CSV source file", - Run: func(cmd *cobra.Command, args []string) { - if srcfile == "" { - fmt.Printf("Error: source file not specified.\n") - os.Exit(1) - } - - if dawgfile == "" { - fmt.Printf("Error: outfile not specified.\n") - os.Exit(1) - } - - _, err := os.Stat(srcfile) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - fmt.Printf("Error: source file \"%s\" does not exist.\n", srcfile) - os.Exit(1) - } else { - fmt.Printf("Error: %v\n", err) - } - } - - switch srcformat { - case "csv": - CompileDawgFromCSV(srcfile, dawgfile) - case "text": - CompileDawgFromText(srcfile, dawgfile) - default: - fmt.Printf("Error: format \"%s\" of source file \"%s\" unknown. Must be either \"csv\" or \"text\".\n", - srcformat, srcfile) - os.Exit(1) - } - }, -} - -var dawgLookupCmd = &cobra.Command{ - Use: "lookup", - Short: "Look up a name in an existing DAWG file", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command.`, - Run: func(cmd *cobra.Command, args []string) { - if dawgfile == "" { - fmt.Printf("Error: DAWG file not specified.\n") - os.Exit(1) - } - - if dawgname == "" { - fmt.Printf("Error: Name to look up not specified.\n") - os.Exit(1) - } - - fmt.Printf("Loading DAWG: %s\n", dawgfile) - dawgf, err := dawg.Load(dawgfile) - if err != nil { - fmt.Printf("Error from dawg.Load(%s): %v", dawgfile, err) - os.Exit(1) - } - - dawgname = dns.Fqdn(dawgname) - idx := dawgf.IndexOf(dawgname) - - switch idx { - case -1: - fmt.Printf("Name not found\n") - default: - fmt.Printf("Name %s found, index: %d\n", dawgname, idx) - } - }, -} - -var dawgListCmd = &cobra.Command{ - Use: "list", - Short: "List all names in an existing DAWG file", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command.`, - Run: func(cmd *cobra.Command, args []string) { - if dawgfile == "" { - fmt.Printf("Error: DAWG file not specified.\n") - os.Exit(1) - } - - fmt.Printf("Loading DAWG: %s\n", dawgfile) - dawgf, err := dawg.Load(dawgfile) - if err != nil { - fmt.Printf("Error from dawg.Load(%s): %v", dawgfile, err) - os.Exit(1) - } - - if tapir.GlobalCF.Debug { - fmt.Printf("DAWG has %d nodes, %d added and %d edges.\n", dawgf.NumNodes(), - dawgf.NumAdded(), dawgf.NumEdges()) - } - - count, result := tapir.ListDawg(dawgf) - fmt.Printf("%v\n", result) - if tapir.GlobalCF.Verbose { - fmt.Printf("Enumeration func was called %d times\n", count) - } - }, -} - -func init() { - rootCmd.AddCommand(dawgCmd) - dawgCmd.AddCommand(dawgCompileCmd, dawgLookupCmd, dawgListCmd) - - dawgCmd.PersistentFlags().StringVarP(&dawgfile, "dawg", "", "", - "Name of DAWG file, must end in \".dawg\"") - dawgCompileCmd.Flags().StringVarP(&srcformat, "format", "", "", - "Format of text file, either csv or text") - dawgCompileCmd.Flags().StringVarP(&srcfile, "src", "", "", - "Name of source text file") - // dawgCompileCmd.Flags().StringVarP(&outfile, "outfile", "", "", - // "Name of outfile, must end in \".dawg\"") - // dawgLookupCmd.Flags().StringVarP(&dawgfile, "dawg", "", "", - // "Name of DAWG file") - dawgLookupCmd.Flags().StringVarP(&dawgname, "name", "", "", - "Name to look up") - dawgListCmd.Flags().StringVarP(&dawgname, "name", "", "", - "Name to find prefixes of") -} - -func CompileDawgFromCSV(srcfile, outfile string) { - ofd, err := os.Create(outfile) - if err != nil { - fmt.Printf("Error creating \"%s\": %v\n", outfile, err) - os.Exit(1) - } - - sortednames, err := tapir.ParseCSV(srcfile, map[string]tapir.TapirName{}, false) - if err != nil { - fmt.Printf("Error parsing CSV source \"%s\": %v\n", srcfile, err) - os.Exit(1) - } - - if tapir.GlobalCF.Debug { - fmt.Print("Sorted list of names:\n") - for _, n := range sortednames { - fmt.Printf("%s\n", n) - } - } - - err = tapir.CreateDawg(sortednames, outfile) - if err != nil { - fmt.Printf("Error creating DAWG \"%s\" from sorted list of names: %v\n", outfile, err) - os.Exit(1) - } - - ofd.Close() -} - -func CompileDawgFromText(srcfile, outfile string) { - ofd, err := os.Create(outfile) - if err != nil { - fmt.Printf("Error creating \"%s\": %v\n", outfile, err) - os.Exit(1) - } - - sortednames, err := tapir.ParseText(srcfile, map[string]tapir.TapirName{}, false) - if err != nil { - fmt.Printf("Error parsing text source \"%s\": %v\n", srcfile, err) - os.Exit(1) - } - - if tapir.GlobalCF.Debug { - fmt.Print("Sorted list of names:\n") - for _, n := range sortednames { - fmt.Printf("%s\n", n) - } - } - - err = tapir.CreateDawg(sortednames, outfile) - if err != nil { - fmt.Printf("Error creating DAWG \"%s\" from sorted list of names: %v\n", outfile, err) - os.Exit(1) - } - - ofd.Close() -} diff --git a/cmd/debugcmd.go b/cmd/debugcmd.go deleted file mode 100644 index c0965b0..0000000 --- a/cmd/debugcmd.go +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ -package cmd - -import ( - "bytes" - "encoding/gob" - "encoding/json" - "fmt" - "log" - "net/http" - "os" - "strings" - "time" - - "github.com/dnstapir/tapir" - "github.com/ryanuber/columnize" - - // "github.com/ryanuber/columnize" - "github.com/miekg/dns" - //"github.com/santhosh-tekuri/jsonschema/v2" - "github.com/invopop/jsonschema" - "github.com/spf13/cobra" -) - -var debugCmd = &cobra.Command{ - Use: "debug", - Short: "Prefix command to various debug tools; do not use in production", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("debug called") - - var tm tapir.TagMask = 345 - fmt.Printf("%032b num tags: %d\n", tm, tm.NumTags()) - }, -} - -var debugZoneDataCmd = &cobra.Command{ - Use: "zonedata", - Short: "Return the ZoneData struct for the specified zone from server", - Long: `Return the ZoneData struct from server - (mostly useful with -d JSON prettyprinter).`, - Run: func(cmd *cobra.Command, args []string) { - resp := SendDebugCmd(tapir.DebugPost{ - Command: "zonedata", - Zone: dns.Fqdn(tapir.GlobalCF.Zone), - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - // zd := resp.ZoneData - - fmt.Printf("Received %d bytes of data\n", len(resp.Msg)) - // fmt.Printf("Zone %s: RRs: %d Owners: %d\n", tapir.GlobalCF.Zone, - // len(zd.RRs), len(zd.Owners)) - if resp.Msg != "" { - fmt.Printf("%s\n", resp.Msg) - } - }, -} - -var debugColourlistsCmd = &cobra.Command{ - Use: "colourlists", - Short: "Return the white/black/greylists from the current data structures", - Run: func(cmd *cobra.Command, args []string) { - resp := SendDebugCmd(tapir.DebugPost{ - Command: "colourlists", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - fmtstring := "%-35s|%-20s|%-10s|%-10s\n" - - // fmt.Printf("Received %d bytes of data\n", len(resp.Msg)) - - // print the column headings - fmt.Printf(fmtstring, "Domain", "Source", "Src Fmt", "Colour") - fmt.Println(strings.Repeat("-", 78)) // A nice ruler over the data rows - - for _, l := range resp.Lists["whitelist"] { - for _, n := range l.Names { - fmt.Printf(fmtstring, n.Name, l.Name, "-", "white") - } - } - for _, l := range resp.Lists["blacklist"] { - for _, n := range l.Names { - fmt.Printf(fmtstring, n.Name, l.Name, "-", "black") - } - } - for _, l := range resp.Lists["greylist"] { - for _, n := range l.Names { - fmt.Printf(fmtstring, n.Name, l.Name, l.SrcFormat, "grey") - } - } - }, -} - -var debugGenRpzCmd = &cobra.Command{ - Use: "genrpz", - Short: "Return the white/black/greylists from the current data structures", - Run: func(cmd *cobra.Command, args []string) { - resp := SendDebugCmd(tapir.DebugPost{ - Command: "gen-output", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("Received %d bytes of data\n", len(resp.Msg)) - - fmt.Printf("black count=%d: %v\n", resp.BlacklistedNames) - fmt.Printf("grey count=%d: %v\n", resp.GreylistedNames) - // fmt.Printf("count=%d: %v\n", res.RpzOutput) - for _, tn := range resp.RpzOutput { - fmt.Printf("%s\n", (*tn.RR).String()) - } - }, -} - -var debugMqttStatsCmd = &cobra.Command{ - Use: "mqtt-stats", - Short: "Return the MQTT stats counters from the MQTT Engine", - Run: func(cmd *cobra.Command, args []string) { - resp := SendDebugCmd(tapir.DebugPost{ - Command: "mqtt-stats", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - if resp.Msg != "" { - fmt.Printf("%s\n", resp.Msg) - } - - var out = []string{"MQTT Topic|Msgs|Last MQTT Message|Time since last msg"} - for topic, count := range resp.MqttStats.MsgCounters { - t := resp.MqttStats.MsgTimeStamps[topic] - out = append(out, fmt.Sprintf("%s|%d|%s|%v\n", topic, count, t.Format(timelayout), time.Since(t).Round(time.Second))) - } - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - }, -} - -var debugReaperStatsCmd = &cobra.Command{ - Use: "reaper-stats", - Short: "Return the reaper status for all known greylists", - Run: func(cmd *cobra.Command, args []string) { - resp := SendDebugCmd(tapir.DebugPost{ - Command: "reaper-stats", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - if resp.Msg != "" { - fmt.Printf("%s\n", resp.Msg) - } - - for greylist, data := range resp.ReaperStats { - if len(data) == 0 { - fmt.Printf("No reaper data for greylist %s\n", greylist) - continue - } - fmt.Printf("From greylist %s at the following times these names will be deleted:\n", greylist) - out := []string{"Time|Count|Names"} - for t, d := range data { - out = append(out, fmt.Sprintf("%s|%d|%v", t.Format(timelayout), len(d), d)) - } - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - } - }, -} - -var popcomponent, popstatus string - -var debugUpdatePopStatusCmd = &cobra.Command{ - Use: "update-pop-status", - Short: "Update the status of a TAPIR-POP component, to trigger a status update over MQTT", - Run: func(cmd *cobra.Command, args []string) { - switch popstatus { - case "ok", "warn", "fail": - default: - fmt.Printf("Invalid status: %s\n", popstatus) - os.Exit(1) - } - - resp := SendDebugCmd(tapir.DebugPost{ - Command: "send-status", - Component: popcomponent, - Status: tapir.StringToStatus[popstatus], - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - if resp.Msg != "" { - fmt.Printf("%s\n", resp.Msg) - } - }, -} - -var zonefile string - -var debugSyncZoneCmd = &cobra.Command{ - Use: "synczone", - Short: "A brief description of your command", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("synczone called") - - if tapir.GlobalCF.Zone == "" { - fmt.Printf("Zone name not specified.\n") - os.Exit(1) - } - - if zonefile == "" { - fmt.Printf("Zone file not specified.\n") - os.Exit(1) - } - - zd := tapir.ZoneData{ - ZoneType: 3, // zonetype=3 keeps RRs in a []OwnerData, with an OwnerIndex map[string]int to locate stuff - ZoneName: tapir.GlobalCF.Zone, - Logger: log.Default(), - } - - _, err := zd.ReadZoneFile(zonefile) - if err != nil { - log.Fatalf("ReloadAuthZones: Error from ReadZoneFile(%s): %v", zonefile, err) - } - - // XXX: This will be wrong for zonetype=3 (which we're using) - fmt.Printf("----- zd.BodyRRs: ----\n") - tapir.PrintRRs(zd.BodyRRs) - fmt.Printf("----- zd.RRs (pre-sync): ----\n") - tapir.PrintRRs(zd.RRs) - zd.Sync() - fmt.Printf("----- zd.RRs (post-sync): ----\n") - tapir.PrintRRs(zd.RRs) - zd.Sync() - fmt.Printf("----- zd.RRs (post-sync): ----\n") - tapir.PrintRRs(zd.RRs) - fmt.Printf("----- zd.BodyRRs: ----\n") - tapir.PrintRRs(zd.BodyRRs) - }, -} - -var Listname string - -var debugGreylistStatusCmd = &cobra.Command{ - Use: "greylist-status", - Short: "Return the greylist status for all greylists", - Run: func(cmd *cobra.Command, args []string) { - status, buf, err := api.RequestNG(http.MethodPost, "/bootstrap", tapir.BootstrapPost{ - Command: "greylist-status", - }, false) - if err != nil { - fmt.Printf("Error from RequestNG: %v\n", err) - return - } - - if status != http.StatusOK { - fmt.Printf("HTTP Error: %s\n", buf) - return - } - var br tapir.BootstrapResponse - err = json.Unmarshal(buf, &br) - if err != nil { - fmt.Printf("Error decoding bootstrap response as a tapir.BootstrapResponse: %v. Giving up.\n", err) - return - } - if br.Error { - fmt.Printf("Bootstrap Error: %s\n", br.ErrorMsg) - } - if len(br.Msg) != 0 { - fmt.Printf("Bootstrap response: %s\n", br.Msg) - } - out := []string{"Server|Uptime|Topic|Last Msg|Time since last msg"} - - // for topic, count := range br.MsgCounters { - // out = append(out, fmt.Sprintf("%s|%v|%v|%v", topic, count, br.MsgTimeStamps[topic].Format(time.RFC3339), time.Now().Sub(br.MsgTimeStamps[topic]))) - // } - - for topic, topicdata := range br.TopicData { - // out = append(out, fmt.Sprintf("%s|%v|%s|%s|%s|%d|%s|%d|%s", server, uptime, name, src.Name, topic, topicdata.PubMsgs, topicdata.LatestPub.Format(time.RFC3339), topicdata.SubMsgs, topicdata.LatestSub.Format(time.RFC3339))) - out = append(out, fmt.Sprintf("%s|%d|%s|%d|%s", topic, topicdata.PubMsgs, topicdata.LatestPub.Format(time.RFC3339), topicdata.SubMsgs, topicdata.LatestSub.Format(time.RFC3339))) - } - - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - }, -} - -var debugGenerateSchemaCmd = &cobra.Command{ - Use: "generate-schema", - Short: "Experimental: Generate the JSON schema for the current data structures", - Run: func(cmd *cobra.Command, args []string) { - - reflector := &jsonschema.Reflector{ - DoNotReference: true, - } - schema := reflector.Reflect(&tapir.WBGlist{}) // WBGlist is only used as a example. - schemaJson, err := schema.MarshalJSON() - if err != nil { - fmt.Printf("Error marshalling schema: %v\n", err) - os.Exit(1) - } - var prettyJSON bytes.Buffer - - // XXX: This doesn't work. It isn't necessary that the response is JSON. - err = json.Indent(&prettyJSON, schemaJson, "", " ") - if err != nil { - fmt.Printf("Error indenting schema: %v\n", err) - os.Exit(1) - } - fmt.Printf("%v\n", string(prettyJSON.Bytes())) - }, -} - -var debugImportGreylistCmd = &cobra.Command{ - Use: "import-greylist", - Short: "Import the current data for the named greylist from the TEM bootstrap server", - Run: func(cmd *cobra.Command, args []string) { - - if Listname == "" { - fmt.Printf("No greylist name specified, using 'dns-tapir'\n") - Listname = "dns-tapir" - } - - status, buf, err := api.RequestNG(http.MethodPost, "/bootstrap", tapir.BootstrapPost{ - Command: "export-greylist", - ListName: Listname, - Encoding: "gob", - }, false) - if err != nil { - fmt.Printf("Error from RequestNG: %v\n", err) - return - } - - if status != http.StatusOK { - fmt.Printf("HTTP Error: %s\n", buf) - return - } - // if resp.Error { - // fmt.Printf("Error: %s\n", resp.ErrorMsg) - // return - // } - - var greylist tapir.WBGlist - decoder := gob.NewDecoder(bytes.NewReader(buf)) - err = decoder.Decode(&greylist) - if err != nil { - // fmt.Printf("Error decoding greylist data: %v\n", err) - // If decoding the gob failed, perhaps we received a tapir.CommandResponse instead? - var br tapir.BootstrapResponse - err = json.Unmarshal(buf, &br) - if err != nil { - fmt.Printf("Error decoding response either as a GOB blob or as a tapir.CommandResponse: %v. Giving up.\n", err) - return - } - if br.Error { - fmt.Printf("Command Error: %s\n", br.ErrorMsg) - } - if len(br.Msg) != 0 { - fmt.Printf("Command response: %s\n", br.Msg) - } - return - } - - // fmt.Printf("%v\n", greylist) - fmt.Printf("Names present in greylist %s:", Listname) - if len(greylist.Names) == 0 { - fmt.Printf(" None\n") - } else { - fmt.Printf("\n") - out := []string{"Name|Time added|TTL|Tags"} - for _, n := range greylist.Names { - ttl := n.TTL - time.Now().Sub(n.TimeAdded).Round(time.Second) - out = append(out, fmt.Sprintf("%s|%v|%v|%v", n.Name, n.TimeAdded.Format(tapir.TimeLayout), ttl, n.TagMask)) - } - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - } - - fmt.Printf("ReaperData present in greylist %s:", Listname) - if len(greylist.ReaperData) == 0 { - fmt.Printf(" None\n") - } else { - fmt.Printf("\n") - out := []string{"Time|Count|Names"} - for t, d := range greylist.ReaperData { - var names []string - for n := range d { - names = append(names, n) - } - out = append(out, fmt.Sprintf("%s|%d|%v", t.Format(timelayout), len(d), names)) - } - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - } - }, -} - -func init() { - rootCmd.AddCommand(debugCmd) - debugCmd.AddCommand(debugSyncZoneCmd, debugZoneDataCmd, debugColourlistsCmd, debugGenRpzCmd) - debugCmd.AddCommand(debugMqttStatsCmd, debugReaperStatsCmd) - debugCmd.AddCommand(debugImportGreylistCmd, debugGreylistStatusCmd) - debugCmd.AddCommand(debugGenerateSchemaCmd, debugUpdatePopStatusCmd) - - debugUpdatePopStatusCmd.Flags().StringVarP(&popcomponent, "component", "c", "", "Component name") - debugUpdatePopStatusCmd.Flags().StringVarP(&popstatus, "status", "s", "", "Component status (ok, warn, fail)") - - debugImportGreylistCmd.Flags().StringVarP(&Listname, "list", "l", "", "Greylist name") - debugSyncZoneCmd.Flags().StringVarP(&tapir.GlobalCF.Zone, "zone", "z", "", "Zone name") - debugZoneDataCmd.Flags().StringVarP(&tapir.GlobalCF.Zone, "zone", "z", "", "Zone name") - debugSyncZoneCmd.Flags().StringVarP(&zonefile, "file", "f", "", "Zone file") -} - -type DebugResponse struct { - Msg string - Data interface{} - Error bool - ErrorMsg string -} - -func SendDebugCmd(data tapir.DebugPost) tapir.DebugResponse { - _, buf, _ := api.RequestNG(http.MethodPost, "/debug", data, true) - - var dr tapir.DebugResponse - - var pretty bytes.Buffer - err := json.Indent(&pretty, buf, "", " ") - if err != nil { - fmt.Printf("JSON parse error: %v", err) - } - // fmt.Printf("Received %d bytes of data: %v\n", len(buf), pretty.String()) - // os.Exit(1) - - err = json.Unmarshal(buf, &dr) - if err != nil { - log.Fatalf("Error from json.Unmarshal: %v\n", err) - } - return dr -} diff --git a/cmd/keyupload.go b/cmd/keyupload.go deleted file mode 100644 index d63b144..0000000 --- a/cmd/keyupload.go +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ -package cmd - -import ( - "crypto/sha256" - "encoding/pem" - "path/filepath" - - "fmt" - "log" - "os" - "time" - - "github.com/dnstapir/tapir" - "github.com/lestrrat-go/jwx/v2/jwa" - "github.com/lestrrat-go/jwx/v2/jws" - "github.com/spf13/cobra" -) - -var pubkeyfile string - -var KeyUploadCmd = &cobra.Command{ - Use: "keyupload", - Short: "Upload a public key to a TAPIR Core", - Long: `Upload a public key to a TAPIR Core. The key must be in PEM format.`, - Run: func(cmd *cobra.Command, args []string) { - // if len(args) != 1 { - // log.Fatal("keyupload must have exactly one argument: the path to the public key file") - // } - - var statusch = make(chan tapir.ComponentStatusUpdate, 10) - - // If any status updates arrive, print them out - go func() { - for status := range statusch { - fmt.Printf("Status update: %+v\n", status) - } - }() - - certCN, _, clientCert, err := tapir.FetchTapirClientCert(log.Default(), statusch) - if err != nil { - fmt.Printf("Error from FetchTapirClientCert: %v\n", err) - os.Exit(1) - } - - meng, err := tapir.NewMqttEngine("keyupload", mqttclientid, tapir.TapirPub, statusch, log.Default()) // pub, no sub - if err != nil { - fmt.Printf("Error from NewMqttEngine: %v\n", err) - os.Exit(1) - } - - // Start of Selection - if pubkeyfile == "" { - fmt.Println("Error: Public key file not specified") - os.Exit(1) - } - - pubkeyfile = filepath.Clean(pubkeyfile) - pubkeyData, err := os.ReadFile(pubkeyfile) - if err != nil { - fmt.Printf("Error reading public key file %s: %v\n", pubkeyfile, err) - os.Exit(1) - } - - if tapir.GlobalCF.Debug { - fmt.Printf("Public key loaded from %s\n", pubkeyfile) - fmt.Printf("Public key:\n%s\n", string(pubkeyData)) - } - - data := tapir.TapirPubKey{ - Pubkey: string(pubkeyData), - } - - // Create a new struct to send off - var certChainPEM string - for _, cert := range clientCert.Certificate { - certChainPEM += string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})) - } - - if tapir.GlobalCF.Debug { - fmt.Printf("Client certificate chain:\n%s\n", certChainPEM) - } - - // Sign the data using the client certificate's private key and include the cert chain and key ID in the JWS header - headers := jws.NewHeaders() - headers.Set(jws.X509CertChainKey, clientCert.Certificate) - - // Compute key ID as SHA-256 hash of the client certificate - certBytes := clientCert.Leaf.Raw - hash := sha256.Sum256(certBytes) - kid := fmt.Sprintf("%x", hash) - headers.Set(jws.KeyIDKey, kid) - - // Fix the arguments to jws.Sign - jwsMessage, err := jws.Sign([]byte(data.Pubkey), jws.WithKey(jwa.RS256, clientCert.PrivateKey), jws.WithHeaders(headers)) - if err != nil { - fmt.Printf("Error signing data: %v\n", err) - os.Exit(1) - } - - fmt.Printf("JWS Key ID: %s\n", kid) - fmt.Printf("JWS Message: %s\n", string(jwsMessage)) - - msg := tapir.PubKeyUpload{ - JWSMessage: string(jwsMessage), - ClientCertPEM: certChainPEM, - } - - // mqtttopic = viper.GetString("tapir.keyupload.topic") - mqtttopic, err := tapir.MqttTopic(certCN, "tapir.keyupload.topic") - if err != nil { - fmt.Println("Error: tapir.keyupload.topic not specified in config") - os.Exit(1) - } - fmt.Printf("Using DNS TAPIR keyupload MQTT topic: %s\n", mqtttopic) - // signkey, err := tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.config.signingkey")) - // if err != nil { - // fmt.Printf("Error fetching MQTT signing key: %v", err) - // os.Exit(1) - // } - meng.PubToTopic(mqtttopic, nil, "struct", false) // XXX: Brr. kludge. - - cmnder, outbox, _, err := meng.StartEngine() - if err != nil { - fmt.Printf("Error from StartEngine(): %v\n", err) - os.Exit(1) - } - - SetupInterruptHandler(cmnder) - - srcname := "foobar" // XXX: Kludge. Should be the EdgeId from the client certificate. - if srcname == "" { - fmt.Println("Error: tapir.config.srcname not specified in config") - os.Exit(1) - } - - outbox <- tapir.MqttPkgOut{ - Type: "raw", - Topic: mqtttopic, - RawData: msg, - } - - fmt.Println("[Waiting 1000 ms to ensure message has been sent]") - // Here we need to hang around for a while to ensure that the message has time to be sent. - time.Sleep(1000 * time.Millisecond) - fmt.Printf("Hopefully the public key upload message has been sent.\n") - }, -} - -func init() { - rootCmd.AddCommand(KeyUploadCmd) - - KeyUploadCmd.Flags().StringVarP(&pubkeyfile, "pubkey", "P", "", "Name of file containing public key to upload") -} diff --git a/cmd/mqtt.go b/cmd/mqtt.go deleted file mode 100644 index 5bdfc41..0000000 --- a/cmd/mqtt.go +++ /dev/null @@ -1,1053 +0,0 @@ -/* - * Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ - -package cmd - -import ( - "bufio" - "bytes" - "crypto/ecdsa" - "encoding/json" - "net/http" - "path/filepath" - "regexp" - - "fmt" - "io" - "log" - "os" - "os/signal" - "strings" - "sync" - "syscall" - "time" - - "github.com/google/uuid" - - "github.com/dnstapir/tapir" - "github.com/miekg/dns" - "github.com/ryanuber/columnize" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "gopkg.in/yaml.v3" -) - -var mqttclientid, mqtttopic, defaulttopic, mqttgreylist, gcfgfile string - -var mqttfid string -var mqttpub, mqttsub, mqttretain, mqttconfigclear bool - -var mqttCmd = &cobra.Command{ - Use: "mqtt", - Short: "Prefix command, not usable directly", - Long: `Prefix command, not usable directly.`, -} - -var mqttEngineCmd = &cobra.Command{ - Use: "engine", - Short: "Start an MQTT engine that can publish and subscribe to topics", - Long: `Start an MQTT engine that can publish and subscribe to topics. -The engine can be configured to publish to and subscribe from the tapir config, observations and status topics.`, - Run: func(cmd *cobra.Command, args []string) { - var wg sync.WaitGroup - - var statusch = make(chan tapir.ComponentStatusUpdate, 10) - - // If any status updates arrive, print them out - go func() { - for status := range statusch { - fmt.Printf("Status update: %+v\n", status) - } - }() - - certCN, _, _, err := tapir.FetchTapirClientCert(log.Default(), statusch) - if err != nil { - fmt.Printf("Error fetching client certificate: %v", err) - os.Exit(1) - } - - var pubsub uint8 - if mqttpub { - pubsub = pubsub | tapir.TapirPub - } - if mqttsub { - pubsub = pubsub | tapir.TapirSub - } - - meng, err := tapir.NewMqttEngine("engine", mqttclientid, pubsub, statusch, log.Default()) - if err != nil { - fmt.Printf("Error from NewMqttEngine: %v\n", err) - os.Exit(1) - } - - var canPub = true - var canSub = true - var signkey *ecdsa.PrivateKey - var valkey *ecdsa.PublicKey - - var sign, validate bool - - switch mqtttopic { - case "config": - mqtttopic, err = tapir.MqttTopic(certCN, "tapir.config.topic") - if err != nil { - fmt.Printf("Error getting MQTT topic: %v\n", err) - os.Exit(1) - } - signkey, err = tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.config.signingkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.config.signingkey")) - canPub = false - } else { - sign = true - } - valkey, err = tapir.FetchMqttValidatorKey(mqtttopic, viper.GetString("tapir.config.validatorkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.config.validatorkey")) - canSub = false - } else { - validate = true - } - - case "observations": - mqtttopic, err = tapir.MqttTopic(certCN, "tapir.observations.topic") - if err != nil { - fmt.Printf("Error getting MQTT topic: %v\n", err) - os.Exit(1) - } - signkey, err = tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.observations.signingkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.observations.signingkey")) - canPub = false - } else { - sign = true - } - valkey, err = tapir.FetchMqttValidatorKey(mqtttopic, viper.GetString("tapir.observations.validatorkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.observations.validatorkey")) - canSub = false - } else { - validate = true - } - - case "status": - mqtttopic, err = tapir.MqttTopic(certCN, "tapir.status.topic") - if err != nil { - fmt.Printf("Error getting MQTT topic: %v\n", err) - os.Exit(1) - } - signkey, err = tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.status.signingkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.status.signingkey")) - canPub = false - } else { - sign = true - } - valkey, err = tapir.FetchMqttValidatorKey(mqtttopic, viper.GetString("tapir.status.validatorkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.status.validatorkey")) - canSub = false - } else { - validate = true - } - - case "keyupload": - mqtttopic, err = tapir.MqttTopic(certCN, "tapir.keyupload.topic") - if err != nil { - fmt.Printf("Error getting MQTT topic: %v\n", err) - os.Exit(1) - } - canPub = false - canSub = true - validate = false - // signkey, err = tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.status.signingkey")) - // if err != nil { - // fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.status.signingkey")) - // canPub = false - // } - // valkey, err = tapir.FetchMqttValidatorKey(mqtttopic, viper.GetString("tapir.status.validatorkey")) - // if err != nil { - // fmt.Printf("Error fetching MQTT signing key: %s\n", viper.GetString("tapir.status.validatorkey")) - // canSub = false - // } - - default: - log.Fatalf("Invalid MQTT topic: %s (must be config or observations)", mqtttopic) - } - - if canPub { - fmt.Printf("Adding pub topic: %s\n", mqtttopic) - // meng.AddTopic(mqtttopic, signkey, valkey) - meng.PubToTopic(mqtttopic, signkey, "struct", sign) // XXX: Brr. kludge. - } - - var subch chan tapir.MqttPkgIn - - if canSub { - fmt.Printf("Adding sub topic: %s\n", mqtttopic) - subch = make(chan tapir.MqttPkgIn, 10) - _, err = meng.SubToTopic(mqtttopic, valkey, subch, "struct", validate) // XXX: Brr. kludge. - if err != nil { - fmt.Printf("Error from SubToTopic: %v\n", err) - os.Exit(1) - } - } - - // cmnder, outbox, inbox, err := meng.StartEngine() - cmnder, outbox, _, err := meng.StartEngine() - if err != nil { - log.Fatalf("Error from StartEngine(): %v", err) - } - - stdin := bufio.NewReader(os.Stdin) - count := 0 - buf := new(bytes.Buffer) - - SetupInterruptHandler(cmnder) - - fmt.Printf("subch: %+v\n", subch) - - if mqttsub { - wg.Add(1) - go SetupSubPrinter(subch) - } - - srcname := viper.GetString("tapir.observations.srcname") - if srcname == "" { - fmt.Printf("Error: tapir.observations.srcname not specified in config") - os.Exit(1) - } - - if mqttpub { - for { - count++ - msg, err := stdin.ReadString('\n') - if err == io.EOF { - os.Exit(0) - } - fmt.Printf("Read: %s", msg) - msg = tapir.Chomp(msg) - if len(msg) == 0 { - fmt.Printf("Empty message ignored.\n") - continue - } - if strings.ToUpper(msg) == "QUIT" { - wg.Done() - break - } - - buf.Reset() - outbox <- tapir.MqttPkgOut{ - Type: "data", - Data: tapir.TapirMsg{ - Msg: msg, - SrcName: srcname, - TimeStamp: time.Now(), - }, - } - } - respch := make(chan tapir.MqttEngineResponse, 2) - meng.CmdChan <- tapir.MqttEngineCmd{Cmd: "stop", Resp: respch} - // var r tapir.MqttEngineResponse - r := <-respch - fmt.Printf("Response from MQTT Engine: %v\n", r) - } - wg.Wait() - }, -} - -var mqttTapirCmd = &cobra.Command{ - Use: "tapir", - Short: "Prefix command only usable via sub-commands", -} - -type ConfigFoo struct { - GlobalConfig tapir.GlobalConfig -} - -var mqttTapirConfigCmd = &cobra.Command{ - Use: "config", - Short: "Send TAPIR-POP global config in TapirMsg form to the tapir config MQTT topic", - Long: `Send TAPIR-POP global config in TapirMsg form to the tapir config MQTT topic. - The -F option is required and specifies the file containing the global config in YAML format. - If -R is specified, will send a retained message, otherwise will send a normal message. - If -C is specified, will clear the retained config message, otherwise will send the new config.`, - Run: func(cmd *cobra.Command, args []string) { - - var statusch = make(chan tapir.ComponentStatusUpdate, 10) - - // If any status updates arrive, print them out - go func() { - for status := range statusch { - fmt.Printf("Status update: %+v\n", status) - } - }() - - certCN, _, _, err := tapir.FetchTapirClientCert(log.Default(), statusch) - if err != nil { - fmt.Printf("Error fetching client certificate: %v", err) - os.Exit(1) - } - - meng, err := tapir.NewMqttEngine("config", mqttclientid, tapir.TapirPub, statusch, log.Default()) // pub, no sub - if err != nil { - fmt.Printf("Error from NewMqttEngine: %v\n", err) - os.Exit(1) - } - - if gcfgfile == "" { - fmt.Println("Error: Global config file not specified") - os.Exit(1) - } - - gcfgfile = filepath.Clean(gcfgfile) - gcfgData, err := os.ReadFile(gcfgfile) - if err != nil { - fmt.Printf("Error reading configuration file %s: %v\n", gcfgfile, err) - os.Exit(1) - } - - var cf ConfigFoo - err = yaml.Unmarshal(gcfgData, &cf) - if err != nil { - fmt.Printf("Error unmarshalling YAML data from file %s: %v\n", gcfgfile, err) - os.Exit(1) - } - - fmt.Printf("Global configuration loaded from %s\n", gcfgfile) - pretty, err := yaml.Marshal(cf.GlobalConfig) - if err != nil { - fmt.Printf("Error marshalling YAML data: %v\n", err) - os.Exit(1) - } - fmt.Printf("Global configuration:\n%s\n", string(pretty)) - - mqtttopic, err := tapir.MqttTopic(certCN, "tapir.config.topic") - if err != nil { - fmt.Println("Error: tapir.config.topic not specified in config") - os.Exit(1) - } - fmt.Printf("Using DNS TAPIR config MQTT topic: %s\n", mqtttopic) - signkey, err := tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.config.signingkey")) - if err != nil { - fmt.Printf("Error fetching MQTT signing key: %v", err) - os.Exit(1) - } - meng.PubToTopic(mqtttopic, signkey, "struct", true) // XXX: Brr. kludge. - - cmnder, outbox, _, err := meng.StartEngine() - if err != nil { - fmt.Printf("Error from StartEngine(): %v\n", err) - os.Exit(1) - } - - SetupInterruptHandler(cmnder) - - srcname := viper.GetString("tapir.config.srcname") - if srcname == "" { - fmt.Println("Error: tapir.config.srcname not specified in config") - os.Exit(1) - } - - // var tmsg = tapir.TapirMsg{ - // SrcName: srcname, - // Creator: "tapir-cli", - // MsgType: "global-config", - // GlobalConfig: cf.GlobalConfig, - // TimeStamp: time.Now(), - // } - if mqttconfigclear { - // tmsg.Msg = "" - outbox <- tapir.MqttPkgOut{ - Type: "raw", - Topic: mqtttopic, - Retain: true, - RawData: "", - } - } else { - outbox <- tapir.MqttPkgOut{ - Type: "raw", - Topic: mqtttopic, - Retain: mqttretain, - RawData: cf.GlobalConfig, - } - } - - fmt.Println("[Waiting 1000 ms to ensure message has been sent]") - // Here we need to hang around for a while to ensure that the message has time to be sent. - time.Sleep(1000 * time.Millisecond) - fmt.Printf("Hopefully the config message has been sent.\n") - }, -} - -var mqttTapirObservationsCmd = &cobra.Command{ - Use: "observations", - Short: "Interactively create and send observations to the tapir intel MQTT topic (debug tool)", - Long: `Will query for operation (add|del|show|send|set-ttl|list-tags|quit), domain name and tags. -Will end the loop on the operation (or domain name) "QUIT"`, - Run: func(cmd *cobra.Command, args []string) { - - var statusch = make(chan tapir.ComponentStatusUpdate, 10) - - // If any status updates arrive, print them out - go func() { - for status := range statusch { - fmt.Printf("Status update: %+v\n", status) - } - }() - - certCN, _, _, err := tapir.FetchTapirClientCert(log.Default(), statusch) - if err != nil { - fmt.Printf("Error fetching client certificate: %v", err) - os.Exit(1) - } - - meng, err := tapir.NewMqttEngine("observations", mqttclientid, tapir.TapirPub, statusch, log.Default()) // pub, no sub - if err != nil { - fmt.Printf("Error from NewMqttEngine: %v\n", err) - os.Exit(1) - } - - mqtttopic, err := tapir.MqttTopic(certCN, "tapir.observations.topic") - if err != nil { - fmt.Println("Error: tapir.observations.topic not specified in config") - os.Exit(1) - } - fmt.Printf("Using DNS TAPIR observation MQTT topic: %s\n", mqtttopic) - - signkey, err := tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.observations.signingkey")) - if err != nil { - log.Fatalf("Error fetching MQTT signing key: %v", err) - } - // meng.AddTopic(mqtttopic, signkey, nil) - meng.PubToTopic(mqtttopic, signkey, "struct", true) // XXX: Brr. kludge. - - cmnder, outbox, _, err := meng.StartEngine() - if err != nil { - log.Fatalf("Error from StartEngine(): %v", err) - } - - count := 0 - - SetupInterruptHandler(cmnder) - - srcname := viper.GetString("tapir.observations.srcname") - if srcname == "" { - fmt.Println("Error: tapir.observations.srcname not specified in config") - os.Exit(1) - } - - var op, names, tags string - var tmsg = tapir.TapirMsg{ - SrcName: srcname, - Creator: "tapir-cli", - MsgType: "observation", - ListType: "greylist", - TimeStamp: time.Now(), - } - - var snames []string - var tagmask tapir.TagMask - - var ops = []string{"add", "del", "show", "send", "set-ttl", "list-tags", "quit"} - fmt.Printf("Defined operations are: %v\n", ops) - - var tds []tapir.Domain - // var ttl time.Duration = 60 * time.Second - var ttl int = 60 - - cmdloop: - for { - count++ - op = tapir.TtyRadioButtonQ("Operation", "add", ops) - switch op { - case "quit": - fmt.Println("QUIT cmd recieved.") - break cmdloop - - case "set-ttl": - ttl = tapir.TtyIntQuestion("TTL (in seconds)", 60, false) - // fmt.Printf("TTL: got: %d\n", tmp) - // ttl = time.Duration(tmp) * time.Second - // fmt.Printf("TTL: got: %d ttl: %v\n", tmp, ttl) - case "add", "del": - names = tapir.TtyQuestion("Domain names", names, false) - snames = strings.Fields(names) - if len(snames) > 0 && strings.ToUpper(snames[0]) == "QUIT" { - break cmdloop - } - - if op == "add" { - retry: - for { - tags = tapir.TtyQuestion("Tags", tags, false) - tagmask, err = tapir.StringsToTagMask(strings.Fields(tags)) - if err != nil { - fmt.Printf("Error from StringsToTagMask: %v\n", err) - fmt.Printf("Defined tags are: %v\n", tapir.DefinedTags) - continue retry - } - break - } - if tapir.GlobalCF.Verbose { - fmt.Printf("TagMask: %032b\n", tagmask) - } - } - for _, name := range snames { - tds = append(tds, tapir.Domain{ - Name: dns.Fqdn(name), - TimeAdded: time.Now(), - TTL: ttl, - TagMask: tagmask, - }) - } - - if op == "add" { - tmsg.Added = append(tmsg.Added, tds...) - tmsg.Msg = "it is greater to give than to take" - } else { - tmsg.Removed = append(tmsg.Removed, tds...) - tmsg.Msg = "happiness is a negative diff" - } - tds = []tapir.Domain{} - - case "show": - var out = []string{"Domain|Tags"} - for _, td := range tmsg.Added { - out = append(out, fmt.Sprintf("ADD: %s|%032b", td.Name, td.TagMask)) - } - for _, td := range tmsg.Removed { - out = append(out, fmt.Sprintf("DEL: %s", td.Name)) - } - fmt.Println(columnize.SimpleFormat(out)) - - case "list-tags": - var out = []string{"Name|Bit"} - var tagmask tapir.TagMask - for _, t := range tapir.DefinedTags { - tagmask, _ = tapir.StringsToTagMask([]string{t}) - out = append(out, fmt.Sprintf("%s|%032b", t, tagmask)) - } - fmt.Println(columnize.SimpleFormat(out)) - - case "send": - if tapir.GlobalCF.Verbose { - fmt.Printf("Sending TAPIR-POP observation message to topic %s\n", mqtttopic) - } - outbox <- tapir.MqttPkgOut{ - Type: "data", - Topic: mqtttopic, - Retain: false, - Data: tmsg, - } - - tmsg = tapir.TapirMsg{ - SrcName: srcname, - Creator: "tapir-cli", - MsgType: "observation", - ListType: "greylist", - TimeStamp: time.Now(), - } - tds = []tapir.Domain{} - } - } - respch := make(chan tapir.MqttEngineResponse, 2) - meng.CmdChan <- tapir.MqttEngineCmd{Cmd: "stop", Resp: respch} - r := <-respch - fmt.Printf("Response from MQTT Engine: %v\n", r) - }, -} - -var mqttTapirStatusCmd = &cobra.Command{ - Use: "status", - Short: "Interactively create and send status updates to the tapir intel MQTT topic (debug tool)", - Long: `Will query for operation (add|del|show|send|set-ttl|list-tags|quit), component name and status. -Will end the loop on the operation (or component name) "QUIT"`, - Run: func(cmd *cobra.Command, args []string) { - - var statusch = make(chan tapir.ComponentStatusUpdate, 10) - - // If any status updates arrive, print them out - go func() { - for status := range statusch { - fmt.Printf("Status update: %+v\n", status) - } - }() - - certCN, _, _, err := tapir.FetchTapirClientCert(log.Default(), statusch) - if err != nil { - fmt.Printf("Error fetching client certificate: %v", err) - os.Exit(1) - } - - meng, err := tapir.NewMqttEngine("status", mqttclientid, tapir.TapirPub, statusch, log.Default()) // pub, no sub - if err != nil { - fmt.Printf("Error from NewMqttEngine: %v\n", err) - os.Exit(1) - } - - mqtttopic, err := tapir.MqttTopic(certCN, "tapir.status.topic") - if err != nil { - fmt.Println("Error: tapir.status.topic not specified in config") - os.Exit(1) - } - fmt.Printf("Using DNS TAPIR status MQTT topic: %s\n", mqtttopic) - - signkey, err := tapir.FetchMqttSigningKey(mqtttopic, viper.GetString("tapir.status.signingkey")) - if err != nil { - log.Fatalf("Error fetching MQTT signing key: %v", err) - } - - meng.PubToTopic(mqtttopic, signkey, "struct", true) // XXX: Brr. kludge. - - cmnder, outbox, _, err := meng.StartEngine() - if err != nil { - log.Fatalf("Error from StartEngine(): %v", err) - } - - count := 0 - - SetupInterruptHandler(cmnder) - - var op, cname, status string - // var tmsg = tapir.TapirMsg{ - // SrcName: "status", - // Creator: "tapir-cli", - // MsgType: "status", - // TimeStamp: time.Now(), - // } - - var ops = []string{"add", "del", "show", "send", "set-ttl", "list-tags", "quit"} - fmt.Printf("Defined operations are: %v\n", ops) - - tfs := tapir.TapirFunctionStatus{ - Function: "tapir-pop", - FunctionID: mqttfid, - ComponentStatus: map[string]tapir.TapirComponentStatus{ - "downstream-notify": { - Component: "downstream-notify", - Status: tapir.StatusFail, - ErrorMsg: "Downstream notify is boiling over", - }, - }, - } - - known_components := []string{"downstream-notify", "main-boot", "rpz-update", "mqtt-msg", "config", "rpz-update"} - - cmdloop: - for { - count++ - op = tapir.TtyRadioButtonQ("Operation", "add", ops) - switch op { - case "quit": - fmt.Println("QUIT cmd recieved.") - break cmdloop - - case "add", "del": - cname = tapir.TtyQuestion("Component name", cname, false) - if len(cname) > 0 && strings.ToUpper(cname) == "QUIT" { - break cmdloop - } - if op == "del" { - delete(tfs.ComponentStatus, cname) - continue - } - - for { - status = tapir.TtyQuestion("Status", status, false) - switch status { - case "ok", "fail", "warn": - break - default: - fmt.Printf("Error: unknown status: %s\n", status) - status = "fail" - continue - } - break - } - - _, exist := tfs.ComponentStatus[cname] - if !exist { - tfs.ComponentStatus[cname] = tapir.TapirComponentStatus{ - Component: cname, - Status: tapir.StatusOK, - ErrorMsg: "", - } - } - comp := tfs.ComponentStatus[cname] - switch status { - case "ok", "fail", "warn": - default: - fmt.Printf("Invalid status: %s\n", status) - os.Exit(1) - } - comp.Status = tapir.StringToStatus[status] - switch comp.Status { - case tapir.StatusFail: - comp.LastFail = time.Now() - comp.NumFails++ - comp.ErrorMsg = tapir.TtyQuestion("Error message", "", false) - case tapir.StatusWarn: - comp.ErrorMsg = tapir.TtyQuestion("Warning message", "", false) - comp.LastWarn = time.Now() - comp.NumWarnings++ - case tapir.StatusOK: - comp.LastSuccess = time.Now() - comp.ErrorMsg = "" - comp.Msg = tapir.TtyQuestion("Message", "", false) - } - tfs.ComponentStatus[cname] = comp - - case "show": - var out = []string{"Component|Status|ErrorMsg|Msg|NumFailures|LastFailure|LastSuccess"} - for cname, comp := range tfs.ComponentStatus { - out = append(out, fmt.Sprintf("%s|%s|%s|%s|%d|%s|%s", cname, tapir.StatusToString[comp.Status], comp.ErrorMsg, comp.Msg, comp.NumFails, - comp.LastFail.Format(tapir.TimeLayout), comp.LastSuccess.Format(tapir.TimeLayout))) - } - fmt.Println(columnize.SimpleFormat(out)) - - case "list-comp": - fmt.Printf("%v\n", known_components) - - case "send": - if tapir.GlobalCF.Verbose { - fmt.Printf("Sending TAPIR-POP status message to topic %s\n", mqtttopic) - } - // tmsg.TapirFunctionStatus = tfs - outbox <- tapir.MqttPkgOut{ - Type: "raw", - Topic: mqtttopic, - RawData: tfs, - } - - // tmsg = tapir.TapirMsg{ - // Creator: "tapir-cli", - // MsgType: "status", - // TimeStamp: time.Now(), - // } - - } - } - respch := make(chan tapir.MqttEngineResponse, 2) - meng.CmdChan <- tapir.MqttEngineCmd{Cmd: "stop", Resp: respch} - r := <-respch - fmt.Printf("Response from MQTT Engine: %v\n", r) - }, -} - -var mqttTapirBootstrapCmd = &cobra.Command{ - Use: "bootstrap", - Short: "MQTT Bootstrap commands", -} - -var mqttTapirBootstrapStatusCmd = &cobra.Command{ - Use: "status", - Short: "Send send greylist-status request to MQTT Bootstrap Server", - Run: func(cmd *cobra.Command, args []string) { - srcs, err := ParseSources() - if err != nil { - log.Fatalf("Error parsing sources: %v", err) - } - - var src *SourceConf - for k, v := range srcs { - // fmt.Printf("Src: %s, Name: %s, Type: %s, Bootstrap: %v\n", k, v.Name, v.Type, v.Bootstrap) - if v.Name == mqttgreylist && v.Source == "mqtt" && v.Type == "greylist" { - src = &v - - PrintBootstrapMqttStatus(k, src) - } - } - - if src == nil { - fmt.Printf("Error: greylist source \"%s\" not found in sources", mqttgreylist) - os.Exit(1) - } - }, -} - -func init() { - debugCmd.AddCommand(mqttCmd) - mqttCmd.AddCommand(mqttEngineCmd, mqttTapirCmd) - mqttTapirCmd.AddCommand(mqttTapirObservationsCmd, mqttTapirConfigCmd, mqttTapirStatusCmd, mqttTapirBootstrapCmd) - mqttTapirBootstrapCmd.AddCommand(mqttTapirBootstrapStatusCmd) - - mqttCmd.PersistentFlags().StringVarP(&mqtttopic, "topic", "t", "", "MQTT topic, default from tapir-cli config") - - mqttclientid = "tapir-cli-" + uuid.New().String() - mqttCmd.PersistentFlags().StringVarP(&mqttclientid, "clientid", "", mqttclientid, "MQTT client id, default is a random string") - mqttEngineCmd.Flags().BoolVarP(&mqttpub, "pub", "", false, "Enable pub support") - mqttEngineCmd.Flags().BoolVarP(&mqttsub, "sub", "", false, "Enable sub support") - mqttTapirConfigCmd.Flags().BoolVarP(&mqttretain, "retain", "R", false, "Publish a retained message") - mqttTapirConfigCmd.Flags().BoolVarP(&mqttconfigclear, "clear", "C", false, "Clear retained config message") - mqttTapirConfigCmd.Flags().StringVarP(&gcfgfile, "cfgfile", "F", "", "Name of file containing global config to send") - mqttTapirBootstrapCmd.PersistentFlags().StringVarP(&mqttgreylist, "greylist", "G", "dns-tapir", "Greylist to inquire about") - - mqttTapirStatusCmd.Flags().StringVarP(&mqttfid, "functionid", "F", "tapir-cli debug tool", "Function ID to send status for") -} - -func PrintBootstrapMqttStatus(name string, src *SourceConf) error { - if len(src.Bootstrap) == 0 { - if len(src.Bootstrap) == 0 { - fmt.Printf("Note: greylist source %s (name \"%s\") has no bootstrap servers\n", name, src.Name) - return fmt.Errorf("no bootstrap servers") - } - } - - // Initialize the API client - api := &tapir.ApiClient{ - BaseUrl: fmt.Sprintf(src.BootstrapUrl, src.Bootstrap[0]), // Must specify a valid BaseUrl - ApiKey: src.BootstrapKey, - AuthMethod: "X-API-Key", - } - - cd := viper.GetString("certs.certdir") - if cd == "" { - log.Fatalf("Error: missing config key: certs.certdir") - } - // cert := cd + "/" + certname - cert := cd + "/" + "tapir-pop" - tlsConfig, err := tapir.NewClientConfig(viper.GetString("certs.cacertfile"), cert+".key", cert+".crt") - if err != nil { - log.Fatalf("BootstrapMqttSource: Error: Could not set up TLS: %v", err) - } - // XXX: Need to verify that the server cert is valid for the bootstrap server - tlsConfig.InsecureSkipVerify = true - err = api.SetupTLS(tlsConfig) - if err != nil { - return fmt.Errorf("error setting up TLS for the API client: %v", err) - } - - // out := []string{"Server|Uptime|Src|Name|MQTT Topic|Msgs|LastMsg"} - out := []string{"Server|Uptime|Src|Name|MQTT Topic|Pub Msgs|LastPub|Sub Msgs|LastSub"} - - // Iterate over the bootstrap servers - for _, server := range src.Bootstrap { - api.BaseUrl = fmt.Sprintf(src.BootstrapUrl, server) - - // Send an API ping command - pr, err := api.SendPing(0, false) - if err != nil { - fmt.Printf("Ping to MQTT bootstrap server %s failed: %v\n", server, err) - continue - } - - uptime := time.Since(pr.BootTime).Round(time.Second) - // fmt.Printf("MQTT bootstrap server %s uptime: %v. It has processed %d MQTT messages", server, uptime, 17) - - status, buf, err := api.RequestNG(http.MethodPost, "/bootstrap", tapir.BootstrapPost{ - Command: "greylist-status", - ListName: src.Name, - Encoding: "json", // XXX: This is our default, but we'll test other encodings later - }, true) - if err != nil { - fmt.Printf("Error from RequestNG: %v\n", err) - continue - } - - if status != http.StatusOK { - fmt.Printf("Bootstrap server %s responded with error: %s (instead of greylist status)\n", server, http.StatusText(status)) - continue - } - - var br tapir.BootstrapResponse - err = json.Unmarshal(buf, &br) - if err != nil { - fmt.Printf("Error decoding greylist-status response from %s: %v. Giving up.\n", server, err) - continue - } - if br.Error { - fmt.Printf("Bootstrap server %s responded with error: %s (instead of greylist status)\n", server, br.ErrorMsg) - } - if tapir.GlobalCF.Verbose && len(br.Msg) != 0 { - fmt.Printf("MQTT Bootstrap server %s responded with message: %s\n", server, br.Msg) - } - - // for topic, v := range br.MsgCounters { - // out = append(out, fmt.Sprintf("%s|%v|%s|%s|%s|%d|%s", server, uptime, name, src.Name, topic, v, br.MsgTimeStamps[topic].Format(time.RFC3339))) - // } - - for topic, topicdata := range br.TopicData { - out = append(out, fmt.Sprintf("%s|%v|%s|%s|%s|%d|%s|%d|%s", server, uptime, name, src.Name, topic, topicdata.PubMsgs, topicdata.LatestPub.Format(time.RFC3339), topicdata.SubMsgs, topicdata.LatestSub.Format(time.RFC3339))) - } - } - - fmt.Println(columnize.SimpleFormat(out)) - - return nil -} - -type SrcFoo struct { - Src struct { - Style string `yaml:"style"` - } `yaml:"src"` - Sources map[string]SourceConf `yaml:"sources"` -} - -type SourceConf struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - Type string `yaml:"type"` - Topic string `yaml:"topic"` - Source string `yaml:"source"` - SrcFormat string `yaml:"src_format"` - Format string `yaml:"format"` - Datasource string `yaml:"datasource"` - Bootstrap []string - BootstrapUrl string - BootstrapKey string -} - -func ParseSources() (map[string]SourceConf, error) { - var srcfoo SrcFoo - configFile := filepath.Clean(tapir.PopSourcesCfgFile) - data, err := os.ReadFile(configFile) - if err != nil { - return nil, fmt.Errorf("error reading config file: %v", err) - } - - err = yaml.Unmarshal(data, &srcfoo) - if err != nil { - return nil, fmt.Errorf("error unmarshalling YAML data: %v", err) - } - - srcs := srcfoo.Sources - // fmt.Printf("*** ParseSourcesNG: there are %d defined sources in config\n", len(srcs)) - return srcs, nil -} - -// func SetupSubPrinter(inbox chan tapir.MqttPkg) { -func SetupSubPrinter(inbox chan tapir.MqttPkgIn) { - fmt.Println("SetupSubPrinter: Starting") - go func() { - for pkg := range inbox { - - fmt.Printf("SetupSubPrinter: Received TAPIR MQTT Message on topic '%s'\n", pkg.Topic) - - switch { - case regexp.MustCompile(`^events/up/[^/]+/observations$`).MatchString(pkg.Topic), - regexp.MustCompile(`^events/down/[^/]+/general$`).MatchString(pkg.Topic): - parts := strings.Split(pkg.Topic, "/") - if len(parts) == 4 { - edgeId := parts[2] - edgeComponent := parts[3] - _ = edgeId // Avoid unused variable error - _ = edgeComponent // Avoid unused variable error - - fmt.Printf("SetupSubPrinter: Received TAPIR MQTT Message on topic '%s':\n%+v\n", pkg.Topic, string(pkg.Payload)) - - var tm tapir.TapirMsg - err := json.Unmarshal(pkg.Payload, &tm) - if err != nil { - fmt.Printf("MQTT: failed to decode json: %v", err) - continue - } - fmt.Printf("Received TAPIR Observation Message on topic %s\n", pkg.Topic) - var out []string - for _, a := range tm.Added { - out = append(out, fmt.Sprintf("ADD: %s|%032b", a.Name, a.TagMask)) - } - for _, a := range tm.Removed { - out = append(out, fmt.Sprintf("DEL: %s", a.Name)) - } - fmt.Println(columnize.SimpleFormat(out)) - } else { - fmt.Printf("Received TAPIR MQTT Message on unknown topic %s\n", pkg.Topic) - } - - case pkg.Topic == "status/up/axfr/tapir-pop": // payload is a tapir.TapirFunctionStatus - var tfs tapir.TapirFunctionStatus - err := json.Unmarshal(pkg.Payload, &tfs) - if err != nil { - fmt.Printf("MQTT: failed to decode json: %v", err) - } - - fmt.Printf("Received TAPIR MQTT Message of type: %s\n", tfs.FunctionID) - for _, comp := range tfs.ComponentStatus { - switch comp.Status { - case tapir.StatusFail: - fmt.Printf("TAPIR-POP %s Component: %s, Status: %s, Message: %s, Time of failure: %s\n", - tfs.FunctionID, comp.Component, tapir.StatusToString[comp.Status], comp.Msg, comp.LastFail.Format(time.RFC3339)) - case tapir.StatusWarn: - fmt.Printf("TAPIR-POP %s: Component: %s, Status: %s, Message: %s, Time of warning: %s\n", - tfs.FunctionID, comp.Component, tapir.StatusToString[comp.Status], comp.Msg, comp.LastWarn.Format(time.RFC3339)) - case tapir.StatusOK: - fmt.Printf("TAPIR-POP %s Component: %s, Status: %s, Message: %s, Time of success: %s\n", - tfs.FunctionID, comp.Component, tapir.StatusToString[comp.Status], comp.Msg, comp.LastSuccess.Format(time.RFC3339)) - } - } - - case strings.HasPrefix(pkg.Topic, "config/down/"): // payload is a tapir.GlobalConfig - var gc tapir.GlobalConfig - err := json.Unmarshal(pkg.Payload, &gc) - if err != nil { - fmt.Printf("MQTT: failed to decode json: %v", err) - } - yamlData, err := yaml.Marshal(gc) - if err != nil { - fmt.Printf("Error marshalling YAML data: %v\n", err) - } - fmt.Printf("Received TAPIR Global config update message:\n%s\n", string(yamlData)) - - case pkg.Topic == "pubkey/up/axfr/tapir-pop", pkg.Topic == "status/up/axfr/tapir-pop": // payload is a tapir.TapirPubkeyUpload - var tpk tapir.PubKeyUpload - err := json.Unmarshal(pkg.Payload, &tpk) - if err != nil { - fmt.Printf("MQTT: failed to decode json: %v", err) - } - yamlData, err := yaml.Marshal(tpk) - if err != nil { - fmt.Printf("Error marshalling YAML data: %v\n", err) - } - fmt.Printf("Received TAPIR PubKeyUpload message:\n%s\n", string(yamlData)) - - default: - fmt.Printf("Received TAPIR MQTT Message of unknown type on topic: %s\n", pkg.Topic) - } - - // case tapir.MqttPkgIn: - // p := pkg.(tapir.MqttPkgIn) - // var out []string - // fmt.Printf("Received TAPIR MQTT Message of type: %s\n", p.Data.MsgType) - // for _, a := range p.Data.Added { - // out = append(out, fmt.Sprintf("ADD: %s|%032b", a.Name, a.TagMask)) - // } - // for _, a := range p.Data.Removed { - // out = append(out, fmt.Sprintf("DEL: %s", a.Name)) - // } - // fmt.Println(columnize.SimpleFormat(out)) - // pretty, err := yaml.Marshal(p.Data) - // if err != nil { - // fmt.Printf("Error marshalling YAML data: %v\n", err) - // os.Exit(1) - // } - // fmt.Printf("Received TAPIR MQTT Message:\n%s\n", string(pretty)) - // } - } - }() -} - -func SetupInterruptHandler(cmnder chan tapir.MqttEngineCmd) { - respch := make(chan tapir.MqttEngineResponse, 2) - - ic := make(chan os.Signal, 1) - signal.Notify(ic, os.Interrupt, syscall.SIGTERM) - go func() { - for { - select { - - case <-ic: - fmt.Println("SIGTERM interrupt received, sending stop signal to MQTT Engine") - cmnder <- tapir.MqttEngineCmd{Cmd: "stop", Resp: respch} - r := <-respch - if r.Error { - fmt.Printf("Error: %s\n", r.ErrorMsg) - } else { - fmt.Printf("MQTT Engine: %s\n", r.Status) - } - os.Exit(1) - } - } - }() -} diff --git a/cmd/ping_cmd.go b/cmd/ping_cmd.go deleted file mode 100644 index a0bcca1..0000000 --- a/cmd/ping_cmd.go +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ - -package cmd - -import ( - "fmt" - "log" - "time" - - "github.com/spf13/cobra" - "github.com/dnstapir/tapir" -) - -var newapi bool - -const timelayout = "2006-01-02 15:04:05" - -var ServerName string = "PLACEHOLDER" - -var PopPingCmd = &cobra.Command{ - Use: "ping", - Short: "Send an API ping request to TAPIR-POP and present the response", - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - log.Fatal("ping must have no arguments") - } - - pr, err := tapir.GlobalCF.Api.SendPing(tapir.GlobalCF.PingCount, false) - if err != nil { - log.Fatalf("Error from SendPing: %v", err) - } - - uptime := time.Now().Sub(pr.BootTime).Round(time.Second) - if tapir.GlobalCF.Verbose { - fmt.Printf("%s from %s @ %s (version %s): pings: %d, pongs: %d, uptime: %v time: %s, client: %s\n", - pr.Msg, pr.Daemon, pr.ServerHost, pr.Version, pr.Pings, - pr.Pongs, uptime, pr.Time.Format(timelayout), pr.Client) - } else { - fmt.Printf("%s: pings: %d, pongs: %d, uptime: %v, time: %s\n", - pr.Msg, pr.Pings, pr.Pongs, uptime, pr.Time.Format(timelayout)) - } - }, -} - -var DaemonApiCmd = &cobra.Command{ - Use: "api", - Short: "request a TAPIR-POP api summary", - Long: `Query TAPIR-POP for the provided API endpoints and print that out in a (hopefully) comprehensible fashion.`, - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - log.Fatal("api must have no arguments") - } - tapir.GlobalCF.Api.ShowApi() - }, -} - -func init() { - rootCmd.AddCommand(DaemonApiCmd) - PopCmd.AddCommand(PopPingCmd) - - PopPingCmd.Flags().IntVarP(&tapir.GlobalCF.PingCount, "count", "c", 0, "#pings to send") - PopPingCmd.Flags().BoolVarP(&newapi, "newapi", "n", false, "use new api client") -} diff --git a/cmd/root.go b/cmd/root.go index 36363cf..d091bcd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,6 +14,7 @@ import ( "github.com/spf13/viper" "github.com/dnstapir/tapir" + "github.com/dnstapir/tapir/cmd" ) var imr string @@ -54,6 +55,10 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&tapir.GlobalCF.Debug, "debug", "d", false, "Debugging output") rootCmd.PersistentFlags().BoolVarP(&tapir.GlobalCF.ShowHdr, "headers", "H", false, "Show column headers") rootCmd.PersistentFlags().BoolVarP(&tapir.GlobalCF.UseTLS, "tls", "", true, "Use a TLS connection to TAPIR-POP") + + rootCmd.AddCommand(cmd.PopCmd) + rootCmd.AddCommand(cmd.DawgCmd) + rootCmd.AddCommand(cmd.ApiCmd) // TODO move into pop command } var validate *validator.Validate @@ -92,7 +97,7 @@ func RootInitConfig() { } else { switch Prog { case "tapir-cli": - certname = "tapir-cli" + tapir.GlobalCF.Certname = "tapir-cli" servername = "tapir-pop" viper.SetConfigFile(tapir.DefaultPopCfgFile) viper.AutomaticEnv() // read in environment variables that match @@ -150,7 +155,7 @@ func RootInitConfig() { if cd == "" { log.Fatalf("Error: missing config key: certs.certdir") } - cert := cd + "/" + certname + cert := cd + "/" + tapir.GlobalCF.Certname tlsConfig, err := tapir.NewClientConfig(viper.GetString("certs.cacertfile"), cert+".key", cert+".crt") if err != nil { diff --git a/cmd/rpz.go b/cmd/rpz.go deleted file mode 100644 index 4aa4bfa..0000000 --- a/cmd/rpz.go +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ - -package cmd - -import ( - "fmt" - "os" - - "github.com/dnstapir/tapir" - "github.com/miekg/dns" - "github.com/spf13/cobra" -) - -var rpzname, rpztype, rpzaction, rpzpolicy string - -var RpzCmd = &cobra.Command{ - Use: "rpz", - Short: "Instruct TAPIR-POP to modify the RPZ zone; must use sub-command", - Long: `Known actions are: -drop send no response at all -nxdomain return an NXDOMAIN response -nodata return a NODATA response`, -} - -var RpzAddCmd = &cobra.Command{ - Use: "add", - Short: "Instruct TAPIR-POP to add a new rule to the RPZ zone", - Run: func(cmd *cobra.Command, args []string) { - if rpzname == "" { - fmt.Printf("Error: domain name for which to add new RPZ rule for not specified.\n") - os.Exit(1) - } - - if rpztype == "" { - fmt.Printf("Error: RPZ list type for domain name \"%s\" not specified.\n", rpzname) - fmt.Printf("Error: must be one of: whitelist, greylist or blacklist.\n") - os.Exit(1) - } - - if rpzpolicy == "" { - fmt.Printf("Error: desired RPZ policy for domain name \"%s\" not specified.\n", rpzname) - os.Exit(1) - } - - // if rpzaction == "" { - // fmt.Printf("Error: desired RPZ action for domain name \"%s\" not specified.\n", rpzname) - // os.Exit(1) - // } - - resp := SendCommandCmd(tapir.CommandPost{ - Command: "rpz-add", - Name: dns.Fqdn(rpzname), - ListType: rpztype, - Action: rpzaction, - Policy: rpzpolicy, - Zone: dns.Fqdn(tapir.GlobalCF.Zone), - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - if resp.Msg != "" { - fmt.Printf("%s\n", resp.Msg) - } - }, -} - -var RpzRemoveCmd = &cobra.Command{ - Use: "remove", - Short: "Instruct TAPIR-POP to remove a rule from the RPZ zone", - Run: func(cmd *cobra.Command, args []string) { - if rpzname == "" { - fmt.Printf("Error: domain name to add rule for not specified.\n") - os.Exit(1) - } - - resp := SendCommandCmd(tapir.CommandPost{ - Command: "rpz-remove", - Name: dns.Fqdn(rpzname), - Zone: dns.Fqdn(tapir.GlobalCF.Zone), - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -var RpzLookupCmd = &cobra.Command{ - Use: "lookup", - Short: "Instruct TAPIR-POP to remove a rule from the RPZ zone", - Run: func(cmd *cobra.Command, args []string) { - if rpzname == "" { - fmt.Printf("Error: domain name look up not specified.\n") - os.Exit(1) - } - - resp := SendCommandCmd(tapir.CommandPost{ - Command: "rpz-lookup", - Name: dns.Fqdn(rpzname), - Zone: dns.Fqdn(tapir.GlobalCF.Zone), - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -var RpzListCmd = &cobra.Command{ - Use: "list", - Short: "Instruct TAPIR-POP to remove a rule from the RPZ zone", - Run: func(cmd *cobra.Command, args []string) { - - resp := SendCommandCmd(tapir.CommandPost{ - Command: "rpz-list-sources", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - }, -} - -func init() { - rootCmd.AddCommand(RpzCmd) - RpzCmd.AddCommand(RpzAddCmd, RpzRemoveCmd, RpzLookupCmd, RpzListCmd) - - RpzAddCmd.Flags().StringVarP(&rpzname, "name", "", "", "Domain name to add rule for") - RpzLookupCmd.Flags().StringVarP(&rpzname, "name", "", "", "Domain name to look up") - RpzAddCmd.Flags().StringVarP(&rpztype, "type", "", "", "One of: whitelist, greylist or blacklist") - RpzAddCmd.Flags().StringVarP(&rpzaction, "action", "", "", "Desired action") - RpzAddCmd.Flags().StringVarP(&rpzpolicy, "policy", "", "", "Desired policy for this domain name") -} diff --git a/cmd/slogger.go b/cmd/slogger.go deleted file mode 100644 index 7543106..0000000 --- a/cmd/slogger.go +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2024 Johan Stenstam, johan.stenstam@internetstiftelsen.se - */ -package cmd - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "os" - "time" - - "github.com/dnstapir/tapir" - "github.com/ryanuber/columnize" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var SloggerCmd = &cobra.Command{ - Use: "slogger", - Short: "Prefix command to TAPIR-Slogger, only usable in TAPIR Core, not in TAPIR Edge", -} - -var SloggerPopCmd = &cobra.Command{ - Use: "pop", - Short: "Prefix command, only usable via sub-commands", -} - -var SloggerEdmCmd = &cobra.Command{ - Use: "edm", - Short: "Prefix command, only usable via sub-commands", -} - -var onlyfails bool - -var SloggerPopStatusCmd = &cobra.Command{ - Use: "status", - Short: "Get the TAPIR-POP status report from TAPIR-Slogger", - Run: func(cmd *cobra.Command, args []string) { - resp := SendSloggerCommand(tapir.SloggerCmdPost{ - Command: "status", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - - if len(resp.PopStatus) == 0 { - fmt.Printf("No Status reports from any TAPIR-POP received\n") - os.Exit(0) - } - - showfails := "" - if onlyfails { - showfails = " (only fails)" - } - - var out []string - for functionid, ps := range resp.PopStatus { - fmt.Printf("Status for TAPIR-POP%s: %s\n", showfails, functionid) - out = []string{"Component|Status|Error msg|NumFailures|LastFailure|LastSuccess"} - for comp, v := range ps.ComponentStatus { - if !onlyfails || v.Status == tapir.StatusFail { - out = append(out, fmt.Sprintf("%s|%s|%s|%d|%s|%s", comp, tapir.StatusToString[v.Status], v.ErrorMsg, v.NumFails, - v.LastFail.Format(tapir.TimeLayout), v.LastSuccess.Format(tapir.TimeLayout))) - } - } - } - - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - }, -} - -var SloggerEdmStatusCmd = &cobra.Command{ - Use: "status", - Short: "Get the TAPIR-EDM status report from TAPIR-Slogger", - Run: func(cmd *cobra.Command, args []string) { - resp := SendSloggerCommand(tapir.SloggerCmdPost{ - Command: "status", - }) - if resp.Error { - fmt.Printf("%s\n", resp.ErrorMsg) - } - - fmt.Printf("%s\n", resp.Msg) - - if len(resp.EdmStatus) == 0 { - fmt.Printf("No Status reports from any TAPIR-EDM received\n") - os.Exit(0) - } - - showfails := "" - if onlyfails { - showfails = " (only fails)" - } - - var out []string - for functionid, ps := range resp.EdmStatus { - fmt.Printf("Status for TAPIR-EDM%s: %s\n", showfails, functionid) - out = []string{"Component|Status|Error msg|NumFailures|LastFailure|LastSuccess"} - for comp, v := range ps.ComponentStatus { - if !onlyfails || v.Status == tapir.StatusFail { - out = append(out, fmt.Sprintf("%s|%s|%s|%d|%s|%s", comp, tapir.StatusToString[v.Status], v.ErrorMsg, v.NumFails, - v.LastFail.Format(tapir.TimeLayout), v.LastSuccess.Format(tapir.TimeLayout))) - } - } - } - - fmt.Printf("%s\n", columnize.SimpleFormat(out)) - }, -} - -var SloggerPingCmd = &cobra.Command{ - Use: "ping", - Short: "Send an API ping request to TAPIR-Slogger and present the response", - Run: func(cmd *cobra.Command, args []string) { - if len(args) != 0 { - log.Fatal("ping must have no arguments") - } - - api, err := SloggerApi() - if err != nil { - log.Fatalf("Error: Could not set up API client to TAPIR-SLOGGER: %v", err) - } - - pr, err := api.SendPing(tapir.GlobalCF.PingCount, false) - if err != nil { - log.Fatalf("Error from SendPing: %v", err) - } - - uptime := time.Now().Sub(pr.BootTime).Round(time.Second) - if tapir.GlobalCF.Verbose { - fmt.Printf("%s from %s @ %s (version %s): pings: %d, pongs: %d, uptime: %v time: %s, client: %s\n", - pr.Msg, pr.Daemon, pr.ServerHost, pr.Version, pr.Pings, - pr.Pongs, uptime, pr.Time.Format(timelayout), pr.Client) - } else { - fmt.Printf("%s: pings: %d, pongs: %d, uptime: %v, time: %s\n", - pr.Msg, pr.Pings, pr.Pongs, uptime, pr.Time.Format(timelayout)) - } - }, -} - -func init() { - rootCmd.AddCommand(SloggerCmd) - SloggerCmd.AddCommand(SloggerPopCmd, SloggerPingCmd, SloggerEdmCmd) - SloggerPopCmd.AddCommand(SloggerPopStatusCmd) - SloggerEdmCmd.AddCommand(SloggerEdmStatusCmd) - - SloggerCmd.PersistentFlags().BoolVarP(&tapir.GlobalCF.ShowHdr, "headers", "H", false, "Show column headers") - SloggerPopStatusCmd.Flags().BoolVarP(&onlyfails, "onlyfails", "f", false, "Show only components that currently fail") - SloggerEdmStatusCmd.Flags().BoolVarP(&onlyfails, "onlyfails", "f", false, "Show only components that currently fail") -} - -func SloggerApi() (*tapir.ApiClient, error) { - servername := "tapir-slogger" - var baseurl, urlkey string - var err error - - switch tapir.GlobalCF.UseTLS { - case true: - urlkey = "cli." + servername + ".tlsurl" - baseurl = viper.GetString(urlkey) - case false: - urlkey = "cli." + servername + ".url" - baseurl = viper.GetString(urlkey) - } - if baseurl == "" { - return nil, fmt.Errorf("Error: missing config key: %s", urlkey) - } - - api = &tapir.ApiClient{ - BaseUrl: baseurl, - ApiKey: viper.GetString("cli." + servername + ".apikey"), - AuthMethod: "X-API-Key", - Debug: tapir.GlobalCF.Debug, - Verbose: tapir.GlobalCF.Verbose, - } - - if tapir.GlobalCF.UseTLS { // default = true - cd := viper.GetString("certs.certdir") - if cd == "" { - return nil, fmt.Errorf("Error: missing config key: certs.certdir") - } - cert := cd + "/" + certname - tlsConfig, err := tapir.NewClientConfig(viper.GetString("certs.cacertfile"), - cert+".key", cert+".crt") - if err != nil { - return nil, fmt.Errorf("Error: Could not set up TLS: %v", err) - } - tlsConfig.InsecureSkipVerify = true - err = api.SetupTLS(tlsConfig) - } else { - err = api.Setup() - } - if err != nil { - return nil, fmt.Errorf("Error: Could not set up API client to TAPIR-SLOGGER at %s: %v", baseurl, err) - } - return api, nil -} - -func SendSloggerCommand(data tapir.SloggerCmdPost) tapir.SloggerCmdResponse { - - api, err := SloggerApi() - if err != nil { - log.Fatalf("Error: Could not set up API client to TAPIR-SLOGGER: %v", err) - } - - _, buf, _ := api.RequestNG(http.MethodPost, "/status", data, true) - - var cr tapir.SloggerCmdResponse - - err = json.Unmarshal(buf, &cr) - if err != nil { - log.Fatalf("Error from json.Unmarshal: %v\n", err) - } - return cr -} From 0ba2079fc81326784250e19f11de2baa5f5830e1 Mon Sep 17 00:00:00 2001 From: Leon Fernandez Date: Thu, 31 Oct 2024 17:16:17 +0100 Subject: [PATCH 2/2] Add colourlists command to cli tool --- cmd/root.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/root.go b/cmd/root.go index d091bcd..dafc05f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -59,6 +59,7 @@ func init() { rootCmd.AddCommand(cmd.PopCmd) rootCmd.AddCommand(cmd.DawgCmd) rootCmd.AddCommand(cmd.ApiCmd) // TODO move into pop command + rootCmd.AddCommand(cmd.ColourlistsCmd) // TODO move into pop command } var validate *validator.Validate