diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Danny Navarro
+
+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 Danny Navarro 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/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/network-simple-sockaddr.cabal b/network-simple-sockaddr.cabal
new file mode 100644
--- /dev/null
+++ b/network-simple-sockaddr.cabal
@@ -0,0 +1,34 @@
+name:                network-simple-sockaddr
+version:             0.1
+cabal-version:       >=1.10
+tested-with:         GHC == 7.6.3
+build-type:          Simple
+license:             BSD3
+license-file:        LICENSE
+author:              Danny Navarro
+maintainer:          j@dannynavarro.net
+category:            Network
+homepage:            https://github.com/jdnavarro/network-simple-sockaddr
+bug-reports:         https://github.com/jdnavarro/network-simple-sockaddr/issues
+synopsis:            network-simple for resolved addresses
+description:
+  @<http://hackage.haskell.org/package/network-simple-0.3.0 network-simple>@
+  works by resolving 'HostName's. This packages offers a similar API but
+  working with unresolved addresses in the form of 'SockAddr'. In addition to
+  'IPv4' addresses, 'IPv6' and @Unix Domain Sockets@ are also supported.
+
+source-repository head
+  type: git
+  location: git@github.com:jdnavarro/network-simple-sockaddr.git
+
+library
+  exposed-modules:     Network.Simple.SockAddr
+  build-depends:       base >=4.6 && <4.8,
+                       bytestring,
+                       directory,
+                       transformers >=0.2,
+                       network >=2.4,
+                       exceptions >=0.3
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+  ghc-options:         -Wall
diff --git a/src/Network/Simple/SockAddr.hs b/src/Network/Simple/SockAddr.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Simple/SockAddr.hs
@@ -0,0 +1,175 @@
+{-# LANGUAGE RankNTypes #-}
+
+{-| This is the same API as @network-simple@ with the difference
+    of working on 'SockAddr' instead of @'HostName's@.
+
+    For a more detailed explanation check
+    @<http://hackage.haskell.org/package/network-simple-0.3.0/docs/Network-Simple-TCP.html Network.Simple.TCP>@
+-}
+
+module Network.Simple.SockAddr
+  (
+  -- * Client side
+    connect
+  , connectFork
+  -- * Server side
+  , serve
+  , listen
+  , bind
+  , acceptFork
+  -- * Utils
+  , send
+  , recv
+  , close
+  -- * Re-exported from @Network.Socket@
+  , Socket
+  , SockAddr
+  ) where
+
+import Control.Monad (forever, when)
+import Control.Concurrent (ThreadId, forkIO, forkFinally)
+import Data.ByteString (ByteString)
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import System.Directory (removeFile)
+import qualified Network.Socket as NS
+import Network.Socket
+  ( SockAddr(SockAddrInet, SockAddrInet6, SockAddrUnix)
+  , SocketType(Stream)
+  , Family(AF_INET, AF_INET6, AF_UNIX)
+  , Socket
+  , defaultProtocol
+  )
+import qualified Network.Socket.ByteString as NSB
+import Control.Monad.Catch (MonadCatch, bracket, bracketOnError, throwM)
+
+-- * Client side
+
+{-| Connect to a server and use the connection.
+
+    The connection socket is closed when done or in case of exceptions.
+-}
+connect :: (MonadIO m, MonadCatch m)
+        => SockAddr
+        -- ^ Server address.
+        -> (Socket -> m r)
+        -- ^ Computation taking the socket connection socket.
+        -> m r
+connect addr = bracket connect' (liftIO . NS.close)
+  where
+    connect' = do sock <- newSocket addr
+                  liftIO $ NS.connect sock addr
+                  return sock
+
+-- | Like 'connect' but fork the connection in a different thread.
+connectFork :: MonadIO m
+            => SockAddr
+            -- ^ Server address.
+            -> (forall m' . (Functor m', MonadIO m', MonadCatch m')
+                         => Socket -> m' ())
+            -- ^ Computation taking the socket connection socket.
+            -> m ThreadId
+connectFork addr k = liftIO . forkIO $ connect addr k
+{-# INLINABLE connectFork #-}
+
+-- * Server side
+
+{-| Start a server that accepts incoming connections and handles them
+    concurrently in different threads.
+
+    Any acquired network resources are properly closed and discarded when done
+    or in case of exceptions.
+-}
+serve :: (MonadIO m, MonadCatch m)
+      => SockAddr
+      -- ^ Address to bind to.
+      -> (forall m' . (Functor m', MonadIO m', MonadCatch m')
+                   => SockAddr -> Socket -> m' ())
+      -- ^ Computation to run in a different thread
+      --   once an incoming connection is accepted. Takes the
+      --   the remote end address and the connection socket.
+      -> m ()
+serve addr k = listen addr $ \sock -> forever $ acceptFork sock k
+
+{-| Bind a listening socket and use it.
+
+    The listening socket is closed when done or in case of exceptions.
+-}
+listen :: (MonadIO m, MonadCatch m)
+       => SockAddr
+       -- ^ Address to bind to.
+       -> (Socket -> m r)
+       -- ^ Computation taking the listening socket.
+       -> m r
+listen addr = bracket listen' (close addr)
+  where
+    listen' = liftIO $ do sock <- bind addr
+                          NS.listen sock $ max 2048 NS.maxListenQueue
+                          return sock
+{-| Obtain a 'Socket' bound to the given 'SockAddr'.
+
+   The obtained 'Socket' should be closed manually using 'close' when it's not
+   needed anymore.
+
+   Prefer to use 'listen' if you will be listening on this socket and using it
+   within a limited scope, and would like it to be closed immediately after its
+   usage or in case of exceptions.
+-}
+bind :: (MonadIO m, MonadCatch m) => SockAddr -> m Socket
+bind addr = bracketOnError (newSocket addr) (close addr)
+          $ \sock -> liftIO $ do
+                let set so n = when (NS.isSupportedSocketOption so)
+                                    (NS.setSocketOption sock so n)
+                when (isTCP addr) (set NS.NoDelay 1)
+                set NS.ReuseAddr 1
+                NS.bindSocket sock addr
+                return sock
+  where
+    isTCP (SockAddrUnix {}) = False
+    isTCP _                 = True
+
+{-| Accept a single incoming connection and use it in a different thread.
+
+    The connection socket is closed when done or in case of exceptions.
+-}
+acceptFork :: (MonadIO m, MonadCatch m)
+           => Socket
+           -- ^ Listening and bound socket.
+           -> (forall m' . (Functor m', MonadIO m', MonadCatch m')
+                        => SockAddr -> Socket -> m' ())
+           -- ^ Computation to run in a different thread
+           --   once an incoming connection is accepted. Takes the
+           --   remote end address and connection socket.
+           -> m ThreadId
+acceptFork lsock k = liftIO $ do
+    (csock,caddr) <- NS.accept lsock
+    forkFinally (k caddr csock)
+                (\ea -> NS.close csock >> either throwM return ea)
+{-# INLINABLE acceptFork #-}
+
+-- * Utils
+
+-- | Writes the given bytes to the socket.
+send :: MonadIO m => Socket -> ByteString -> m ()
+send sock bs = liftIO $ NSB.sendAll sock bs
+{-# INLINE send #-}
+
+-- | Read up to a limited number of bytes from a socket.
+recv :: MonadIO m => Socket -> Int -> m ByteString
+recv sock n = liftIO $ NSB.recv sock n
+{-# INLINE recv #-}
+
+-- | Close the 'Socket' and unlinks the 'SockAddr' for Unix sockets.
+close :: MonadIO m => SockAddr -> Socket -> m ()
+close (SockAddrUnix path) sock = liftIO $ NS.close sock >> removeFile path
+close _                   sock = liftIO $ NS.close sock
+{-# INLINE close #-}
+
+-- * Internal
+
+newSocket :: MonadIO m => SockAddr -> m Socket
+newSocket addr = liftIO $ NS.socket (fam addr) Stream defaultProtocol
+  where
+    fam (SockAddrInet  {}) = AF_INET
+    fam (SockAddrInet6 {}) = AF_INET6
+    fam (SockAddrUnix  {}) = AF_UNIX
+{-# INLINABLE newSocket #-}
