mirror of
https://github.com/AdguardTeam/dnsproxy.git
synced 2026-10-12 02:01:26 +00:00
Merge in GO/dnsproxy from ADG-8967-upd-golibs to master Squashed commit of the following: commit 4d65445abc60d8c64ffdedd24006f78f2d9abcba Author: f.setrakov <[email protected]> Date: Wed Oct 8 13:16:53 2025 +0300 all: rm default loggers commit 06be98ffdcbcabefd2f178f029c244ccd5244be7 Author: f.setrakov <[email protected]> Date: Tue Oct 7 19:07:59 2025 +0300 all: imp tests, upd golibs to tag commit e5894f62069324f017aba158b78eeca6d0da028f Author: f.setrakov <[email protected]> Date: Tue Oct 7 09:48:55 2025 +0300 upstream: imp tests commit 8e68b3987ede2633a471574a6841f45af938d2bd Author: f.setrakov <[email protected]> Date: Fri Oct 3 19:17:18 2025 +0300 all: upd golibs
117 lines
2.7 KiB
Go
117 lines
2.7 KiB
Go
package upstream
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/fs"
|
|
"log/slog"
|
|
"net/netip"
|
|
"slices"
|
|
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
"github.com/AdguardTeam/golibs/hostsfile"
|
|
)
|
|
|
|
// HostsResolver is a [Resolver] that looks into system hosts files, see
|
|
// [hostsfile].
|
|
type HostsResolver struct {
|
|
// strg contains all the hosts file data needed for lookups.
|
|
strg hostsfile.Storage
|
|
}
|
|
|
|
// NewHostsResolver is the resolver based on system hosts files.
|
|
func NewHostsResolver(hosts hostsfile.Storage) (hr *HostsResolver) {
|
|
return &HostsResolver{
|
|
strg: hosts,
|
|
}
|
|
}
|
|
|
|
// NewDefaultHostsResolver returns a resolver based on system hosts files
|
|
// provided by the [hostsfile.DefaultHostsPaths] and read from rootFSys. In
|
|
// case the file by any default path doesn't exist it adds a log debug record.
|
|
// If l is nil, [slog.Default] is used.
|
|
func NewDefaultHostsResolver(
|
|
ctx context.Context,
|
|
rootFSys fs.FS,
|
|
l *slog.Logger,
|
|
) (hr *HostsResolver, err error) {
|
|
if l == nil {
|
|
l = slog.Default()
|
|
}
|
|
|
|
paths, err := hostsfile.DefaultHostsPaths()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting default hosts paths: %w", err)
|
|
}
|
|
|
|
// The error is always nil here since no readers passed.
|
|
strg, _ := hostsfile.NewDefaultStorage(ctx, &hostsfile.DefaultStorageConfig{
|
|
Logger: l,
|
|
})
|
|
|
|
for _, filename := range paths {
|
|
err = parseHostsFile(ctx, rootFSys, strg, filename, l)
|
|
if err != nil {
|
|
// Don't wrap the error since it's already informative enough as is.
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return NewHostsResolver(strg), nil
|
|
}
|
|
|
|
// parseHostsFile reads a single hosts file from fsys and parses it into hosts.
|
|
func parseHostsFile(
|
|
ctx context.Context,
|
|
fsys fs.FS,
|
|
hosts hostsfile.Set,
|
|
filename string,
|
|
l *slog.Logger,
|
|
) (err error) {
|
|
f, err := fsys.Open(filename)
|
|
if err != nil {
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
l.DebugContext(ctx, "hosts file does not exist", "filename", filename)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Don't wrap the error since it's already informative enough as is.
|
|
return err
|
|
}
|
|
|
|
defer func() { err = errors.WithDeferred(err, f.Close()) }()
|
|
|
|
return hostsfile.Parse(ctx, hosts, f, nil)
|
|
}
|
|
|
|
// type check
|
|
var _ Resolver = (*HostsResolver)(nil)
|
|
|
|
// LookupNetIP implements the [Resolver] interface for *hostsResolver.
|
|
func (hr *HostsResolver) LookupNetIP(
|
|
context context.Context,
|
|
network string,
|
|
host string,
|
|
) (addrs []netip.Addr, err error) {
|
|
var ipMatches func(netip.Addr) (ok bool)
|
|
switch network {
|
|
case "ip4":
|
|
ipMatches = netip.Addr.Is4
|
|
case "ip6":
|
|
ipMatches = netip.Addr.Is6
|
|
case "ip":
|
|
return slices.Clone(hr.strg.ByName(host)), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported network %q", network)
|
|
}
|
|
|
|
for _, addr := range hr.strg.ByName(host) {
|
|
if ipMatches(addr) {
|
|
addrs = append(addrs, addr)
|
|
}
|
|
}
|
|
|
|
return addrs, nil
|
|
}
|