all: implement router setup for openwrt

This commit is contained in:
Cuong Manh Le
2023-03-22 00:18:04 +07:00
committed by Cuong Manh Le
parent 4b6a976747
commit c94be0df35
9 changed files with 237 additions and 29 deletions

View File

@@ -0,0 +1,74 @@
package router
import (
"bytes"
"errors"
"fmt"
"os"
"os/exec"
"strings"
)
var errUCIEntryNotFound = errors.New("uci: Entry not found")
const openwrtDNSMasqConfigPath = "/tmp/dnsmasq.d/ctrld.conf"
const openwrtDNSMasqConfigContent = `# GENERATED BY ctrld - DO NOT MODIFY
port=0
`
func setupOpenWrt() error {
// Delete dnsmasq port if set.
if _, err := uci("delete", "dhcp.@dnsmasq[0].port"); err != nil && !errors.Is(err, errUCIEntryNotFound) {
return err
}
// Disable dnsmasq as DNS server.
if err := os.WriteFile(openwrtDNSMasqConfigPath, []byte(openwrtDNSMasqConfigContent), 0600); err != nil {
return err
}
// Commit.
if _, err := uci("commit"); err != nil {
return err
}
// Restart dnsmasq service.
if err := restartDNSMasq(); err != nil {
return err
}
return nil
}
func cleanupOpenWrt() error {
// Remove the custom dnsmasq config
if err := os.Remove(openwrtDNSMasqConfigPath); err != nil {
return err
}
// Restart dnsmasq service.
if err := restartDNSMasq(); err != nil {
return err
}
return nil
}
func postInstallOpenWrt() error {
return exec.Command("/etc/init.d/ctrld", "enable").Run()
}
func uci(args ...string) (string, error) {
cmd := exec.Command("uci", args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
if strings.HasPrefix(stderr.String(), errUCIEntryNotFound.Error()) {
return "", errUCIEntryNotFound
}
return "", fmt.Errorf("%s:%w", stderr.String(), err)
}
return strings.TrimSpace(stdout.String()), nil
}
func restartDNSMasq() error {
if out, err := exec.Command("/etc/init.d/dnsmasq", "restart").CombinedOutput(); err != nil {
return fmt.Errorf("%s: %w", string(out), err)
}
return nil
}

24
internal/router/procd.go Normal file
View File

@@ -0,0 +1,24 @@
package router
const openWrtScript = `#!/bin/sh /etc/rc.common
USE_PROCD=1
# After network starts
START=21
# Before network stops
STOP=89
cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}"
name="{{.Name}}"
pid_file="/var/run/${name}.pid"
start_service() {
echo "Starting ${name}"
procd_open_instance
procd_set_param command ${cmd}
procd_set_param respawn # respawn automatically if something died
procd_set_param stdout 1 # forward stdout of the command to logd
procd_set_param stderr 1 # same for stderr
procd_set_param pidfile ${pid_file} # write a pid file on instance start and remove it on stop
procd_close_instance
echo "${name} has been started"
}
`

View File

@@ -8,6 +8,8 @@ import (
"os/exec"
"sync/atomic"
"github.com/kardianos/service"
"github.com/Control-D-Inc/ctrld"
)
@@ -21,7 +23,7 @@ const (
// ErrNotSupported reports the current router is not supported error.
var ErrNotSupported = errors.New("unsupported platform")
var routerAtomic atomic.Pointer[router]
var routerPlatform atomic.Pointer[router]
type router struct {
name string
@@ -32,11 +34,13 @@ func SupportedPlatforms() []string {
return []string{DDWrt, Merlin, OpenWrt, Ubios}
}
// Configure change the given *ctrld.Config for running on the router.
// Configure configures things for running ctrld on the router.
func Configure(c *ctrld.Config) error {
name := Name()
switch name {
case DDWrt, Merlin, OpenWrt, Ubios:
case OpenWrt:
return setupOpenWrt()
case DDWrt, Merlin, Ubios:
default:
return ErrNotSupported
}
@@ -45,14 +49,57 @@ func Configure(c *ctrld.Config) error {
return nil
}
// ConfigureService performs necessary setup for running ctrld as a service on router.
func ConfigureService(sc *service.Config) {
name := Name()
switch name {
case OpenWrt:
sc.Option["SysvScript"] = openWrtScript
case DDWrt, Merlin, Ubios:
}
}
// PostInstall performs task after installing ctrld on router.
func PostInstall() error {
name := Name()
switch name {
case OpenWrt:
return postInstallOpenWrt()
case DDWrt, Merlin, Ubios:
}
return nil
}
// Cleanup cleans ctrld setup on the router.
func Cleanup() error {
name := Name()
switch name {
case OpenWrt:
return cleanupOpenWrt()
case DDWrt, Merlin, Ubios:
}
return nil
}
// ListenAddress returns the listener address of ctrld on router.
func ListenAddress() string {
name := Name()
switch name {
case OpenWrt:
return ":53"
case DDWrt, Merlin, Ubios:
}
return ""
}
// Name returns name of the router platform.
func Name() string {
if r := routerAtomic.Load(); r != nil {
if r := routerPlatform.Load(); r != nil {
return r.name
}
r := &router{}
r.name = distroName()
routerAtomic.Store(r)
routerPlatform.Store(r)
return r.name
}