sexta-feira, janeiro 04, 2008

Port Scanner em Haskell

Para quem acha que Haskell é inútil, aqui fica um dos muitos exemplos das aplicações desta linguagem. Em poucas linhas de código consegue-se criar um port scanner funcional utilizando o paradigma de programação concorrente.

--
-- --------------------------------------------------------
-- A simple port scanner written in Haskell
-- Author: Tom Moertel http://blog.moertel.com
-- Compile using ghc: ghc -o Portscan --make Portscan.hs
-- --------------------------------------------------------
--

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 ()
main = do
args <- getArgs
case args of
[host, from, to] -> withSocketsDo $
scanRange host [read from ... read to]
_ -> usage

usage = do
hPutStrLn stderr "Usage: Portscan host from_port to_port"
exitFailure

scanRange host ports =
mapM (threadWithChannel - scanPort host . fromIntegral) ports >>=
mapM_hitCheck
where
hitCheck mvar = takeMVar >>= maybe (return ()) printHit
printHit port = putStrLn =<< showService port

threadWithChannel action = do
mvar <- newEmptyMVar
forkIO (action >>= putMVar mvar)
return mvar

scanPort host port =
withDefault Nothing (tryPort >> return (Just port))
where
tryPort = connectTo host (PortNumber port) >>= hClose

showService port =
withDefault (show port) $ do
service <- getServiceByPort port "tcp"
return (show port ++ " " ++ serviceName service)

withDefault defaultVal action =
handle (const $ return defaultVal) action


Para compilar é necessário o Glasgow Haskell Compiler, seguindo as instruções indicadas no início do código. Podem sempre usar o interpretador Hugs, mas torna-se mais prático com o compilador.