Pull request: 2302 static ip
Merge in DNS/adguard-home from 2302-static-ip to master Closes #2302. Squashed commit of the following: commit e62b7b033861f1c55f0d06811ca005b3934ddc5b Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 19:38:15 2020 +0300 all: format changelog commit 4127aa7630674ddcfe84f712e6c7c8d06b1cab9a Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 19:24:53 2020 +0300 all: fix changelog typo commit f8a432056d3682facae0cdec99d7d80a5c2bd9b5 Merge: b809a866ee4383189a
Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 19:22:27 2020 +0300 Merge branch 'master' into 2302-static-ip commit b809a866e49147354f9c6952b2f958b6b56ad873 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 19:20:05 2020 +0300 all: log changes commit 248c35ba411af731d6eae755a901cdbc77980628 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 18:57:15 2020 +0300 sysutil: use bufio.Scanner commit 0dc19dd5c232fbe9552a2b0d846e048274d73a74 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 17:26:18 2020 +0300 sysutil: fix linux tests commit 91202d6763595cff187040516dd1db10a20762b7 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 17:15:29 2020 +0300 sysutil: fix linux files commit 40fbdbb95876322ebaeef1cbdaa8e3299b83ca7e Merge: d9a43ffb69b963fc77
Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 16:52:35 2020 +0300 Merge branch 'master' into 2302-static-ip commit d9a43ffb68a2ddbbcf185b69fc75aed139cd6919 Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 16:49:22 2020 +0300 sysutil: add main test commit bfef89186035ab0423d23246d46511584c26534c Author: Eugene Burkov <e.burkov@adguard.com> Date: Mon Dec 7 16:21:59 2020 +0300 sysutil: improve code quality commit a5f57a373f736971fdeb0c03371da7c8138b3a82 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Dec 4 14:14:08 2020 +0300 all: move system functionality from dhcpd package to sysutil. commit 020b51864f85a39ca80e2b4e06faeb47cf318e11 Merge: 967e111a6ab8defdb0
Author: Eugene Burkov <e.burkov@adguard.com> Date: Wed Dec 2 14:53:43 2020 +0300 Merge branch 'master' into 2302-static-ip commit 967e111a663c18b5f4a87f3ae38d076f3ab6c200 Author: Eugene Burkov <e.burkov@adguard.com> Date: Wed Dec 2 13:52:17 2020 +0300 all: improve code quality
This commit is contained in:
parent
e4383189a5
commit
2313eda123
|
@ -15,6 +15,8 @@ and this project adheres to
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Detecting of network interface configurated to have static IP address via
|
||||||
|
`/etc/network/interfaces` ([#2302]).
|
||||||
- DNSCrypt protocol support [#1361].
|
- DNSCrypt protocol support [#1361].
|
||||||
- A 5 second wait period until a DHCP server's network interface gets an IP
|
- A 5 second wait period until a DHCP server's network interface gets an IP
|
||||||
address ([#2304]).
|
address ([#2304]).
|
||||||
|
@ -22,6 +24,7 @@ and this project adheres to
|
||||||
- HTTP API request body size limit ([#2305]).
|
- HTTP API request body size limit ([#2305]).
|
||||||
|
|
||||||
[#1361]: https://github.com/AdguardTeam/AdGuardHome/issues/1361
|
[#1361]: https://github.com/AdguardTeam/AdGuardHome/issues/1361
|
||||||
|
[#2302]: https://github.com/AdguardTeam/AdGuardHome/issues/2302
|
||||||
[#2304]: https://github.com/AdguardTeam/AdGuardHome/issues/2304
|
[#2304]: https://github.com/AdguardTeam/AdGuardHome/issues/2304
|
||||||
[#2305]: https://github.com/AdguardTeam/AdGuardHome/issues/2305
|
[#2305]: https://github.com/AdguardTeam/AdGuardHome/issues/2305
|
||||||
[#2337]: https://github.com/AdguardTeam/AdGuardHome/issues/2337
|
[#2337]: https://github.com/AdguardTeam/AdGuardHome/issues/2337
|
||||||
|
|
|
@ -81,11 +81,6 @@ type ServerInterface interface {
|
||||||
SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
|
SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckConfig checks the configuration
|
|
||||||
func (s *Server) CheckConfig(config ServerConfig) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create - create object
|
// Create - create object
|
||||||
func Create(config ServerConfig) *Server {
|
func Create(config ServerConfig) *Server {
|
||||||
s := &Server{}
|
s := &Server{}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/sysutil"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
||||||
"github.com/AdguardTeam/golibs/jsonutil"
|
"github.com/AdguardTeam/golibs/jsonutil"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
@ -205,9 +206,9 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
s.dbLoad()
|
s.dbLoad()
|
||||||
|
|
||||||
if s.conf.Enabled {
|
if s.conf.Enabled {
|
||||||
staticIP, err := HasStaticIP(newconfig.InterfaceName)
|
staticIP, err := sysutil.IfaceHasStaticIP(newconfig.InterfaceName)
|
||||||
if !staticIP && err == nil {
|
if !staticIP && err == nil {
|
||||||
err = SetStaticIP(newconfig.InterfaceName)
|
err = sysutil.IfaceSetStaticIP(newconfig.InterfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(r, w, http.StatusInternalServerError, "Failed to configure static IP: %s", err)
|
httpError(r, w, http.StatusInternalServerError, "Failed to configure static IP: %s", err)
|
||||||
return
|
return
|
||||||
|
@ -282,7 +283,7 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(jsonIface.Addrs4)+len(jsonIface.Addrs6) != 0 {
|
if len(jsonIface.Addrs4)+len(jsonIface.Addrs6) != 0 {
|
||||||
jsonIface.GatewayIP = getGatewayIP(iface.Name)
|
jsonIface.GatewayIP = sysutil.GatewayIP(iface.Name)
|
||||||
response[iface.Name] = jsonIface
|
response[iface.Name] = jsonIface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,7 +320,7 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
|
||||||
found4, err4 := CheckIfOtherDHCPServersPresentV4(interfaceName)
|
found4, err4 := CheckIfOtherDHCPServersPresentV4(interfaceName)
|
||||||
|
|
||||||
staticIP := map[string]interface{}{}
|
staticIP := map[string]interface{}{}
|
||||||
isStaticIP, err := HasStaticIP(interfaceName)
|
isStaticIP, err := sysutil.IfaceHasStaticIP(interfaceName)
|
||||||
staticIPStatus := "yes"
|
staticIPStatus := "yes"
|
||||||
if err != nil {
|
if err != nil {
|
||||||
staticIPStatus = "error"
|
staticIPStatus = "error"
|
||||||
|
|
|
@ -1,312 +0,0 @@
|
||||||
package dhcpd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"os/exec"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/file"
|
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HasStaticIP check if the network interface has a static IP configured
|
|
||||||
//
|
|
||||||
// Supports: Raspbian.
|
|
||||||
func HasStaticIP(ifaceName string) (bool, error) {
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
body, err := ioutil.ReadFile("/etc/dhcpcd.conf")
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasStaticIPDhcpcdConf(string(body), ifaceName), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
return hasStaticIPDarwin(ifaceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, fmt.Errorf("cannot check if IP is static: not supported on %s", runtime.GOOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetStaticIP sets a static IP for the network interface.
|
|
||||||
func SetStaticIP(ifaceName string) error {
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
return setStaticIPDhcpdConf(ifaceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
return setStaticIPDarwin(ifaceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("cannot set static IP on %s", runtime.GOOS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for dhcpcd.conf
|
|
||||||
func hasStaticIPDhcpcdConf(dhcpConf, ifaceName string) bool {
|
|
||||||
lines := strings.Split(dhcpConf, "\n")
|
|
||||||
nameLine := fmt.Sprintf("interface %s", ifaceName)
|
|
||||||
withinInterfaceCtx := false
|
|
||||||
|
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
|
|
||||||
if withinInterfaceCtx && len(line) == 0 {
|
|
||||||
// an empty line resets our state
|
|
||||||
withinInterfaceCtx = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(line) == 0 || line[0] == '#' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
|
|
||||||
if !withinInterfaceCtx {
|
|
||||||
if line == nameLine {
|
|
||||||
// we found our interface
|
|
||||||
withinInterfaceCtx = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if strings.HasPrefix(line, "interface ") {
|
|
||||||
// we found another interface - reset our state
|
|
||||||
withinInterfaceCtx = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(line, "static ip_address=") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get gateway IP address
|
|
||||||
func getGatewayIP(ifaceName string) string {
|
|
||||||
cmd := exec.Command("ip", "route", "show", "dev", ifaceName)
|
|
||||||
log.Tracef("executing %s %v", cmd.Path, cmd.Args)
|
|
||||||
d, err := cmd.Output()
|
|
||||||
if err != nil || cmd.ProcessState.ExitCode() != 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := strings.Fields(string(d))
|
|
||||||
if len(fields) < 3 || fields[0] != "default" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := net.ParseIP(fields[2])
|
|
||||||
if ip == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
// setStaticIPDhcpdConf - updates /etc/dhcpd.conf and sets the current IP address to be static
|
|
||||||
func setStaticIPDhcpdConf(ifaceName string) error {
|
|
||||||
ip := util.GetSubnet(ifaceName)
|
|
||||||
if len(ip) == 0 {
|
|
||||||
return errors.New("can't get IP address")
|
|
||||||
}
|
|
||||||
|
|
||||||
ip4, _, err := net.ParseCIDR(ip)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
gatewayIP := getGatewayIP(ifaceName)
|
|
||||||
add := updateStaticIPDhcpcdConf(ifaceName, ip, gatewayIP, ip4.String())
|
|
||||||
|
|
||||||
body, err := ioutil.ReadFile("/etc/dhcpcd.conf")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
body = append(body, []byte(add)...)
|
|
||||||
err = file.SafeWrite("/etc/dhcpcd.conf", body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updates dhcpd.conf content -- sets static IP address there
|
|
||||||
// for dhcpcd.conf
|
|
||||||
func updateStaticIPDhcpcdConf(ifaceName, ip, gatewayIP, dnsIP string) string {
|
|
||||||
var body []byte
|
|
||||||
|
|
||||||
add := fmt.Sprintf("\ninterface %s\nstatic ip_address=%s\n",
|
|
||||||
ifaceName, ip)
|
|
||||||
body = append(body, []byte(add)...)
|
|
||||||
|
|
||||||
if len(gatewayIP) != 0 {
|
|
||||||
add = fmt.Sprintf("static routers=%s\n",
|
|
||||||
gatewayIP)
|
|
||||||
body = append(body, []byte(add)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
add = fmt.Sprintf("static domain_name_servers=%s\n\n",
|
|
||||||
dnsIP)
|
|
||||||
body = append(body, []byte(add)...)
|
|
||||||
|
|
||||||
return string(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if network interface has a static IP configured
|
|
||||||
// Supports: MacOS.
|
|
||||||
func hasStaticIPDarwin(ifaceName string) (bool, error) {
|
|
||||||
portInfo, err := getCurrentHardwarePortInfo(ifaceName)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return portInfo.static, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setStaticIPDarwin - uses networksetup util to set the current IP address to be static
|
|
||||||
// Additionally it configures the current DNS servers as well
|
|
||||||
func setStaticIPDarwin(ifaceName string) error {
|
|
||||||
portInfo, err := getCurrentHardwarePortInfo(ifaceName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if portInfo.static {
|
|
||||||
return errors.New("IP address is already static")
|
|
||||||
}
|
|
||||||
|
|
||||||
dnsAddrs, err := getEtcResolvConfServers()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]string, 0)
|
|
||||||
args = append(args, "-setdnsservers", portInfo.name)
|
|
||||||
args = append(args, dnsAddrs...)
|
|
||||||
|
|
||||||
// Setting DNS servers is necessary when configuring a static IP
|
|
||||||
code, _, err := util.RunCommand("networksetup", args...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if code != 0 {
|
|
||||||
return fmt.Errorf("failed to set DNS servers, code=%d", code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actually configures hardware port to have static IP
|
|
||||||
code, _, err = util.RunCommand("networksetup", "-setmanual",
|
|
||||||
portInfo.name, portInfo.ip, portInfo.subnet, portInfo.gatewayIP)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if code != 0 {
|
|
||||||
return fmt.Errorf("failed to set DNS servers, code=%d", code)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCurrentHardwarePortInfo gets information the specified network interface
|
|
||||||
func getCurrentHardwarePortInfo(ifaceName string) (hardwarePortInfo, error) {
|
|
||||||
// First of all we should find hardware port name
|
|
||||||
m := getNetworkSetupHardwareReports()
|
|
||||||
hardwarePort, ok := m[ifaceName]
|
|
||||||
if !ok {
|
|
||||||
return hardwarePortInfo{}, fmt.Errorf("could not find hardware port for %s", ifaceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return getHardwarePortInfo(hardwarePort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getNetworkSetupHardwareReports parses the output of the `networksetup -listallhardwareports` command
|
|
||||||
// it returns a map where the key is the interface name, and the value is the "hardware port"
|
|
||||||
// returns nil if it fails to parse the output
|
|
||||||
func getNetworkSetupHardwareReports() map[string]string {
|
|
||||||
_, out, err := util.RunCommand("networksetup", "-listallhardwareports")
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
re, err := regexp.Compile("Hardware Port: (.*?)\nDevice: (.*?)\n")
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
m := make(map[string]string)
|
|
||||||
|
|
||||||
matches := re.FindAllStringSubmatch(out, -1)
|
|
||||||
for i := range matches {
|
|
||||||
port := matches[i][1]
|
|
||||||
device := matches[i][2]
|
|
||||||
m[device] = port
|
|
||||||
}
|
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// hardwarePortInfo - information obtained using MacOS networksetup
|
|
||||||
// about the current state of the internet connection
|
|
||||||
type hardwarePortInfo struct {
|
|
||||||
name string
|
|
||||||
ip string
|
|
||||||
subnet string
|
|
||||||
gatewayIP string
|
|
||||||
static bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHardwarePortInfo(hardwarePort string) (hardwarePortInfo, error) {
|
|
||||||
h := hardwarePortInfo{}
|
|
||||||
|
|
||||||
_, out, err := util.RunCommand("networksetup", "-getinfo", hardwarePort)
|
|
||||||
if err != nil {
|
|
||||||
return h, err
|
|
||||||
}
|
|
||||||
|
|
||||||
re := regexp.MustCompile("IP address: (.*?)\nSubnet mask: (.*?)\nRouter: (.*?)\n")
|
|
||||||
|
|
||||||
match := re.FindStringSubmatch(out)
|
|
||||||
if len(match) == 0 {
|
|
||||||
return h, errors.New("could not find hardware port info")
|
|
||||||
}
|
|
||||||
|
|
||||||
h.name = hardwarePort
|
|
||||||
h.ip = match[1]
|
|
||||||
h.subnet = match[2]
|
|
||||||
h.gatewayIP = match[3]
|
|
||||||
|
|
||||||
if strings.Index(out, "Manual Configuration") == 0 {
|
|
||||||
h.static = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets a list of nameservers currently configured in the /etc/resolv.conf
|
|
||||||
func getEtcResolvConfServers() ([]string, error) {
|
|
||||||
body, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
re := regexp.MustCompile("nameserver ([a-zA-Z0-9.:]+)")
|
|
||||||
|
|
||||||
matches := re.FindAllStringSubmatch(string(body), -1)
|
|
||||||
if len(matches) == 0 {
|
|
||||||
return nil, errors.New("found no DNS servers in /etc/resolv.conf")
|
|
||||||
}
|
|
||||||
|
|
||||||
addrs := make([]string, 0)
|
|
||||||
for i := range matches {
|
|
||||||
addrs = append(addrs, matches[i][1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return addrs, nil
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package dhcpd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHasStaticIPDhcpcdConf(t *testing.T) {
|
|
||||||
dhcpdConf := `#comment
|
|
||||||
# comment
|
|
||||||
|
|
||||||
interface eth0
|
|
||||||
static ip_address=192.168.0.1/24
|
|
||||||
|
|
||||||
# interface wlan0
|
|
||||||
static ip_address=192.168.1.1/24
|
|
||||||
|
|
||||||
# comment
|
|
||||||
`
|
|
||||||
assert.True(t, !hasStaticIPDhcpcdConf(dhcpdConf, "wlan0"))
|
|
||||||
|
|
||||||
dhcpdConf = `#comment
|
|
||||||
# comment
|
|
||||||
|
|
||||||
interface eth0
|
|
||||||
static ip_address=192.168.0.1/24
|
|
||||||
|
|
||||||
# interface wlan0
|
|
||||||
static ip_address=192.168.1.1/24
|
|
||||||
|
|
||||||
# comment
|
|
||||||
|
|
||||||
interface wlan0
|
|
||||||
# comment
|
|
||||||
static ip_address=192.168.2.1/24
|
|
||||||
`
|
|
||||||
assert.True(t, hasStaticIPDhcpcdConf(dhcpdConf, "wlan0"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetStaticIPDhcpcdConf(t *testing.T) {
|
|
||||||
dhcpcdConf := `
|
|
||||||
interface wlan0
|
|
||||||
static ip_address=192.168.0.2/24
|
|
||||||
static routers=192.168.0.1
|
|
||||||
static domain_name_servers=192.168.0.2
|
|
||||||
|
|
||||||
`
|
|
||||||
s := updateStaticIPDhcpcdConf("wlan0", "192.168.0.2/24", "192.168.0.1", "192.168.0.2")
|
|
||||||
assert.Equal(t, dhcpcdConf, s)
|
|
||||||
|
|
||||||
// without gateway
|
|
||||||
dhcpcdConf = `
|
|
||||||
interface wlan0
|
|
||||||
static ip_address=192.168.0.2/24
|
|
||||||
static domain_name_servers=192.168.0.2
|
|
||||||
|
|
||||||
`
|
|
||||||
s = updateStaticIPDhcpcdConf("wlan0", "192.168.0.2/24", "", "192.168.0.2")
|
|
||||||
assert.Equal(t, dhcpcdConf, s)
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
"github.com/AdguardTeam/AdGuardHome/internal/sysutil"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
)
|
)
|
||||||
|
@ -167,7 +167,7 @@ func handleStaticIP(ip string, set bool) staticIPJSON {
|
||||||
|
|
||||||
if set {
|
if set {
|
||||||
// Try to set static IP for the specified interface
|
// Try to set static IP for the specified interface
|
||||||
err := dhcpd.SetStaticIP(interfaceName)
|
err := sysutil.IfaceSetStaticIP(interfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Static = "error"
|
resp.Static = "error"
|
||||||
resp.Error = err.Error()
|
resp.Error = err.Error()
|
||||||
|
@ -177,7 +177,7 @@ func handleStaticIP(ip string, set bool) staticIPJSON {
|
||||||
|
|
||||||
// Fallthrough here even if we set static IP
|
// Fallthrough here even if we set static IP
|
||||||
// Check if we have a static IP and return the details
|
// Check if we have a static IP and return the details
|
||||||
isStaticIP, err := dhcpd.HasStaticIP(interfaceName)
|
isStaticIP, err := sysutil.IfaceHasStaticIP(interfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Static = "error"
|
resp.Static = "error"
|
||||||
resp.Error = err.Error()
|
resp.Error = err.Error()
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IfaceHasStaticIP checks if interface is configured to have static IP address.
|
||||||
|
func IfaceHasStaticIP(ifaceName string) (has bool, err error) {
|
||||||
|
return ifaceHasStaticIP(ifaceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IfaceSetStaticIP sets static IP address for network interface.
|
||||||
|
func IfaceSetStaticIP(ifaceName string) (err error) {
|
||||||
|
return ifaceSetStaticIP(ifaceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GatewayIP returns IP address of interface's gateway.
|
||||||
|
func GatewayIP(ifaceName string) string {
|
||||||
|
cmd := exec.Command("ip", "route", "show", "dev", ifaceName)
|
||||||
|
log.Tracef("executing %s %v", cmd.Path, cmd.Args)
|
||||||
|
d, err := cmd.Output()
|
||||||
|
if err != nil || cmd.ProcessState.ExitCode() != 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(string(d))
|
||||||
|
// 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 || fields[0] != "default" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.ParseIP(fields[2])
|
||||||
|
if ip == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields[2]
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hardwarePortInfo - information obtained using MacOS networksetup
|
||||||
|
// about the current state of the internet connection
|
||||||
|
type hardwarePortInfo struct {
|
||||||
|
name string
|
||||||
|
ip string
|
||||||
|
subnet string
|
||||||
|
gatewayIP string
|
||||||
|
static bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func ifaceHasStaticIP(ifaceName string) (bool, error) {
|
||||||
|
portInfo, err := getCurrentHardwarePortInfo(ifaceName)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return portInfo.static, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCurrentHardwarePortInfo gets information the specified network interface.
|
||||||
|
func getCurrentHardwarePortInfo(ifaceName string) (hardwarePortInfo, error) {
|
||||||
|
// First of all we should find hardware port name
|
||||||
|
m := getNetworkSetupHardwareReports()
|
||||||
|
hardwarePort, ok := m[ifaceName]
|
||||||
|
if !ok {
|
||||||
|
return hardwarePortInfo{}, fmt.Errorf("could not find hardware port for %s", ifaceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHardwarePortInfo(hardwarePort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getNetworkSetupHardwareReports parses the output of the `networksetup -listallhardwareports` command
|
||||||
|
// it returns a map where the key is the interface name, and the value is the "hardware port"
|
||||||
|
// returns nil if it fails to parse the output
|
||||||
|
func getNetworkSetupHardwareReports() map[string]string {
|
||||||
|
_, out, err := util.RunCommand("networksetup", "-listallhardwareports")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile("Hardware Port: (.*?)\nDevice: (.*?)\n")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]string)
|
||||||
|
|
||||||
|
matches := re.FindAllStringSubmatch(out, -1)
|
||||||
|
for i := range matches {
|
||||||
|
port := matches[i][1]
|
||||||
|
device := matches[i][2]
|
||||||
|
m[device] = port
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHardwarePortInfo(hardwarePort string) (hardwarePortInfo, error) {
|
||||||
|
h := hardwarePortInfo{}
|
||||||
|
|
||||||
|
_, out, err := util.RunCommand("networksetup", "-getinfo", hardwarePort)
|
||||||
|
if err != nil {
|
||||||
|
return h, err
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile("IP address: (.*?)\nSubnet mask: (.*?)\nRouter: (.*?)\n")
|
||||||
|
|
||||||
|
match := re.FindStringSubmatch(out)
|
||||||
|
if len(match) == 0 {
|
||||||
|
return h, errors.New("could not find hardware port info")
|
||||||
|
}
|
||||||
|
|
||||||
|
h.name = hardwarePort
|
||||||
|
h.ip = match[1]
|
||||||
|
h.subnet = match[2]
|
||||||
|
h.gatewayIP = match[3]
|
||||||
|
|
||||||
|
if strings.Index(out, "Manual Configuration") == 0 {
|
||||||
|
h.static = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||||
|
portInfo, err := getCurrentHardwarePortInfo(ifaceName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if portInfo.static {
|
||||||
|
return errors.New("IP address is already static")
|
||||||
|
}
|
||||||
|
|
||||||
|
dnsAddrs, err := getEtcResolvConfServers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
args := make([]string, 0)
|
||||||
|
args = append(args, "-setdnsservers", portInfo.name)
|
||||||
|
args = append(args, dnsAddrs...)
|
||||||
|
|
||||||
|
// Setting DNS servers is necessary when configuring a static IP
|
||||||
|
code, _, err := util.RunCommand("networksetup", args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if code != 0 {
|
||||||
|
return fmt.Errorf("failed to set DNS servers, code=%d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually configures hardware port to have static IP
|
||||||
|
code, _, err = util.RunCommand("networksetup", "-setmanual",
|
||||||
|
portInfo.name, portInfo.ip, portInfo.subnet, portInfo.gatewayIP)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if code != 0 {
|
||||||
|
return fmt.Errorf("failed to set DNS servers, code=%d", code)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEtcResolvConfServers returns a list of nameservers configured in
|
||||||
|
// /etc/resolv.conf.
|
||||||
|
func getEtcResolvConfServers() ([]string, error) {
|
||||||
|
body, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile("nameserver ([a-zA-Z0-9.:]+)")
|
||||||
|
|
||||||
|
matches := re.FindAllStringSubmatch(string(body), -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return nil, errors.New("found no DNS servers in /etc/resolv.conf")
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs := make([]string, 0)
|
||||||
|
for i := range matches {
|
||||||
|
addrs = append(addrs, matches[i][1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return addrs, nil
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
||||||
|
"github.com/AdguardTeam/golibs/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
// maxConfigFileSize is the maximum length of interfaces configuration file.
|
||||||
|
const maxConfigFileSize = 1024 * 1024
|
||||||
|
|
||||||
|
func ifaceHasStaticIP(ifaceName string) (has bool, err error) {
|
||||||
|
var f *os.File
|
||||||
|
for _, check := range []struct {
|
||||||
|
checker func(io.Reader, string) (bool, error)
|
||||||
|
filePath string
|
||||||
|
}{{
|
||||||
|
checker: dhcpcdStaticConfig,
|
||||||
|
filePath: "/etc/dhcpcd.conf",
|
||||||
|
}, {
|
||||||
|
checker: ifacesStaticConfig,
|
||||||
|
filePath: "/etc/network/interfaces",
|
||||||
|
}} {
|
||||||
|
f, err = os.Open(check.filePath)
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
fileReadCloser, err := aghio.LimitReadCloser(f, maxConfigFileSize)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer fileReadCloser.Close()
|
||||||
|
|
||||||
|
has, err = check.checker(fileReadCloser, ifaceName)
|
||||||
|
if has || err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return has, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// dhcpcdStaticConfig checks if interface is configured by /etc/dhcpcd.conf to
|
||||||
|
// have a static IP.
|
||||||
|
func dhcpcdStaticConfig(r io.Reader, ifaceName string) (has bool, err error) {
|
||||||
|
s := bufio.NewScanner(r)
|
||||||
|
var withinInterfaceCtx bool
|
||||||
|
|
||||||
|
for s.Scan() {
|
||||||
|
line := strings.TrimSpace(s.Text())
|
||||||
|
|
||||||
|
if withinInterfaceCtx && len(line) == 0 {
|
||||||
|
// An empty line resets our state.
|
||||||
|
withinInterfaceCtx = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(line) == 0 || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
if withinInterfaceCtx {
|
||||||
|
if len(fields) >= 2 && fields[0] == "static" && strings.HasPrefix(fields[1], "ip_address=") {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if len(fields) > 0 && fields[0] == "interface" {
|
||||||
|
// Another interface found.
|
||||||
|
withinInterfaceCtx = false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fields) == 2 && fields[0] == "interface" && fields[1] == ifaceName {
|
||||||
|
// The interface found.
|
||||||
|
withinInterfaceCtx = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, s.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ifacesStaticConfig checks if interface is configured by
|
||||||
|
// /etc/network/interfaces to have a static IP.
|
||||||
|
func ifacesStaticConfig(r io.Reader, ifaceName string) (has bool, err error) {
|
||||||
|
s := bufio.NewScanner(r)
|
||||||
|
for s.Scan() {
|
||||||
|
line := strings.TrimSpace(s.Text())
|
||||||
|
|
||||||
|
if len(line) == 0 || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
// Man page interfaces(5) declares that interface definition
|
||||||
|
// should consist of the key word "iface" followed by interface
|
||||||
|
// name, and method at fourth field.
|
||||||
|
if len(fields) >= 4 && fields[0] == "iface" && fields[1] == ifaceName && fields[3] == "static" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, s.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ifaceSetStaticIP(ifaceName string) (err error) {
|
||||||
|
ip := util.GetSubnet(ifaceName)
|
||||||
|
if len(ip) == 0 {
|
||||||
|
return errors.New("can't get IP address")
|
||||||
|
}
|
||||||
|
|
||||||
|
ip4, _, err := net.ParseCIDR(ip)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gatewayIP := GatewayIP(ifaceName)
|
||||||
|
add := updateStaticIPdhcpcdConf(ifaceName, ip, gatewayIP, ip4.String())
|
||||||
|
|
||||||
|
body, err := ioutil.ReadFile("/etc/dhcpcd.conf")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body = append(body, []byte(add)...)
|
||||||
|
err = file.SafeWrite("/etc/dhcpcd.conf", body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateStaticIPdhcpcdConf sets static IP address for the interface by writing
|
||||||
|
// into dhcpd.conf.
|
||||||
|
func updateStaticIPdhcpcdConf(ifaceName, ip, gatewayIP, dnsIP string) string {
|
||||||
|
var body []byte
|
||||||
|
|
||||||
|
add := fmt.Sprintf("\ninterface %s\nstatic ip_address=%s\n",
|
||||||
|
ifaceName, ip)
|
||||||
|
body = append(body, []byte(add)...)
|
||||||
|
|
||||||
|
if len(gatewayIP) != 0 {
|
||||||
|
add = fmt.Sprintf("static routers=%s\n",
|
||||||
|
gatewayIP)
|
||||||
|
body = append(body, []byte(add)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
add = fmt.Sprintf("static domain_name_servers=%s\n\n",
|
||||||
|
dnsIP)
|
||||||
|
body = append(body, []byte(add)...)
|
||||||
|
|
||||||
|
return string(body)
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
const nl = "\n"
|
||||||
|
|
||||||
|
func TestDHCPCDStaticConfig(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
want bool
|
||||||
|
}{{
|
||||||
|
name: "has_not",
|
||||||
|
data: []byte(`#comment` + nl +
|
||||||
|
`# comment` + nl +
|
||||||
|
`interface eth0` + nl +
|
||||||
|
`static ip_address=192.168.0.1/24` + nl +
|
||||||
|
`# interface wlan0` + nl +
|
||||||
|
`static ip_address=192.168.1.1/24` + nl +
|
||||||
|
`# comment` + nl,
|
||||||
|
),
|
||||||
|
want: false,
|
||||||
|
}, {
|
||||||
|
name: "has",
|
||||||
|
data: []byte(`#comment` + nl +
|
||||||
|
`# comment` + nl +
|
||||||
|
`interface eth0` + nl +
|
||||||
|
`static ip_address=192.168.0.1/24` + nl +
|
||||||
|
`# interface wlan0` + nl +
|
||||||
|
`static ip_address=192.168.1.1/24` + nl +
|
||||||
|
`# comment` + nl +
|
||||||
|
`interface wlan0` + nl +
|
||||||
|
`# comment` + nl +
|
||||||
|
`static ip_address=192.168.2.1/24` + nl,
|
||||||
|
),
|
||||||
|
want: true,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
r := bytes.NewReader(tc.data)
|
||||||
|
has, err := dhcpcdStaticConfig(r, "wlan0")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, tc.want, has)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfacesStaticConfig(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
want bool
|
||||||
|
}{{
|
||||||
|
name: "has_not",
|
||||||
|
data: []byte(`allow-hotplug enp0s3` + nl +
|
||||||
|
`#iface enp0s3 inet static` + nl +
|
||||||
|
`# address 192.168.0.200` + nl +
|
||||||
|
`# netmask 255.255.255.0` + nl +
|
||||||
|
`# gateway 192.168.0.1` + nl +
|
||||||
|
`iface enp0s3 inet dhcp` + nl,
|
||||||
|
),
|
||||||
|
want: false,
|
||||||
|
}, {
|
||||||
|
name: "has",
|
||||||
|
data: []byte(`allow-hotplug enp0s3` + nl +
|
||||||
|
`iface enp0s3 inet static` + nl +
|
||||||
|
` address 192.168.0.200` + nl +
|
||||||
|
` netmask 255.255.255.0` + nl +
|
||||||
|
` gateway 192.168.0.1` + nl +
|
||||||
|
`#iface enp0s3 inet dhcp` + nl,
|
||||||
|
),
|
||||||
|
want: true,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
r := bytes.NewReader(tc.data)
|
||||||
|
has, err := ifacesStaticConfig(r, "enp0s3")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, tc.want, has)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetStaticIPdhcpcdConf(t *testing.T) {
|
||||||
|
dhcpcdConf := nl + `interface wlan0` + nl +
|
||||||
|
`static ip_address=192.168.0.2/24` + nl +
|
||||||
|
`static routers=192.168.0.1` + nl +
|
||||||
|
`static domain_name_servers=192.168.0.2` + nl + nl
|
||||||
|
|
||||||
|
s := updateStaticIPdhcpcdConf("wlan0", "192.168.0.2/24", "192.168.0.1", "192.168.0.2")
|
||||||
|
assert.Equal(t, dhcpcdConf, s)
|
||||||
|
|
||||||
|
// without gateway
|
||||||
|
dhcpcdConf = nl + `interface wlan0` + nl +
|
||||||
|
`static ip_address=192.168.0.2/24` + nl +
|
||||||
|
`static domain_name_servers=192.168.0.2` + nl + nl
|
||||||
|
|
||||||
|
s = updateStaticIPdhcpcdConf("wlan0", "192.168.0.2/24", "", "192.168.0.2")
|
||||||
|
assert.Equal(t, dhcpcdConf, s)
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
// +build !linux,!darwin
|
||||||
|
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ifaceHasStaticIP(string) (bool, error) {
|
||||||
|
return false, fmt.Errorf("cannot check if IP is static: not supported on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ifaceSetStaticIP(string) error {
|
||||||
|
return fmt.Errorf("cannot set static IP on %s", runtime.GOOS)
|
||||||
|
}
|
|
@ -24,8 +24,3 @@ func HaveAdminRights() (bool, error) {
|
||||||
func SendProcessSignal(pid int, sig syscall.Signal) error {
|
func SendProcessSignal(pid int, sig syscall.Signal) error {
|
||||||
return sendProcessSignal(pid, sig)
|
return sendProcessSignal(pid, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigureSyslog reroutes standard logger output to syslog.
|
|
||||||
func ConfigureSyslog(serviceName string) error {
|
|
||||||
return configureSyslog(serviceName)
|
|
||||||
}
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
// ConfigureSyslog reroutes standard logger output to syslog.
|
||||||
|
func ConfigureSyslog(serviceName string) error {
|
||||||
|
return configureSyslog(serviceName)
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package sysutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
testutil.DiscardLogOutput(m)
|
||||||
|
}
|
|
@ -33,10 +33,7 @@ func GetValidNetInterfaces() ([]net.Interface, error) {
|
||||||
|
|
||||||
netIfaces := []net.Interface{}
|
netIfaces := []net.Interface{}
|
||||||
|
|
||||||
for i := range ifaces {
|
netIfaces = append(netIfaces, ifaces...)
|
||||||
iface := ifaces[i]
|
|
||||||
netIfaces = append(netIfaces, iface)
|
|
||||||
}
|
|
||||||
|
|
||||||
return netIfaces, nil
|
return netIfaces, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue