Skip to content

Instantly share code, notes, and snippets.

@cs8425
Last active March 5, 2023 05:17
Show Gist options
  • Save cs8425/107e01a0652f1f1f6e033b5b68364b5e to your computer and use it in GitHub Desktop.
Save cs8425/107e01a0652f1f1f6e033b5b68364b5e to your computer and use it in GitHub Desktop.
DNS resolve workaround for android in pure go
package main
import (
"fmt"
"net"
"sync"
"time"
_ "unsafe"
)
// DNS resolve workaround for android in pure go
//go:linkname defaultNS net.defaultNS
var defaultNS []string
// need to keep sync with go version
//go:linkname resolvConf net.resolvConf
var resolvConf resolverConfig
// copy from /src/net/dnsconfig_unix.go
type dnsConfig struct {
servers []string // server addresses (in host:port form) to use
search []string // rooted suffixes to append to local name
ndots int // number of dots in name to trigger absolute lookup
timeout time.Duration // wait before giving up on a query, including retries
attempts int // lost packets before giving up on server
rotate bool // round robin among servers
unknownOpt bool // anything unknown was encountered
lookup []string // OpenBSD top-level database "lookup" order
err error // any error that occurs during open of resolv.conf
mtime time.Time // time of resolv.conf modification
soffset uint32 // used by serverOffset
}
// copy from /src/net/dnsclient_unix.go
type resolverConfig struct {
initOnce sync.Once // guards init of resolverConfig
// ch is used as a semaphore that only allows one lookup at a
// time to recheck resolv.conf.
ch chan struct{} // guards lastChecked and modTime
lastChecked time.Time // last time resolv.conf was checked
mu sync.RWMutex // protects dnsConfig
dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups
}
//go:linkname (*resolverConfig).tryUpdate net.(*resolverConfig).tryUpdate
func (conf *resolverConfig) tryUpdate(name string)
// need to put a empty .s file
func setDefaultNS(addrs []string, loadFromSystem bool) {
if resolvConf.dnsConfig == nil {
resolvConf.tryUpdate("")
}
if loadFromSystem {
now := time.Now()
resolvConf.lastChecked = now.Add(-6 * time.Second)
resolvConf.dnsConfig.mtime = now
}
resolvConf.dnsConfig.servers = addrs
defaultNS = addrs
}
// --------------
func test() {
ips, err := net.LookupIP("google.com")
if err != nil {
fmt.Printf("Could not get IPs: %v\n", err)
return
}
fmt.Println("IPs:", ips)
}
func main() {
// force use a non-exist DNS server
setDefaultNS([]string{"127.0.0.1:5300"}, false)
test() // error
fmt.Println("------------------")
// force use a list of DNS server
setDefaultNS([]string{"8.8.8.8:53", "1.1.1.1:53"}, false)
test() // ok
fmt.Println("------------------")
// set DNS & try reload from system config
setDefaultNS([]string{"127.0.0.1:5300"}, true)
// check & test net.defaultNS
test() // ok
fmt.Println("------------------")
}
package main
import (
"fmt"
"net"
_ "unsafe"
)
// DNS resolve workaround for android in pure go
// this only work before any Lookup call and net.dnsReadConfig() failed
//go:linkname defaultNS net.defaultNS
var defaultNS []string
func setDefaultNS2(addrs []string) {
defaultNS = addrs
}
// --------------
func test() {
ips, err := net.LookupIP("google.com")
if err != nil {
fmt.Printf("Could not get IPs: %v\n", err)
return
}
fmt.Println("IPs:", ips)
}
func main() {
// print net.defaultNS
fmt.Println("use DNS", defaultNS)
//test() // should setup before any call!!
fmt.Println("------------------")
// set net.defaultNS
setDefaultNS2([]string{"8.8.8.8:53", "1.1.1.1:53"})
// check & test net.defaultNS
fmt.Println("use DNS", defaultNS)
test()
fmt.Println("------------------")
}
@mtibben
Copy link

mtibben commented Sep 3, 2020

Thanks @cs8425, I've turned this into an importable library at https://github.com/mtibben/androiddnsfix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment