Port Scanner
Tuesday, February 15, 2011
For fun, I thought I’d show how to build a simple port scanner using Factor
We start by listing vocabularies that we will be using and a namespace for our work:
USING: continuations formatting kernel ranges
io.encodings.binary io.sockets make sequences ;
IN: port-scan
We need to decide how to check for an open port. In this case, we are going to attempt to establish a TCP connection. If it succeeds, then the port is open, otherwise it will throw an error connecting and we will assume the port was not open.
: open-port? ( host port -- ? )
<inet> [ binary [ t ] with-client ] [ 2drop f ] recover ;
Note: we should be setting a connection timeout, so that we do not let a connection attempt last forever. However, I’m not quite sure how to do that – the documentation for
io.sockets
andio.timeouts
didn’t make it obvious.
Next, we will make a word that returns an array of all open ports (checking ports from 1 to 1024). We use the make vocabulary to build the sequence dynamically.
: open-ports ( host -- seq )
1024 [1..b] [
[ 2dup open-port? [ , ] [ drop ] if ] each drop
] { } make ;
Finally, we can make a word that provides some visual output back to the user:
: scan-ports ( host -- )
[ "Scanning %s...\n" printf ]
[ open-ports [ "%d is open\n" printf ] each ]
bi ;
Using this on my laptop returns the following:
IN: scratchpad "127.0.0.1" scan-ports
Scanning 127.0.0.1...
631 is open
It is quite simple and functional as is. However, some obvious improvements could be made:
- adding the connection timeout as mentioned above
- providing the output of
scan-ports
to the user as open ports are found - using the concurrent combinators to test ports in parallel
- using a list of port numbers to identify services that might be on open ports
The code for this is on my GitHub.