Skip to content

Commit

Permalink
Merge branch 'master' into 3136-show-default
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Jun 1, 2021
2 parents 76e8492 + e17e1f2 commit 69e402c
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 208 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ and this project adheres to

- Output of the default addresses of the upstreams used for resolving PTRs for
private addresses ([#3136]).
- Detection and handling of recurrent requests ([#3185]).
- Detection and handling of recurrent PTR requests for locally-served addresses
([#3185]).
- The ability to completely disable reverse DNS resolving of IPs from
locally-served networks ([#3184]).
- New flag `--local-frontend` to serve dinamically changeable frontend files
Expand All @@ -38,6 +39,7 @@ released by then.

### Fixed

- Domain name case in responses ([#3194]).
- Custom upstreams selection for clients with client IDs in DNS-over-TLS and
DNS-over-HTTP ([#3186]).
- Incorrect client-based filtering applying logic ([#2875]).
Expand All @@ -49,6 +51,7 @@ released by then.
[#3184]: https://github.com/AdguardTeam/AdGuardHome/issues/3184
[#3185]: https://github.com/AdguardTeam/AdGuardHome/issues/3185
[#3186]: https://github.com/AdguardTeam/AdGuardHome/issues/3186
[#3194]: https://github.com/AdguardTeam/AdGuardHome/issues/3194
[#3198]: https://github.com/AdguardTeam/AdGuardHome/issues/3198


Expand Down
79 changes: 40 additions & 39 deletions internal/aghnet/etchostscontainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package aghnet

import (
"bufio"
"io"
"net"
"os"
"path/filepath"
Expand Down Expand Up @@ -231,40 +230,53 @@ func (ehc *EtcHostsContainer) updateTableRev(tableRev map[string][]string, newHo
log.Debug("etchostscontainer: added reverse-address %s -> %s", ipStr, newHost)
}

// Read IP-hostname pairs from file
// Multiple hostnames per line (per one IP) is supported.
func (ehc *EtcHostsContainer) load(table map[string][]net.IP, tableRev map[string][]string, fn string) {
// parseHostsLine parses hosts from the fields.
func parseHostsLine(fields []string) (hosts []string) {
for _, f := range fields {
hashIdx := strings.IndexByte(f, '#')
if hashIdx == 0 {
// The rest of the fields are a part of the comment.
// Skip immediately.
return
} else if hashIdx > 0 {
// Only a part of the field is a comment.
hosts = append(hosts, f[:hashIdx])

return hosts
}

hosts = append(hosts, f)
}

return hosts
}

// load reads IP-hostname pairs from the hosts file. Multiple hostnames per
// line for one IP are supported.
func (ehc *EtcHostsContainer) load(
table map[string][]net.IP,
tableRev map[string][]string,
fn string,
) {
f, err := os.Open(fn)
if err != nil {
log.Error("etchostscontainer: %s", err)

return
}

defer func() {
derr := f.Close()
if derr != nil {
log.Error("etchostscontainer: closing file: %s", err)
}
}()

r := bufio.NewReader(f)
log.Debug("etchostscontainer: loading hosts from file %s", fn)

for done := false; !done; {
var line string
line, err = r.ReadString('\n')
if err == io.EOF {
done = true
} else if err != nil {
log.Error("etchostscontainer: %s", err)

return
}

line = strings.TrimSpace(line)
if len(line) == 0 || line[0] == '#' {
continue
}

s := bufio.NewScanner(f)
for s.Scan() {
line := strings.TrimSpace(s.Text())
fields := strings.Fields(line)
if len(fields) < 2 {
continue
Expand All @@ -275,28 +287,17 @@ func (ehc *EtcHostsContainer) load(table map[string][]net.IP, tableRev map[strin
continue
}

for i := 1; i != len(fields); i++ {
host := fields[i]
if len(host) == 0 {
break
}

sharp := strings.IndexByte(host, '#')
if sharp == 0 {
// Skip the comments.
break
} else if sharp > 0 {
host = host[:sharp]
}

hosts := parseHostsLine(fields[1:])
for _, host := range hosts {
ehc.updateTable(table, host, ip)
ehc.updateTableRev(tableRev, host, ip)
if sharp >= 0 {
// Skip the comments again.
break
}
}
}

err = s.Err()
if err != nil {
log.Error("etchostscontainer: %s", err)
}
}

// onlyWrites is a filter for (*fsnotify.Watcher).Events.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ func prepareTestFile(t *testing.T) (f *os.File) {
dir := t.TempDir()

f, err := os.CreateTemp(dir, "")
require.Nil(t, err)
require.NoError(t, err)
require.NotNil(t, f)

t.Cleanup(func() {
assert.Nil(t, f.Close())
assert.NoError(t, f.Close())
})

return f
Expand All @@ -37,7 +38,7 @@ func assertWriting(t *testing.T, f *os.File, strs ...string) {

for _, str := range strs {
n, err := f.WriteString(str)
require.Nil(t, err)
require.NoError(t, err)
assert.Equal(t, n, len(str))
}
}
Expand Down Expand Up @@ -77,16 +78,16 @@ func TestEtcHostsContainerResolution(t *testing.T) {
t.Run("ptr", func(t *testing.T) {
testCases := []struct {
wantIP string
wantLen int
wantHost string
wantLen int
}{
{wantIP: "127.0.0.1", wantLen: 2, wantHost: "host"},
{wantIP: "::1", wantLen: 1, wantHost: "localhost"},
{wantIP: "127.0.0.1", wantHost: "host", wantLen: 2},
{wantIP: "::1", wantHost: "localhost", wantLen: 1},
}

for _, tc := range testCases {
a, err := dns.ReverseAddr(tc.wantIP)
require.Nil(t, err)
require.NoError(t, err)

a = strings.TrimSuffix(a, ".")
hosts := ehc.ProcessReverse(a, dns.TypePTR)
Expand Down Expand Up @@ -114,7 +115,7 @@ func TestEtcHostsContainerFSNotify(t *testing.T) {
t.Cleanup(ehc.Close)

assertWriting(t, f, "127.0.0.2 newhost\n")
require.Nil(t, f.Sync())
require.NoError(t, f.Sync())

// Wait until fsnotify has triggerred and processed the
// file-modification event.
Expand Down
49 changes: 25 additions & 24 deletions internal/aghnet/net_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,40 +68,41 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) {
return false, ErrNoStaticIPInfo
}

// findIfaceLine scans s until it finds the line that declares an interface with
// the given name. If findIfaceLine can't find the line, it returns false.
func findIfaceLine(s *bufio.Scanner, name string) (ok bool) {
for s.Scan() {
line := strings.TrimSpace(s.Text())
fields := strings.Fields(line)
if len(fields) == 2 && fields[0] == "interface" && fields[1] == name {
return true
}
}

return false
}

// 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
ifaceFound := findIfaceLine(s, ifaceName)
if !ifaceFound {
return false, s.Err()
}

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] == "static" &&
strings.HasPrefix(fields[1], "ip_address=") {
return true, s.Err()
}

if len(fields) == 2 && fields[0] == "interface" && fields[1] == ifaceName {
// The interface found.
withinInterfaceCtx = true
if len(fields) > 0 && fields[0] == "interface" {
// Another interface found.
break
}
}

Expand Down
13 changes: 0 additions & 13 deletions internal/aghnet/systemresolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package aghnet
import (
"time"

"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
)

Expand All @@ -25,18 +24,6 @@ type SystemResolvers interface {
refresh() (err error)
}

const (
// errBadAddrPassed is returned when dialFunc can't parse an IP address.
errBadAddrPassed errors.Error = "the passed string is not a valid IP address"

// errFakeDial is an error which dialFunc is expected to return.
errFakeDial errors.Error = "this error signals the successful dialFunc work"

// errUnexpectedHostFormat is returned by validateDialedHost when the host has
// more than one percent sign.
errUnexpectedHostFormat errors.Error = "unexpected host format"
)

// refreshWithTicker refreshes the cache of sr after each tick form tickCh.
func refreshWithTicker(sr SystemResolvers, tickCh <-chan time.Time) {
defer log.OnPanic("systemResolvers")
Expand Down
12 changes: 12 additions & 0 deletions internal/aghnet/systemresolvers_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ type systemResolvers struct {
addrsLock sync.RWMutex
}

const (
// errBadAddrPassed is returned when dialFunc can't parse an IP address.
errBadAddrPassed errors.Error = "the passed string is not a valid IP address"

// errFakeDial is an error which dialFunc is expected to return.
errFakeDial errors.Error = "this error signals the successful dialFunc work"

// errUnexpectedHostFormat is returned by validateDialedHost when the host has
// more than one percent sign.
errUnexpectedHostFormat errors.Error = "unexpected host format"
)

func (sr *systemResolvers) refresh() (err error) {
defer func() { err = errors.Annotate(err, "systemResolvers: %w") }()

Expand Down
Loading

0 comments on commit 69e402c

Please sign in to comment.