In another draft of his article about Scheme programming, jacob shows how he approaches the problem of writing a TCP port scanner. That seemed like a fun problem, and so I whipped up this version in one of my favorite programming languages, Haskell:
module Main (main) where
import Control.Concurrent
import Control.Exception
import Data.Maybe
import Network
import Network.BSD
import System.Environment
import System.Exit
import System.IO
main :: IO ()
= do
main <- getArgs
args case args of
-> withSocketsDo $
[host, from, to] read from .. read to]
scanRange host [-> usage
_
= do
usage "Usage: Portscan host from_port to_port"
hPutStrLn stderr
exitFailure
=
scanRange host ports mapM (threadWithChannel . scanPort host . fromIntegral) ports >>=
mapM_ hitCheck
where
= takeMVar mvar >>= maybe (return ()) printHit
hitCheck mvar = putStrLn =<< showService port
printHit port
= do
threadWithChannel action <- newEmptyMVar
mvar >>= putMVar mvar)
forkIO (action return mvar
=
scanPort host port Nothing (tryPort >> return (Just port))
withDefault where
= connectTo host (PortNumber port) >>= hClose
tryPort
=
showService port show port) $ do
withDefault (<- getServiceByPort port "tcp"
service return (show port ++ " " ++ serviceName service)
=
withDefault defaultVal action const $ return defaultVal) action
handle (
-- Local Variables: ***
-- compile-command: "ghc -o Portscan --make Portscan.hs" ***
-- End: ***
Example usage:
$ ./Portscan internalhost.moertel.com 1 1000
21 ftp
22 ssh
80 http
111 sunrpc
139 netbios-ssn
443 https
445 microsoft-ds
631 ipp
709
720
Care to give it a try in your favorite programming language?