dnscache

package module
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2022 License: MIT Imports: 9 Imported by: 0

README

DNS Lookup Cache

license Go Report Card Build Status Coverage godoc

The dnscache package provides a DNS cache layer to Go's net.Resolver.

Install

Install using the "go get" command:

go get -u github.com/rs/dnscache

Usage

Create a new instance and use it in place of net.Resolver. New names will be cached. Call the Refresh method at regular interval to update cached entries and cleanup unused ones.

resolver := &dnscache.Resolver{}

// First call will cache the result
addrs, err := resolver.LookupHost(context.Background(), "example.com")

// Subsequent calls will use the cached result
addrs, err = resolver.LookupHost(context.Background(), "example.com")

// Call to refresh will refresh names in cache. If you pass true, it will also
// remove cached names not looked up since the last call to Refresh. It is a good idea
// to call this method on a regular interval.
go func() {
    t := time.NewTicker(5 * time.Minute)
    defer t.Stop()
    for range t.C {
        resolver.Refresh(true)
    }
}()

If you are using an http.Transport, you can use this cache by specifying a DialContext function:

r := &dnscache.Resolver{}
t := &http.Transport{
    DialContext: func(ctx context.Context, network string, addr string) (conn net.Conn, err error) {
        host, port, err := net.SplitHostPort(addr)
        if err != nil {
            return nil, err
        }
        ips, err := r.LookupHost(ctx, host)
        if err != nil {
            return nil, err
        }
        for _, ip := range ips {
            var dialer net.Dialer
            conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip, port))
            if err == nil {
                break
            }
        }
        return
    },
}

In addition to the Refresh method, you can RefreshWithOptions. This method adds an option to persist resource records on failed lookups

r := &Resolver{}
options := dnscache.ResolverRefreshOptions{}
options.ClearUnused = true
options.PersistOnFailure = false
resolver.RefreshWithOptions(options)

Documentation

Overview

Example
r := &Resolver{}
t := &http.Transport{
	DialContext: func(ctx context.Context, network string, addr string) (conn net.Conn, err error) {
		host, port, err := net.SplitHostPort(addr)
		if err != nil {
			return nil, err
		}
		ips, err := r.LookupHost(ctx, host)
		if err != nil {
			return nil, err
		}
		for _, ip := range ips {
			var dialer net.Dialer
			conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip, port))
			if err == nil {
				break
			}
		}
		return
	},
}
c := &http.Client{Transport: t}
res, err := c.Get("http://httpbin.org/status/418")
if err == nil {
	fmt.Println(res.StatusCode)
}
Output:

418

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	DefaultCacheTimeout = 10 * time.Minute
)

Functions

func DialFunc

func DialFunc(resolver *Resolver, baseDialFunc dialFunc) dialFunc

DialFunc is a helper function which returns `net.DialContext` function. It randomly fetches an IP from the DNS cache and dials it by the given dial function. It dials one by one and returns first connected `net.Conn`. If it fails to dial all IPs from cache it returns first error. If no baseDialFunc is given, it sets default dial function.

You can use returned dial function for `http.Transport.DialContext`.

In this function, it uses functions from `rand` package. To make it really random, you MUST call `rand.Seed` and change the value from the default in your application

Example
resolver, _ := New(3*time.Second, 5*time.Second, 10*time.Minute, &ResolverRefreshOptions{})

// You can create a HTTP client which selects an IP from dnscache
// randomly and dials it.
rand.Seed(time.Now().UTC().UnixNano()) // You MUST run in once in your application
client := http.Client{
	Transport: &http.Transport{
		DialContext: DialFunc(resolver, nil),
	},
}

// Do what you want.
_ = client
Output:

Types

type ConcurrentMapSlice added in v0.0.3

type ConcurrentMapSlice struct {
	// contains filtered or unexported fields
}

type DNSResolver

type DNSResolver interface {
	LookupHost(ctx context.Context, host string) (addrs []string, err error)
	LookupAddr(ctx context.Context, addr string) (names []string, err error)
}

type Resolver

type Resolver struct {
	// Timeout defines the maximum allowed time allowed for a lookup.
	Timeout time.Duration

	// Resolver is used to perform actual DNS lookup. If nil,
	// net.DefaultResolver is used instead.
	Resolver DNSResolver

	// OnCacheMiss is executed if the host or address is not included in
	// the cache and the default lookup is executed.
	OnCacheMiss func()

	// cache timeout, when cache will expire, then refresh the key
	CacheTimeout time.Duration
	// 缓存到期时间需要大于2倍刷新时间
	// 自动刷新时间间隔
	RefreshTime time.Duration
	// contains filtered or unexported fields
}

func New

func New(freq time.Duration, lookupTimeout time.Duration, cacheTimeout time.Duration, options *ResolverRefreshOptions) (*Resolver, error)

New initializes DNS cache resolver and starts auto refreshing in a new goroutine. To stop refreshing, call `Stop()` function.

func (*Resolver) LookupAddr

func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error)

LookupAddr performs a reverse lookup for the given address, returning a list of names mapping to that address.

func (*Resolver) LookupHost

func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error)

LookupHost looks up the given host using the local resolver. It returns a slice of that host's addresses.

func (*Resolver) Refresh

func (r *Resolver) Refresh(clearUnused bool)

func (*Resolver) RefreshWithOptions

func (r *Resolver) RefreshWithOptions(options ResolverRefreshOptions)

func (*Resolver) Stop

func (r *Resolver) Stop()

Stop stops auto refreshing.

type ResolverRefreshOptions

type ResolverRefreshOptions struct {
	ClearUnused      bool
	PersistOnFailure bool
	// ClearUnused 方案是,在上一个刷新时间周期里若缓存没有被访问则删除
	// ClearUnused 方案,在每次访问缓存时需要加读锁和写锁,性能不太好
	// 如果采用 CacheExpireUnused 缓存过期方案,ClearUnused 策略便不使用了
	CacheExpireUnused bool
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL