mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-02-03 22:18:39 +00:00
internal/router: support openwrt 24.10
openwrt 24.10 changes the dnsmasq default config path, causing breaking changes to softwares which depends on old behavior. This commit adds a workaround for the issue, by querying the actual config directory from ubus service list, instead of relying on the default hardcode one.
This commit is contained in:
committed by
Cuong Manh Le
parent
043a28eb33
commit
8ccaeeab60
@@ -2,10 +2,13 @@ package openwrt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/kardianos/service"
|
||||
@@ -15,10 +18,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Name = "openwrt"
|
||||
openwrtDNSMasqConfigPath = "/tmp/dnsmasq.d/ctrld.conf"
|
||||
Name = "openwrt"
|
||||
openwrtDNSMasqConfigName = "ctrld.conf"
|
||||
openwrtDNSMasqDefaultConfigDir = "/tmp/dnsmasq.d"
|
||||
)
|
||||
|
||||
var openwrtDnsmasqDefaultConfigPath = filepath.Join(openwrtDNSMasqDefaultConfigDir, openwrtDNSMasqConfigName)
|
||||
|
||||
type Openwrt struct {
|
||||
cfg *ctrld.Config
|
||||
dnsmasqCacheSize string
|
||||
@@ -67,7 +73,7 @@ func (o *Openwrt) Setup() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(openwrtDNSMasqConfigPath, []byte(data), 0600); err != nil {
|
||||
if err := os.WriteFile(dnsmasqConfPathFromUbus(), []byte(data), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
// Restart dnsmasq service.
|
||||
@@ -82,7 +88,7 @@ func (o *Openwrt) Cleanup() error {
|
||||
return nil
|
||||
}
|
||||
// Remove the custom dnsmasq config
|
||||
if err := os.Remove(openwrtDNSMasqConfigPath); err != nil {
|
||||
if err := os.Remove(dnsmasqConfPathFromUbus()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -126,3 +132,60 @@ func uci(args ...string) (string, error) {
|
||||
}
|
||||
return strings.TrimSpace(stdout.String()), nil
|
||||
}
|
||||
|
||||
// openwrtServiceList represents openwrt services config.
|
||||
type openwrtServiceList struct {
|
||||
Dnsmasq dnsmasqConf `json:"dnsmasq"`
|
||||
}
|
||||
|
||||
// dnsmasqConf represents dnsmasq config.
|
||||
type dnsmasqConf struct {
|
||||
Instances map[string]confInstances `json:"instances"`
|
||||
}
|
||||
|
||||
// confInstances represents an instance config of a service.
|
||||
type confInstances struct {
|
||||
Mount map[string]string `json:"mount"`
|
||||
}
|
||||
|
||||
// dnsmasqConfPath returns the dnsmasq config path.
|
||||
//
|
||||
// Since version 24.10, openwrt makes some changes to dnsmasq to support
|
||||
// multiple instances of dnsmasq. This change causes breaking changes to
|
||||
// software which depends on the default dnsmasq path.
|
||||
//
|
||||
// There are some discussion/PRs in openwrt repo to address this:
|
||||
//
|
||||
// - https://github.com/openwrt/openwrt/pull/16806
|
||||
// - https://github.com/openwrt/openwrt/pull/16890
|
||||
//
|
||||
// In the meantime, workaround this problem by querying the actual config path
|
||||
// by querying ubus service list.
|
||||
func dnsmasqConfPath(r io.Reader) string {
|
||||
var svc openwrtServiceList
|
||||
if err := json.NewDecoder(r).Decode(&svc); err != nil {
|
||||
return openwrtDnsmasqDefaultConfigPath
|
||||
}
|
||||
for _, inst := range svc.Dnsmasq.Instances {
|
||||
for mount := range inst.Mount {
|
||||
dirName := filepath.Base(mount)
|
||||
parts := strings.Split(dirName, ".")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
if parts[0] == "dnsmasq" && parts[len(parts)-1] == "d" {
|
||||
return filepath.Join(mount, openwrtDNSMasqConfigName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return openwrtDnsmasqDefaultConfigPath
|
||||
}
|
||||
|
||||
// dnsmasqConfPathFromUbus get dnsmasq config path from ubus service list.
|
||||
func dnsmasqConfPathFromUbus() string {
|
||||
output, err := exec.Command("ubus", "call", "service", "list").Output()
|
||||
if err != nil {
|
||||
return openwrtDnsmasqDefaultConfigPath
|
||||
}
|
||||
return dnsmasqConfPath(bytes.NewReader(output))
|
||||
}
|
||||
|
||||
58
internal/router/openwrt/openwrt_test.go
Normal file
58
internal/router/openwrt/openwrt_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package openwrt
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Sample output from https://github.com/openwrt/openwrt/pull/16806#issuecomment-2448255734
|
||||
const ubusDnsmasqBefore2410 = `{
|
||||
"dnsmasq": {
|
||||
"instances": {
|
||||
"guest_dns": {
|
||||
"mount": {
|
||||
"/tmp/dnsmasq.d": "0",
|
||||
"/var/run/dnsmasq/": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const ubusDnsmasq2410 = `{
|
||||
"dnsmasq": {
|
||||
"instances": {
|
||||
"guest_dns": {
|
||||
"mount": {
|
||||
"/tmp/dnsmasq.guest_dns.d": "0",
|
||||
"/var/run/dnsmasq/": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
func Test_dnsmasqConfPath(t *testing.T) {
|
||||
var dnsmasq2410expected = filepath.Join("/tmp/dnsmasq.guest_dns.d", openwrtDNSMasqConfigName)
|
||||
tests := []struct {
|
||||
name string
|
||||
in io.Reader
|
||||
expected string
|
||||
}{
|
||||
{"empty", strings.NewReader(""), openwrtDnsmasqDefaultConfigPath},
|
||||
{"invalid", strings.NewReader("}}"), openwrtDnsmasqDefaultConfigPath},
|
||||
{"before 24.10", strings.NewReader(ubusDnsmasqBefore2410), openwrtDnsmasqDefaultConfigPath},
|
||||
{"24.10", strings.NewReader(ubusDnsmasq2410), dnsmasq2410expected},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := dnsmasqConfPath(tc.in); got != tc.expected {
|
||||
t.Errorf("dnsmasqConfPath() = %v, want %v", got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user