initial commit
This commit is contained in:
12
go.mod
Normal file
12
go.mod
Normal file
@@ -0,0 +1,12 @@
|
||||
module fpdns_client
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/miekg/dns v1.1.58
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
)
|
||||
11
go.sum
Normal file
11
go.sum
Normal file
@@ -0,0 +1,11 @@
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
13
main.go
Normal file
13
main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"fpdns_client/methods"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, err := methods.BehaviorTest("127.0.0.1", "127.0.0.1", "8888", "echodns.xyz")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
96
methods/test_methods.go
Normal file
96
methods/test_methods.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package methods
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"fpdns_client/utils"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func ProbeStart(addr string, sld string) (int, error) {
|
||||
time_now := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
domain := dns.Fqdn("start-" + time_now + "." + sld)
|
||||
res, err := utils.DNSQuery(addr, domain, false, 1, 1, false)
|
||||
if err == nil {
|
||||
if len(res.Answer) == 1 {
|
||||
if a, ok := res.Answer[0].(*dns.A); ok {
|
||||
ip_str := a.A.String()
|
||||
ip_val, _ := utils.IPv4ToInt(ip_str)
|
||||
return int(ip_val), nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0, err
|
||||
}
|
||||
return 0, errors.New("wrong token response")
|
||||
}
|
||||
|
||||
func InitProbe(addr string, token int, sld string) error {
|
||||
time_now := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
domain := dns.Fqdn("init-" + time_now + "-" + strconv.Itoa(token) + "." + sld)
|
||||
res, err := utils.DNSQuery(addr, domain, true, 1, 1, false)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if len(res.Answer) == 1 {
|
||||
if a, ok := res.Answer[0].(*dns.A); ok {
|
||||
ip_str := a.A.String()
|
||||
if ip_str == "200.200.200.200" {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return errors.New("invalid Reply Code")
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("init query failure")
|
||||
}
|
||||
|
||||
func ProbeTerminate(addr string, token int, sld string) error {
|
||||
time_now := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
domain := dns.Fqdn("end-" + time_now + "-" + strconv.Itoa(token) + "." + sld)
|
||||
res, err := utils.DNSQuery(addr, domain, false, 1, 1, false)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if len(res.Answer) == 1 {
|
||||
if a, ok := res.Answer[0].(*dns.A); ok {
|
||||
ip_str := a.A.String()
|
||||
if ip_str == "200.200.200.200" {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return errors.New("invalid Reply Code")
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("terminate query failure")
|
||||
}
|
||||
|
||||
func BehaviorTest(target string, server string, api_port string, sld string) (string, error) {
|
||||
target_addr := target + ":53"
|
||||
server_addr := server + ":53"
|
||||
result_addr := server + ":" + api_port
|
||||
token, err := ProbeStart(server_addr, sld)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = InitProbe(target_addr, token, sld)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = ProbeTerminate(server_addr, token, sld)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, err := utils.GetResult(result_addr, token)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
json_str, _ := utils.OutputJson(data)
|
||||
fmt.Println(json_str)
|
||||
return "", nil
|
||||
}
|
||||
31
utils/dns_utils.go
Normal file
31
utils/dns_utils.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// dns utils
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// build the question section of a dns packet
|
||||
func QuestionMaker(domain string, qclass uint16, qtype uint16) *dns.Question {
|
||||
return &dns.Question{Name: dns.Fqdn(domain), Qtype: qtype, Qclass: qclass}
|
||||
}
|
||||
|
||||
// build a specific query message
|
||||
func QueryMaker(domain string, rd bool, qclass uint16, qtype uint16, edns bool) *dns.Msg {
|
||||
msg := new(dns.Msg)
|
||||
msg.Id = dns.Id()
|
||||
msg.RecursionDesired = rd
|
||||
msg.Question = make([]dns.Question, 1)
|
||||
msg.Question[0] = *QuestionMaker(domain, qclass, qtype)
|
||||
if edns {
|
||||
msg = msg.SetEdns0(4096, false)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// query and receive the response
|
||||
func DNSQuery(addr string, domain string, rd bool, qclass uint16, qtype uint16, edns bool) (*dns.Msg, error) {
|
||||
msg := QueryMaker(domain, rd, qclass, qtype, edns)
|
||||
res, err := dns.Exchange(msg, addr)
|
||||
return res, err
|
||||
}
|
||||
68
utils/other_utils.go
Normal file
68
utils/other_utils.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ResolverBehavior struct {
|
||||
Dnssec bool `json:"dnssec"`
|
||||
QnameEncode bool `json:"0x20"`
|
||||
QueryMerge int `json:"merge_dup"`
|
||||
MaxNsDepth int `json:"max_ns_depth"`
|
||||
MaxCnameDepth int `json:"max_cname_depth"`
|
||||
RetryLimit int `json:"retry_limit"`
|
||||
FetchLimit int `json:"fetch_limit"`
|
||||
TimeoutStart int64 `json:"timeout_start"`
|
||||
TimeoutEnd int64 `json:"timeout_end"`
|
||||
}
|
||||
|
||||
func IsValidIP(ip string) bool {
|
||||
res := net.ParseIP(ip)
|
||||
return res != nil
|
||||
}
|
||||
|
||||
func IPv4ToInt(ip string) (uint32, error) {
|
||||
if !IsValidIP(ip) {
|
||||
return 0, fmt.Errorf("invalid IP address: %s", ip)
|
||||
}
|
||||
labels := strings.Split(ip, ".")
|
||||
var result uint32
|
||||
for _, label := range labels {
|
||||
label_val, _ := strconv.Atoi(label)
|
||||
result = (result << 8) | uint32(label_val)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetResult(addr string, token int) (*ResolverBehavior, error) {
|
||||
data := new(ResolverBehavior)
|
||||
url := "http://" + addr + "/results/" + strconv.Itoa(token)
|
||||
response, err := http.Get(url)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return data, fmt.Errorf("wrong HTTP status code : %v", response.StatusCode)
|
||||
}
|
||||
|
||||
err = json.NewDecoder(response.Body).Decode(data)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func OutputJson(data interface{}) (string, error) {
|
||||
json_byte, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(json_byte), nil
|
||||
}
|
||||
Reference in New Issue
Block a user