Pull request: 2508 ip conversion vol.2

Merge in DNS/adguard-home from 2508-ip-conversion-vol2 to master

Closes #2508.

Squashed commit of the following:

commit 5b9d33f9cd352756831f63e34c4aea48674628c1
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Jan 20 17:15:17 2021 +0300

    util: replace net.IPNet with pointer

commit 680126de7d59464077f9edf1bbaa925dd3fcee19
Merge: d3ba6a6c 5a50efad
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Jan 20 17:02:41 2021 +0300

    Merge branch 'master' into 2508-ip-conversion-vol2

commit d3ba6a6cdd01c0aa736418fdb86ed40120169fe9
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Jan 19 18:29:54 2021 +0300

    all: remove last conversion

commit 88b63f11a6c3f8705d7fa0c448c50dd646cc9214
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Jan 19 14:12:45 2021 +0300

    all: improve code quality

commit 71af60c70a0dbaf55e2221023d6d2e4993c9e9a7
Merge: 98af3784 9f75725d
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Jan 18 17:13:27 2021 +0300

    Merge branch 'master' into 2508-ip-conversion-vol2

commit 98af3784ce44d0993d171653c13d6e83bb8d1e6a
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Jan 18 16:32:53 2021 +0300

    all: log changes

commit e99595a172bae1e844019d344544be84ddd65e4e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Jan 18 16:06:49 2021 +0300

    all: fix or remove remaining net.IP <-> string conversions

commit 7fd0634ce945f7e4c9b856684c5199f8a84a543e
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Jan 15 15:36:17 2021 +0300

    all: remove redundant net.IP <-> string converions

commit 5df8af030421237d41b67ed659f83526cc258199
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Jan 14 16:35:25 2021 +0300

    stats: remove redundant net.IP <-> string conversion

commit fbe4e3fc015e6898063543a90c04401d76dbb18f
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Thu Jan 14 16:20:35 2021 +0300

    querylog: remove redundant net.IP <-> string conversion
This commit is contained in:
Eugene Burkov
2021-01-20 17:27:53 +03:00
parent 5a50efadb2
commit 7fab31beae
45 changed files with 324 additions and 302 deletions

View File

