diff --git a/Hsns.hs b/Hsns.hs
new file mode 100644
--- /dev/null
+++ b/Hsns.hs
@@ -0,0 +1,127 @@
+--run as root, otherwise you'll fail with an device error
+module Main where
+import System.Console.GetOpt
+import System.Environment
+import System.Process
+import qualified Network.Pcap as PCap
+import Control.Monad
+import Text.Printf
+import System.Exit
+import Data.Maybe
+import System.IO
+import Data.List
+import Data.Char
+import Options
+import Foreign
+
+
+
+-- our packet output format
+data PacketFmt = PacketFmt {
+                   ascii       :: String,
+                   hexadecimal :: [Word8]
+                 }
+ deriving (Eq,Show)
+
+initPktFmt a h = 
+  PacketFmt {
+    ascii       = a,
+    hexadecimal = h
+}
+
+hsnsVersion = "hsns: the haskell network sniffer, version 0.5"
+
+formatData :: PacketFmt -> IO ()
+formatData pf = do
+  let (x,x') = splitAt 10 a
+      (y,y') = splitAt 10 h
+  unless (x' == [] && y' == []) $ do
+    mapM_ (printf "%02.2x ") (fmtHex y)
+    printf "\t\t%s\n" x
+    formatData (initPktFmt x' y')
+  return ()
+ where
+  a = ascii pf
+  h = hexadecimal pf
+  fmtHex :: [Word8] -> [Int]
+  fmtHex bytes = [ (read $ show y) | y <- bytes] :: [Int]
+  
+captcha :: PCap.PktHdr -> Ptr Word8 -> IO ()
+captcha pkth datap = do
+  a  <- peekArray (fromIntegral (PCap.caplen pkth)) datap
+  s  <- return $ map (\x -> if (x >= 32 && x <= 126) then x else 46) a
+  s' <- return $ map (\x -> chr (read $ show x)) s
+  formatData (initPktFmt s' a)
+  printf "\n"
+  hFlush stdout
+
+starter :: HsnsOpts -> IO ()
+starter o = do
+
+  -- options that don't depend on anything else
+  if (help o)    == "True" then putStrLn (usageInfo "hsns: \"filter program\" [OPTIONS]..." options) >> exitWith ExitSuccess 
+   else return ()
+  if (version o) == "True" then (putStrLn hsnsVersion >> (exitWith ExitSuccess)) else return ()   
+  if (buffered o) == "True" then hSetBuffering stdout LineBuffering else return ()
+
+  -- our variables, the interface-listing option depends on these and therefore root access
+  devs <- PCap.findAllDevs
+  let devnames = map (\i -> (PCap.ifName i)) devs
+  let dev      = (interface o)
+  net  <- PCap.lookupNet dev
+  spy  <- PCap.openLive dev (read $ snarflen o) (if (nopromiscuous o) == "True" then True else False) 100000
+
+  if (iflist o)  == "True" then do
+    putStrLn "interfaces:" 
+    mapM_ (printf " -- %s\n") devnames
+    exitWith ExitSuccess
+   else return ()
+    
+  withForeignPtr spy $ \ptr -> do
+    -- set our filter, it must happen in this context as spy is
+    -- a ForeignPtr, rather than a Ptr like we need for
+    -- setFilter/loop
+
+    if (bpf o) == "" then return () else PCap.setFilter ptr (bpf o) False (PCap.netMask net)
+    -- loop and capture
+    PCap.loop ptr (read $ count o) captcha
+    --print statistics
+    s <- PCap.statistics ptr
+    putStrLn ("Packets recieved: " ++ (show $ PCap.recv s))
+    putStrLn ("Packets dropped: " ++ (show $ PCap.drop s))
+    putStrLn ("Packets dropped by interface: " ++ (show $ PCap.ifdrop s))
+
+
+
+main = do
+  (o,n)  <- parseOpts -- our options and filter in a pair, we assume the filter is the first thing
+                      -- on the command line
+
+  starter (create o n)
+  return ()
+ where
+  parseOpts     = (getArgs >>= hsnsOptions)
+  create x f =
+    let y = construct x in
+    Opts {count         = fromMaybe "5"        (lookup "count"     y),
+          snarflen      = fromMaybe "68"       (lookup "snarf"     y),
+          interface     = fromMaybe "eth0"     (lookup "listen"    y),
+          version       = fromMaybe "False"    (lookup "version"   y),
+          nopromiscuous = fromMaybe "False"    (lookup "nopromisc" y),
+          iflist        = fromMaybe "False"    (lookup "ifList"    y),
+          buffered      = fromMaybe "False"    (lookup "buffered"  y),
+          help          = fromMaybe "False"    (lookup "help"      y),
+          bpf           = if f == [] then "" else (f !! 0)
+         }
+
+  construct   f = map construct' f
+   where
+     construct' x = case x of
+       Help          -> ("help","True")
+       Count    s    -> ("count",s)
+       SnarfLen s    -> ("snarf",s)
+       Listen   s    -> ("listen",s)
+       NoPromiscuous -> ("nopromisc","True")
+       IfList        -> ("ifList","True")
+       LineBuffered  -> ("buffered","True")
+       Version       -> ("version","True")
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright Austin Seipp 2007
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Austin Seipp  nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Options.hs b/Options.hs
new file mode 100644
--- /dev/null
+++ b/Options.hs
@@ -0,0 +1,43 @@
+module Options where
+import System.Console.GetOpt
+import Data.Maybe
+
+data HsnsOpts = Opts {
+          count         :: String, --done
+          snarflen      :: String, --done
+          interface     :: String, --done
+          version       :: String, --done
+          nopromiscuous :: String, --done
+          iflist        :: String, --done
+          buffered      :: String, --done
+          help          :: String, --done
+          bpf           :: String -- filter string that will be passed to setfilter
+}
+
+data Flags =
+           Count String    |    -- amount of packets to take, must be String in constructor, that's how getOpt returns it
+           IfList          |    -- List the available interfaces
+           Listen String   |    -- Listen on the specified interface
+           LineBuffered    |    -- Turn on Line buffering
+           NoPromiscuous   |    -- Don't go into promiscuous mode.
+           SnarfLen String |    -- Amount of data to snarf, default is 68
+           Version         |    -- version number
+           Help                 -- help info
+
+options :: [OptDescr Flags]
+options = [ Option     ['h','?']    ["help"]           (NoArg Help)              "print this help information"
+           ,Option     ['c']        ["count"]          (ReqArg Count "NUM")      "take in NUM packets, default is 5, 0 means unlimited"
+           ,Option     ['D']        ["iflist"]         (NoArg IfList)            "list interfaces that can be captured upon"
+           ,Option     ['i']        ["interface"]      (ReqArg Listen "INT")     "listen on interface INT, defaults to eth0"
+           ,Option     ['l']        ["linebuffered"]   (NoArg LineBuffered)      "make output line-buffered"
+           ,Option     ['p']        ["nopromiscuous"]  (NoArg NoPromiscuous)     "do not go into promiscuous mode"
+           ,Option     ['s']        ["snarf"]          (ReqArg SnarfLen "LEN")   "change snarf length from default 68 to LEN"
+           ,Option     ['V']        ["version"]        (NoArg Version)           "output version number and exit"]
+
+hsnsOptions :: [String] -> IO ([Flags],[String])
+hsnsOptions av = do
+  case getOpt Permute options av of
+    (o,n,[]) -> return (o,n)
+    (_,_,e)  -> ioError (userError (concat e ++ usageInfo header options))
+   where
+    header = "usage: hsns \"[PACKET FILTER]\" [OPTIONS...]"
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,71 @@
+hsns: the haskell network sniffer.
+
+* What is Hsns?
+* Installation
+* Packet filters
+* Options
+
+
+What is Hsns?
+=============
+hsns is a packet sniffer for unicies written totally
+in Haskell (http://www.haskell.org) Currently, hsns 
+has only been tested to work on Linux. 
+
+
+Installation
+============
+To install, you need to have a haskell compiler such as the
+Glasgow Haskell Compiler installed, the Pcap library to be
+installed, and the Network.Pcap libraries for GHC.
+You may obtain Network.Pcap from http://hackage.haskell.org
+
+To install, run the Setup.lhs script like so (you can skip
+the chmod part if you have pulled hsns from the darcs
+repository with the --set-scripts-executable flag):
+
+[austin@continuum hsns]$ chmod +x ./Setup.lhs
+[austin@continuum hsns]$ ./Setup.lhs configure
+...
+[austin@continuum hsns]$ ./Setup.lhs build
+...
+[austin@continuum hsns]$ su -c './Setup.lhs install'
+Password: 
+...
+[austin@continuum hsns]$ 
+
+hsns is now installed.
+
+
+Packet filters
+==============
+hsns can receive a berkeley packet filter
+in it's command line (anywhere) that can
+be used to filter packets in the same style
+as Tcpdump. For a reference on bpf's, see the
+tcpdump man page.
+
+
+Options
+=======
+
+Currently, hsns accepts the following options:
+
+	-h,-?	  --help		Display help
+
+	-c[COUNT] --count=COUNT    	Exit after receiving COUNT packets.
+				   	0 is receive forever, default is 5.
+
+	-D	  --iflist	   	List interfaces that can be captured
+				   	on
+
+	-i INT    --interface=INT    	Listen on interface INT.
+					
+	-l        --linebuffered	Make output line buffered.
+
+	-p        --nopromiscuous	Do not go into promiscuous mode
+	
+	-s LEN	  --snarf=LEN		change snarf length from 68 (default)
+					to LEN.
+
+	-V	  --version		Display version and exit.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/hsns.cabal b/hsns.cabal
new file mode 100644
--- /dev/null
+++ b/hsns.cabal
@@ -0,0 +1,17 @@
+Name:                hsns
+Version:             0.5
+Description:         a network sniffer written in a purely fun language
+Synopsis:            the haskell network sniffer
+Category:            Network
+License:             BSD3
+License-file:        LICENSE
+Author:              Austin Seipp 
+Maintainer:          austin@youareinferior.net
+Build-Depends:       base,network,pcap
+Extra-source-files:  README,
+		     Options.hs
+
+ 
+Executable:          hsns
+Main-is:             Hsns.hs
+ghc-options:         -O -lpcap
