forked from google/namebench
-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathmain.go
186 lines (163 loc) · 5.62 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package main
import (
"embed"
"flag"
"fmt"
"github.com/cheggaaa/pb/v3"
"github.com/miekg/dns"
"log"
"os/exec"
"regexp"
"runtime"
"sort"
)
var VERSION = "custom"
var appConfiguration AppConfig
type AppConfig struct {
numberOfDomains int
debug bool
contest bool
nameserver string
}
//go:embed datasrc
var datasrc embed.FS
// process flags
func processFlags() {
var appConfig AppConfig
flagNumberOfDomains := flag.Int("domains", 100, "number of domains to be tested")
flagNameserver := flag.String("nameserver", "", "specify a nameserver instead of using defaults")
flagContest := flag.Bool("contest", true, "contest=true/false : enable or disable a contest against your locally configured DNS server (default true)")
flagDebug := flag.Bool("debug", false, "debug=true/false : enable or disable debugging (default false)")
flag.Parse()
appConfig.numberOfDomains = *flagNumberOfDomains
appConfig.debug = *flagDebug
appConfig.contest = *flagContest
appConfig.nameserver = *flagNameserver
appConfiguration = appConfig
}
// return the IP of the DNS used by the operating system
func getOSdns() string {
// get local dns ip
out, err := exec.Command("nslookup", ".").Output()
if appConfiguration.debug {
fmt.Println("DEBUG: nslookup output")
fmt.Printf("%s\n", out)
}
var errorCode = fmt.Sprint(err)
if err != nil {
if errorCode == "exit status 1" {
// newer versions of nslookup return error code 1 when executing "nslookup ." - but that's fine for us
_ = err
} else {
log.Print("Something went wrong obtaining the local DNS Server - is \"nslookup\" available?")
log.Fatal(err)
}
}
// fmt.Printf("%s\n", out)
re := regexp.MustCompile("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})|(([a-f0-9:]+:+)+[a-f0-9]+)")
// fmt.Printf("%q\n", re.FindString(string(out)))
var localDNS = re.FindString(string(out))
if appConfiguration.debug {
fmt.Println("DEBUG: dns server")
fmt.Printf("%s\n", localDNS)
}
return localDNS
}
// prints welcome messages
func printWelcome() {
fmt.Println("starting NAMEinator - version " + VERSION)
fmt.Printf("understood the following configuration: %+v\n", appConfiguration)
fmt.Println("-------------")
fmt.Println("NOTE: as this is an alpha - we rely on feedback - please report bugs and feature requests to https://github.com/mwiora/NAMEinator/issues and provide this output")
fmt.Println("OS: " + runtime.GOOS + " ARCH: " + runtime.GOARCH)
fmt.Println("-------------")
}
func processResults(nsStore *nsInfoMap) []NInfo {
nsStore.mutex.Lock()
defer nsStore.mutex.Unlock()
var nsStoreSorted []NInfo
for _, entry := range nsStore.ns {
nsResults := nsStoreGetMeasurement(nsStore, entry.IPAddr)
entry.rttAvg = nsResults.rttAvg
entry.rttMin = nsResults.rttMin
entry.rttMax = nsResults.rttMax
entry.ID = int64(nsResults.rttAvg)
nsStore.ns[entry.IPAddr] = entry
nsStoreSorted = append(nsStoreSorted, NInfo{entry.IPAddr, entry.Name, entry.Country, entry.Count, entry.ErrorsConnection, entry.ErrorsValidation, entry.ID, entry.rtt, entry.rttAvg, entry.rttMin, entry.rttMax})
}
sort.Slice(nsStoreSorted, func(i, j int) bool {
return nsStoreSorted[i].ID < nsStoreSorted[j].ID
})
return nsStoreSorted
}
// prints results
func printResults(nsStore *nsInfoMap, nsStoreSorted []NInfo) {
fmt.Println("")
fmt.Println("finished - presenting results: ") // TODO: Colorful representation in a table PLEASE
for _, nameserver := range nsStoreSorted {
fmt.Println("")
fmt.Println(nameserver.IPAddr + ": ")
fmt.Printf("Avg. [%v], Min. [%v], Max. [%v] ", nameserver.rttAvg, nameserver.rttMin, nameserver.rttMax)
if appConfiguration.debug {
fmt.Println(nsStoreGetRecord(nsStore, nameserver.IPAddr))
}
fmt.Println("")
}
}
// prints bye messages
func printBye() {
fmt.Println("")
fmt.Println("Au revoir!")
}
func prepareBenchmark(nsStore *nsInfoMap, dStore *dInfoMap) {
if appConfiguration.contest {
// we need to know who we are testing
var localDNS = getOSdns()
loadNameserver(nsStore, localDNS, "localhost")
}
prepareBenchmarkNameservers(nsStore)
prepareBenchmarkDomains(dStore)
}
func performBenchmark(nsStore *nsInfoMap, dStore *dInfoMap) {
// create progress bar
bar := pb.Full.Start(len(nsStore.ns) * len(dStore.d))
// initialize DNS client
c := new(dns.Client)
// to avoid overload against one server we will test all defined nameservers with one domain before proceeding
for _, domain := range dStore.d {
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{Name: domain.FQDN, Qtype: dns.TypeA, Qclass: dns.ClassINET}
// iterate through all given nameservers
for _, nameserver := range nsStore.ns {
in, rtt, err := c.Exchange(m1, "["+nameserver.IPAddr+"]"+":53")
_ = in
nsStoreSetRTT(nsStore, nameserver.IPAddr, rtt)
// increment progress bar
bar.Increment()
_ = err // TODO: Take care about errors during queries against the DNS - we will accept X fails
}
//fmt.Print(".")
}
bar.Finish()
}
func main() {
// process startup parameters and welcome
processFlags()
printWelcome()
// prepare storage for nameservers and domains
var nsStore = &nsInfoMap{ns: make(map[string]NInfo)}
var dStore = &dInfoMap{d: make(map[string]DInfo)}
// var nsStoreSorted []NInfo
// based on startup configuration we have to do some preparation
prepareBenchmark(nsStore, dStore)
// let's go benchmark - iterate through all domains
fmt.Println("LETS GO")
performBenchmark(nsStore, dStore)
// benchmark has been completed - now we have to tell the results and say good bye
var nsStoreSorted = processResults(nsStore)
printResults(nsStore, nsStoreSorted)
printBye()
}