Skip to content

Instantly share code, notes, and snippets.

@ssut
Created February 16, 2017 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ssut/350892bc48b3ab7677b5647d27fea2a7 to your computer and use it in GitHub Desktop.
Save ssut/350892bc48b3ab7677b5647d27fea2a7 to your computer and use it in GitHub Desktop.
dnsoverhttps
package main
import (
"encoding/json"
"errors"
"net/url"
fasthttp "github.com/valyala/fasthttp"
)
const (
RCODE_NOERROR = iota
RCODE_FORMERR
RCODE_SERVFAIL
RCODE_NXDOMAIN
RCODE_NOTIME
RCODE_REFUSED
RCODE_YXDOMAIN
RCODE_XRRSET
RCODE_NOTAUTH
RCODE_NOTZONE
)
type DNSResponseJson struct {
Status int32 `json:"Status,omitempty"`
TC bool `json:"TC,omitempty"`
RD bool `json:"RD,omitempty"`
RA bool `json:"RA,omitempty"`
AD bool `json:"AD,omitempty"`
CD bool `json:"CD,omitempty"`
Question []DNSQuestion `json:"Question,omitempty"`
Answer []DNSRR `json:"Answer,omitempty"`
Authority []DNSRR `json:"Authority,omitempty"`
Additional []DNSRR `json:"Additional,omitempty"`
Edns_client_subnet string `json:"edns_client_subnet,omitempty"`
Comment string `json:"Comment,omitempty"`
}
type DNSQuestion struct {
Name string `json:"name,omitempty"`
Type int32 `json:"type,omitempty"`
}
type DNSRR struct {
Name string `json:"name,omitempty"`
Type int32 `json:"type,omitempty"`
TTL int32 `json:"TTL,omitempty"`
Data string `json:"data,omitempty"`
}
type DNSQueryClient struct {
client *fasthttp.HostClient
url url.URL
}
func NewDNSQueryClient() *DNSQueryClient {
client := &fasthttp.HostClient{
Addr: "dns.google.com",
}
baseURL := url.URL{
Scheme: "https",
Host: "dns.google.com",
Path: "/resolve",
}
queryClient := &DNSQueryClient{
client: client,
url: baseURL,
}
return queryClient
}
func (c *DNSQueryClient) generateQueryURL(name string, querytype string) string {
u := c.url
q := u.Query()
q.Set("name", name)
q.Set("type", querytype)
q.Set("edns_client_subnet", "0.0.0.0/0")
u.RawQuery = q.Encode()
return u.String()
}
func (c *DNSQueryClient) Query(name string, querytype string) (*DNSResponseJson, error) {
url := c.generateQueryURL(name, querytype)
status, resp, httperr := c.client.Get(nil, url)
if status != 200 || httperr != nil {
return nil, httperr
}
var dnsresp *DNSResponseJson
json.Unmarshal(resp, &dnsresp)
var err error
switch dnsresp.Status {
case RCODE_NOERROR:
err = nil
case RCODE_FORMERR:
err = errors.New("DNS Query Format Error")
case RCODE_SERVFAIL:
err = errors.New("Server failed to complete the DNS request")
case RCODE_NXDOMAIN:
err = errors.New("Domain name does not exist")
case RCODE_NOTIME:
err = errors.New("Function not implemented")
case RCODE_REFUSED:
err = errors.New("The server refused to answer for the reply")
case RCODE_YXDOMAIN:
err = errors.New("Name that should not exist, does exist")
case RCODE_XRRSET:
err = errors.New("RRset should not exist, does exist")
case RCODE_NOTAUTH:
err = errors.New("Server not authoritative for the zone")
case RCODE_NOTZONE:
err = errors.New("Name not in zone")
}
return dnsresp, err
}
package main
import (
"fmt"
"sync"
)
func main() {
client := NewDNSQueryClient()
domains := []string{
"www.naver.com",
"www.google.com",
"www.google.co.kr",
"www.daum.net",
"daum.net",
"ssut.me",
"translate.google.com",
"qiita.com",
}
tasks := make(chan string, 2)
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func(wg *sync.WaitGroup) {
for domain := range tasks {
resp, err := client.Query(domain, "A")
if err != nil {
panic(err)
}
fmt.Println(domain, "->", resp.Answer[len(resp.Answer)-1].Data)
}
wg.Done()
}(&wg)
}
for _, domain := range domains {
tasks <- domain
}
close(tasks)
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment