-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The internal and external repositories are out of sync. This Pull Request attempts to brings them back in sync by patching the GitHub repository. Please carefully review this patch. You must disable ShipIt for your project in order to merge this pull request. DO NOT IMPORT this pull request. Instead, merge it directly on GitHub using the MERGE BUTTON. Re-enable ShipIt after merging.
- Loading branch information
1 parent
68b977e
commit 05c7785
Showing
15 changed files
with
1,236 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
module github.com/facebook/dns/goose | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/miekg/dns v1.1.55 | ||
github.com/prometheus/client_golang v1.17.0 | ||
github.com/sirupsen/logrus v1.9.3 | ||
github.com/stretchr/testify v1.8.4 | ||
go.uber.org/ratelimit v0.3.0 | ||
gonum.org/v1/gonum v0.14.0 | ||
) | ||
|
||
require ( | ||
github.com/benbjohnson/clock v1.3.0 // indirect | ||
github.com/beorn7/perks v1.0.1 // indirect | ||
github.com/cespare/xxhash/v2 v2.2.0 // indirect | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/golang/protobuf v1.5.3 // indirect | ||
github.com/kr/text v0.2.0 // indirect | ||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect | ||
github.com/prometheus/common v0.44.0 // indirect | ||
github.com/prometheus/procfs v0.11.1 // indirect | ||
golang.org/x/mod v0.9.0 // indirect | ||
golang.org/x/net v0.10.0 // indirect | ||
golang.org/x/sys v0.11.0 // indirect | ||
golang.org/x/tools v0.7.0 // indirect | ||
google.golang.org/protobuf v1.31.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= | ||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | ||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= | ||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= | ||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | ||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | ||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= | ||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | ||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= | ||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= | ||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= | ||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= | ||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= | ||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= | ||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= | ||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= | ||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= | ||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= | ||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= | ||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= | ||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= | ||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= | ||
go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw= | ||
go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyBaI= | ||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= | ||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= | ||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= | ||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | ||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= | ||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= | ||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= | ||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= | ||
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= | ||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= | ||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= | ||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"math/rand" | ||
"net/http" | ||
_ "net/http/pprof" | ||
"os" | ||
"os/signal" | ||
"sync" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/facebook/dns/goose/query" | ||
"github.com/facebook/dns/goose/report" | ||
"github.com/facebook/dns/goose/stats" | ||
"github.com/miekg/dns" | ||
|
||
"go.uber.org/ratelimit" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
const pprofHTTP = "localhost:6060" | ||
|
||
var ( | ||
daemon bool | ||
logLevel string | ||
totalQueries int | ||
dport int | ||
// names string | ||
domain string | ||
host string | ||
logging bool | ||
timeout time.Duration | ||
duration time.Duration | ||
samplingInterval time.Duration | ||
debugger bool | ||
maxqps int | ||
randomiseQueries bool | ||
qTypeStr string | ||
monitorPort int | ||
monitorHost string | ||
parallelConnections int | ||
reportJSON bool | ||
inputFile string | ||
exporterAddr string | ||
) | ||
|
||
func main() { | ||
flag.BoolVar(&daemon, "daemon", false, | ||
"Running in daemon mode means that metrics will be exported rather than printed to stdout") | ||
flag.StringVar(&logLevel, "loglevel", "info", "Set a log level. Can be: debug, info, warning, error") | ||
flag.IntVar(&totalQueries, "total-queries", 50000, "Total queries to send") | ||
flag.IntVar(&dport, "port", 53, "destination port") | ||
flag.StringVar(&domain, "domain", "", "Domain for uncached queries") | ||
flag.StringVar(&qTypeStr, "query-type", "A", "Query type to be used for the query") | ||
flag.StringVar(&inputFile, "input-file", "", "The file that contains queries to be made in qname qtype format") | ||
flag.StringVar(&host, "host", "127.0.0.1", "IP address of DNS server to test") | ||
flag.BoolVar(&logging, "enable-logging", true, "Whether to enable logging or not") | ||
flag.BoolVar(&randomiseQueries, "randomise-queries", false, "Whether to randomise dns queries to bypass potential caching") | ||
flag.IntVar(&monitorPort, "monitor-port", 8953, "DNS queries not sent if this port is down on the monitored host (defaults to unbound remote-control port)") | ||
flag.StringVar(&monitorHost, "monitor-host", "127.0.0.1", "DNS queries not sent if the monitored port on this host is down") | ||
flag.StringVar(&exporterAddr, "exporter-addr", ":6869", "Exporter bind address") | ||
flag.DurationVar(&duration, "max-duration", 0*time.Second, "Maximum duration of test (seconds)") | ||
flag.DurationVar(&timeout, "timeout", 3*time.Second, "Duration of timeout for queries") | ||
flag.DurationVar(&samplingInterval, "sample", 0*time.Second, "Sampling frequency for reporting (seconds)") | ||
flag.BoolVar(&debugger, "pprof", false, "Enable pprof") | ||
flag.IntVar(&maxqps, "max-qps", 0, "max number of QPS") | ||
flag.IntVar(¶llelConnections, "parallel-connections", 1, "max number of parallel connections") | ||
flag.BoolVar(&reportJSON, "report-json", false, "Report run results to stdout in json format") | ||
flag.Parse() | ||
|
||
// Set the seed | ||
rand.Seed(time.Now().UTC().UnixNano()) | ||
|
||
switch logLevel { | ||
case "debug": | ||
log.SetLevel(log.DebugLevel) | ||
case "info": | ||
log.SetLevel(log.InfoLevel) | ||
case "warning": | ||
log.SetLevel(log.WarnLevel) | ||
case "error": | ||
log.SetLevel(log.ErrorLevel) | ||
default: | ||
log.Fatalf("Unrecognized log level: %v", logLevel) | ||
} | ||
|
||
if domain == "" && inputFile == "" { | ||
log.Fatal("Need to specify either domain or input file, neither is specified") | ||
|
||
} | ||
if domain != "" && inputFile != "" { | ||
log.Fatal("Need to specify either domain or input file, both are specified, please only specify one of them") | ||
|
||
} | ||
qnames := make([]string, 0) | ||
qtypes := make([]dns.Type, 0) | ||
var err error | ||
if inputFile != "" { | ||
qnames, qtypes, err = query.ProcessQueryInputFile(inputFile) | ||
if err != nil { | ||
log.Fatalf("Failed to process query input file: %s %v", inputFile, err) | ||
} | ||
} else { | ||
qnames = []string{domain} | ||
qType, qtypeErr := query.QTypeStrToDNSQtype(qTypeStr) | ||
if qtypeErr != nil { | ||
log.Fatalf("%v", err) | ||
} | ||
qtypes = []dns.Type{qType} | ||
} | ||
sigStop := make(chan os.Signal, 1) | ||
sigPause := make(chan struct{}, 1) | ||
|
||
var reporter stats.Reporter = &report.LogStatsReporter{} | ||
if reportJSON { | ||
reporter = &report.JSONStatsReporter{} | ||
} | ||
// Do not stop unless interrupted | ||
signal.Notify(sigStop, syscall.SIGINT) // ^C (Control-C). | ||
signal.Notify(sigStop, syscall.SIGQUIT) // ^\ (Control-Backslash) | ||
signal.Notify(sigStop, syscall.SIGTERM) // kill/pkill etc | ||
|
||
if debugger { | ||
log.Infof("Starting profiler on %s", pprofHTTP) | ||
go func() { | ||
listenError := http.ListenAndServe(pprofHTTP, nil) | ||
if listenError != nil { | ||
log.Errorf("failed to start pprof: %s", listenError.Error()) | ||
} | ||
}() | ||
} | ||
|
||
if daemon { | ||
log.Infof("Running in daemon mode") | ||
log.Infof("Monitor Host/Port is %s:%d", monitorHost, monitorPort) | ||
query.MonitorTarget(sigPause, monitorPort, monitorHost) | ||
// @fb-only: reporter = &report.ODSMetricsReporter{Prefix: "dns.goose", Addr: exporterAddr} | ||
reporter = &report.PrometheusMetricsReporter{Addr: exporterAddr} // @oss-only | ||
|
||
// Do nothing on SIGHUP (terminal disconnect) | ||
signal.Notify(make(chan os.Signal, 1), syscall.SIGHUP) | ||
|
||
} else { | ||
log.Infof("The total number of DNS requests will be: %v", totalQueries) | ||
} | ||
|
||
goosestr := ` | ||
_______________________________ | ||
< Honking at %s:%d with %s QPS.> | ||
-------------------------------- | ||
\ | ||
\ | ||
\ | ||
___ | ||
.^ ""-. | ||
_.-^( e _ '. | ||
'-===.>_.-^ '. " | ||
" " | ||
: " | ||
: | __.--._ | ||
| '--" ""-._ _.^) | ||
/ ""-^ _> | ||
: -^> | ||
: .__> __) | ||
\ '._ .__.-' .-' | ||
'.___ '-.__.-' / | ||
'-.__ . _.' / | ||
\_____> >'.__/_."" | ||
.'.----' | | | ||
.' / | | | ||
'^-/ ___| : | ||
>-- / | ||
>.'.' | ||
'-^` | ||
go func() { | ||
reporterInitError := reporter.Initialize() | ||
if reporterInitError != nil { | ||
log.Errorf("Failed to initialize stats reporter %v", reporterInitError) | ||
} | ||
}() | ||
var rate ratelimit.Limiter | ||
qpsStr := "Unlimited" | ||
if maxqps > 0 { | ||
log.Infof("Limiting max qps to: %d", maxqps) | ||
rate = ratelimit.New(maxqps) | ||
qpsStr = fmt.Sprint(maxqps) | ||
} else { | ||
rate = ratelimit.NewUnlimited() | ||
} | ||
log.Infof(goosestr, host, dport, qpsStr) | ||
runState := query.NewRunState(totalQueries, rate, daemon, time.Now) | ||
if duration != 0 && !daemon { | ||
timer := time.NewTimer(duration) | ||
go func() { | ||
<-timer.C | ||
log.Info("Max duration reached. Exiting.") | ||
close(sigStop) | ||
}() | ||
} | ||
periodicReporterStop := make(chan os.Signal, 1) | ||
if samplingInterval != 0 { | ||
log.Infof("Sampling interval is %v", samplingInterval) | ||
samplingTicker := time.NewTicker(samplingInterval) | ||
go func() { | ||
for { | ||
select { | ||
case <-samplingTicker.C: | ||
sampledMetrics := runState.ExportIntermediateResults() | ||
repErr := reporter.ReportMetrics(sampledMetrics) | ||
if err != nil { | ||
log.Errorf("Failed to report metrics %v", repErr) | ||
} | ||
case <-periodicReporterStop: | ||
return | ||
} | ||
} | ||
}() | ||
} | ||
|
||
go func() { | ||
|
||
log.Infof( | ||
"Starting the test and running %d connections in parallel", | ||
parallelConnections, | ||
) | ||
var wg sync.WaitGroup | ||
for i := 0; i < parallelConnections; i++ { | ||
wg.Add(1) | ||
go func() { | ||
qErr := query.RunQueries(dport, host, qnames, timeout, randomiseQueries, qtypes, time.Now, runState, sigPause) | ||
if err != nil { | ||
log.Errorf("Failed to run queries %v", qErr) | ||
} | ||
wg.Done() | ||
}() | ||
} | ||
wg.Wait() | ||
|
||
log.Info("Finished running all connections") | ||
close(sigStop) | ||
}() | ||
select { // nolint: gosimple | ||
case <-sigStop: | ||
log.Infof("No more requests will be sent") | ||
close(periodicReporterStop) | ||
} | ||
if !daemon { | ||
log.Info("The test results are:") | ||
|
||
finishedMetrics := runState.ExportResults() | ||
err = reporter.ReportMetrics(finishedMetrics) | ||
if err != nil { | ||
log.Errorf("Failed to report metrics %v", err) | ||
} | ||
} | ||
} |
Oops, something went wrong.