initial commit
This commit is contained in:
46
cmd/root.go
Normal file
46
cmd/root.go
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "dtool",
|
||||
Short: "dns resolver probing tool",
|
||||
Long: `A tool for probing open resolvers for various purpose. The following modules are implemented.
|
||||
|
||||
Modules:
|
||||
upstream probe to get the upstream recursive resolvers of the given resolver as many as possible
|
||||
ttl probe to test if resolvers on the resolution path change the authoritative TTL value
|
||||
cache probe to enumerate the cache`,
|
||||
// Uncomment the following line if your bare application
|
||||
// has an action associated with it:
|
||||
// Run: func(cmd *cobra.Command, args []string) { },
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.dtool.yaml)")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
||||
32
cmd/upstream.go
Normal file
32
cmd/upstream.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
_ "dtool/prober"
|
||||
"dtool/utils"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var filename string
|
||||
var thread_num int
|
||||
var upstreamCmd = &cobra.Command{
|
||||
Use: "upstream",
|
||||
//Aliases: []string{"up", "stream"},
|
||||
Short: "probe upstream recursive resolvers",
|
||||
Long: `get the upstream recursive resolvers of the input resolvers
|
||||
input target can be added as an argument or as a file
|
||||
|
||||
-f input file with limited ip addresses (limit=50)
|
||||
-t number of goroutine`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
//prober.Get_upstream_ip(args[0])
|
||||
utils.SendTencentHttpdnsQuery()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
upstreamCmd.Flags().StringVarP(&filename, "file", "f", "", "input filename")
|
||||
upstreamCmd.Flags().IntVarP(&thread_num, "threads", "t", 10, "number of concurrent threads")
|
||||
rootCmd.AddCommand(upstreamCmd)
|
||||
}
|
||||
15
go.mod
Normal file
15
go.mod
Normal file
@@ -0,0 +1,15 @@
|
||||
module dtool
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/spf13/cobra v1.7.0
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/miekg/dns v1.1.54 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.2.0 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/tools v0.3.0 // indirect
|
||||
)
|
||||
20
go.sum
Normal file
20
go.sum
Normal file
@@ -0,0 +1,20 @@
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
|
||||
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
11
main.go
Normal file
11
main.go
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package main
|
||||
|
||||
import "dtool/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
133
prober/rdns_prober.go
Normal file
133
prober/rdns_prober.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package prober
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"dtool/utils"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
target string
|
||||
dict map[string]bool
|
||||
}
|
||||
|
||||
var dataset map[string][]string
|
||||
|
||||
func retrieve_ip(pool chan string, filename string) {
|
||||
cnt := 0
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
fmt.Printf("cannot open file %s\n", filename)
|
||||
return
|
||||
}
|
||||
fmt.Println("sending msg ...")
|
||||
reader := bufio.NewReader(f)
|
||||
for {
|
||||
s, err := reader.ReadString('\n')
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
s = strings.Trim(s, "\n")
|
||||
pool <- s
|
||||
cnt++
|
||||
if cnt%10 == 0 {
|
||||
fmt.Println(cnt)
|
||||
}
|
||||
}
|
||||
close(pool)
|
||||
}
|
||||
|
||||
func active_probe(n int, addr string) Data {
|
||||
target_ip := addr[:len(addr)-3]
|
||||
data := Data{target_ip, make(map[string]bool)}
|
||||
stop := 0
|
||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
for i := 0; i < n; i++ {
|
||||
subdomain := strings.Join([]string{strings.Replace(target_ip, ".", "-", -1), "echo", strconv.Itoa(i), timestamp}, "-")
|
||||
rdns_ip, err := utils.SendQuery(addr, subdomain)
|
||||
if err == nil {
|
||||
data.dict[rdns_ip] = true
|
||||
} else {
|
||||
stop += 1
|
||||
}
|
||||
if stop == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func upstream_prober(ip_pool chan string, data_pool chan Data, wg *sync.WaitGroup) {
|
||||
for {
|
||||
if s, ok := <-ip_pool; ok {
|
||||
addr := s + ":53"
|
||||
data := active_probe(20, addr)
|
||||
if data.dict != nil {
|
||||
data_pool <- data
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func create_probers(num int, ip_pool chan string, data_pool chan Data, wg *sync.WaitGroup) {
|
||||
for i := 0; i < num; i++ {
|
||||
wg.Add(1)
|
||||
go upstream_prober(ip_pool, data_pool, wg)
|
||||
}
|
||||
}
|
||||
|
||||
func store_data(pool chan Data, wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
for {
|
||||
var temp []string
|
||||
if data, ok := <-pool; ok {
|
||||
if len(data.dict) > 0 {
|
||||
for rdns := range data.dict {
|
||||
temp = append(temp, rdns)
|
||||
}
|
||||
dataset[data.target] = temp
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func Get_upstream_file(filename string, prober_num int) {
|
||||
dataset = map[string][]string{}
|
||||
ip_pool := make(chan string, 500)
|
||||
data_pool := make(chan Data, 200)
|
||||
var probe_tasks sync.WaitGroup
|
||||
var store_task sync.WaitGroup
|
||||
|
||||
go retrieve_ip(ip_pool, filename)
|
||||
create_probers(prober_num, ip_pool, data_pool, &probe_tasks)
|
||||
go store_data(data_pool, &store_task)
|
||||
probe_tasks.Wait()
|
||||
close(data_pool)
|
||||
store_task.Wait()
|
||||
utils.OutputJSON(dataset)
|
||||
}
|
||||
|
||||
func Get_upstream_ip(ip string) {
|
||||
dataset = make(map[string][]string)
|
||||
var temp []string
|
||||
addr := ip + ":53"
|
||||
data := active_probe(10, addr)
|
||||
for rdns := range data.dict {
|
||||
temp = append(temp, rdns)
|
||||
}
|
||||
dataset[data.target] = temp
|
||||
utils.OutputJSON(dataset)
|
||||
}
|
||||
55
utils/dns_utils.go
Normal file
55
utils/dns_utils.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type WrongAnswerError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *WrongAnswerError) Error() string {
|
||||
return fmt.Sprintf("Wrong Answer: %s", e.Message)
|
||||
}
|
||||
|
||||
func SendQuery(addr string, dn string) (string, error) {
|
||||
var (
|
||||
domain string
|
||||
rdns_ip string
|
||||
)
|
||||
if dn == "timestamp" {
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
domain = strings.Join([]string{timestamp, "-scan.echodns.xyz."}, "")
|
||||
} else {
|
||||
domain = strings.Join([]string{dn, ".echodns.xyz."}, "")
|
||||
}
|
||||
//fmt.Println(domain)
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(domain, dns.TypeA)
|
||||
m.RecursionDesired = true
|
||||
|
||||
res, err := dns.Exchange(m, addr)
|
||||
if err == nil {
|
||||
if len(res.Answer) == 1 {
|
||||
if a, ok := res.Answer[0].(*dns.A); ok {
|
||||
rdns_ip = a.A.String()
|
||||
} else {
|
||||
rdns_ip = ""
|
||||
err = &WrongAnswerError{
|
||||
Message: "Wrong Record Type",
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rdns_ip = ""
|
||||
err = &WrongAnswerError{
|
||||
Message: "Wrong Answer Section",
|
||||
}
|
||||
}
|
||||
}
|
||||
return rdns_ip, err
|
||||
}
|
||||
112
utils/httpdns_utils.go
Normal file
112
utils/httpdns_utils.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/des"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func pkcs5Padding(plaintext []byte, blocksize int) []byte {
|
||||
padding := blocksize - len(plaintext)%blocksize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(plaintext, padtext...)
|
||||
}
|
||||
|
||||
func pkcs5Unpadding(plaintext []byte) []byte {
|
||||
padding := plaintext[len(plaintext)-1]
|
||||
return plaintext[:len(plaintext)-int(padding)]
|
||||
}
|
||||
|
||||
func encryptDES(plaintext, key []byte) ([]byte, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blocksize := block.BlockSize()
|
||||
plaintext = pkcs5Padding(plaintext, blocksize)
|
||||
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
for i := 0; i < len(plaintext); i += blocksize {
|
||||
block.Encrypt(ciphertext[i:], plaintext[i:i+blocksize])
|
||||
}
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func decryptDES(ciphertext, key []byte) ([]byte, error) {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocksize := block.BlockSize()
|
||||
decryptedtext := make([]byte, len(ciphertext))
|
||||
for i := 0; i < len(ciphertext); i += blocksize {
|
||||
block.Decrypt(decryptedtext[i:], ciphertext[i:i+blocksize])
|
||||
}
|
||||
decryptedtext = pkcs5Unpadding(decryptedtext)
|
||||
return decryptedtext, nil
|
||||
}
|
||||
|
||||
func SendTencentHttpdnsQuery() {
|
||||
client := &http.Client{}
|
||||
domain := []byte("echo.echodns.xyz")
|
||||
key := []byte("046Ju3Cw")
|
||||
encrypted_bytes, err := encryptDES(domain, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encrypted_domain := hex.EncodeToString(encrypted_bytes)
|
||||
url := fmt.Sprintf("http://119.29.29.98/d?dn=%s&id=61188", encrypted_domain)
|
||||
fmt.Println(url)
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("create new request failed. Error: %s\n", err)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("request went wrong. Error: %s\n", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("read content failed. Error: %s\n", err)
|
||||
return
|
||||
}
|
||||
encrypted_response, _ := hex.DecodeString(string(body))
|
||||
decrypted_response, err := decryptDES(encrypted_response, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(decrypted_response))
|
||||
}
|
||||
|
||||
func SendAlicloudHttpdnsQurey() {
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", "http://203.107.1.33/149702/d?host=echo.echodns.xyz", nil)
|
||||
if err != nil {
|
||||
fmt.Printf("create new request failed. Error: %s\n", err)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Printf("request went wrong. Error: %s\n", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("read content failed. Error: %s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
15
utils/output_utils.go
Normal file
15
utils/output_utils.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func OutputJSON(data map[string][]string) {
|
||||
jsonstr, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
fmt.Println("JSON encoding error:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(jsonstr))
|
||||
}
|
||||
Reference in New Issue
Block a user