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