Skip to content

Commit

Permalink
Merge pull request #65 from Tantalor93/duration
Browse files Browse the repository at this point in the history
  • Loading branch information
Tantalor93 committed Jul 8, 2022
2 parents 11c01f4 + 2d4f28c commit 7d839c7
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 6 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This tool supports wide variety of options to customize DNS benchmark and benchm
* benchmark DNS servers with IPv4 and IPv6 addresses (for example GoogleDNS `8.8.8.8` and `2001:4860:4860::8888`)
* benchmark DNS servers with all kinds of query types (A, AAAA, CNAME, HTTPS, ...)
* benchmark DNS servers with a lot of parallel queries and connections (`--number`, `--concurrency` options)
* benchmark DNS servers for a specified duration (`--duration` option)
* benchmark DNS servers using DNS queries over UDP or TCP
* benchmark DNS servers with DoT
* benchmark DNS servers using DoH
Expand Down Expand Up @@ -74,7 +75,7 @@ Flags:
-s, --server="127.0.0.1" DNS server IP:port to test. IPv6 is also supported, for example '[fddd:dddd::]:53'. Also DoH servers are supported such as `https://1.1.1.1/dns-query`, when such server is provided, the benchmark automatically switches to
the use of DoH. Note that path on which DoH server handles requests (like `/dns-query`) has to be provided as well.
-t, --type=A ... Query type. Repeatable flag. If multiple query types are specified then each query will be duplicated for each type.
-n, --number=1 How many times the provided queries are repeated. Note that the total number of queries issued = types*number*concurrency*len(queries).
-n, --number=NUMBER How many times the provided queries are repeated. Note that the total number of queries issued = types*number*concurrency*len(queries).
-c, --concurrency=1 Number of concurrent queries to issue.
-l, --rate-limit=0 Apply a global questions / second rate limit.
--query-per-conn=0 Queries on a connection before creating a new one. 0: unlimited
Expand All @@ -99,11 +100,13 @@ Flags:
--plotf=png Format of graphs. Supported formats png, svg, pdf.
--doh-method=post HTTP method to use for DoH requests
--doh-protocol=1.1 HTTP protocol to use for DoH requests
-d, --duration=1m Specifies for how long the benchmark should be executing, the benchmark will run for the specified time while sending DNS requests in infinite loop based on data source. After running for specified duration, the benchmark
is cancelled. This option is exclusive with --number option. The duration is specified in GO duration format e.g. 10s, 15m, 1h.
--version Show application version.
Args:
<queries> Queries to issue. Can be local file referenced using @<file-path>, for example @data/2-domains.Can also be resource accessible using HTTP, like https://raw.githubusercontent.com/Tantalor93/dnspyre/master/data/1000-domains, in that case the
file will be downloaded and saved inmemory.
<queries> Queries to issue. Can be local file referenced using @<file-path>, for example @data/2-domains.Can also be resource accessible using HTTP, like https://raw.githubusercontent.com/Tantalor93/dnspyre/master/data/1000-domains, in that case the
file will be downloaded and saved inmemory.
```

## Examples
Expand Down
19 changes: 18 additions & 1 deletion cmd/dnspyre/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ type Benchmark struct {

Queries []string

Duration time.Duration

// internal variable so we do not have to parse the address with each request.
useDoH bool
}
Expand All @@ -108,6 +110,15 @@ func (b *Benchmark) normalize() {
if !strings.Contains(b.Server, ":") && !b.useDoH {
b.Server += ":53"
}

if b.Count == 0 && b.Duration == 0 {
b.Count = 1
}

if b.Duration > 0 && b.Count > 0 {
fmt.Fprintln(os.Stderr, "--number and --duration is specified at once, only one can be used")
os.Exit(1)
}
}

// Run executes benchmark.
Expand Down Expand Up @@ -137,6 +148,12 @@ func (b *Benchmark) Run(ctx context.Context) []*ResultStats {
}
}

if b.Duration != 0 {
timeoutCtx, cancel := context.WithTimeout(ctx, b.Duration)
ctx = timeoutCtx
defer cancel()
}

if !b.Silent {
fmt.Printf("Using %d hostnames\n", len(questions))
}
Expand Down Expand Up @@ -222,7 +239,7 @@ func (b *Benchmark) Run(ctx context.Context) []*ResultStats {
rando := rand.New(rand.NewSource(time.Now().Unix()))

var i int64
for i = 0; i < b.Count; i++ {
for i = 0; i < b.Count || b.Duration != 0; i++ {
for _, qt := range qTypes {
for _, q := range questions {
if rando.Float64() > b.Probability {
Expand Down
29 changes: 29 additions & 0 deletions cmd/dnspyre/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,35 @@ func Test_download_external_datasource_using_http(t *testing.T) {
assertResult(t, rs)
}

func Test_do_classic_dns_with_duration(t *testing.T) {
s := NewServer("udp", func(w dns.ResponseWriter, r *dns.Msg) {
ret := new(dns.Msg)
ret.SetReply(r)
ret.Answer = append(ret.Answer, A("example.org. IN A 127.0.0.1"))
w.WriteMsg(ret)
})
defer s.Close()

bench := Benchmark{
Queries: []string{"example.org"},
Types: []string{"A"},
Server: s.Addr,
Concurrency: 1,
Duration: 2 * time.Second,
Probability: 1,
WriteTimeout: 5 * time.Second,
ReadTimeout: 5 * time.Second,
Rcodes: true,
Recurse: true,
}

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
rs := bench.Run(ctx)

assert.GreaterOrEqual(t, rs[0].Counters.Total, int64(1), "there should be atleast one execution")
}

func assertResult(t *testing.T, rs []*ResultStats) {
if assert.Len(t, rs, 2, "Run(ctx) rstats") {
rs0 := rs[0]
Expand Down
8 changes: 7 additions & 1 deletion cmd/dnspyre/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
"Note that path on which DoH server handles requests (like `/dns-query`) has to be provided as well.").Short('s').Default("127.0.0.1").String()

pTypes = pApp.Flag("type", "Query type. Repeatable flag. If multiple query types are specified then each query will be duplicated for each type.").Short('t').Default("A").Enums(getSupportedDNSTypes()...)
pCount = pApp.Flag("number", "How many times the provided queries are repeated. Note that the total number of queries issued = types*number*concurrency*len(queries).").Short('n').Default("1").Int64()
pCount = pApp.Flag("number", "How many times the provided queries are repeated. Note that the total number of queries issued = types*number*concurrency*len(queries).").Short('n').Int64()
pConcurrency = pApp.Flag("concurrency", "Number of concurrent queries to issue.").Short('c').Default("1").Uint32()

pRate = pApp.Flag("rate-limit", "Apply a global questions / second rate limit.").Short('l').Default("0").Int()
Expand Down Expand Up @@ -66,6 +66,11 @@ var (
pDoHmethod = pApp.Flag("doh-method", "HTTP method to use for DoH requests").Default("post").Enum("get", "post")
pDoHProtocol = pApp.Flag("doh-protocol", "HTTP protocol to use for DoH requests").Default("1.1").Enum("1.1", "2")

pDuration = pApp.Flag("duration", "Specifies for how long the benchmark should be executing, the benchmark will run for the specified time "+
"while sending DNS requests in infinite loop based on data source. After running for specified duration, the benchmark is cancelled. "+
"This option is exclusive with --number option. The duration is specified in GO duration format e.g. 10s, 15m, 1h.").
PlaceHolder("1m").Short('d').Duration()

pQueries = pApp.Arg("queries", "Queries to issue. Can be local file referenced using @<file-path>, for example @data/2-domains."+
"Can also be resource accessible using HTTP, like https://raw.githubusercontent.com/Tantalor93/dnspyre/master/data/1000-domains, in that "+
"case the file will be downloaded and saved inmemory.").Required().Strings()
Expand Down Expand Up @@ -107,6 +112,7 @@ func Execute() {
PlotFormat: *pPlotFormat,
DohMethod: *pDoHmethod,
DohProtocol: *pDoHProtocol,
Duration: *pDuration,
Queries: *pQueries,
}

Expand Down
11 changes: 10 additions & 1 deletion docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Examples
+ [parallel benchmark with repeating queries](#parallel-benchmark-with-repeating-queries)
+ [run benchmark over specified time](#run-benchmark-over-specified-time)
+ [sending AAAA DNS queries](#sending-AAAA-DNS-queries)
+ [hostnames provided directly](#multiple-hostnames-provided-directly)
+ [hostnames provided using file](#hostnames-provided-using-file)
Expand All @@ -17,11 +18,18 @@

### parallel benchmark with repeating queries
this example will execute the benchmark in 10 parallel threads, where each thread will
send 2 `A example.com.` DNS queries serially
send 2 `A example.com.` DNS queries serially to the `8.8.8.8` server
```
dnspyre -n 2 -c 10 --server 8.8.8.8 --recurse example.com
```

### run benchmark over specified time
this example will execute the benchmark in 10 parallel threads for a duration of 30 seconds while sending `A example.com` DNS queries
to the `8.8.8.8` server
```
dnspyre --duration 30s -c 10 --server 8.8.8.8 google.com
```

### sending AAAA DNS queries
```
dnspyre -n 2 -c 10 --server 8.8.8.8 -t AAAA --recurse example.com
Expand Down Expand Up @@ -72,6 +80,7 @@ coming from the local/experimental range with payload `fddddddd10000000000000000
```
dnspyre -n 10 -c 10 --recurse idnes.cz --server 127.0.0.1 --ednsopt=65518:fddddddd100000000000000000000001
```

### DoT
benchmarking DoT server
```
Expand Down

0 comments on commit 7d839c7

Please sign in to comment.