First basic version

- NFT and DNS Update skeletons
- Integrated viper configuration management
- Integrated cobra CLI management
- Basic webservice skeleton
This commit is contained in:
2021-08-15 21:37:11 +02:00
parent 34d02ba590
commit 7dd11a0879
17 changed files with 1171 additions and 1 deletions

30
cmd/config.go Normal file
View File

@ -0,0 +1,30 @@
package cmd
import (
"fmt"
"log"
"gitea.nehmer.net/torben/dyndns/service"
"gitea.nehmer.net/torben/dyndns/webapi"
"github.com/spf13/viper"
)
func InitializeViper() {
viper.SetConfigName("conf.yml")
viper.SetConfigType("yaml")
viper.AddConfigPath("/etc/dyndns")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
log.Println("Could not find configfile, using defaults")
} else {
log.Fatalln(fmt.Sprintf("configuration is invalid: %s", err))
}
}
}
func setAllConfigDefaults() {
service.SetConfigDefaults()
webapi.SetConfigDefaults()
}

39
cmd/dns-update.go Normal file
View File

@ -0,0 +1,39 @@
package cmd
import (
"log"
"gitea.nehmer.net/torben/dyndns/service"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cmdDNSUpdate = &cobra.Command{
Use: "dns-update",
Short: "Dynamically update a DNS record",
Long: `Dynamically updates a given DNS FQDN based on the given v4 and/or v6 addresses.
At least one IP must be specified, the call fails if both IPs are empty.`,
// Run is defined inline in init to capture Flag variables in the closure
}
func init() {
rootCmd.AddCommand(cmdDNSUpdate)
ip4 := cmdDNSUpdate.Flags().IPP("ipv4", "4", nil, "IPv4 Address to set")
ip6 := cmdDNSUpdate.Flags().IPP("ipv6", "6", nil, "IPv6 Address to set")
name := cmdDNSUpdate.Flags().StringP("name", "n", "", "Hostname to set within the domain")
cmdDNSUpdate.MarkFlagRequired("name")
domain := cmdDNSUpdate.Flags().StringP("domain", "d", "", "Domain to set the records in.")
cmdDNSUpdate.MarkFlagRequired("domain")
cmdDNSUpdate.Run = func(cmd *cobra.Command, args []string) {
log.Printf("Configuration in use: %v", viper.AllSettings())
service.LoadConfig()
err := service.UpdateDNSEntry(*domain, *name, *ip4, *ip6)
if err != nil {
log.Fatalf("Could not update DNS: %s", err)
}
log.Println("DNS has been successfully updated.")
}
}

40
cmd/nft-update.go Normal file
View File

@ -0,0 +1,40 @@
package cmd
import (
"log"
"gitea.nehmer.net/torben/dyndns/service"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cmdNFTUpdate = &cobra.Command{
Use: "nft-update",
Short: "Dynamically update a NFT firewall",
Long: `Dynamically updates the given NFT Firewall sets based on the given v4 and/or v6 addresses.
At least one IP must be specified, the call fails if both IPs are empty.
The call will flush the sets given in the table before adding the IPs.`,
// Run is defined inline in init to capture Flag variables in the closure
}
func init() {
rootCmd.AddCommand(cmdNFTUpdate)
ip4 := cmdNFTUpdate.Flags().IPP("ipv4", "4", nil, "IPv4 Address to add to the set")
ip6 := cmdNFTUpdate.Flags().IPP("ipv6", "6", nil, "IPv6 Address to add to the set")
table := cmdNFTUpdate.Flags().StringP("table", "t", "", "The name of the NFT table to modifiy")
cmdNFTUpdate.MarkFlagRequired("table")
set4 := cmdNFTUpdate.Flags().StringP("set4", "s", "", "The IPv4 NFT set name in the given table.")
set6 := cmdNFTUpdate.Flags().StringP("set6", "r", "", "The IPv6 NFT Set name in the given table.")
cmdNFTUpdate.Run = func(cmd *cobra.Command, args []string) {
log.Printf("Configuration in use: %v", viper.AllSettings())
service.LoadConfig()
err := service.UpdateNFTSets(*table, *set4, *ip4, *set6, *ip6)
if err != nil {
log.Fatalf("Could not update NFT: %s", err)
}
log.Println("NFT has been successfully updated.")
}
}

23
cmd/root.go Normal file
View File

@ -0,0 +1,23 @@
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "dyndns",
Short: "Go DynDNS Server",
Long: `A DynDNS Server implementation in Go, requires both an
NFTable Firewall and a properly configured Bind DNS Server.`,
}
func Exec() {
err := rootCmd.Execute()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}

28
cmd/serve.go Normal file
View File

@ -0,0 +1,28 @@
package cmd
import (
"log"
"gitea.nehmer.net/torben/dyndns/service"
"gitea.nehmer.net/torben/dyndns/webapi"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cmdServe = &cobra.Command{
Use: "server",
Short: "Start webserver",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
log.Printf("Configuration in use: %v", viper.AllSettings())
webapi.LoadConfig()
service.LoadConfig()
webapi.Server()
},
}
func init() {
rootCmd.AddCommand(cmdServe)
cmdServe.Flags().StringP("ListenAddress", "l", "", "ListenAddress for the application server")
viper.BindPFlag("WebAPI.ListenAddress", cmdServe.Flags().Lookup("ListenAddress"))
}

View File

@ -0,0 +1,41 @@
package cmd
import (
"log"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cmdWriteDefaultConfig = &cobra.Command{
Use: "write-default-config",
Short: "Write default config to file",
Long: `Writes the default configuration to a new configuration file, which
can be further customized by you.`,
// Run is defined inline in init to capture Flag variables in the closure
}
func init() {
rootCmd.AddCommand(cmdWriteDefaultConfig)
filename := cmdWriteDefaultConfig.Flags().StringP("filename", "f", "conf-default.yml",
"The config filename to use, defaults to conf-default.yml")
cmdWriteDefaultConfig.Run = func(cmd *cobra.Command, args []string) {
writeDefaultConfig(*filename)
}
}
func writeDefaultConfig(filename string) {
if filepath.Ext(filename) != ".yml" {
log.Fatalln("The default config filename must end in .yml")
}
viper.Reset()
setAllConfigDefaults()
err := viper.WriteConfigAs(filename)
if err != nil {
log.Fatalf("Could not write default configuration file %s: %s", filename, err)
}
log.Printf("Default configuration written as %s", filename)
}