| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- package local
- import (
- "os"
- "runtime"
- "strings"
- "sync"
- "sync/atomic"
- "time"
- )
- const (
- // net.maxDNSPacketSize
- maxDNSPacketSize = 1232
- )
- type resolverConfig struct {
- initOnce sync.Once
- ch chan struct{}
- lastChecked time.Time
- dnsConfig atomic.Pointer[dnsConfig]
- }
- var resolvConf resolverConfig
- func getSystemDNSConfig() *dnsConfig {
- resolvConf.tryUpdate("/etc/resolv.conf")
- return resolvConf.dnsConfig.Load()
- }
- func (conf *resolverConfig) init() {
- conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
- conf.lastChecked = time.Now()
- conf.ch = make(chan struct{}, 1)
- }
- func (conf *resolverConfig) tryUpdate(name string) {
- conf.initOnce.Do(conf.init)
- if conf.dnsConfig.Load().noReload {
- return
- }
- if !conf.tryAcquireSema() {
- return
- }
- defer conf.releaseSema()
- now := time.Now()
- if conf.lastChecked.After(now.Add(-5 * time.Second)) {
- return
- }
- conf.lastChecked = now
- if runtime.GOOS != "windows" {
- var mtime time.Time
- if fi, err := os.Stat(name); err == nil {
- mtime = fi.ModTime()
- }
- if mtime.Equal(conf.dnsConfig.Load().mtime) {
- return
- }
- }
- dnsConf := dnsReadConfig(name)
- conf.dnsConfig.Store(dnsConf)
- }
- func (conf *resolverConfig) tryAcquireSema() bool {
- select {
- case conf.ch <- struct{}{}:
- return true
- default:
- return false
- }
- }
- func (conf *resolverConfig) releaseSema() {
- <-conf.ch
- }
- type dnsConfig struct {
- servers []string
- search []string
- ndots int
- timeout time.Duration
- attempts int
- rotate bool
- unknownOpt bool
- lookup []string
- err error
- mtime time.Time
- soffset uint32
- singleRequest bool
- useTCP bool
- trustAD bool
- noReload bool
- }
- func (c *dnsConfig) serverOffset() uint32 {
- if c.rotate {
- return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start
- }
- return 0
- }
- func (conf *dnsConfig) nameList(name string) []string {
- l := len(name)
- rooted := l > 0 && name[l-1] == '.'
- if l > 254 || l == 254 && !rooted {
- return nil
- }
- if rooted {
- if avoidDNS(name) {
- return nil
- }
- return []string{name}
- }
- hasNdots := strings.Count(name, ".") >= conf.ndots
- name += "."
- // l++
- names := make([]string, 0, 1+len(conf.search))
- if hasNdots && !avoidDNS(name) {
- names = append(names, name)
- }
- for _, suffix := range conf.search {
- fqdn := name + suffix
- if !avoidDNS(fqdn) && len(fqdn) <= 254 {
- names = append(names, fqdn)
- }
- }
- if !hasNdots && !avoidDNS(name) {
- names = append(names, name)
- }
- return names
- }
- func avoidDNS(name string) bool {
- if name == "" {
- return true
- }
- if name[len(name)-1] == '.' {
- name = name[:len(name)-1]
- }
- return strings.HasSuffix(name, ".onion")
- }
|