mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-10-26 11:27:18 +00:00
all: aghnet use executil
This commit is contained in:
parent
2bffd664f0
commit
3fed265d8f
@ -13,7 +13,6 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
@ -27,19 +26,8 @@ type DialContextFunc = func(ctx context.Context, network, addr string) (conn net
|
||||
|
||||
// Variables and functions to substitute in tests.
|
||||
var (
|
||||
// aghosRunCommand is the function to run shell commands.
|
||||
//
|
||||
// TODO(s.chzhen): Use [aghos.RunCommand] directly.
|
||||
aghosRunCommand = (func() func(string, ...string) (int, []byte, error) {
|
||||
ctx := context.TODO()
|
||||
cmdCons := executil.SystemCommandConstructor{}
|
||||
|
||||
return func(command string, arguments ...string) (int, []byte, error) {
|
||||
return aghos.RunCommand(ctx, cmdCons, command, arguments...)
|
||||
}
|
||||
})()
|
||||
|
||||
// netInterfaces is the function to get the available network interfaces.
|
||||
// netInterfaceAddrs is the function to get the available network
|
||||
// interfaces.
|
||||
netInterfaceAddrs = net.InterfaceAddrs
|
||||
|
||||
// rootDirFS is the filesystem pointing to the root directory.
|
||||
@ -53,32 +41,53 @@ const ErrNoStaticIPInfo errors.Error = "no information about static ip"
|
||||
// IfaceHasStaticIP checks if interface is configured to have static IP address.
|
||||
// If it can't give a definitive answer, it returns false and an error for which
|
||||
// errors.Is(err, ErrNoStaticIPInfo) is true.
|
||||
func IfaceHasStaticIP(ifaceName string) (has bool, err error) {
|
||||
return ifaceHasStaticIP(ifaceName)
|
||||
func IfaceHasStaticIP(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (has bool, err error) {
|
||||
return ifaceHasStaticIP(ctx, cmdCons, ifaceName)
|
||||
}
|
||||
|
||||
// IfaceSetStaticIP sets static IP address for network interface.
|
||||
func IfaceSetStaticIP(ifaceName string) (err error) {
|
||||
return ifaceSetStaticIP(ifaceName)
|
||||
func IfaceSetStaticIP(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (err error) {
|
||||
return ifaceSetStaticIP(ctx, cmdCons, ifaceName)
|
||||
}
|
||||
|
||||
// GatewayIP returns IP address of interface's gateway.
|
||||
//
|
||||
// TODO(e.burkov): Investigate if the gateway address may be fetched in another
|
||||
// way since not every machine has the software installed.
|
||||
func GatewayIP(ifaceName string) (ip netip.Addr) {
|
||||
code, out, err := aghosRunCommand("ip", "route", "show", "dev", ifaceName)
|
||||
func GatewayIP(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (ip netip.Addr) {
|
||||
stdout := bytes.Buffer{}
|
||||
err := executil.Run(
|
||||
ctx,
|
||||
cmdCons,
|
||||
&executil.CommandConfig{
|
||||
Path: "ip",
|
||||
Args: []string{"route", "show", "dev", ifaceName},
|
||||
Stdout: &stdout,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Debug("%s", err)
|
||||
|
||||
return netip.Addr{}
|
||||
} else if code != 0 {
|
||||
log.Debug("fetching gateway ip: unexpected exit code: %d", code)
|
||||
if code, ok := executil.ExitCodeFromError(err); ok {
|
||||
log.Debug("fetching gateway ip: unexpected exit code: %d", code)
|
||||
} else {
|
||||
log.Debug("%s", err)
|
||||
}
|
||||
|
||||
return netip.Addr{}
|
||||
}
|
||||
|
||||
fields := bytes.Fields(out)
|
||||
fields := bytes.Fields(stdout.Bytes())
|
||||
// The meaningful "ip route" command output should contain the word
|
||||
// "default" at first field and default gateway IP address at third field.
|
||||
if len(fields) < 3 || string(fields[0]) != "default" {
|
||||
|
||||
@ -5,12 +5,14 @@ package aghnet
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
)
|
||||
|
||||
// hardwarePortInfo contains information about the current state of the internet
|
||||
@ -23,8 +25,12 @@ type hardwarePortInfo struct {
|
||||
static bool
|
||||
}
|
||||
|
||||
func ifaceHasStaticIP(ifaceName string) (ok bool, err error) {
|
||||
portInfo, err := getCurrentHardwarePortInfo(ifaceName)
|
||||
func ifaceHasStaticIP(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (ok bool, err error) {
|
||||
portInfo, err := getCurrentHardwarePortInfo(ctx, cmdCons, ifaceName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -34,15 +40,19 @@ func ifaceHasStaticIP(ifaceName string) (ok bool, err error) {
|
||||
|
||||
// getCurrentHardwarePortInfo gets information for the specified network
|
||||
// interface.
|
||||
func getCurrentHardwarePortInfo(ifaceName string) (hardwarePortInfo, error) {
|
||||
func getCurrentHardwarePortInfo(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (hardwarePortInfo, error) {
|
||||
// First of all we should find hardware port name.
|
||||
m := getNetworkSetupHardwareReports()
|
||||
m := getNetworkSetupHardwareReports(ctx, cmdCons)
|
||||
hardwarePort, ok := m[ifaceName]
|
||||
if !ok {
|
||||
return hardwarePortInfo{}, fmt.Errorf("could not find hardware port for %s", ifaceName)
|
||||
}
|
||||
|
||||
return getHardwarePortInfo(hardwarePort)
|
||||
return getHardwarePortInfo(ctx, cmdCons, hardwarePort)
|
||||
}
|
||||
|
||||
// hardwareReportsReg is the regular expression matching the lines of
|
||||
@ -57,8 +67,11 @@ var hardwareReportsReg = regexp.MustCompile("Hardware Port: (.*?)\nDevice: (.*?)
|
||||
// TODO(e.burkov): There should be more proper approach than parsing the
|
||||
// command output. For example, see
|
||||
// https://developer.apple.com/documentation/systemconfiguration.
|
||||
func getNetworkSetupHardwareReports() (reports map[string]string) {
|
||||
_, out, err := aghosRunCommand("networksetup", "-listallhardwareports")
|
||||
func getNetworkSetupHardwareReports(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
) (reports map[string]string) {
|
||||
_, out, err := aghos.RunCommand(ctx, cmdCons, "networksetup", "-listallhardwareports")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -77,8 +90,12 @@ func getNetworkSetupHardwareReports() (reports map[string]string) {
|
||||
// command output lines containing the port information.
|
||||
var hardwarePortReg = regexp.MustCompile("IP address: (.*?)\nSubnet mask: (.*?)\nRouter: (.*?)\n")
|
||||
|
||||
func getHardwarePortInfo(hardwarePort string) (h hardwarePortInfo, err error) {
|
||||
_, out, err := aghosRunCommand("networksetup", "-getinfo", hardwarePort)
|
||||
func getHardwarePortInfo(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
hardwarePort string,
|
||||
) (h hardwarePortInfo, err error) {
|
||||
_, out, err := aghos.RunCommand(ctx, cmdCons, "networksetup", "-getinfo", hardwarePort)
|
||||
if err != nil {
|
||||
return h, err
|
||||
}
|
||||
@ -97,8 +114,12 @@ func getHardwarePortInfo(hardwarePort string) (h hardwarePortInfo, err error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||
portInfo, err := getCurrentHardwarePortInfo(ifaceName)
|
||||
func ifaceSetStaticIP(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (err error) {
|
||||
portInfo, err := getCurrentHardwarePortInfo(ctx, cmdCons, ifaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -115,7 +136,7 @@ func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||
args := append([]string{"-setdnsservers", portInfo.name}, dnsAddrs...)
|
||||
|
||||
// Setting DNS servers is necessary when configuring a static IP
|
||||
code, _, err := aghosRunCommand("networksetup", args...)
|
||||
code, _, err := aghos.RunCommand(ctx, cmdCons, "networksetup", args...)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if code != 0 {
|
||||
@ -123,7 +144,9 @@ func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||
}
|
||||
|
||||
// Actually configures hardware port to have static IP
|
||||
code, _, err = aghosRunCommand(
|
||||
code, _, err = aghos.RunCommand(
|
||||
ctx,
|
||||
cmdCons,
|
||||
"networksetup",
|
||||
"-setmanual",
|
||||
portInfo.name,
|
||||
|
||||
@ -7,7 +7,9 @@ import (
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/agh"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/AdguardTeam/golibs/testutil/fakeio/fakefs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -16,48 +18,46 @@ import (
|
||||
func TestIfaceHasStaticIP(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
shell mapShell
|
||||
cmdCons executil.CommandConstructor
|
||||
ifaceName string
|
||||
wantHas assert.BoolAssertionFunc
|
||||
wantErrMsg string
|
||||
}{{
|
||||
name: "success",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
}),
|
||||
ifaceName: "en0",
|
||||
wantHas: assert.False,
|
||||
wantErrMsg: ``,
|
||||
}, {
|
||||
name: "success_static",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "Manual Configuration\nIP address: 1.2.3.4\n" +
|
||||
"Subnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "Manual Configuration\nIP address: 1.2.3.4\n" +
|
||||
"Subnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
}),
|
||||
ifaceName: "en0",
|
||||
wantHas: assert.True,
|
||||
wantErrMsg: ``,
|
||||
}, {
|
||||
name: "reports_error",
|
||||
shell: theOnlyCmd(
|
||||
cmdCons: agh.NewCommandConstructor(
|
||||
"networksetup -listallhardwareports",
|
||||
0,
|
||||
"",
|
||||
@ -68,35 +68,33 @@ func TestIfaceHasStaticIP(t *testing.T) {
|
||||
wantErrMsg: `could not find hardware port for en0`,
|
||||
}, {
|
||||
name: "port_error",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: errors.Error("can't get"),
|
||||
out: ``,
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: errors.Error("can't get"),
|
||||
Out: ``,
|
||||
Code: 0,
|
||||
}),
|
||||
ifaceName: "en0",
|
||||
wantHas: assert.False,
|
||||
wantErrMsg: `can't get`,
|
||||
}, {
|
||||
name: "port_bad_output",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "nothing meaningful",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "nothing meaningful",
|
||||
Code: 0,
|
||||
}),
|
||||
ifaceName: "en0",
|
||||
wantHas: assert.False,
|
||||
wantErrMsg: `could not find hardware port info`,
|
||||
@ -104,9 +102,8 @@ func TestIfaceHasStaticIP(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
substShell(t, tc.shell.RunCmd)
|
||||
|
||||
has, err := IfaceHasStaticIP(tc.ifaceName)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
has, err := IfaceHasStaticIP(ctx, tc.cmdCons, tc.ifaceName)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
|
||||
tc.wantHas(t, has)
|
||||
@ -126,55 +123,53 @@ func TestIfaceSetStaticIP(t *testing.T) {
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
shell mapShell
|
||||
cmdCons executil.CommandConstructor
|
||||
fsys fs.FS
|
||||
wantErrMsg string
|
||||
}{{
|
||||
name: "success",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -setdnsservers hwport 1.1.1.1": {
|
||||
err: nil,
|
||||
out: "",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -setmanual hwport 1.2.3.4 255.255.255.0 1.2.3.1": {
|
||||
err: nil,
|
||||
out: "",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -setdnsservers hwport 1.1.1.1",
|
||||
Err: nil,
|
||||
Out: "",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -setmanual hwport 1.2.3.4 255.255.255.0 1.2.3.1",
|
||||
Err: nil,
|
||||
Out: "",
|
||||
Code: 0,
|
||||
}),
|
||||
fsys: succFsys,
|
||||
wantErrMsg: ``,
|
||||
}, {
|
||||
name: "static_already",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "Manual Configuration\nIP address: 1.2.3.4\n" +
|
||||
"Subnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "Manual Configuration\nIP address: 1.2.3.4\n" +
|
||||
"Subnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
}),
|
||||
fsys: panicFsys,
|
||||
wantErrMsg: `ip address is already static`,
|
||||
}, {
|
||||
name: "reports_error",
|
||||
shell: theOnlyCmd(
|
||||
cmdCons: agh.NewCommandConstructor(
|
||||
"networksetup -listallhardwareports",
|
||||
0,
|
||||
"",
|
||||
@ -184,18 +179,18 @@ func TestIfaceSetStaticIP(t *testing.T) {
|
||||
wantErrMsg: `could not find hardware port for en0`,
|
||||
}, {
|
||||
name: "resolv_conf_error",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
},
|
||||
),
|
||||
fsys: fstest.MapFS{
|
||||
"etc/resolv.conf": &fstest.MapFile{
|
||||
Data: []byte("this resolv.conf is invalid"),
|
||||
@ -204,59 +199,57 @@ func TestIfaceSetStaticIP(t *testing.T) {
|
||||
wantErrMsg: `found no dns servers in etc/resolv.conf`,
|
||||
}, {
|
||||
name: "set_dns_error",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -setdnsservers hwport 1.1.1.1": {
|
||||
err: errors.Error("can't set"),
|
||||
out: "",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -setdnsservers hwport 1.1.1.1",
|
||||
Err: errors.Error("can't set"),
|
||||
Out: "",
|
||||
Code: 0,
|
||||
}),
|
||||
fsys: succFsys,
|
||||
wantErrMsg: `can't set`,
|
||||
}, {
|
||||
name: "set_manual_error",
|
||||
shell: mapShell{
|
||||
"networksetup -listallhardwareports": {
|
||||
err: nil,
|
||||
out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -getinfo hwport": {
|
||||
err: nil,
|
||||
out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -setdnsservers hwport 1.1.1.1": {
|
||||
err: nil,
|
||||
out: "",
|
||||
code: 0,
|
||||
},
|
||||
"networksetup -setmanual hwport 1.2.3.4 255.255.255.0 1.2.3.1": {
|
||||
err: errors.Error("can't set"),
|
||||
out: "",
|
||||
code: 0,
|
||||
},
|
||||
},
|
||||
cmdCons: agh.NewMultipleCommandConstructor(agh.ExternalCommand{
|
||||
Cmd: "networksetup -listallhardwareports",
|
||||
Err: nil,
|
||||
Out: "Hardware Port: hwport\nDevice: en0\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -getinfo hwport",
|
||||
Err: nil,
|
||||
Out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -setdnsservers hwport 1.1.1.1",
|
||||
Err: nil,
|
||||
Out: "",
|
||||
Code: 0,
|
||||
}, agh.ExternalCommand{
|
||||
Cmd: "networksetup -setmanual hwport 1.2.3.4 255.255.255.0 1.2.3.1",
|
||||
Err: errors.Error("can't set"),
|
||||
Out: "",
|
||||
Code: 0,
|
||||
}),
|
||||
fsys: succFsys,
|
||||
wantErrMsg: `can't set`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
substShell(t, tc.shell.RunCmd)
|
||||
substRootDirFS(t, tc.fsys)
|
||||
|
||||
err := IfaceSetStaticIP("en0")
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
err := IfaceSetStaticIP(ctx, tc.cmdCons, "en0")
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,15 +4,21 @@ package aghnet
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
)
|
||||
|
||||
func ifaceHasStaticIP(ifaceName string) (ok bool, err error) {
|
||||
func ifaceHasStaticIP(
|
||||
_ context.Context,
|
||||
_ executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (ok bool, err error) {
|
||||
const rcConfFilename = "etc/rc.conf"
|
||||
|
||||
walker := aghos.FileWalker(interfaceName(ifaceName).rcConfStaticConfig)
|
||||
@ -52,6 +58,6 @@ func (n interfaceName) rcConfStaticConfig(r io.Reader) (_ []string, cont bool, e
|
||||
return nil, true, s.Err()
|
||||
}
|
||||
|
||||
func ifaceSetStaticIP(string) (err error) {
|
||||
func ifaceSetStaticIP(_ context.Context, _ executil.CommandConstructor, _ string) (err error) {
|
||||
return aghos.Unsupported("setting static ip")
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@ import (
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -67,7 +69,8 @@ func TestIfaceHasStaticIP(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
substRootDirFS(t, tc.rootFsys)
|
||||
|
||||
has, err := IfaceHasStaticIP(ifaceName)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
has, err := IfaceHasStaticIP(ctx, executil.EmptyCommandConstructor{}, ifaceName)
|
||||
require.NoError(t, err)
|
||||
|
||||
tc.wantHas(t, has)
|
||||
|
||||
@ -3,20 +3,24 @@ package aghnet
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/agh"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// testTimeout is the common timeout for tests.
|
||||
const testTimeout = 1 * time.Second
|
||||
|
||||
// substRootDirFS replaces the aghos.RootDirFS function used throughout the
|
||||
// package with fsys for tests ran under t.
|
||||
func substRootDirFS(tb testing.TB, fsys fs.FS) {
|
||||
@ -30,43 +34,6 @@ func substRootDirFS(tb testing.TB, fsys fs.FS) {
|
||||
// RunCmdFunc is the signature of aghos.RunCommand function.
|
||||
type RunCmdFunc func(cmd string, args ...string) (code int, out []byte, err error)
|
||||
|
||||
// substShell replaces the the aghos.RunCommand function used throughout the
|
||||
// package with rc for tests ran under t.
|
||||
func substShell(tb testing.TB, rc RunCmdFunc) {
|
||||
tb.Helper()
|
||||
|
||||
prev := aghosRunCommand
|
||||
tb.Cleanup(func() { aghosRunCommand = prev })
|
||||
aghosRunCommand = rc
|
||||
}
|
||||
|
||||
// mapShell is a substitution of aghos.RunCommand that maps the command to it's
|
||||
// execution result. It's only needed to simplify testing.
|
||||
//
|
||||
// TODO(e.burkov): Perhaps put all the shell interactions behind an interface.
|
||||
type mapShell map[string]struct {
|
||||
err error
|
||||
out string
|
||||
code int
|
||||
}
|
||||
|
||||
// theOnlyCmd returns mapShell that only handles a single command and arguments
|
||||
// combination from cmd.
|
||||
func theOnlyCmd(cmd string, code int, out string, err error) (s mapShell) {
|
||||
return mapShell{cmd: {code: code, out: out, err: err}}
|
||||
}
|
||||
|
||||
// RunCmd is a RunCmdFunc handled by s.
|
||||
func (s mapShell) RunCmd(cmd string, args ...string) (code int, out []byte, err error) {
|
||||
key := strings.Join(append([]string{cmd}, args...), " ")
|
||||
ret, ok := s[key]
|
||||
if !ok {
|
||||
return 0, nil, fmt.Errorf("unexpected shell command %q", key)
|
||||
}
|
||||
|
||||
return ret.code, []byte(ret.out), ret.err
|
||||
}
|
||||
|
||||
// ifaceAddrsFunc is the signature of net.InterfaceAddrs function.
|
||||
type ifaceAddrsFunc func() (ifaces []net.Addr, err error)
|
||||
|
||||
@ -85,36 +52,35 @@ func TestGatewayIP(t *testing.T) {
|
||||
const cmd = "ip route show dev " + ifaceName
|
||||
|
||||
testCases := []struct {
|
||||
shell mapShell
|
||||
want netip.Addr
|
||||
name string
|
||||
cmdCons executil.CommandConstructor
|
||||
want netip.Addr
|
||||
name string
|
||||
}{{
|
||||
shell: theOnlyCmd(cmd, 0, `default via 1.2.3.4 onlink`, nil),
|
||||
want: netip.MustParseAddr("1.2.3.4"),
|
||||
name: "success_v4",
|
||||
cmdCons: agh.NewCommandConstructor(cmd, 0, `default via 1.2.3.4 onlink`, nil),
|
||||
want: netip.MustParseAddr("1.2.3.4"),
|
||||
name: "success_v4",
|
||||
}, {
|
||||
shell: theOnlyCmd(cmd, 0, `default via ::ffff onlink`, nil),
|
||||
want: netip.MustParseAddr("::ffff"),
|
||||
name: "success_v6",
|
||||
cmdCons: agh.NewCommandConstructor(cmd, 0, `default via ::ffff onlink`, nil),
|
||||
want: netip.MustParseAddr("::ffff"),
|
||||
name: "success_v6",
|
||||
}, {
|
||||
shell: theOnlyCmd(cmd, 0, `non-default via 1.2.3.4 onlink`, nil),
|
||||
want: netip.Addr{},
|
||||
name: "bad_output",
|
||||
cmdCons: agh.NewCommandConstructor(cmd, 0, `non-default via 1.2.3.4 onlink`, nil),
|
||||
want: netip.Addr{},
|
||||
name: "bad_output",
|
||||
}, {
|
||||
shell: theOnlyCmd(cmd, 0, "", errors.Error("can't run command")),
|
||||
want: netip.Addr{},
|
||||
name: "err_runcmd",
|
||||
cmdCons: agh.NewCommandConstructor(cmd, 0, "", errors.Error("can't run command")),
|
||||
want: netip.Addr{},
|
||||
name: "err_runcmd",
|
||||
}, {
|
||||
shell: theOnlyCmd(cmd, 1, "", nil),
|
||||
want: netip.Addr{},
|
||||
name: "bad_code",
|
||||
cmdCons: agh.NewCommandConstructor(cmd, 1, "", nil),
|
||||
want: netip.Addr{},
|
||||
name: "bad_code",
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
substShell(t, tc.shell.RunCmd)
|
||||
|
||||
assert.Equal(t, tc.want, GatewayIP(ifaceName))
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
assert.Equal(t, tc.want, GatewayIP(ctx, tc.cmdCons, ifaceName))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ package aghnet
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
@ -13,6 +14,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"github.com/google/renameio/v2/maybe"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -104,7 +106,11 @@ func (n interfaceName) ifacesStaticConfig(r io.Reader) (sub []string, cont bool,
|
||||
return sub, true, s.Err()
|
||||
}
|
||||
|
||||
func ifaceHasStaticIP(ifaceName string) (has bool, err error) {
|
||||
func ifaceHasStaticIP(
|
||||
_ context.Context,
|
||||
_ executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (has bool, err error) {
|
||||
// TODO(a.garipov): Currently, this function returns the first definitive
|
||||
// result. So if /etc/dhcpcd.conf has and /etc/network/interfaces has no
|
||||
// static IP configuration, it will return true. Perhaps this is not the
|
||||
@ -149,7 +155,11 @@ func findIfaceLine(s *bufio.Scanner, name string) (ok bool) {
|
||||
|
||||
// ifaceSetStaticIP configures the system to retain its current IP on the
|
||||
// interface through dhcpcd.conf.
|
||||
func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||
func ifaceSetStaticIP(
|
||||
ctx context.Context,
|
||||
cmdCons executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (err error) {
|
||||
ipNet := GetSubnet(ifaceName)
|
||||
if !ipNet.Addr().IsValid() {
|
||||
return errors.Error("can't get IP address")
|
||||
@ -160,7 +170,7 @@ func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
gatewayIP := GatewayIP(ifaceName)
|
||||
gatewayIP := GatewayIP(ctx, cmdCons, ifaceName)
|
||||
add := dhcpcdConfIface(ifaceName, ipNet, gatewayIP)
|
||||
|
||||
body = append(body, []byte(add)...)
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -117,7 +118,8 @@ func TestHasStaticIP(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
substRootDirFS(t, tc.rootFsys)
|
||||
|
||||
has, err := IfaceHasStaticIP(ifaceName)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
has, err := IfaceHasStaticIP(ctx, executil.EmptyCommandConstructor{}, ifaceName)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
|
||||
tc.wantHas(t, has)
|
||||
|
||||
@ -4,15 +4,21 @@ package aghnet
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
)
|
||||
|
||||
func ifaceHasStaticIP(ifaceName string) (ok bool, err error) {
|
||||
func ifaceHasStaticIP(
|
||||
_ context.Context,
|
||||
_ executil.CommandConstructor,
|
||||
ifaceName string,
|
||||
) (ok bool, err error) {
|
||||
filename := fmt.Sprintf("etc/hostname.%s", ifaceName)
|
||||
|
||||
return aghos.FileWalker(hostnameIfStaticConfig).Walk(rootDirFS, filename)
|
||||
@ -39,6 +45,6 @@ func hostnameIfStaticConfig(r io.Reader) (_ []string, ok bool, err error) {
|
||||
return nil, true, s.Err()
|
||||
}
|
||||
|
||||
func ifaceSetStaticIP(string) (err error) {
|
||||
func ifaceSetStaticIP(_ context.Context, _ executil.CommandConstructor, _ string) (err error) {
|
||||
return aghos.Unsupported("setting static ip")
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ import (
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -62,7 +64,8 @@ func TestIfaceHasStaticIP(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
substRootDirFS(t, tc.rootFsys)
|
||||
|
||||
has, err := IfaceHasStaticIP(ifaceName)
|
||||
ctx := testutil.ContextWithTimeout(t, testTimeout)
|
||||
has, err := IfaceHasStaticIP(ctx, executil.EmptyCommandConstructor{}, ifaceName)
|
||||
require.NoError(t, err)
|
||||
|
||||
tc.wantHas(t, has)
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
package aghnet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
@ -16,11 +18,15 @@ func canBindPrivilegedPorts() (can bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func ifaceHasStaticIP(string) (ok bool, err error) {
|
||||
func ifaceHasStaticIP(
|
||||
_ context.Context,
|
||||
_ executil.CommandConstructor,
|
||||
_ string,
|
||||
) (ok bool, err error) {
|
||||
return false, aghos.Unsupported("checking static ip")
|
||||
}
|
||||
|
||||
func ifaceSetStaticIP(string) (err error) {
|
||||
func ifaceSetStaticIP(_ context.Context, _ executil.CommandConstructor, _ string) (err error) {
|
||||
return aghos.Unsupported("setting static ip")
|
||||
}
|
||||
|
||||
|
||||
@ -11,11 +11,15 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
)
|
||||
|
||||
// ServerConfig is the configuration for the DHCP server. The order of YAML
|
||||
// fields is important, since the YAML configuration file follows it.
|
||||
type ServerConfig struct {
|
||||
// CommandConstructor is used to run external commands. It must not be nil.
|
||||
CommandConstructor executil.CommandConstructor `yaml:"-"`
|
||||
|
||||
// ConfModifier is used to update the global configuration. It must not be
|
||||
// nil.
|
||||
ConfModifier agh.ConfigModifier `yaml:"-"`
|
||||
|
||||
@ -107,7 +107,8 @@ var _ Interface = (*server)(nil)
|
||||
func Create(conf *ServerConfig) (s *server, err error) {
|
||||
s = &server{
|
||||
conf: &ServerConfig{
|
||||
ConfModifier: conf.ConfModifier,
|
||||
CommandConstructor: conf.CommandConstructor,
|
||||
ConfModifier: conf.ConfModifier,
|
||||
|
||||
HTTPRegister: conf.HTTPRegister,
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
"github.com/AdguardTeam/golibs/osutil/executil"
|
||||
)
|
||||
|
||||
type v4ServerConfJSON struct {
|
||||
@ -171,9 +173,10 @@ func (s *server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
|
||||
aghhttp.WriteJSONResponseOK(w, r, status)
|
||||
}
|
||||
|
||||
func (s *server) enableDHCP(ifaceName string) (code int, err error) {
|
||||
func (s *server) enableDHCP(ctx context.Context, ifaceName string) (code int, err error) {
|
||||
var hasStaticIP bool
|
||||
hasStaticIP, err = aghnet.IfaceHasStaticIP(ifaceName)
|
||||
cmdCons := s.conf.CommandConstructor
|
||||
hasStaticIP, err = aghnet.IfaceHasStaticIP(ctx, cmdCons, ifaceName)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrPermission) {
|
||||
// ErrPermission may happen here on Linux systems where AdGuard Home
|
||||
@ -202,7 +205,7 @@ func (s *server) enableDHCP(ifaceName string) (code int, err error) {
|
||||
}
|
||||
|
||||
if !hasStaticIP {
|
||||
err = aghnet.IfaceSetStaticIP(ifaceName)
|
||||
err = aghnet.IfaceSetStaticIP(ctx, cmdCons, ifaceName)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("setting static ip: %w", err)
|
||||
|
||||
@ -309,6 +312,8 @@ func (s *server) createServers(conf *dhcpServerConfigJSON) (srv4, srv6 DHCPServe
|
||||
// handleDHCPSetConfig is the handler for the POST /control/dhcp/set_config
|
||||
// HTTP API.
|
||||
func (s *server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
conf := &dhcpServerConfigJSON{}
|
||||
conf.Enabled = aghalg.BoolToNullBool(s.conf.Enabled)
|
||||
conf.InterfaceName = s.conf.InterfaceName
|
||||
@ -346,7 +351,7 @@ func (s *server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if s.conf.Enabled {
|
||||
var code int
|
||||
code, err = s.enableDHCP(conf.InterfaceName)
|
||||
code, err = s.enableDHCP(ctx, conf.InterfaceName)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, code, "enabling dhcp: %s", err)
|
||||
}
|
||||
@ -405,7 +410,7 @@ func (s *server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||
continue
|
||||
}
|
||||
|
||||
jsonIface, iErr := newNetInterfaceJSON(iface)
|
||||
jsonIface, iErr := newNetInterfaceJSON(r.Context(), iface, s.conf.CommandConstructor)
|
||||
if iErr != nil {
|
||||
aghhttp.Error(r, w, http.StatusInternalServerError, "%s", iErr)
|
||||
|
||||
@ -421,7 +426,11 @@ func (s *server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// newNetInterfaceJSON creates a JSON object from a [net.Interface] iface.
|
||||
func newNetInterfaceJSON(iface net.Interface) (out *netInterfaceJSON, err error) {
|
||||
func newNetInterfaceJSON(
|
||||
ctx context.Context,
|
||||
iface net.Interface,
|
||||
cmdCons executil.CommandConstructor,
|
||||
) (out *netInterfaceJSON, err error) {
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
@ -473,7 +482,7 @@ func newNetInterfaceJSON(iface net.Interface) (out *netInterfaceJSON, err error)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out.GatewayIP = aghnet.GatewayIP(iface.Name)
|
||||
out.GatewayIP = aghnet.GatewayIP(ctx, cmdCons, iface.Name)
|
||||
|
||||
return out, nil
|
||||
}
|
||||
@ -558,7 +567,8 @@ func (s *server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
|
||||
},
|
||||
}
|
||||
|
||||
if isStaticIP, serr := aghnet.IfaceHasStaticIP(ifaceName); serr != nil {
|
||||
cmdCons := s.conf.CommandConstructor
|
||||
if isStaticIP, serr := aghnet.IfaceHasStaticIP(r.Context(), cmdCons, ifaceName); serr != nil {
|
||||
result.V4.StaticIP.Static = "error"
|
||||
result.V4.StaticIP.Error = serr.Error()
|
||||
} else if !isStaticIP {
|
||||
|
||||
@ -175,6 +175,8 @@ func (req *checkConfReq) validateDNS(
|
||||
|
||||
// handleInstallCheckConfig handles the /check_config endpoint.
|
||||
func (web *webAPI) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
req := &checkConfReq{}
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(req)
|
||||
@ -190,11 +192,11 @@ func (web *webAPI) handleInstallCheckConfig(w http.ResponseWriter, r *http.Reque
|
||||
resp.Web.Status = err.Error()
|
||||
}
|
||||
|
||||
resp.DNS.CanAutofix, err = req.validateDNS(r.Context(), web.logger, tcpPorts, web.cmdCons)
|
||||
resp.DNS.CanAutofix, err = req.validateDNS(ctx, web.logger, tcpPorts, web.cmdCons)
|
||||
if err != nil {
|
||||
resp.DNS.Status = err.Error()
|
||||
} else if !req.DNS.IP.IsUnspecified() {
|
||||
resp.StaticIP = handleStaticIP(req.DNS.IP, req.SetStaticIP)
|
||||
resp.StaticIP = handleStaticIP(ctx, req.DNS.IP, req.SetStaticIP, web.cmdCons)
|
||||
}
|
||||
|
||||
aghhttp.WriteJSONResponseOK(w, r, resp)
|
||||
@ -203,7 +205,12 @@ func (web *webAPI) handleInstallCheckConfig(w http.ResponseWriter, r *http.Reque
|
||||
// handleStaticIP - handles static IP request
|
||||
// It either checks if we have a static IP
|
||||
// Or if set=true, it tries to set it
|
||||
func handleStaticIP(ip netip.Addr, set bool) staticIPJSON {
|
||||
func handleStaticIP(
|
||||
ctx context.Context,
|
||||
ip netip.Addr,
|
||||
set bool,
|
||||
cmdCons executil.CommandConstructor,
|
||||
) staticIPJSON {
|
||||
resp := staticIPJSON{}
|
||||
|
||||
interfaceName := aghnet.InterfaceByIP(ip)
|
||||
@ -217,7 +224,7 @@ func handleStaticIP(ip netip.Addr, set bool) staticIPJSON {
|
||||
|
||||
if set {
|
||||
// Try to set static IP for the specified interface
|
||||
err := aghnet.IfaceSetStaticIP(interfaceName)
|
||||
err := aghnet.IfaceSetStaticIP(ctx, cmdCons, interfaceName)
|
||||
if err != nil {
|
||||
resp.Static = "error"
|
||||
resp.Error = err.Error()
|
||||
@ -227,7 +234,7 @@ func handleStaticIP(ip netip.Addr, set bool) staticIPJSON {
|
||||
|
||||
// Fallthrough here even if we set static IP
|
||||
// Check if we have a static IP and return the details
|
||||
isStaticIP, err := aghnet.IfaceHasStaticIP(interfaceName)
|
||||
isStaticIP, err := aghnet.IfaceHasStaticIP(ctx, cmdCons, interfaceName)
|
||||
if err != nil {
|
||||
resp.Static = "error"
|
||||
resp.Error = err.Error()
|
||||
|
||||
@ -306,6 +306,7 @@ func initContextClients(
|
||||
config.DHCP.WorkDir = globalContext.workDir
|
||||
config.DHCP.DataDir = globalContext.getDataDir()
|
||||
config.DHCP.HTTPRegister = httpRegister
|
||||
config.DHCP.CommandConstructor = executil.SystemCommandConstructor{}
|
||||
config.DHCP.ConfModifier = confModifier
|
||||
|
||||
globalContext.dhcpServer, err = dhcpd.Create(config.DHCP)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user