Files
ctrld/internal/router/tomato/tomato.go
T
Cuong Manh Le 7af59ee589 all: rework fetching/generating config in cd mode
Config fetching/generating in cd mode is currently weird, error prone,
and easy for user to break ctrld when using custom config.

This commit reworks the flow:

 - Fetching config from Control D API.
 - No custom config, use the current default config.
 - If custom config presents, but there's no listener, use 0.0.0.0:53.
 - Try listening on current ip+port config, if ok, ctrld could be a
   direct listener with current setup, moving on.
 - If failed, trying 127.0.0.1:53.
 - If failed, trying current ip + port 5354
 - If still failed, pick a random ip:port pair, retry until listening ok.

With this flow, thing is more predictable/stable, and help removing the
Config interface for router.
2023-08-09 23:54:23 +07:00

126 lines
3.0 KiB
Go

package tomato
import (
"fmt"
"os/exec"
"github.com/Control-D-Inc/ctrld"
"github.com/Control-D-Inc/ctrld/internal/router/dnsmasq"
"github.com/Control-D-Inc/ctrld/internal/router/ntp"
"github.com/Control-D-Inc/ctrld/internal/router/nvram"
"github.com/kardianos/service"
)
const (
Name = "freshtomato"
tomatoDnsCryptProxySvcName = "dnscrypt-proxy"
tomatoStubbySvcName = "stubby"
tomatoDNSMasqSvcName = "dnsmasq"
)
var nvramKvMap = map[string]string{
"dnsmasq_custom": "", // Configuration of dnsmasq set by ctrld, filled by setupTomato.
"dnscrypt_proxy": "0", // Disable DNSCrypt.
"dnssec_enable": "0", // Disable DNSSEC.
"stubby_proxy": "0", // Disable Stubby
}
type FreshTomato struct {
cfg *ctrld.Config
}
// New returns a router.Router for configuring/setup/run ctrld on Ubios routers.
func New(cfg *ctrld.Config) *FreshTomato {
return &FreshTomato{cfg: cfg}
}
func (f *FreshTomato) ConfigureService(config *service.Config) error {
return nil
}
func (f *FreshTomato) Install(_ *service.Config) error {
return nil
}
func (f *FreshTomato) Uninstall(_ *service.Config) error {
return nil
}
func (f *FreshTomato) PreRun() error {
_ = f.Cleanup()
return ntp.Wait()
}
func (f *FreshTomato) Setup() error {
// Already setup.
if val, _ := nvram.Run("get", nvram.CtrldSetupKey); val == "1" {
return nil
}
data, err := dnsmasq.ConfTmpl(dnsmasq.ConfigContentTmpl, f.cfg)
if err != nil {
return err
}
nvramKvMap["dnsmasq_custom"] = data
if err := nvram.SetKV(nvramKvMap, nvram.CtrldSetupKey); err != nil {
return err
}
// Restart dnscrypt-proxy service.
if err := tomatoRestartServiceWithKill(tomatoDnsCryptProxySvcName, true); err != nil {
return err
}
// Restart stubby service.
if err := tomatoRestartService(tomatoStubbySvcName); err != nil {
return err
}
// Restart dnsmasq service.
if err := restartDNSMasq(); err != nil {
return err
}
return nil
}
func (f *FreshTomato) Cleanup() error {
if val, _ := nvram.Run("get", nvram.CtrldSetupKey); val == "1" {
nvramKvMap["dnsmasq_custom"] = ""
// Restore old configs.
if err := nvram.Restore(nvramKvMap, nvram.CtrldSetupKey); err != nil {
return err
}
}
// Restart dnscrypt-proxy service.
if err := tomatoRestartServiceWithKill(tomatoDnsCryptProxySvcName, true); err != nil {
return err
}
// Restart stubby service.
if err := tomatoRestartService(tomatoStubbySvcName); err != nil {
return err
}
// Restart dnsmasq service.
if err := restartDNSMasq(); err != nil {
return err
}
return nil
}
func tomatoRestartService(name string) error {
return tomatoRestartServiceWithKill(name, false)
}
func tomatoRestartServiceWithKill(name string, killBeforeRestart bool) error {
if killBeforeRestart {
_, _ = exec.Command("killall", name).CombinedOutput()
}
if out, err := exec.Command("service", name, "restart").CombinedOutput(); err != nil {
return fmt.Errorf("service restart %s: %s, %w", name, string(out), err)
}
return nil
}
func restartDNSMasq() error {
return tomatoRestartService(tomatoDNSMasqSvcName)
}