blackhat-go/bhg

Suggest to use net.DialTimeout

sergii4 opened this issue · 4 comments

Even big timeout 10*time.Second can increase performance:

conn, err := net.DialTimeout("tcp", address, 10*time.Second)

conn, err := net.Dial("tcp", address)

old:
go run main.go scanme.nmap.org 1,28s user 1,26s system 1% cpu 2:12,38 total
new:
go run main.go scanme.nmap.org 1,01s user 0,63s system 12% cpu 13,153 total

This, I think, is the only thing that will make the port scanner work when it encounters filtered ports. If I run with net.Dial, it hangs after 1017 ports (i.e., 7 results still pending). Compare that with nmap's output:

$ nmap scanme.nmap.org -p 1-1024

Starting Nmap 7.60 ( https://nmap.org ) at 2020-03-14 18:04 EDT
Nmap scan report for scanme.nmap.org (45.33.32.156)
Host is up (0.089s latency).
Other addresses for scanme.nmap.org (not scanned): 2600:3c01::f03c:91ff:fe18:bb2f
Not shown: 1013 closed ports
PORT    STATE    SERVICE
21/tcp  open     ftp
22/tcp  open     ssh
25/tcp  filtered smtp
80/tcp  open     http
135/tcp filtered msrpc
136/tcp filtered profile
137/tcp filtered netbios-ns
138/tcp filtered netbios-dgm
139/tcp filtered netbios-ssn
445/tcp filtered microsoft-ds
554/tcp open     rtsp

We have 7 filtered ports.

I'm not sure if net.Dial would time out eventually, but if it doesn't, I don't think the current implementation would ever complete.

Thanks for the input! You are indeed correct, you will want to use DialTimeout, 500 MS is probably good actually. If you are interested to know, the default is actually up to the OS.

// It is safe to call Dialer's methods concurrently.
type Dialer struct {
	// Timeout is the maximum amount of time a dial will wait for
	// a connect to complete. If Deadline is also set, it may fail
	// earlier.
	//
	// The default is no timeout.
	//
	// When using TCP and dialing a host name with multiple IP
	// addresses, the timeout may be divided between them.
	//
	// With or without a timeout, the operating system may impose
	// its own earlier timeout. For instance, TCP timeouts are
	// often around 3 minutes.
	Timeout time.Duration

Did you check out the scanner here https://github.com/blackhat-go/bhg/blob/56620f7153a25b0ca5317d67be4c3364a9561ad4/ch-8/syn-flood/main.go

For the earlier one, we're building on concepts. It maybe useful to bring in DialTimeout if we do a second edition, for now, I think we should keep this as it simplifies the exercise for the reader. Additionally, DialTimeout is discussed in later scanners as well :)

FWIW: I've picked up a copy of the book direct from No Starch Press (really enjoying it thus far), but ended up on this GH issue via a Google Search. The discussion here led me in the right direction.

In case it is helpful to someone else landing here from Google, here are the other relevant references that I used to set a timeout for tls.Dial() (actually tls.DialWithDialer):

Example code snippet (outer indentation and surrounding code body removed):

dialer := &net.Dialer{
	Timeout: time.Duration(config.Timeout) * time.Second,
}

conn, err := tls.DialWithDialer(dialer, "tcp", server, &cfg)

time.Second was used here because it matched the application use case.