@@ -70,10 +70,12 @@ type ClientHost struct {
}
type clientsContainer struct {
list map[string]*Client // name -> client
idIndex map[string]*Client // IP -> client
ipHost map[string]*ClientHost // IP -> Hostname
lock sync.Mutex
list map[string]*Client // name -> client
idIndex map[string]*Client // IP -> client
// TODO(e.burkov): Think of a way to not require string conversion for
// IP addresses.
ipHost map[string]*ClientHost // IP -> Hostname
lock sync.Mutex
allTags map[string]bool
@@ -239,7 +241,7 @@ func (clients *clientsContainer) onHostsChanged() {
}
// Exists checks if client with this IP already exists
func (clients *clientsContainer) Exists(ip string, source clientSource) bool {
func (clients *clientsContainer) Exists(ip net.IP, source clientSource) bool {
clients.lock.Lock()
defer clients.lock.Unlock()
@@ -248,7 +250,7 @@ func (clients *clientsContainer) Exists(ip string, source clientSource) bool {
return true
}
ch, ok := clients.ipHost[ip]
ch, ok := clients.ipHost[ip.String()]
if !ok {
return false
}
@@ -265,7 +267,7 @@ func stringArrayDup(a []string) []string {
}
// Find searches for a client by IP
func (clients *clientsContainer) Find(ip string) (Client, bool) {
func (clients *clientsContainer) Find(ip net.IP) (Client, bool) {
clients.lock.Lock()
defer clients.lock.Unlock()
@@ -287,7 +289,7 @@ func (clients *clientsContainer) FindUpstreams(ip string) *proxy.UpstreamConfig
clients.lock.Lock()
defer clients.lock.Unlock()
c, ok := clients.findByIP(ip)
c, ok := clients.findByIP(net.ParseIP(ip))
if !ok {
return nil
}
@@ -307,13 +309,12 @@ func (clients *clientsContainer) FindUpstreams(ip string) *proxy.UpstreamConfig
}
// Find searches for a client by IP (and does not lock anything)
func (clients *clientsContainer) findByIP(ip string) (Client, bool) {
ipAddr := net.ParseIP(ip)
if ipAddr == nil {
func (clients *clientsContainer) findByIP(ip net.IP) (Client, bool) {
if ip == nil {
return Client{}, false
}
c, ok := clients.idIndex[ip]
c, ok := clients.idIndex[ip.String()]
if ok {
return *c, true
}
@@ -324,7 +325,7 @@ func (clients *clientsContainer) findByIP(ip string) (Client, bool) {
if err != nil {
continue
}
if ipnet.Contains(ipAddr) {
if ipnet.Contains(ip) {
return *c, true
}
}
@@ -333,7 +334,7 @@ func (clients *clientsContainer) findByIP(ip string) (Client, bool) {
if clients.dhcpServer == nil {
return Client{}, false
}
macFound := clients.dhcpServer.FindMACbyIP(ipAddr)
macFound := clients.dhcpServer.FindMACbyIP(ip)
if macFound == nil {
return Client{}, false
}
@@ -353,16 +354,15 @@ func (clients *clientsContainer) findByIP(ip string) (Client, bool) {
}
// FindAutoClient - search for an auto-client by IP
func (clients *clientsContainer) FindAutoClient(ip string) (ClientHost, bool) {
ipAddr := net.ParseIP(ip)
if ipAddr == nil {
func (clients *clientsContainer) FindAutoClient(ip net.IP) (ClientHost, bool) {
if ip == nil {
return ClientHost{}, false
}
clients.lock.Lock()
defer clients.lock.Unlock()
ch, ok := clients.ipHost[ip]
ch, ok := clients.ipHost[ip.String()]
if ok {
return *ch, true
}
@@ -539,7 +539,7 @@ func (clients *clientsContainer) Update(name string, c Client) error {
}
// SetWhoisInfo - associate WHOIS information with a client
func (clients *clientsContainer) SetWhoisInfo(ip string, info [][]string) {
func (clients *clientsContainer) SetWhoisInfo(ip net.IP, info [][]string) {
clients.lock.Lock()
defer clients.lock.Unlock()
@@ -549,7 +549,8 @@ func (clients *clientsContainer) SetWhoisInfo(ip string, info [][]string) {
return
}
ch, ok := clients.ipHost[ip]
ipStr := ip.String()
ch, ok := clients.ipHost[ipStr]
if ok {
ch.WhoisInfo = info
log.Debug("Clients: set WHOIS info for auto-client %s: %v", ch.Host, ch.WhoisInfo)
@@ -561,7 +562,7 @@ func (clients *clientsContainer) SetWhoisInfo(ip string, info [][]string) {
Source: ClientSourceWHOIS,
}
ch.WhoisInfo = info
clients.ipHost[ip] = ch
clients.ipHost[ipStr] = ch
log.Debug("Clients: set WHOIS info for auto-client with IP %s: %v", ip, ch.WhoisInfo)
}

View File

@@ -36,21 +36,21 @@ func TestClients(t *testing.T) {
assert.True(t, b)
assert.Nil(t, err)
c, b = clients.Find("1.1.1.1")
c, b = clients.Find(net.IPv4(1, 1, 1, 1))
assert.True(t, b)
assert.Equal(t, c.Name, "client1")
c, b = clients.Find("1:2:3::4")
c, b = clients.Find(net.ParseIP("1:2:3::4"))
assert.True(t, b)
assert.Equal(t, c.Name, "client1")
c, b = clients.Find("2.2.2.2")
c, b = clients.Find(net.IPv4(2, 2, 2, 2))
assert.True(t, b)
assert.Equal(t, c.Name, "client2")
assert.False(t, clients.Exists("1.2.3.4", ClientSourceHostsFile))
assert.True(t, clients.Exists("1.1.1.1", ClientSourceHostsFile))
assert.True(t, clients.Exists("2.2.2.2", ClientSourceHostsFile))
assert.False(t, clients.Exists(net.IPv4(1, 2, 3, 4), ClientSourceHostsFile))
assert.True(t, clients.Exists(net.IPv4(1, 1, 1, 1), ClientSourceHostsFile))
assert.True(t, clients.Exists(net.IPv4(2, 2, 2, 2), ClientSourceHostsFile))
})
t.Run("add_fail_name", func(t *testing.T) {
@@ -112,8 +112,8 @@ func TestClients(t *testing.T) {
err := clients.Update("client1", c)
assert.Nil(t, err)
assert.False(t, clients.Exists("1.1.1.1", ClientSourceHostsFile))
assert.True(t, clients.Exists("1.1.1.2", ClientSourceHostsFile))
assert.False(t, clients.Exists(net.IPv4(1, 1, 1, 1), ClientSourceHostsFile))
assert.True(t, clients.Exists(net.IPv4(1, 1, 1, 2), ClientSourceHostsFile))
c = Client{
IDs: []string{"1.1.1.2"},
@@ -124,7 +124,7 @@ func TestClients(t *testing.T) {
err = clients.Update("client1", c)
assert.Nil(t, err)
c, b := clients.Find("1.1.1.2")
c, b := clients.Find(net.IPv4(1, 1, 1, 2))
assert.True(t, b)
assert.Equal(t, "client1-renamed", c.Name)
assert.Equal(t, "1.1.1.2", c.IDs[0])
@@ -135,7 +135,7 @@ func TestClients(t *testing.T) {
t.Run("del_success", func(t *testing.T) {
b := clients.Del("client1-renamed")
assert.True(t, b)
assert.False(t, clients.Exists("1.1.1.2", ClientSourceHostsFile))
assert.False(t, clients.Exists(net.IPv4(1, 1, 1, 2), ClientSourceHostsFile))
})
t.Run("del_fail", func(t *testing.T) {
@@ -156,7 +156,7 @@ func TestClients(t *testing.T) {
assert.True(t, b)
assert.Nil(t, err)
assert.True(t, clients.Exists("1.1.1.1", ClientSourceHostsFile))
assert.True(t, clients.Exists(net.IPv4(1, 1, 1, 1), ClientSourceHostsFile))
})
t.Run("addhost_fail", func(t *testing.T) {
@@ -174,12 +174,12 @@ func TestClientsWhois(t *testing.T) {
whois := [][]string{{"orgname", "orgname-val"}, {"country", "country-val"}}
// set whois info on new client
clients.SetWhoisInfo("1.1.1.255", whois)
clients.SetWhoisInfo(net.IPv4(1, 1, 1, 255), whois)
assert.Equal(t, "orgname-val", clients.ipHost["1.1.1.255"].WhoisInfo[0][1])
// set whois info on existing auto-client
_, _ = clients.AddHost("1.1.1.1", "host", ClientSourceRDNS)
clients.SetWhoisInfo("1.1.1.1", whois)
clients.SetWhoisInfo(net.IPv4(1, 1, 1, 1), whois)
assert.Equal(t, "orgname-val", clients.ipHost["1.1.1.1"].WhoisInfo[0][1])
// Check that we cannot set whois info on a manually-added client
@@ -188,7 +188,7 @@ func TestClientsWhois(t *testing.T) {
Name: "client1",
}
_, _ = clients.Add(c)
clients.SetWhoisInfo("1.1.1.2", whois)
clients.SetWhoisInfo(net.IPv4(1, 1, 1, 2), whois)
assert.Nil(t, clients.ipHost["1.1.1.2"])
_ = clients.Del("client1")
}

View File

@@ -3,6 +3,7 @@ package home
import (
"encoding/json"
"fmt"
"net"
"net/http"
)
@@ -229,8 +230,9 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
q := r.URL.Query()
data := []map[string]interface{}{}
for i := 0; ; i++ {
ip := q.Get(fmt.Sprintf("ip%d", i))
if len(ip) == 0 {
ipStr := q.Get(fmt.Sprintf("ip%d", i))
ip := net.ParseIP(ipStr)
if ip == nil {
break
}
@@ -248,7 +250,7 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
cj.Disallowed, cj.DisallowedRule = clients.dnsServer.IsBlockedIP(ip)
}
el[ip] = cj
el[ipStr] = cj
data = append(data, el)
}
@@ -267,7 +269,8 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
// findTemporary looks up the IP in temporary storages, like autohosts or
// blocklists.
func (clients *clientsContainer) findTemporary(ip string) (cj clientJSON, found bool) {
func (clients *clientsContainer) findTemporary(ip net.IP) (cj clientJSON, found bool) {
ipStr := ip.String()
ch, ok := clients.FindAutoClient(ip)
if !ok {
// It is still possible that the IP used to be in the runtime
@@ -281,7 +284,7 @@ func (clients *clientsContainer) findTemporary(ip string) (cj clientJSON, found
}
cj = clientJSON{
IDs: []string{ip},
IDs: []string{ipStr},
Disallowed: disallowed,
DisallowedRule: rule,
}
@@ -289,7 +292,7 @@ func (clients *clientsContainer) findTemporary(ip string) (cj clientJSON, found
return cj, true
}
cj = clientHostToJSON(ip, ch)
cj = clientHostToJSON(ipStr, ch)
cj.Disallowed, cj.DisallowedRule = clients.dnsServer.IsBlockedIP(ip)
return cj, true

View File

@@ -2,6 +2,7 @@ package home
import (
"io/ioutil"
"net"
"os"
"path/filepath"
"sync"
@@ -40,7 +41,7 @@ type configuration struct {
// It's reset after config is parsed
fileData []byte
BindHost string `yaml:"bind_host"` // BindHost is the IP address of the HTTP server to bind to
BindHost net.IP `yaml:"bind_host"` // BindHost is the IP address of the HTTP server to bind to
BindPort int `yaml:"bind_port"` // BindPort is the port the HTTP server
BetaBindPort int `yaml:"beta_bind_port"` // BetaBindPort is the port for new client
Users []User `yaml:"users"` // Users that can access HTTP server
@@ -74,7 +75,7 @@ type configuration struct {
// field ordering is important -- yaml fields will mirror ordering from here
type dnsConfig struct {
BindHost string `yaml:"bind_host"`
BindHost net.IP `yaml:"bind_host"`
Port int `yaml:"port"`
// time interval for statistics (in days)
@@ -121,9 +122,9 @@ type tlsConfigSettings struct {
var config = configuration{
BindPort: 3000,
BetaBindPort: 0,
BindHost: "0.0.0.0",
BindHost: net.IP{0, 0, 0, 0},
DNS: dnsConfig{
BindHost: "0.0.0.0",
BindHost: net.IP{0, 0, 0, 0},
Port: 53,
StatsInterval: 1,
FilteringConfig: dnsforward.FilteringConfig{

View File

@@ -36,11 +36,12 @@ func httpError(w http.ResponseWriter, code int, format string, args ...interface
// ---------------
// dns run control
// ---------------
func addDNSAddress(dnsAddresses *[]string, addr string) {
func addDNSAddress(dnsAddresses *[]string, addr net.IP) {
hostport := addr.String()
if config.DNS.Port != 53 {
addr = fmt.Sprintf("%s:%d", addr, config.DNS.Port)
hostport = net.JoinHostPort(hostport, strconv.Itoa(config.DNS.Port))
}
*dnsAddresses = append(*dnsAddresses, addr)
*dnsAddresses = append(*dnsAddresses, hostport)
}
func handleStatus(w http.ResponseWriter, _ *http.Request) {

View File

@@ -31,7 +31,7 @@ type netInterfaceJSON struct {
Name string `json:"name"`
MTU int `json:"mtu"`
HardwareAddr string `json:"hardware_address"`
Addresses []string `json:"ip_addresses"`
Addresses []net.IP `json:"ip_addresses"`
Flags string `json:"flags"`
}
@@ -69,7 +69,7 @@ func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request
type checkConfigReqEnt struct {
Port int `json:"port"`
IP string `json:"ip"`
IP net.IP `json:"ip"`
Autofix bool `json:"autofix"`
}
@@ -138,7 +138,7 @@ func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request)
if err != nil {
respData.DNS.Status = err.Error()
} else if reqData.DNS.IP != "0.0.0.0" {
} else if !reqData.DNS.IP.IsUnspecified() {
respData.StaticIP = handleStaticIP(reqData.DNS.IP, reqData.SetStaticIP)
}
}
@@ -154,7 +154,7 @@ func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request)
// 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 string, set bool) staticIPJSON {
func handleStaticIP(ip net.IP, set bool) staticIPJSON {
resp := staticIPJSON{}
interfaceName := util.GetInterfaceByIP(ip)
@@ -186,7 +186,7 @@ func handleStaticIP(ip string, set bool) staticIPJSON {
if isStaticIP {
resp.Static = "yes"
}
resp.IP = util.GetSubnet(interfaceName)
resp.IP = util.GetSubnet(interfaceName).String()
}
return resp
}
@@ -262,7 +262,7 @@ func disableDNSStubListener() error {
}
type applyConfigReqEnt struct {
IP string `json:"ip"`
IP net.IP `json:"ip"`
Port int `json:"port"`
}
@@ -297,7 +297,7 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) {
}
restartHTTP := true
if config.BindHost == newSettings.Web.IP && config.BindPort == newSettings.Web.Port {
if config.BindHost.Equal(newSettings.Web.IP) && config.BindPort == newSettings.Web.Port {
// no need to rebind
restartHTTP = false
}
@@ -307,7 +307,7 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) {
err = util.CheckPortAvailable(newSettings.Web.IP, newSettings.Web.Port)
if err != nil {
httpError(w, http.StatusBadRequest, "Impossible to listen on IP:port %s due to %s",
net.JoinHostPort(newSettings.Web.IP, strconv.Itoa(newSettings.Web.Port)), err)
net.JoinHostPort(newSettings.Web.IP.String(), strconv.Itoa(newSettings.Web.Port)), err)
return
}
@@ -388,18 +388,18 @@ func (web *Web) registerInstallHandlers() {
// checkConfigReqEntBeta is a struct representing new client's config check
// request entry. It supports multiple IP values unlike the checkConfigReqEnt.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default checkConfigReqEnt.
type checkConfigReqEntBeta struct {
Port int `json:"port"`
IP []string `json:"ip"`
IP []net.IP `json:"ip"`
Autofix bool `json:"autofix"`
}
// checkConfigReqBeta is a struct representing new client's config check request
// body. It uses checkConfigReqEntBeta instead of checkConfigReqEnt.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default checkConfigReq.
type checkConfigReqBeta struct {
Web checkConfigReqEntBeta `json:"web"`
@@ -410,7 +410,7 @@ type checkConfigReqBeta struct {
// handleInstallCheckConfigBeta is a substitution of /install/check_config
// handler for new client.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default handleInstallCheckConfig.
func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Request) {
reqData := checkConfigReqBeta{}
@@ -456,17 +456,17 @@ func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Requ
// applyConfigReqEntBeta is a struct representing new client's config setting
// request entry. It supports multiple IP values unlike the applyConfigReqEnt.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default applyConfigReqEnt.
type applyConfigReqEntBeta struct {
IP []string `json:"ip"`
IP []net.IP `json:"ip"`
Port int `json:"port"`
}
// applyConfigReqBeta is a struct representing new client's config setting
// request body. It uses applyConfigReqEntBeta instead of applyConfigReqEnt.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default applyConfigReq.
type applyConfigReqBeta struct {
Web applyConfigReqEntBeta `json:"web"`
@@ -478,7 +478,7 @@ type applyConfigReqBeta struct {
// handleInstallConfigureBeta is a substitution of /install/configure handler
// for new client.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default handleInstallConfigure.
func (web *Web) handleInstallConfigureBeta(w http.ResponseWriter, r *http.Request) {
reqData := applyConfigReqBeta{}
@@ -523,7 +523,7 @@ func (web *Web) handleInstallConfigureBeta(w http.ResponseWriter, r *http.Reques
// firstRunDataBeta is a struct representing new client's getting addresses
// request body. It uses array of structs instead of map.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default firstRunData.
type firstRunDataBeta struct {
WebPort int `json:"web_port"`
@@ -534,7 +534,7 @@ type firstRunDataBeta struct {
// handleInstallConfigureBeta is a substitution of /install/get_addresses
// handler for new client.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default handleInstallGetAddresses.
func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Request) {
data := firstRunDataBeta{}
@@ -570,7 +570,7 @@ func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Req
// registerBetaInstallHandlers registers the install handlers for new client
// with the structures it supports.
//
// TODO(e.burkov): this should removed with the API v1 when the appropriate
// TODO(e.burkov): This should removed with the API v1 when the appropriate
// functionality will appear in default handlers.
func (web *Web) registerBetaInstallHandlers() {
Context.mux.HandleFunc("/control/install/get_addresses_beta", preInstall(ensureGET(web.handleInstallGetAddressesBeta)))

View File

@@ -55,8 +55,8 @@ func initDNSServer() error {
filterConf := config.DNS.DnsfilterConf
bindhost := config.DNS.BindHost
if config.DNS.BindHost == "0.0.0.0" {
bindhost = "127.0.0.1"
if config.DNS.BindHost.IsUnspecified() {
bindhost = net.IPv4(127, 0, 0, 1)
}
filterConf.ResolverAddress = fmt.Sprintf("%s:%d", bindhost, config.DNS.Port)
filterConf.AutoHosts = &Context.autoHosts
@@ -98,26 +98,24 @@ func isRunning() bool {
}
func onDNSRequest(d *proxy.DNSContext) {
ip := dnsforward.IPStringFromAddr(d.Addr)
if ip == "" {
ip := dnsforward.IPFromAddr(d.Addr)
if ip == nil {
// This would be quite weird if we get here
return
}
ipAddr := net.ParseIP(ip)
if !ipAddr.IsLoopback() {
if !ip.IsLoopback() {
Context.rdns.Begin(ip)
}
if !Context.ipDetector.detectSpecialNetwork(ipAddr) {
if !Context.ipDetector.detectSpecialNetwork(ip) {
Context.whois.Begin(ip)
}
}
func generateServerConfig() (newconfig dnsforward.ServerConfig, err error) {
bindHost := net.ParseIP(config.DNS.BindHost)
newconfig = dnsforward.ServerConfig{
UDPListenAddr: &net.UDPAddr{IP: bindHost, Port: config.DNS.Port},
TCPListenAddr: &net.TCPAddr{IP: bindHost, Port: config.DNS.Port},
UDPListenAddr: &net.UDPAddr{IP: config.DNS.BindHost, Port: config.DNS.Port},
TCPListenAddr: &net.TCPAddr{IP: config.DNS.BindHost, Port: config.DNS.Port},
FilteringConfig: config.DNS.FilteringConfig,
ConfigModified: onConfigModified,
HTTPRegister: httpRegister,
@@ -131,20 +129,20 @@ func generateServerConfig() (newconfig dnsforward.ServerConfig, err error) {
if tlsConf.PortDNSOverTLS != 0 {
newconfig.TLSListenAddr = &net.TCPAddr{
IP: bindHost,
IP: config.DNS.BindHost,
Port: tlsConf.PortDNSOverTLS,
}
}
if tlsConf.PortDNSOverQUIC != 0 {
newconfig.QUICListenAddr = &net.UDPAddr{
IP: bindHost,
IP: config.DNS.BindHost,
Port: int(tlsConf.PortDNSOverQUIC),
}
}
if tlsConf.PortDNSCrypt != 0 {
newconfig.DNSCryptConfig, err = newDNSCrypt(bindHost, tlsConf)
newconfig.DNSCryptConfig, err = newDNSCrypt(config.DNS.BindHost, tlsConf)
if err != nil {
// Don't wrap the error, because it's already
// wrapped by newDNSCrypt.
@@ -245,7 +243,7 @@ func getDNSEncryption() dnsEncryption {
func getDNSAddresses() []string {
dnsAddresses := []string{}
if config.DNS.BindHost == "0.0.0.0" {
if config.DNS.BindHost.IsUnspecified() {
ifaces, e := util.GetValidNetInterfacesForWeb()
if e != nil {
log.Error("Couldn't get network interfaces: %v", e)
@@ -276,10 +274,10 @@ func getDNSAddresses() []string {
}
// If a client has his own settings, apply them
func applyAdditionalFiltering(clientAddr string, setts *dnsfilter.RequestFilteringSettings) {
func applyAdditionalFiltering(clientAddr net.IP, setts *dnsfilter.RequestFilteringSettings) {
Context.dnsFilter.ApplyBlockedServices(setts, nil, true)
if len(clientAddr) == 0 {
if clientAddr == nil {
return
}
setts.ClientIP = clientAddr
@@ -328,13 +326,11 @@ func startDNSServer() error {
Context.queryLog.Start()
const topClientsNumber = 100 // the number of clients to get
topClients := Context.stats.GetTopClientsIP(topClientsNumber)
for _, ip := range topClients {
ipAddr := net.ParseIP(ip)
if !ipAddr.IsLoopback() {
for _, ip := range Context.stats.GetTopClientsIP(topClientsNumber) {
if !ip.IsLoopback() {
Context.rdns.Begin(ip)
}
if !Context.ipDetector.detectSpecialNetwork(ipAddr) {
if !Context.ipDetector.detectSpecialNetwork(ip) {
Context.whois.Begin(ip)
}
}

View File

@@ -206,7 +206,7 @@ func setupConfig(args options) {
}
// override bind host/port from the console
if args.bindHost != "" {
if args.bindHost != nil {
config.BindHost = args.bindHost
}
if args.bindPort != 0 {
@@ -575,36 +575,40 @@ func printHTTPAddresses(proto string) {
port = strconv.Itoa(tlsConf.PortHTTPS)
}
var hostStr string
if proto == "https" && tlsConf.ServerName != "" {
if tlsConf.PortHTTPS == 443 {
log.Printf("Go to https://%s", tlsConf.ServerName)
} else {
log.Printf("Go to https://%s:%s", tlsConf.ServerName, port)
}
} else if config.BindHost == "0.0.0.0" {
} else if config.BindHost.IsUnspecified() {
log.Println("AdGuard Home is available on the following addresses:")
ifaces, err := util.GetValidNetInterfacesForWeb()
if err != nil {
// That's weird, but we'll ignore it
log.Printf("Go to %s://%s", proto, net.JoinHostPort(config.BindHost, port))
hostStr = config.BindHost.String()
log.Printf("Go to %s://%s", proto, net.JoinHostPort(hostStr, port))
if config.BetaBindPort != 0 {
log.Printf("Go to %s://%s (BETA)", proto, net.JoinHostPort(config.BindHost, strconv.Itoa(config.BetaBindPort)))
log.Printf("Go to %s://%s (BETA)", proto, net.JoinHostPort(hostStr, strconv.Itoa(config.BetaBindPort)))
}
return
}
for _, iface := range ifaces {
for _, addr := range iface.Addresses {
log.Printf("Go to %s://%s", proto, net.JoinHostPort(addr, strconv.Itoa(config.BindPort)))
hostStr = addr.String()
log.Printf("Go to %s://%s", proto, net.JoinHostPort(hostStr, strconv.Itoa(config.BindPort)))
if config.BetaBindPort != 0 {
log.Printf("Go to %s://%s (BETA)", proto, net.JoinHostPort(addr, strconv.Itoa(config.BetaBindPort)))
log.Printf("Go to %s://%s (BETA)", proto, net.JoinHostPort(hostStr, strconv.Itoa(config.BetaBindPort)))
}
}
}
} else {
log.Printf("Go to %s://%s", proto, net.JoinHostPort(config.BindHost, port))
hostStr = config.BindHost.String()
log.Printf("Go to %s://%s", proto, net.JoinHostPort(hostStr, port))
if config.BetaBindPort != 0 {
log.Printf("Go to %s://%s (BETA)", proto, net.JoinHostPort(config.BindHost, strconv.Itoa(config.BetaBindPort)))
log.Printf("Go to %s://%s (BETA)", proto, net.JoinHostPort(hostStr, strconv.Itoa(config.BetaBindPort)))
}
}
}

View File

@@ -1,6 +1,6 @@
// +build !race
// TODO(e.burkov): remove this weird buildtag.
// TODO(e.burkov): Remove this weird buildtag.
package home

View File

@@ -2,6 +2,7 @@ package home
import (
"fmt"
"net"
"os"
"strconv"
@@ -13,7 +14,7 @@ type options struct {
verbose bool // is verbose logging enabled
configFilename string // path to the config file
workDir string // path to the working directory where we will store the filters data and the querylog
bindHost string // host address to bind HTTP server on
bindHost net.IP // host address to bind HTTP server on
bindPort int // port to serve HTTP pages on
logFile string // Path to the log file. If empty, write to stdout. If "syslog", writes to syslog
pidFile string // File name to save PID to
@@ -54,10 +55,19 @@ type arg struct {
// against its zero value and return nil if the parameter value is
// zero otherwise they return a string slice of the parameter
func ipSliceOrNil(ip net.IP) []string {
if ip == nil {
return nil
}
return []string{ip.String()}
}
func stringSliceOrNil(s string) []string {
if s == "" {
return nil
}
return []string{s}
}
@@ -65,6 +75,7 @@ func intSliceOrNil(i int) []string {
if i == 0 {
return nil
}
return []string{strconv.Itoa(i)}
}
@@ -72,6 +83,7 @@ func boolSliceOrNil(b bool) []string {
if b {
return []string{}
}
return nil
}
@@ -96,8 +108,8 @@ var workDirArg = arg{
var hostArg = arg{
"Host address to bind HTTP server on",
"host", "h",
func(o options, v string) (options, error) { o.bindHost = v; return o, nil }, nil, nil,
func(o options) []string { return stringSliceOrNil(o.bindHost) },
func(o options, v string) (options, error) { o.bindHost = net.ParseIP(v); return o, nil }, nil, nil,
func(o options) []string { return ipSliceOrNil(o.bindHost) },
}
var portArg = arg{

View File

@@ -2,6 +2,7 @@ package home
import (
"fmt"
"net"
"testing"
)
@@ -65,14 +66,14 @@ func TestParseWorkDir(t *testing.T) {
}
func TestParseBindHost(t *testing.T) {
if testParseOk(t).bindHost != "" {
if testParseOk(t).bindHost != nil {
t.Fatal("empty is no host")
}
if testParseOk(t, "-h", "addr").bindHost != "addr" {
if !testParseOk(t, "-h", "1.2.3.4").bindHost.Equal(net.IP{1, 2, 3, 4}) {
t.Fatal("-h is host")
}
testParseParamMissing(t, "-h")
if testParseOk(t, "--host", "addr").bindHost != "addr" {
if !testParseOk(t, "--host", "1.2.3.4").bindHost.Equal(net.IP{1, 2, 3, 4}) {
t.Fatal("--host is host")
}
testParseParamMissing(t, "--host")
@@ -204,7 +205,7 @@ func TestSerializeWorkDir(t *testing.T) {
}
func TestSerializeBindHost(t *testing.T) {
testSerialize(t, options{bindHost: "addr"}, "-h", "addr")
testSerialize(t, options{bindHost: net.IP{1, 2, 3, 4}}, "-h", "1.2.3.4")
}
func TestSerializeBindPort(t *testing.T) {

View File

@@ -2,6 +2,7 @@ package home
import (
"encoding/binary"
"net"
"strings"
"time"
@@ -15,7 +16,7 @@ import (
type RDNS struct {
dnsServer *dnsforward.Server
clients *clientsContainer
ipChannel chan string // pass data from DNS request handling thread to rDNS thread
ipChannel chan net.IP // pass data from DNS request handling thread to rDNS thread
// Contains IP addresses of clients to be resolved by rDNS
// If IP address is resolved, it stays here while it's inside Clients.
@@ -35,15 +36,15 @@ func InitRDNS(dnsServer *dnsforward.Server, clients *clientsContainer) *RDNS {
cconf.MaxCount = 10000
r.ipAddrs = cache.New(cconf)
r.ipChannel = make(chan string, 256)
r.ipChannel = make(chan net.IP, 256)
go r.workerLoop()
return &r
}
// Begin - add IP address to rDNS queue
func (r *RDNS) Begin(ip string) {
func (r *RDNS) Begin(ip net.IP) {
now := uint64(time.Now().Unix())
expire := r.ipAddrs.Get([]byte(ip))
expire := r.ipAddrs.Get(ip)
if len(expire) != 0 {
exp := binary.BigEndian.Uint64(expire)
if exp > now {
@@ -54,7 +55,7 @@ func (r *RDNS) Begin(ip string) {
expire = make([]byte, 8)
const ttl = 1 * 60 * 60
binary.BigEndian.PutUint64(expire, now+ttl)
_ = r.ipAddrs.Set([]byte(ip), expire)
_ = r.ipAddrs.Set(ip, expire)
if r.clients.Exists(ip, ClientSourceRDNS) {
return
@@ -70,7 +71,7 @@ func (r *RDNS) Begin(ip string) {
}
// Use rDNS to get hostname by IP address
func (r *RDNS) resolve(ip string) string {
func (r *RDNS) resolve(ip net.IP) string {
log.Tracef("Resolving host for %s", ip)
req := dns.Msg{}
@@ -83,7 +84,7 @@ func (r *RDNS) resolve(ip string) string {
},
}
var err error
req.Question[0].Name, err = dns.ReverseAddr(ip)
req.Question[0].Name, err = dns.ReverseAddr(ip.String())
if err != nil {
log.Debug("Error while calling dns.ReverseAddr(%s): %s", ip, err)
return ""
@@ -123,6 +124,6 @@ func (r *RDNS) workerLoop() {
continue
}
_, _ = r.clients.AddHost(ip, host, ClientSourceRDNS)
_, _ = r.clients.AddHost(ip.String(), host, ClientSourceRDNS)
}
}

View File

@@ -1,6 +1,7 @@
package home
import (
"net"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
@@ -16,6 +17,6 @@ func TestResolveRDNS(t *testing.T) {
clients := &clientsContainer{}
rdns := InitRDNS(dns, clients)
r := rdns.resolve("1.1.1.1")
r := rdns.resolve(net.IP{1, 1, 1, 1})
assert.Equal(t, "one.one.one.one", r, r)
}

View File

@@ -31,7 +31,7 @@ const (
type webConfig struct {
firstRun bool
BindHost string
BindHost net.IP
BindPort int
BetaBindPort int
PortHTTPS int
@@ -161,10 +161,11 @@ func (web *Web) Start() {
printHTTPAddresses("http")
errs := make(chan error, 2)
hostStr := web.conf.BindHost.String()
// we need to have new instance, because after Shutdown() the Server is not usable
web.httpServer = &http.Server{
ErrorLog: log.StdLog("web: http", log.DEBUG),
Addr: net.JoinHostPort(web.conf.BindHost, strconv.Itoa(web.conf.BindPort)),
Addr: net.JoinHostPort(hostStr, strconv.Itoa(web.conf.BindPort)),
Handler: withMiddlewares(Context.mux, limitRequestBody),
ReadTimeout: web.conf.ReadTimeout,
ReadHeaderTimeout: web.conf.ReadHeaderTimeout,
@@ -177,7 +178,7 @@ func (web *Web) Start() {
if web.conf.BetaBindPort != 0 {
web.httpServerBeta = &http.Server{
ErrorLog: log.StdLog("web: http", log.DEBUG),
Addr: net.JoinHostPort(web.conf.BindHost, strconv.Itoa(web.conf.BetaBindPort)),
Addr: net.JoinHostPort(hostStr, strconv.Itoa(web.conf.BetaBindPort)),
Handler: withMiddlewares(Context.mux, limitRequestBody, web.wrapIndexBeta),
ReadTimeout: web.conf.ReadTimeout,
ReadHeaderTimeout: web.conf.ReadHeaderTimeout,
@@ -236,7 +237,7 @@ func (web *Web) tlsServerLoop() {
web.httpsServer.cond.L.Unlock()
// prepare HTTPS server
address := net.JoinHostPort(web.conf.BindHost, strconv.Itoa(web.conf.PortHTTPS))
address := net.JoinHostPort(web.conf.BindHost.String(), strconv.Itoa(web.conf.PortHTTPS))
web.httpsServer.server = &http.Server{
ErrorLog: log.StdLog("web: https", log.DEBUG),
Addr: address,

View File

@@ -26,7 +26,7 @@ const (
// Whois - module context
type Whois struct {
clients *clientsContainer
ipChan chan string
ipChan chan net.IP
timeoutMsec uint
// Contains IP addresses of clients
@@ -46,7 +46,7 @@ func initWhois(clients *clientsContainer) *Whois {
cconf.MaxCount = 10000
w.ipAddrs = cache.New(cconf)
w.ipChan = make(chan string, 255)
w.ipChan = make(chan net.IP, 255)
go w.workerLoop()
return &w
}
@@ -183,9 +183,9 @@ func (w *Whois) queryAll(target string) (string, error) {
}
// Request WHOIS information
func (w *Whois) process(ip string) [][]string {
func (w *Whois) process(ip net.IP) [][]string {
data := [][]string{}
resp, err := w.queryAll(ip)
resp, err := w.queryAll(ip.String())
if err != nil {
log.Debug("Whois: error: %s IP:%s", err, ip)
return data
@@ -209,7 +209,7 @@ func (w *Whois) process(ip string) [][]string {
}
// Begin - begin requesting WHOIS info
func (w *Whois) Begin(ip string) {
func (w *Whois) Begin(ip net.IP) {
now := uint64(time.Now().Unix())
expire := w.ipAddrs.Get([]byte(ip))
if len(expire) != 0 {