Thursday, February 17, 2011

Port Knocking

As a followup to my last article, I wanted to show how to implement port knocking functionality in Factor. This was particularly interesting to me since I ran across a recent blog post about the "inventor" of port knocking.

"port knocking is a method of externally opening ports on a firewall by generating a connection attempt on a set of prespecified closed ports"

There are several types of port knocking, with variations using any combination of TCP, UDP, ICMP, or similar network protocols. For this implementation, we will choose to use TCP. In particular, using the open-port? word from our port-scan vocabulary. As a reminder, it looks like this:

USING: continuations io.encodings.binary io.sockets kernel ;

: open-port? ( host port -- ? )
    <inet> [ binary [ t ] with-client ] [ 2drop f ] recover ;

The idea is to knock on a sequence of ports, in order. In its simplest form, we attempt a connection to each port, ignoring whether it is open or closed (not relevant).

: knock-ports ( host ports -- )
    [ dupd open-port? drop ] each drop ;

You can imagine using it something like this (knocking on ports 10000, 10001, 10002 and then write a "Hello" message to port 12345):

( scratchpad ) "localhost"
               [ { 10000 10001 10002 } knock-ports ]
               [ 12345 <inet> ascii [ "Hello" print ] with-client ]
               bi

Some ways to improve this might be to allow "knock delay" between successive knocks, support UDP or ICMP knocks, or perhaps to encompass this functionality transparently into a reusable with-knocking-client word.

3 comments:

Jon said...

Hi John,
I think knock-ports is more idiomatically written as "[ open-port? drop ] with each"

cheers

Unknown said...

: knock-port ( host port -- ) open-port? drop ;

: knock-ports' ( host ports duration -- )
'[ knock-port _ sleep ] with each ;

"127.0.0.1" { 72 63 54 } 1.5 seconds knock-ports''

Unknown said...

Have you considered something more secure, like port knocking on a session # counter (for SALT) + a private 128 bit key ? This way, the exact port # sequence (use 16-bits at a time for the port #) is always different yet well known for a particular client and server.