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 math.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 forio.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:
( 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.
2 comments:
well, this works but it's pretty slow. what is wrong here?
USING: calendar concurrency.combinators concurrency.semaphores
continuations fry io io.encodings.binary io.sockets io.timeouts
kernel math.parser sequences shuffle ;
IN: jbq-scanner
: open-port? ( host port -- ? ) [ binary [ t ] with-client ] [ 2drop f ] recover ;
: peach ( seq quot #limit -- )
swap [ ] dip '[ _ _ with-semaphore ] parallel-each ;
: scanit ( host range -- )
[ tuck
20 milliseconds [ open-port? ] with-timeout*
[ number>string "port " " is opened." surround print ] [ number>string print ] if ] with 8 peach ;
! "127.0.0.1" 1024 [1,b] scanit
oops, there was a lt semaphore gt in the peach word, between "swap [" and "] dip".
Post a Comment