add google https dns support
parent
446fc256e6
commit
1f88a61e05
@ -0,0 +1,181 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/miekg/dns"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ServerAddr is Google dns server ip
|
||||
var ServerAddr = "74.125.200.100"
|
||||
var queryIPApi = "https://www.simicloud.com/media/httpbin/ip"
|
||||
|
||||
// HTTPDns struct
|
||||
type HTTPDns struct {
|
||||
myip string
|
||||
l sync.Mutex
|
||||
}
|
||||
|
||||
func (h *HTTPDns) getMyIP() string {
|
||||
if h.myip != "" {
|
||||
return h.myip
|
||||
}
|
||||
go h.queryMyIP()
|
||||
return ""
|
||||
}
|
||||
|
||||
type ipAPI struct {
|
||||
Ip string `json:"origin"`
|
||||
}
|
||||
|
||||
func (h *HTTPDns) queryMyIP() {
|
||||
h.l.Lock()
|
||||
defer h.l.Unlock()
|
||||
if h.myip != "" {
|
||||
//fmt.Printf("myip: %s\n", h.myip)
|
||||
return
|
||||
}
|
||||
//fmt.Println("get ip...")
|
||||
res, err := http.Get(queryIPApi)
|
||||
if err != nil {
|
||||
//fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
d, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
//fmt.Println(err)
|
||||
return
|
||||
}
|
||||
//fmt.Printf("%s\n", string(d))
|
||||
ip := ipAPI{}
|
||||
err = json.Unmarshal(d, &ip)
|
||||
if err != nil {
|
||||
//fmt.Println(err)
|
||||
return
|
||||
}
|
||||
//fmt.Printf("got: %s\n", ip.Ip)
|
||||
h.myip = ip.Ip
|
||||
}
|
||||
|
||||
func (h *HTTPDns) getMyNet() string {
|
||||
ip := h.getMyIP()
|
||||
if ip == "" {
|
||||
return ""
|
||||
}
|
||||
mask := net.IPv4Mask(255, 255, 255, 0)
|
||||
ipByte := net.ParseIP(ip)
|
||||
ipnet := net.IPNet{ipByte.Mask(mask), mask}
|
||||
return ipnet.String()
|
||||
}
|
||||
|
||||
// Exchange send query to server and return the response
|
||||
func (h *HTTPDns) Exchange(m *dns.Msg, addr string) (*dns.Msg, time.Duration, error) {
|
||||
name := m.Question[0].Name
|
||||
t := dns.TypeToString[m.Question[0].Qtype]
|
||||
mynet := h.getMyNet()
|
||||
r, err := query(name, t, mynet, "", addr)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
m1 := new(dns.Msg)
|
||||
|
||||
m1.SetRcode(m, r.Status)
|
||||
for _, rr := range r.Answer {
|
||||
_rr := fmt.Sprintf("%s %d IN %s %s", rr.Name, rr.TTL,
|
||||
dns.TypeToString[uint16(rr.Type)], rr.Data)
|
||||
|
||||
an, err := dns.NewRR(_rr)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
m1.Answer = append(m1.Answer, an)
|
||||
}
|
||||
return m1, 0, nil
|
||||
|
||||
}
|
||||
|
||||
// DefaultHTTPDnsClient default http dns client
|
||||
var DefaultHTTPDnsClient = &HTTPDns{}
|
||||
|
||||
// Response represent the dns response from server
|
||||
type Response struct {
|
||||
Status int
|
||||
TC bool
|
||||
RD bool
|
||||
RA bool
|
||||
AD bool
|
||||
CD bool
|
||||
Question []RR
|
||||
Answer []RR
|
||||
Additional []RR
|
||||
EDNSClientSubnet string `json:"edns_client_subnet"`
|
||||
Comment string
|
||||
}
|
||||
|
||||
// RR represent the RR record
|
||||
type RR struct {
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
TTL int
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
var httpclient = &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{ServerName: "dns.google.com"},
|
||||
TLSHandshakeTimeout: 3 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
func query(name, t, ednsClientSubnet, padding, srvAddr string) (*Response, error) {
|
||||
srvaddr := ServerAddr
|
||||
if srvAddr != "" {
|
||||
srvaddr = srvAddr
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Add("name", name)
|
||||
v.Add("type", t)
|
||||
|
||||
if ednsClientSubnet != "" {
|
||||
v.Add("edns_client_subnet", ednsClientSubnet)
|
||||
}
|
||||
|
||||
if padding != "" {
|
||||
v.Add("random_padding", padding)
|
||||
}
|
||||
|
||||
u := fmt.Sprintf("https://%s/resolve?%s", srvaddr, v.Encode())
|
||||
r, _ := http.NewRequest("GET", u, nil)
|
||||
r.Host = "dns.google.com"
|
||||
//r.URL.Host = "dns.google.com"
|
||||
|
||||
res, err := httpclient.Do(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := Response{}
|
||||
err = json.Unmarshal(data, &d)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d, nil
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/miekg/dns"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MyIP my ip
|
||||
type MyIP struct {
|
||||
IP string `json:"origin"`
|
||||
}
|
||||
|
||||
func myip() string {
|
||||
res, err := http.Get("https://www.simicloud.com/media/httpbin/ip")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer res.Body.Close()
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
ip := MyIP{}
|
||||
err = json.Unmarshal(data, &ip)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return ip.IP
|
||||
|
||||
}
|
||||
func TestQuery(t *testing.T) {
|
||||
|
||||
m := net.IPv4Mask(255, 255, 255, 0)
|
||||
ip1 := net.ParseIP(myip())
|
||||
ipnet := net.IPNet{ip1.Mask(m), m}
|
||||
r, err := query("www.taobao.com", "a", ipnet.String(), "", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Printf("%+v\n", r)
|
||||
|
||||
r, err = query("www.taobao.com", "a", "", "", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Printf("%+v\n", r)
|
||||
|
||||
}
|
||||
|
||||
func TestHttpsQuery(t *testing.T) {
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("www.taobao.com", dns.TypeA)
|
||||
m2, _, err := DefaultHTTPDnsClient.Exchange(m, ServerAddr)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(m2)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
m2, _, err = DefaultHTTPDnsClient.Exchange(m, ServerAddr)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(m2)
|
||||
}
|
||||
|
||||
func TestGetMyIP(t *testing.T) {
|
||||
a := DefaultHTTPDnsClient.getMyIP()
|
||||
time.Sleep(4 * time.Second)
|
||||
a = DefaultHTTPDnsClient.getMyIP()
|
||||
if a == "" {
|
||||
t.Errorf("get ip failed")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue