Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional feature to set the SO_REUSEADDR option before binding th… #638

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ attack command:
Number of redirects to follow. -1 will not follow but marks as success (default 10)
-resolvers value
List of addresses (ip:port) to use for DNS resolution. Disables use of local system DNS. (comma separated list)
-reuseaddr
Set the SO_REUSEADDR socket option (default false)
-root-certs value
TLS root certificate files (comma separated list)
-session-tickets
Expand Down Expand Up @@ -392,6 +394,12 @@ the response is marked as successful.
Specifies custom DNS resolver addresses to use for name resolution instead of
the ones configured by the operating system. Works only on non Windows systems.

#### `-resolvers`

Specifies whether to set the SO_REUSEADDR option on the TCP socket before binding
it. Can reduce the amount of "bind: address already in use" errors when doing many
connections to the same server and port combination.

#### `-root-certs`

Specifies the trusted TLS root CAs certificate files as a comma separated
Expand Down
3 changes: 3 additions & 0 deletions attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func attackCmd() command {
fs.StringVar(&opts.promAddr, "prometheus-addr", "", "Prometheus exporter listen address [empty = disabled]. Example: 0.0.0.0:8880")
fs.Var(&dnsTTLFlag{&opts.dnsTTL}, "dns-ttl", "Cache DNS lookups for the given duration [-1 = disabled, 0 = forever]")
fs.BoolVar(&opts.sessionTickets, "session-tickets", false, "Enable TLS session resumption using session tickets")
fs.BoolVar(&opts.reuseaddr, "reuseaddr", false, "Set the SO_REUSEADDR socket option (default false)")
systemSpecificFlags(fs, opts)

return command{fs, func(args []string) error {
Expand Down Expand Up @@ -108,6 +109,7 @@ type attackOpts struct {
promAddr string
dnsTTL time.Duration
sessionTickets bool
reuseaddr bool
}

// attack validates the attack arguments, sets up the
Expand Down Expand Up @@ -219,6 +221,7 @@ func attack(opts *attackOpts) (err error) {
vegeta.ChunkedBody(opts.chunked),
vegeta.DNSCaching(opts.dnsTTL),
vegeta.SessionTickets(opts.sessionTickets),
vegeta.Reuseaddr(opts.reuseaddr),
)

res := atk.Attack(tr, opts.rate, opts.duration, opts.name)
Expand Down
19 changes: 19 additions & 0 deletions lib/attack.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"strconv"
"sync"
"time"
"syscall"

"github.com/rs/dnscache"
"golang.org/x/net/http2"
Expand Down Expand Up @@ -134,6 +135,24 @@ func ChunkedBody(b bool) func(*Attacker) {
return func(a *Attacker) { a.chunked = b }
}

// Reuseaddr returns a functional option which makes the attacker set the
// SO_REUSEADDR option on the socket before binding it.
func Reuseaddr(b bool) func(*Attacker) {
return func(a *Attacker) {
if b {
a.dialer.Control = func(network, address string, conn syscall.RawConn) error {
var syserr error
if err := conn.Control(func(fd uintptr) {
syserr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
}); err != nil {
return err
}
return syserr
}
}
}
}

// Redirects returns a functional option which sets the maximum
// number of redirects an Attacker will follow.
func Redirects(n int) func(*Attacker) {
Expand Down