mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-08-10 13:20:33 +02:00
all: initial support for setup linux router
Wiring code to configure router when running ctrld. Future commits will add implementation for each supported platforms.
This commit is contained in:
+22
-7
@@ -18,9 +18,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
|
||||||
|
|
||||||
"github.com/cuonglm/osinfo"
|
"github.com/cuonglm/osinfo"
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/kardianos/service"
|
"github.com/kardianos/service"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
@@ -33,6 +32,7 @@ import (
|
|||||||
"github.com/Control-D-Inc/ctrld"
|
"github.com/Control-D-Inc/ctrld"
|
||||||
"github.com/Control-D-Inc/ctrld/internal/controld"
|
"github.com/Control-D-Inc/ctrld/internal/controld"
|
||||||
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
|
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
|
||||||
|
"github.com/Control-D-Inc/ctrld/internal/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
const selfCheckFQDN = "verify.controld.com"
|
const selfCheckFQDN = "verify.controld.com"
|
||||||
@@ -200,6 +200,18 @@ func initCLI() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "linux" && onRouter {
|
||||||
|
mainLog.Debug().Msg("Router setup")
|
||||||
|
err := router.Configure(&cfg)
|
||||||
|
if errors.Is(err, router.ErrNotSupported) {
|
||||||
|
unsupportedPlatformHelp(cmd)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
mainLog.Fatal().Err(err).Msg("failed to configure router")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
close(waitCh)
|
close(waitCh)
|
||||||
<-stopCh
|
<-stopCh
|
||||||
},
|
},
|
||||||
@@ -218,6 +230,8 @@ func initCLI() {
|
|||||||
_ = runCmd.Flags().MarkHidden("homedir")
|
_ = runCmd.Flags().MarkHidden("homedir")
|
||||||
runCmd.Flags().StringVarP(&iface, "iface", "", "", `Update DNS setting for iface, "auto" means the default interface gateway`)
|
runCmd.Flags().StringVarP(&iface, "iface", "", "", `Update DNS setting for iface, "auto" means the default interface gateway`)
|
||||||
_ = runCmd.Flags().MarkHidden("iface")
|
_ = runCmd.Flags().MarkHidden("iface")
|
||||||
|
runCmd.Flags().BoolVarP(&onRouter, "router", "", false, `Configure onRouter for running ctrld`)
|
||||||
|
_ = runCmd.Flags().MarkHidden("router")
|
||||||
|
|
||||||
rootCmd.AddCommand(runCmd)
|
rootCmd.AddCommand(runCmd)
|
||||||
|
|
||||||
@@ -315,6 +329,8 @@ func initCLI() {
|
|||||||
startCmd.Flags().IntVarP(&cacheSize, "cache_size", "", 0, "Enable cache with size items")
|
startCmd.Flags().IntVarP(&cacheSize, "cache_size", "", 0, "Enable cache with size items")
|
||||||
startCmd.Flags().StringVarP(&cdUID, "cd", "", "", "Control D resolver uid")
|
startCmd.Flags().StringVarP(&cdUID, "cd", "", "", "Control D resolver uid")
|
||||||
startCmd.Flags().StringVarP(&iface, "iface", "", "", `Update DNS setting for iface, "auto" means the default interface gateway`)
|
startCmd.Flags().StringVarP(&iface, "iface", "", "", `Update DNS setting for iface, "auto" means the default interface gateway`)
|
||||||
|
startCmd.Flags().BoolVarP(&onRouter, "router", "", false, `Configure onRouter for running ctrld`)
|
||||||
|
_ = startCmd.Flags().MarkHidden("router")
|
||||||
|
|
||||||
stopCmd := &cobra.Command{
|
stopCmd := &cobra.Command{
|
||||||
PreRun: checkHasElevatedPrivilege,
|
PreRun: checkHasElevatedPrivilege,
|
||||||
@@ -510,11 +526,6 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
|
|||||||
stopCmdAlias.Flags().StringVarP(&ifaceStartStop, "iface", "", "auto", `Reset DNS setting for iface, "auto" means the default interface gateway`)
|
stopCmdAlias.Flags().StringVarP(&ifaceStartStop, "iface", "", "auto", `Reset DNS setting for iface, "auto" means the default interface gateway`)
|
||||||
stopCmdAlias.Flags().AddFlagSet(stopCmd.Flags())
|
stopCmdAlias.Flags().AddFlagSet(stopCmd.Flags())
|
||||||
rootCmd.AddCommand(stopCmdAlias)
|
rootCmd.AddCommand(stopCmdAlias)
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
|
||||||
stderrMsg(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeConfigFile() error {
|
func writeConfigFile() error {
|
||||||
@@ -802,3 +813,7 @@ func selfCheckStatus(status service.Status) service.Status {
|
|||||||
mainLog.Debug().Msgf("self-check against %q failed", selfCheckFQDN)
|
mainLog.Debug().Msgf("self-check against %q failed", selfCheckFQDN)
|
||||||
return service.StatusUnknown
|
return service.StatusUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unsupportedPlatformHelp(cmd *cobra.Command) {
|
||||||
|
cmd.PrintErrln("Unsupported or incorrectly chosen onRouter platform. Please open an issue and provide all relevant information: https://github.com/Control-D-Inc/ctrld/issues/new")
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/Control-D-Inc/ctrld/internal/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initRouterCLI() {
|
||||||
|
validArgs := append(router.SupportedPlatforms(), "auto")
|
||||||
|
var b strings.Builder
|
||||||
|
b.WriteString("Auto-setup Control D on a onRouter.\n\nSupported platforms:\n\n")
|
||||||
|
for _, arg := range validArgs {
|
||||||
|
b.WriteString(" ₒ ")
|
||||||
|
b.WriteString(arg)
|
||||||
|
if arg == "auto" {
|
||||||
|
b.WriteString(" - detect the platform you are running on")
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
routerCmd := &cobra.Command{
|
||||||
|
Use: "setup",
|
||||||
|
Short: b.String(),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
_ = cmd.Help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(args) != 1 {
|
||||||
|
_ = cmd.Help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
platform := args[0]
|
||||||
|
if platform == "auto" {
|
||||||
|
platform = router.Name()
|
||||||
|
}
|
||||||
|
switch platform {
|
||||||
|
case router.DDWrt, router.Merlin, router.OpenWrt, router.Ubios:
|
||||||
|
default:
|
||||||
|
unsupportedPlatformHelp(cmd)
|
||||||
|
}
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdArgs := []string{"start"}
|
||||||
|
cmdArgs = append(cmdArgs, os.Args[3:]...)
|
||||||
|
cmdArgs = append(cmdArgs, "--router=true")
|
||||||
|
command := exec.Command(exe, cmdArgs...)
|
||||||
|
command.Stdout = os.Stdout
|
||||||
|
command.Stderr = os.Stderr
|
||||||
|
command.Stdin = os.Stdin
|
||||||
|
if err := command.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tmpl := routerCmd.UsageTemplate()
|
||||||
|
tmpl = strings.Replace(tmpl, "{{.UseLine}}", "{{.UseLine}} [platform]", 1)
|
||||||
|
routerCmd.SetUsageTemplate(tmpl)
|
||||||
|
rootCmd.AddCommand(routerCmd)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func initRouterCLI() {}
|
||||||
+10
-6
@@ -26,18 +26,22 @@ var (
|
|||||||
cacheSize int
|
cacheSize int
|
||||||
cfg ctrld.Config
|
cfg ctrld.Config
|
||||||
verbose int
|
verbose int
|
||||||
|
cdUID string
|
||||||
|
iface string
|
||||||
|
ifaceStartStop string
|
||||||
|
onRouter bool
|
||||||
|
|
||||||
rootLogger = zerolog.New(io.Discard)
|
mainLog = zerolog.New(io.Discard)
|
||||||
mainLog = rootLogger
|
|
||||||
|
|
||||||
cdUID string
|
|
||||||
iface string
|
|
||||||
ifaceStartStop string
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctrld.InitConfig(v, "ctrld")
|
ctrld.InitConfig(v, "ctrld")
|
||||||
initCLI()
|
initCLI()
|
||||||
|
initRouterCLI()
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
stderrMsg(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeLogFilePath(logFilePath string) string {
|
func normalizeLogFilePath(logFilePath string) string {
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/Control-D-Inc/ctrld"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OpenWrt = "openwrt"
|
||||||
|
DDWrt = "ddwrt"
|
||||||
|
Merlin = "merlin"
|
||||||
|
Ubios = "ubios"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrNotSupported reports the current router is not supported error.
|
||||||
|
var ErrNotSupported = errors.New("unsupported platform")
|
||||||
|
|
||||||
|
var routerAtomic atomic.Pointer[router]
|
||||||
|
|
||||||
|
type router struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedPlatforms return all platforms that can be configured to run with ctrld.
|
||||||
|
func SupportedPlatforms() []string {
|
||||||
|
return []string{DDWrt, Merlin, OpenWrt, Ubios}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure change the given *ctrld.Config for running on the router.
|
||||||
|
func Configure(c *ctrld.Config) error {
|
||||||
|
name := Name()
|
||||||
|
switch name {
|
||||||
|
case DDWrt, Merlin, OpenWrt, Ubios:
|
||||||
|
default:
|
||||||
|
return ErrNotSupported
|
||||||
|
}
|
||||||
|
// TODO: implement all supported platforms.
|
||||||
|
fmt.Printf("Configuring router for: %s\n", name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns name of the router platform.
|
||||||
|
func Name() string {
|
||||||
|
if r := routerAtomic.Load(); r != nil {
|
||||||
|
return r.name
|
||||||
|
}
|
||||||
|
r := &router{}
|
||||||
|
r.name = distroName()
|
||||||
|
routerAtomic.Store(r)
|
||||||
|
return r.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func distroName() string {
|
||||||
|
switch {
|
||||||
|
case bytes.HasPrefix(uname(), []byte("DD-WRT")):
|
||||||
|
return DDWrt
|
||||||
|
case bytes.HasPrefix(uname(), []byte("ASUSWRT-Merlin")):
|
||||||
|
return Merlin
|
||||||
|
case haveFile("/etc/openwrt_version"):
|
||||||
|
return OpenWrt
|
||||||
|
case haveDir("/data/unifi"):
|
||||||
|
return Ubios
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func haveFile(file string) bool {
|
||||||
|
_, err := os.Stat(file)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func haveDir(dir string) bool {
|
||||||
|
fi, _ := os.Stat(dir)
|
||||||
|
return fi != nil && fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func uname() []byte {
|
||||||
|
out, _ := exec.Command("uname", "-o").Output()
|
||||||
|
return out
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user