From cf86fe65047acf2440413ef9fedb94785dcb28c8 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Mon, 13 May 2019 23:13:19 +0200 Subject: [PATCH 01/16] Implement syscall connect --- src/System/Hatrace.hs | 42 ++++++++++++++++++++++++++++++++++-- src/System/Hatrace/Types.hsc | 26 +++++++++++++++++++++- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/System/Hatrace.hs b/src/System/Hatrace.hs index 6775422..35dfa42 100644 --- a/src/System/Hatrace.hs +++ b/src/System/Hatrace.hs @@ -49,6 +49,8 @@ module System.Hatrace , SyscallExitDetails_exit(..) , SyscallEnterDetails_exit_group(..) , SyscallExitDetails_exit_group(..) + , SyscallEnterDetails_connect(..) + , SyscallExitDetails_connect(..) , DetailedSyscallEnter(..) , DetailedSyscallExit(..) , ERRNO(..) @@ -92,13 +94,13 @@ import qualified Data.Text.Encoding as T import Data.Word (Word32, Word64) import Foreign.C.Error (Errno(..), throwErrnoIfMinus1, throwErrnoIfMinus1_, getErrno, resetErrno, eCHILD, eINVAL) import Foreign.C.String (peekCString) -import Foreign.C.Types (CInt(..), CLong(..), CULong(..), CChar(..), CSize(..)) +import Foreign.C.Types (CInt(..), CUInt(..), CLong(..), CULong(..), CChar(..), CSize(..)) import Foreign.ForeignPtr (withForeignPtr) import Foreign.Marshal.Alloc (alloca) import Foreign.Marshal.Array (withArray) import Foreign.Marshal.Utils (withMany) import Foreign.Ptr (Ptr, nullPtr, wordPtrToPtr) -import Foreign.Storable (peekByteOff, sizeOf) +import Foreign.Storable (peek, peekByteOff, sizeOf) import GHC.Stack (HasCallStack, callStack, getCallStack, prettySrcLoc) import System.Directory (canonicalizePath, doesFileExist, findExecutable) import System.Exit (ExitCode(..), die) @@ -541,6 +543,19 @@ data SyscallExitDetails_faccessat = SyscallExitDetails_faccessat { enterDetail :: SyscallEnterDetails_faccessat } deriving (Eq, Ord, Show) +data SyscallEnterDetails_connect = SyscallEnterDetails_connect + { sockfd :: CInt + , addr :: Ptr Void + , addrlen :: CUInt + -- Peeked details + , sockAddr :: SockAddr + } deriving (Eq, Ord, Show) + + +data SyscallExitDetails_connect = SyscallExitDetails_connect + { enterDetail :: SyscallEnterDetails_connect + , sockfd :: CInt + } deriving (Eq, Ord, Show) data SyscallEnterDetails_execve = SyscallEnterDetails_execve { filename :: Ptr CChar @@ -566,6 +581,7 @@ data DetailedSyscallEnter | DetailedSyscallEnter_pipe SyscallEnterDetails_pipe | DetailedSyscallEnter_pipe2 SyscallEnterDetails_pipe2 | DetailedSyscallEnter_access SyscallEnterDetails_access + | DetailedSyscallEnter_connect SyscallEnterDetails_connect | DetailedSyscallEnter_faccessat SyscallEnterDetails_faccessat | DetailedSyscallEnter_write SyscallEnterDetails_write | DetailedSyscallEnter_read SyscallEnterDetails_read @@ -587,6 +603,7 @@ data DetailedSyscallExit | DetailedSyscallExit_pipe SyscallExitDetails_pipe | DetailedSyscallExit_pipe2 SyscallExitDetails_pipe2 | DetailedSyscallExit_access SyscallExitDetails_access + | DetailedSyscallExit_connect SyscallExitDetails_connect | DetailedSyscallExit_faccessat SyscallExitDetails_faccessat | DetailedSyscallExit_write SyscallExitDetails_write | DetailedSyscallExit_read SyscallExitDetails_read @@ -772,6 +789,15 @@ getSyscallEnterDetails syscall syscallArgs pid = let proc = TracedProcess pid in Syscall_exit -> do let SyscallArgs{ arg0 = status } = syscallArgs pure $ DetailedSyscallEnter_exit $ SyscallEnterDetails_exit { status = fromIntegral status } + Syscall_connect -> do + let SyscallArgs{ arg0 = sockfd, arg1 = addr, arg2 = addrlen} = syscallArgs + sockAddr <- (peek (word64ToPtr addr) :: IO SockAddr) + pure $ DetailedSyscallEnter_connect $ SyscallEnterDetails_connect + { sockfd = fromIntegral sockfd + , addr = word64ToPtr addr + , addrlen = fromIntegral addrlen + , sockAddr = sockAddr + } Syscall_exit_group -> do let SyscallArgs{ arg0 = status } = syscallArgs pure $ DetailedSyscallEnter_exit_group $ SyscallEnterDetails_exit_group { status = fromIntegral status } @@ -886,6 +912,10 @@ getSyscallExitDetails knownSyscall syscallArgs pid = do enterDetail@SyscallEnterDetails_exit_group{} -> do pure $ DetailedSyscallExit_exit_group $ SyscallExitDetails_exit_group { enterDetail } + DetailedSyscallEnter_connect + enterDetail@SyscallEnterDetails_connect{} -> do + pure $ DetailedSyscallExit_connect $ SyscallExitDetails_connect { enterDetail, sockfd = fromIntegral result } + DetailedSyscallEnter_unimplemented syscall _syscallArgs -> pure $ DetailedSyscallExit_unimplemented syscall syscallArgs result @@ -983,6 +1013,10 @@ formatDetailedSyscallEnter = \case SyscallEnterDetails_exit_group{ status } -> "exit_group(" ++ show status ++ ")" + DetailedSyscallEnter_connect + SyscallEnterDetails_connect {sockfd, sockAddr, addrlen} -> + "connect(" ++ show sockfd ++ ", " ++ show sockAddr ++ ", " ++ show addrlen ++ ")" + DetailedSyscallEnter_unimplemented syscall syscallArgs -> "unimplemented_syscall_details(" ++ show syscall ++ ", " ++ show syscallArgs ++ ")" @@ -1071,6 +1105,10 @@ formatDetailedSyscallExit = \case SyscallExitDetails_exit_group{ enterDetail = SyscallEnterDetails_exit_group{ status }} -> "exit_group(" ++ show status ++ ")" + DetailedSyscallExit_connect + SyscallExitDetails_connect { enterDetail = SyscallEnterDetails_connect{sockfd, sockAddr, addrlen}} -> + "connect(" ++ show sockfd ++ show sockAddr ++ ", " ++ show addrlen ++ ") = " ++ show sockfd + DetailedSyscallExit_unimplemented syscall syscallArgs result -> "unimplemented_syscall_details(" ++ show syscall ++ ", " ++ show syscallArgs ++ ") = " ++ show result diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index 149688d..b6b0ef4 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -1,4 +1,5 @@ #include +#include module System.Hatrace.Types ( FileAccessMode(..) @@ -6,11 +7,15 @@ module System.Hatrace.Types , fileExistence , CIntRepresentable(..) , HatraceShow(..) + , SockAddr(..) ) where import Data.Bits import Data.List (intercalate) -import Foreign.C.Types (CInt(..)) +import Foreign.C.Types (CInt(..), CUInt(..)) +import Foreign.C.String (CString, peekCString, newCString) +import Foreign.Storable (Storable(..)) + -- | Helper type class for int-sized enum-like types class CIntRepresentable a where @@ -65,3 +70,22 @@ instance CIntRepresentable FileAccessMode where } where accessBits = (#const R_OK) .|. (#const W_OK) .|. (#const X_OK) + +data SockAddr = SockAddr + { sa_family :: CUInt + , sa_data :: String + } deriving (Eq, Ord, Show) + +instance Storable SockAddr where + sizeOf _ = #{size struct sockaddr} + alignment _ = #{alignment struct sockaddr} + peek p = do + f <- #{peek struct sockaddr, sa_family} p + d <- (#{peek struct sockaddr, sa_family} p >>= peekCString) + return SockAddr { sa_family = f + , sa_data = d + } + poke p sockAddr = do + addr <- newCString $ sa_data sockAddr + #{poke struct sockaddr, sa_family} p $ sa_family sockAddr + #{poke struct sockaddr, sa_data} p addr From effa6f7eabb7e7863fd6af418f6dd7af95940f76 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Mon, 13 May 2019 23:49:20 +0200 Subject: [PATCH 02/16] Replace peek by Ptrace.peek --- src/System/Hatrace.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System/Hatrace.hs b/src/System/Hatrace.hs index 35dfa42..8215e90 100644 --- a/src/System/Hatrace.hs +++ b/src/System/Hatrace.hs @@ -100,7 +100,7 @@ import Foreign.Marshal.Alloc (alloca) import Foreign.Marshal.Array (withArray) import Foreign.Marshal.Utils (withMany) import Foreign.Ptr (Ptr, nullPtr, wordPtrToPtr) -import Foreign.Storable (peek, peekByteOff, sizeOf) +import Foreign.Storable (peekByteOff, sizeOf) import GHC.Stack (HasCallStack, callStack, getCallStack, prettySrcLoc) import System.Directory (canonicalizePath, doesFileExist, findExecutable) import System.Exit (ExitCode(..), die) @@ -109,6 +109,7 @@ import System.IO.Error (modifyIOError, ioeGetLocation, ioeSetLocation) import System.Linux.Ptrace (TracedProcess(..), peekBytes, peekNullTerminatedBytes, peekNullWordTerminatedWords, detach) import System.Linux.Ptrace.Syscall hiding (ptrace_syscall, ptrace_detach) import qualified System.Linux.Ptrace.Syscall as Ptrace.Syscall +import qualified System.Linux.Ptrace as Ptrace import System.Linux.Ptrace.Types (Regs(..)) import System.Linux.Ptrace.X86_64Regs (X86_64Regs(..)) import System.Linux.Ptrace.X86Regs (X86Regs(..)) @@ -124,7 +125,6 @@ import UnliftIO.IORef (newIORef, writeIORef, readIORef) import System.Hatrace.SyscallTables.Generated (KnownSyscall(..), syscallName, syscallMap_i386, syscallMap_x64_64) import System.Hatrace.Types - mapLeft :: (a1 -> a2) -> Either a1 b -> Either a2 b mapLeft f = either (Left . f) Right @@ -791,7 +791,7 @@ getSyscallEnterDetails syscall syscallArgs pid = let proc = TracedProcess pid in pure $ DetailedSyscallEnter_exit $ SyscallEnterDetails_exit { status = fromIntegral status } Syscall_connect -> do let SyscallArgs{ arg0 = sockfd, arg1 = addr, arg2 = addrlen} = syscallArgs - sockAddr <- (peek (word64ToPtr addr) :: IO SockAddr) + sockAddr <- (Ptrace.peek (TracedProcess pid) (word64ToPtr addr) :: IO SockAddr) pure $ DetailedSyscallEnter_connect $ SyscallEnterDetails_connect { sockfd = fromIntegral sockfd , addr = word64ToPtr addr From a8d390fdb51e27ddbba469e4480dbe15719d14ab Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Sun, 2 Jun 2019 18:02:59 +0200 Subject: [PATCH 03/16] New types --- src/System/Hatrace/Types.hsc | 62 ++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index b6b0ef4..3051d98 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -12,7 +12,7 @@ module System.Hatrace.Types import Data.Bits import Data.List (intercalate) -import Foreign.C.Types (CInt(..), CUInt(..)) +import Foreign.C.Types (CInt(..), CUShort(..)) import Foreign.C.String (CString, peekCString, newCString) import Foreign.Storable (Storable(..)) @@ -72,16 +72,72 @@ instance CIntRepresentable FileAccessMode where accessBits = (#const R_OK) .|. (#const W_OK) .|. (#const X_OK) data SockAddr = SockAddr - { sa_family :: CUInt + { sa_family :: CUShort , sa_data :: String } deriving (Eq, Ord, Show) + + +data Inet6Addr = Inet6Adrr ByteString -- IPv6 address (16 bytes) + +data SockAddr = UnixSockAddr + { + sun_family :: CUInt -- should be AF_UNIX + sun_path :: String + } + | InetSockAddr + { sin_family :: CUINT -- should be AF_INET + , sin_port :: CUShort + , sin_addr :: CULong + , sin_zero :: String + } + | Inet6SockAddr + { sin6_family :: CUInt -- should be AF_INET6 + , sin6_port :: CUShort -- port number + , sin6_flowinfo :: CULong -- IPv6 flow information + , sin6_addr :: Inet6Addr -- IPv6 address + , sin6_scope_id :: CUInt -- Scope ID + } + | NetlinkSockAddr + { nl_pad :: UShort + , nl_pid :: CInt + , nl_groups :: CUInt + } + | PacketSockAddr + { sll_protocol :: CUShort + , sll_ifindex :: Int + , sll_hatype :: CUShort + , sll_pttype :: Char + , sll_halen :: Char + , sll_len :: ByteString + } + | UnsupportedFamilySockAddr + { sa_family :: CUShort + } + +peekUnixSockAddr :: Pointer -> Int -> IO SockAddr +peekUnixSockAddr p addrSize = do + family <- #{peek struct sockaddr_un, sa_family} p + case addrSize of + {#size struct sockaddr_un} -> return UnixSockAddr { + sun_family = family, + sun_path = "" + } + _ -> do + + instance Storable SockAddr where sizeOf _ = #{size struct sockaddr} alignment _ = #{alignment struct sockaddr} peek p = do f <- #{peek struct sockaddr, sa_family} p - d <- (#{peek struct sockaddr, sa_family} p >>= peekCString) + let d = case f of + (#const AF_UNIX) -> "Unix" + (#const AF_INET) -> "Inet" + (#const AF_INET6) -> "Inet6" + (#const AF_NETLINK) -> "Neetlink" + (#const AF_PACKET) -> "Packet" + _ -> "Unknown" return SockAddr { sa_family = f , sa_data = d } From d6c5e2a1e28bfe72c026edeaab7a7927a0d4180f Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Sun, 2 Jun 2019 23:35:37 +0200 Subject: [PATCH 04/16] Add wrapper for remote pointers in Types.hsc --- src/System/Hatrace.hs | 7 +- src/System/Hatrace/Types.hsc | 172 +++++++++++++++++++++++------------ 2 files changed, 116 insertions(+), 63 deletions(-) diff --git a/src/System/Hatrace.hs b/src/System/Hatrace.hs index 8215e90..821d172 100644 --- a/src/System/Hatrace.hs +++ b/src/System/Hatrace.hs @@ -790,12 +790,13 @@ getSyscallEnterDetails syscall syscallArgs pid = let proc = TracedProcess pid in let SyscallArgs{ arg0 = status } = syscallArgs pure $ DetailedSyscallEnter_exit $ SyscallEnterDetails_exit { status = fromIntegral status } Syscall_connect -> do - let SyscallArgs{ arg0 = sockfd, arg1 = addr, arg2 = addrlen} = syscallArgs - sockAddr <- (Ptrace.peek (TracedProcess pid) (word64ToPtr addr) :: IO SockAddr) + let SyscallArgs{ arg0 = sockfd, arg1 = addr, arg2 = addrLen} = syscallArgs + let addrPtr = word64ToPtr addr + sockAddr <- wrapPeekVariableLength (TracedProcess pid) (word64ToPtr addr) addrLen peekSockAddr pure $ DetailedSyscallEnter_connect $ SyscallEnterDetails_connect { sockfd = fromIntegral sockfd , addr = word64ToPtr addr - , addrlen = fromIntegral addrlen + , addrlen = fromIntegral addrLen , sockAddr = sockAddr } Syscall_exit_group -> do diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index 3051d98..3614882 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -1,5 +1,10 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE ScopedTypeVariables #-} + #include #include +#include module System.Hatrace.Types ( FileAccessMode(..) @@ -8,14 +13,20 @@ module System.Hatrace.Types , CIntRepresentable(..) , HatraceShow(..) , SockAddr(..) + , wrapPeekVariableLength + , peekSockAddr ) where import Data.Bits +import qualified Data.ByteString as BS +import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Data.List (intercalate) -import Foreign.C.Types (CInt(..), CUShort(..)) +import Data.Word (Word64) +import Foreign.C.Types (CInt(..), CUShort(..), CUInt(..), CULong(..), CChar) import Foreign.C.String (CString, peekCString, newCString) import Foreign.Storable (Storable(..)) - +import Foreign.Ptr +import System.Linux.Ptrace (TracedProcess(..), peekBytes) -- | Helper type class for int-sized enum-like types class CIntRepresentable a where @@ -71,59 +82,102 @@ instance CIntRepresentable FileAccessMode where where accessBits = (#const R_OK) .|. (#const W_OK) .|. (#const X_OK) -data SockAddr = SockAddr - { sa_family :: CUShort - , sa_data :: String - } deriving (Eq, Ord, Show) +data Inet6Addr = Inet6Adrr BS.ByteString -- IPv6 address (16 bytes) + deriving (Eq, Ord, Show) + +data SockAddr + = SockAddrUnix UnixSockAddr + | SockAddrInet InetSockAddr + | SockAddrInet6 Inet6SockAddr + | SockAddrNetlink NetlinkSockAddr + | SockAddrPacket PacketSockAddr + | SockAddrUnsupportedFamily UnsupportedFamilySockAddr + deriving (Eq, Ord, Show) + +data UnixSockAddr = UnixSockAddr + { sun_family :: !CUShort -- ^ should be AF_UNIX + , sun_path :: !BS.ByteString + } + deriving (Eq, Ord, Show) + +data InetSockAddr = InetSockAddr + { sin_family :: !CUShort -- ^ should be AF_INET + , sin_port :: !CUShort + , sin_addr :: !CULong + , sin_zero :: !BS.ByteString + } + deriving (Eq, Ord, Show) +data Inet6SockAddr = Inet6SockAddr + { sin6_family :: !CUShort -- ^ should be AF_INET6 + , sin6_port :: !CUShort -- ^ port number + , sin6_flowinfo :: !CULong -- ^ IPv6 flow information + , sin6_addr :: !Inet6Addr -- ^ IPv6 address + , sin6_scope_id :: !CUInt -- ^ Scope ID + } + deriving (Eq, Ord, Show) -data Inet6Addr = Inet6Adrr ByteString -- IPv6 address (16 bytes) - -data SockAddr = UnixSockAddr - { - sun_family :: CUInt -- should be AF_UNIX - sun_path :: String - } - | InetSockAddr - { sin_family :: CUINT -- should be AF_INET - , sin_port :: CUShort - , sin_addr :: CULong - , sin_zero :: String - } - | Inet6SockAddr - { sin6_family :: CUInt -- should be AF_INET6 - , sin6_port :: CUShort -- port number - , sin6_flowinfo :: CULong -- IPv6 flow information - , sin6_addr :: Inet6Addr -- IPv6 address - , sin6_scope_id :: CUInt -- Scope ID - } - | NetlinkSockAddr - { nl_pad :: UShort - , nl_pid :: CInt - , nl_groups :: CUInt - } - | PacketSockAddr - { sll_protocol :: CUShort - , sll_ifindex :: Int - , sll_hatype :: CUShort - , sll_pttype :: Char - , sll_halen :: Char - , sll_len :: ByteString - } - | UnsupportedFamilySockAddr - { sa_family :: CUShort - } - -peekUnixSockAddr :: Pointer -> Int -> IO SockAddr +data NetlinkSockAddr = NetlinkSockAddr + { nl_pad :: !CUShort + , nl_pid :: !CInt + , nl_groups :: !CUInt + } + deriving (Eq, Ord, Show) + +data PacketSockAddr = PacketSockAddr + { sll_protocol :: !CUShort + , sll_ifindex :: !Int + , sll_hatype :: !CUShort + , sll_pttype :: !Char + , sll_halen :: !Char + , sll_len :: !BS.ByteString + } + deriving (Eq, Ord, Show) + +data UnsupportedFamilySockAddr = UnsupportedFamilySockAddr + { sa_family :: !CUShort + } + deriving (Eq, Ord, Show) + + +wrapPeekVariableLength :: TracedProcess -> Ptr a -> Word64 -> (Ptr CChar -> Word64 -> IO b) -> IO b +wrapPeekVariableLength process remotePtr numBytes f = do + bytes <- peekBytes process remotePtr (fromIntegral numBytes) + unsafeUseAsCStringLen bytes (\(ptr, len) -> f ptr (fromIntegral len)) + +-- TODO: check types with Template Haskell + +peekSockAddr :: Ptr CChar -> Word64 -> IO SockAddr +peekSockAddr ptr addrSize = do + (f :: CUShort) <- #{peek struct sockaddr, sa_family} ptr + case f of + (#const AF_UNIX) -> SockAddrUnix <$> peekUnixSockAddr ptr addrSize + (#const AF_INET) -> SockAddrUnix <$> peekUnixSockAddr ptr addrSize + (#const AF_INET6) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} + (#const AF_NETLINK) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} + (#const AF_PACKET) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} + _ -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} + + +peekUnixSockAddr :: Ptr CChar -> Word64 -> IO UnixSockAddr peekUnixSockAddr p addrSize = do - family <- #{peek struct sockaddr_un, sa_family} p + family <- #{peek struct sockaddr_un, sun_family} p + print $ "FAMILY: " ++ show family case addrSize of - {#size struct sockaddr_un} -> return UnixSockAddr { + #{size sa_family_t} -> return UnixSockAddr { sun_family = family, sun_path = "" } + _ -> do + let pathPtr = #{ptr struct sockaddr_un, sun_path} p :: Ptr CChar + let pathSize = addrSize - #{size sa_family_t} :: Word64 + path <- BS.packCStringLen (pathPtr, fromIntegral pathSize) + return UnixSockAddr { + sun_family = family, + sun_path = path + } instance Storable SockAddr where @@ -131,17 +185,15 @@ instance Storable SockAddr where alignment _ = #{alignment struct sockaddr} peek p = do f <- #{peek struct sockaddr, sa_family} p - let d = case f of - (#const AF_UNIX) -> "Unix" - (#const AF_INET) -> "Inet" - (#const AF_INET6) -> "Inet6" - (#const AF_NETLINK) -> "Neetlink" - (#const AF_PACKET) -> "Packet" - _ -> "Unknown" - return SockAddr { sa_family = f - , sa_data = d - } - poke p sockAddr = do - addr <- newCString $ sa_data sockAddr - #{poke struct sockaddr, sa_family} p $ sa_family sockAddr - #{poke struct sockaddr, sa_data} p addr + let d = + case f of + (#const AF_UNIX) -> "Unix" + (#const AF_INET) -> "Inet" + (#const AF_INET6) -> "Inet6" + (#const AF_NETLINK) -> "Netlink" + (#const AF_PACKET) -> "Packet" + _ -> "Unknown" + return $ SockAddrUnsupportedFamily UnsupportedFamilySockAddr + { sa_family = f + } + poke p sockAddr = undefined From f1b6e030a73962378dd660c64ffaf31fe242c574 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Fri, 14 Jun 2019 18:41:51 +0200 Subject: [PATCH 05/16] Add Implementation IPv6 socket --- hatrace.cabal | 1 + src/System/Hatrace/Types.hsc | 83 +++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/hatrace.cabal b/hatrace.cabal index da1d304..3743bf2 100644 --- a/hatrace.cabal +++ b/hatrace.cabal @@ -48,6 +48,7 @@ library , unix , unliftio , unliftio-core + , wide-word ghc-options: -Wall default-language: Haskell2010 diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index 3614882..bfbbadd 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -5,6 +5,8 @@ #include #include #include +#include + module System.Hatrace.Types ( FileAccessMode(..) @@ -21,12 +23,13 @@ import Data.Bits import qualified Data.ByteString as BS import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Data.List (intercalate) -import Data.Word (Word64) +import Data.Word (Word32, Word64) import Foreign.C.Types (CInt(..), CUShort(..), CUInt(..), CULong(..), CChar) -import Foreign.C.String (CString, peekCString, newCString) +import Foreign.C.String (peekCString, newCString) import Foreign.Storable (Storable(..)) import Foreign.Ptr import System.Linux.Ptrace (TracedProcess(..), peekBytes) +import Data.WideWord.Word128 -- | Helper type class for int-sized enum-like types class CIntRepresentable a where @@ -83,7 +86,7 @@ instance CIntRepresentable FileAccessMode where accessBits = (#const R_OK) .|. (#const W_OK) .|. (#const X_OK) -data Inet6Addr = Inet6Adrr BS.ByteString -- IPv6 address (16 bytes) +data Inet6Addr = Inet6Addr { s6_addr :: Word128 } -- IPv6 address (16 bytes) deriving (Eq, Ord, Show) data SockAddr @@ -101,11 +104,13 @@ data UnixSockAddr = UnixSockAddr } deriving (Eq, Ord, Show) +data InetAddr = InetAddr { s_addr :: CUInt } + deriving (Eq, Ord, Show) + data InetSockAddr = InetSockAddr { sin_family :: !CUShort -- ^ should be AF_INET , sin_port :: !CUShort - , sin_addr :: !CULong - , sin_zero :: !BS.ByteString + , sin_addr :: !InetAddr } deriving (Eq, Ord, Show) @@ -153,8 +158,8 @@ peekSockAddr ptr addrSize = do (f :: CUShort) <- #{peek struct sockaddr, sa_family} ptr case f of (#const AF_UNIX) -> SockAddrUnix <$> peekUnixSockAddr ptr addrSize - (#const AF_INET) -> SockAddrUnix <$> peekUnixSockAddr ptr addrSize - (#const AF_INET6) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} + (#const AF_INET) -> SockAddrInet <$> peekInetSockAddr ptr + (#const AF_INET6) -> SockAddrInet6 <$> peekInet6SockAddr ptr (#const AF_NETLINK) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} (#const AF_PACKET) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} _ -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} @@ -163,7 +168,6 @@ peekSockAddr ptr addrSize = do peekUnixSockAddr :: Ptr CChar -> Word64 -> IO UnixSockAddr peekUnixSockAddr p addrSize = do family <- #{peek struct sockaddr_un, sun_family} p - print $ "FAMILY: " ++ show family case addrSize of #{size sa_family_t} -> return UnixSockAddr { sun_family = family, @@ -180,20 +184,49 @@ peekUnixSockAddr p addrSize = do } -instance Storable SockAddr where - sizeOf _ = #{size struct sockaddr} - alignment _ = #{alignment struct sockaddr} - peek p = do - f <- #{peek struct sockaddr, sa_family} p - let d = - case f of - (#const AF_UNIX) -> "Unix" - (#const AF_INET) -> "Inet" - (#const AF_INET6) -> "Inet6" - (#const AF_NETLINK) -> "Netlink" - (#const AF_PACKET) -> "Packet" - _ -> "Unknown" - return $ SockAddrUnsupportedFamily UnsupportedFamilySockAddr - { sa_family = f - } - poke p sockAddr = undefined +peekInetSockAddr :: Ptr CChar -> IO InetSockAddr +peekInetSockAddr ptr = do + family <- #{peek struct sockaddr_in, sin_family} ptr + port <- #{peek struct sockaddr_in, sin_port} ptr + addr <- #{peek struct sockaddr_in, sin_addr} ptr + return InetSockAddr { + sin_family = family, + sin_port = port, + sin_addr = addr + } + + +peekInet6SockAddr :: Ptr CChar -> IO Inet6SockAddr +peekInet6SockAddr ptr = do + family <- #{peek struct sockaddr_in6, sin6_family} ptr + port <- #{peek struct sockaddr_in6, sin6_port} ptr + flowinfo <- #{peek struct sockaddr_in6, sin6_flowinfo} ptr + addr <- #{peek struct sockaddr_in6, sin6_addr} ptr + scopeId <- #{peek struct sockaddr_in6, sin6_scope_id} ptr + return $ Inet6SockAddr { + sin6_family = family, + sin6_port = port, + sin6_flowinfo = flowinfo, + sin6_addr = addr, + sin6_scope_id = scopeId + } + + +instance Storable Inet6Addr where + sizeOf _ = #{size struct in6_addr} + alignment _ = #{alignment struct in6_addr} + peek ptr = do + addr <- #{peek struct in6_addr, s6_addr} ptr + return $ Inet6Addr { s6_addr = addr } + poke ptr (Inet6Addr addr) = do + #{poke struct in6_addr, s6_addr} ptr addr + + +instance Storable InetAddr where + sizeOf _ = #{size struct in_addr} + alignment _ = #{alignment struct in_addr} + peek ptr = do + addr <- #{peek struct in_addr, s_addr} ptr + return $ InetAddr { s_addr = addr} + poke ptr (InetAddr addr) = do + #{poke struct in_addr, s_addr} ptr addr From 82709c773ec77459df3c049b18982417534381b8 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Fri, 14 Jun 2019 19:15:00 +0200 Subject: [PATCH 06/16] Add PacketSockAddr implementation --- src/System/Hatrace/Types.hsc | 55 ++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index bfbbadd..dfb7a8b 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -6,7 +6,8 @@ #include #include #include - +#include +#include module System.Hatrace.Types ( FileAccessMode(..) @@ -24,7 +25,7 @@ import qualified Data.ByteString as BS import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Data.List (intercalate) import Data.Word (Word32, Word64) -import Foreign.C.Types (CInt(..), CUShort(..), CUInt(..), CULong(..), CChar) +import Foreign.C.Types (CInt(..), CUShort(..), CUInt(..), CULong(..), CChar, CUChar) import Foreign.C.String (peekCString, newCString) import Foreign.Storable (Storable(..)) import Foreign.Ptr @@ -124,19 +125,21 @@ data Inet6SockAddr = Inet6SockAddr deriving (Eq, Ord, Show) data NetlinkSockAddr = NetlinkSockAddr - { nl_pad :: !CUShort + { nl_family :: !CUShort + , nl_pad :: !CUShort , nl_pid :: !CInt , nl_groups :: !CUInt } deriving (Eq, Ord, Show) data PacketSockAddr = PacketSockAddr - { sll_protocol :: !CUShort + { sll_family :: !CUShort + , sll_protocol :: !CUShort , sll_ifindex :: !Int , sll_hatype :: !CUShort - , sll_pttype :: !Char - , sll_halen :: !Char - , sll_len :: !BS.ByteString + , sll_pkttype :: !CUChar + , sll_halen :: !CUChar + , sll_addr :: !Word64 } deriving (Eq, Ord, Show) @@ -160,8 +163,8 @@ peekSockAddr ptr addrSize = do (#const AF_UNIX) -> SockAddrUnix <$> peekUnixSockAddr ptr addrSize (#const AF_INET) -> SockAddrInet <$> peekInetSockAddr ptr (#const AF_INET6) -> SockAddrInet6 <$> peekInet6SockAddr ptr - (#const AF_NETLINK) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} - (#const AF_PACKET) -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} + (#const AF_NETLINK) -> SockAddrNetlink <$> peekNetlinkSockAddr ptr + (#const AF_PACKET) -> SockAddrPacket <$> peekPacketSockAddr ptr _ -> SockAddrUnsupportedFamily <$> return UnsupportedFamilySockAddr {sa_family = f} @@ -196,6 +199,20 @@ peekInetSockAddr ptr = do } +peekNetlinkSockAddr :: Ptr CChar -> IO NetlinkSockAddr +peekNetlinkSockAddr ptr = do + family <- #{peek struct sockaddr_nl, nl_family} ptr + pad <- #{peek struct sockaddr_nl, nl_pad} ptr + pid <- #{peek struct sockaddr_nl, nl_pid} ptr + groups <- #{peek struct sockaddr_nl, nl_groups} ptr + return NetlinkSockAddr { + nl_family = family, + nl_pad = pad, + nl_pid = pid, + nl_groups = groups + } + + peekInet6SockAddr :: Ptr CChar -> IO Inet6SockAddr peekInet6SockAddr ptr = do family <- #{peek struct sockaddr_in6, sin6_family} ptr @@ -212,6 +229,26 @@ peekInet6SockAddr ptr = do } +peekPacketSockAddr :: Ptr CChar -> IO PacketSockAddr +peekPacketSockAddr ptr = do + family <- #{peek struct sockaddr_ll, sll_family} ptr + protocol <- #{peek struct sockaddr_ll, sll_protocol} ptr + ifindex <- #{peek struct sockaddr_ll, sll_ifindex} ptr + hatype <- #{peek struct sockaddr_ll, sll_hatype} ptr + pkttype <- #{peek struct sockaddr_ll, sll_pkttype} ptr + halen <- #{peek struct sockaddr_ll, sll_halen} ptr + addr <- #{peek struct sockaddr_ll, sll_addr} ptr + return PacketSockAddr { + sll_family = family, + sll_protocol = protocol, + sll_ifindex = ifindex, + sll_hatype = hatype, + sll_pkttype = pkttype, + sll_halen = halen, + sll_addr = addr + } + + instance Storable Inet6Addr where sizeOf _ = #{size struct in6_addr} alignment _ = #{alignment struct in6_addr} From 4a78e9ee97ce5d360e681dc01f18c3cf45bfdf38 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Sat, 15 Jun 2019 13:21:11 +0200 Subject: [PATCH 07/16] Cleanup Types.hsc --- src/System/Hatrace/Types.hsc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index dfb7a8b..f6f0cb1 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -24,9 +24,8 @@ import Data.Bits import qualified Data.ByteString as BS import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Data.List (intercalate) -import Data.Word (Word32, Word64) +import Data.Word (Word64) import Foreign.C.Types (CInt(..), CUShort(..), CUInt(..), CULong(..), CChar, CUChar) -import Foreign.C.String (peekCString, newCString) import Foreign.Storable (Storable(..)) import Foreign.Ptr import System.Linux.Ptrace (TracedProcess(..), peekBytes) @@ -203,12 +202,12 @@ peekNetlinkSockAddr :: Ptr CChar -> IO NetlinkSockAddr peekNetlinkSockAddr ptr = do family <- #{peek struct sockaddr_nl, nl_family} ptr pad <- #{peek struct sockaddr_nl, nl_pad} ptr - pid <- #{peek struct sockaddr_nl, nl_pid} ptr + pidNl <- #{peek struct sockaddr_nl, nl_pid} ptr groups <- #{peek struct sockaddr_nl, nl_groups} ptr return NetlinkSockAddr { nl_family = family, nl_pad = pad, - nl_pid = pid, + nl_pid = pidNl, nl_groups = groups } From 8b4898602f8001a54bed9e4fd40c3ce5f7032c65 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Sat, 15 Jun 2019 14:52:54 +0200 Subject: [PATCH 08/16] Add test environment for syscall connect --- Makefile | 4 +++ example-programs/connect.c | 57 ++++++++++++++++++++++++++++++++++++++ test/HatraceSpec.hs | 11 ++++++++ 3 files changed, 72 insertions(+) create mode 100644 example-programs/connect.c diff --git a/Makefile b/Makefile index bb044e4..57ab2dd 100644 --- a/Makefile +++ b/Makefile @@ -59,3 +59,7 @@ example-programs-build/write-EBADF: example-programs/write-EBADF.c example-programs-build/access-itself: example-programs/access-itself.c mkdir -p example-programs-build gcc -static -std=c99 -Wall -Werror example-programs/access-itself.c -o example-programs-build/access-itself + +example-programs-build/connect: example-programs/connect.c + mkdir -p example-programs-build + gcc -static -std=c99 -Wall -Werror example-programs/connect.c -o example-programs-build/connect diff --git a/example-programs/connect.c b/example-programs/connect.c new file mode 100644 index 0000000..105c98c --- /dev/null +++ b/example-programs/connect.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include + +void die_usage(void) +{ + fprintf(stderr, "Usage: connect [FLAG]\n"); + exit(1); +} + +void connectInet6() +{ + int s; + struct sockaddr_in6 addr; + + s = socket(AF_INET6, SOCK_STREAM, 0); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(5000); + inet_pton(AF_INET6, "::1", &addr.sin6_addr); + connect(s, (struct sockaddr *)&addr, sizeof(addr)); + close(s); +} + + +void connectInet() +{ + int s; + struct sockaddr_in6 addr; + + s = socket(AF_INET6, SOCK_STREAM, 0); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(5000); + inet_pton(AF_INET6, "::1", &addr.sin6_addr); + connect(s, (struct sockaddr *)&addr, sizeof(addr)); + close(s); +} + +int main(int argc, char const *argv[]) +{ + if (argc != 2){ + die_usage(); + } + int i = atoi(argv[1]); + switch(i){ + case AF_INET6: + connectInet6(); + case AF_INET: + connectInet(); + default: + connectInet6(); + } + /* code */ + return 0; +} diff --git a/test/HatraceSpec.hs b/test/HatraceSpec.hs index 45236e2..58ad17c 100644 --- a/test/HatraceSpec.hs +++ b/test/HatraceSpec.hs @@ -549,3 +549,14 @@ spec = before_ assertNoChildren $ do ] x_OK = 1 accessModesRequested `shouldBe` [x_OK] + + describe "connect" $ do + it "seen when invoked in a program" $ do + let connect = "example-programs-build/connect" + callProcess "make" ["--quiet", connect] + argv <- procToArgv connect ["0"] + (exitCode, events) <- + sourceTraceForkExecvFullPathWithSink argv $ + syscallExitDetailsOnlyConduit .| CL.consume + exitCode `shouldBe` ExitSuccess + From 7f5eb6dc28c51c474e2f9c8a77f98208da806dc4 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Sun, 16 Jun 2019 14:44:27 +0200 Subject: [PATCH 09/16] Finish test suite for connect syscall --- example-programs/connect.c | 81 +++++++++++++++++++++++++++++------- src/System/Hatrace/Types.hsc | 33 +++++++++++---- test/HatraceSpec.hs | 38 +++++++++++++---- 3 files changed, 122 insertions(+), 30 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index 105c98c..791e426 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -1,6 +1,9 @@ #include #include +#include #include +#include +#include #include #include #include @@ -13,29 +16,64 @@ void die_usage(void) void connectInet6() { - int s; + int sockfd = socket(AF_INET6, SOCK_STREAM, 0); + if(sockfd < 0){ + printf("\n Error : Could not create Inet6 socket \n"); + exit(1); + } struct sockaddr_in6 addr; - - s = socket(AF_INET6, SOCK_STREAM, 0); addr.sin6_family = AF_INET6; addr.sin6_port = htons(5000); inet_pton(AF_INET6, "::1", &addr.sin6_addr); - connect(s, (struct sockaddr *)&addr, sizeof(addr)); - close(s); + connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + close(sockfd); } void connectInet() { - int s; - struct sockaddr_in6 addr; + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd < 0){ + printf("\n Error : Could not create Inet socket \n"); + exit(1); + } + struct sockaddr_in addr; + addr.sin_family = AF_INET; + connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + close(sockfd); +} + +void connectNetlink() +{ + int sockfd = socket(PF_NETLINK, SOCK_RAW, 0); + if(sockfd < 0){ + printf("\n Error: Could not create netlink socket \n"); + exit(1); + } + struct sockaddr_nl addr; + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); /* self pid */ + connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + close(sockfd); +} + +void connectUnix() +{ + int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if(sockfd < 0){ + printf("\n Error: Could not create unix socket \n"); + exit(1); + } + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, UNIX_PATH_MAX, "./demo_socket"); + connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); +} + +void connectPacket() +{ - s = socket(AF_INET6, SOCK_STREAM, 0); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(5000); - inet_pton(AF_INET6, "::1", &addr.sin6_addr); - connect(s, (struct sockaddr *)&addr, sizeof(addr)); - close(s); } int main(int argc, char const *argv[]) @@ -45,12 +83,23 @@ int main(int argc, char const *argv[]) } int i = atoi(argv[1]); switch(i){ - case AF_INET6: - connectInet6(); + case AF_UNIX: + connectUnix(); + break; case AF_INET: connectInet(); - default: + break; + case AF_INET6: connectInet6(); + break; + case AF_PACKET: + connectPacket(); + break; + case AF_NETLINK: + connectNetlink(); + break; + default: + die_usage(); } /* code */ return 0; diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index f6f0cb1..d656f62 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -16,8 +16,15 @@ module System.Hatrace.Types , CIntRepresentable(..) , HatraceShow(..) , SockAddr(..) + , UnixSockAddr(..) + , InetSockAddr(..) + , Inet6SockAddr(..) + , NetlinkSockAddr(..) + , PacketSockAddr(..) , wrapPeekVariableLength , peekSockAddr + , AF(..) + , afToInt ) where import Data.Bits @@ -86,9 +93,6 @@ instance CIntRepresentable FileAccessMode where accessBits = (#const R_OK) .|. (#const W_OK) .|. (#const X_OK) -data Inet6Addr = Inet6Addr { s6_addr :: Word128 } -- IPv6 address (16 bytes) - deriving (Eq, Ord, Show) - data SockAddr = SockAddrUnix UnixSockAddr | SockAddrInet InetSockAddr @@ -104,9 +108,6 @@ data UnixSockAddr = UnixSockAddr } deriving (Eq, Ord, Show) -data InetAddr = InetAddr { s_addr :: CUInt } - deriving (Eq, Ord, Show) - data InetSockAddr = InetSockAddr { sin_family :: !CUShort -- ^ should be AF_INET , sin_port :: !CUShort @@ -147,6 +148,25 @@ data UnsupportedFamilySockAddr = UnsupportedFamilySockAddr } deriving (Eq, Ord, Show) +data InetAddr = InetAddr { s_addr :: CUInt } + deriving (Eq, Ord, Show) + +data Inet6Addr = Inet6Addr { s6_addr :: Word128 } -- IPv6 address (16 bytes) + deriving (Eq, Ord, Show) + +data AF = AF_UNIX + | AF_INET + | AF_INET6 + | AF_NETLINK + | AF_PACKET + deriving (Eq, Ord, Show) + +afToInt :: AF -> Int +afToInt AF_UNIX = (#const AF_UNIX) +afToInt AF_INET = (#const AF_INET) +afToInt AF_INET6 = (#const AF_INET6) +afToInt AF_NETLINK = (#const AF_NETLINK) +afToInt AF_PACKET = (#const AF_PACKET) wrapPeekVariableLength :: TracedProcess -> Ptr a -> Word64 -> (Ptr CChar -> Word64 -> IO b) -> IO b wrapPeekVariableLength process remotePtr numBytes f = do @@ -175,7 +195,6 @@ peekUnixSockAddr p addrSize = do sun_family = family, sun_path = "" } - _ -> do let pathPtr = #{ptr struct sockaddr_un, sun_path} p :: Ptr CChar let pathSize = addrSize - #{size sa_family_t} :: Word64 diff --git a/test/HatraceSpec.hs b/test/HatraceSpec.hs index 58ad17c..cbbd6c5 100644 --- a/test/HatraceSpec.hs +++ b/test/HatraceSpec.hs @@ -5,7 +5,7 @@ module HatraceSpec where -import Control.Monad (when) +import Control.Monad (when, forM_) import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Unlift (MonadUnliftIO) import qualified Data.ByteString as BS @@ -31,6 +31,7 @@ import Text.Read (readMaybe) import UnliftIO.Exception (bracket) import System.Hatrace +import System.Hatrace.Types -- | Assertion we run before each test to ensure no leftover child processes @@ -552,11 +553,34 @@ spec = before_ assertNoChildren $ do describe "connect" $ do it "seen when invoked in a program" $ do + let af = show . afToInt let connect = "example-programs-build/connect" callProcess "make" ["--quiet", connect] - argv <- procToArgv connect ["0"] - (exitCode, events) <- - sourceTraceForkExecvFullPathWithSink argv $ - syscallExitDetailsOnlyConduit .| CL.consume - exitCode `shouldBe` ExitSuccess - + forM_ [AF_UNIX, AF_INET, AF_INET6, AF_NETLINK] $ \code -> do + argv <- procToArgv connect [af code] + (exitCode, events) <- + sourceTraceForkExecvFullPathWithSink argv $ + syscallEnterDetailsOnlyConduit .| CL.consume + exitCode `shouldBe` ExitSuccess + let connectEnterData = + [ addr + | (_pid + , (DetailedSyscallEnter_connect + SyscallEnterDetails_connect + { sockAddr = addr }) + ) <- events + ] + length connectEnterData `shouldBe` 1 + let addr:_ = connectEnterData + case (code, addr) of + (AF_UNIX, SockAddrUnix sa) -> do + sun_family sa `shouldBe` fromIntegral (afToInt AF_UNIX) + (AF_INET, SockAddrInet sa) -> do + sin_family sa `shouldBe` fromIntegral (afToInt AF_INET) + (AF_INET6, SockAddrInet6 sa) -> do + sin6_family sa `shouldBe` fromIntegral (afToInt AF_INET6) + (AF_NETLINK, SockAddrNetlink sa) -> do + nl_family sa `shouldBe` fromIntegral (afToInt AF_NETLINK) + (AF_PACKET, SockAddrPacket sa) -> do + sll_family sa `shouldBe` fromIntegral (afToInt AF_PACKET) + _ -> fail $ "Attribute family and code don't match. Expected: " ++ show (af code) ++ "(" ++ show code ++")" From b8357c8a8ff6d7c789e6f60bc1aaaf6c47b530fd Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Sun, 16 Jun 2019 15:04:09 +0200 Subject: [PATCH 10/16] Make code cleaner --- example-programs/connect.c | 2 +- src/System/Hatrace/Types.hsc | 32 ++++++++++++++++---------------- test/HatraceSpec.hs | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index 791e426..1f5cf32 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -73,7 +73,7 @@ void connectUnix() void connectPacket() { - + /* TODO: implement connect call for packet socket */ } int main(int argc, char const *argv[]) diff --git a/src/System/Hatrace/Types.hsc b/src/System/Hatrace/Types.hsc index d656f62..676f763 100644 --- a/src/System/Hatrace/Types.hsc +++ b/src/System/Hatrace/Types.hsc @@ -103,20 +103,20 @@ data SockAddr deriving (Eq, Ord, Show) data UnixSockAddr = UnixSockAddr - { sun_family :: !CUShort -- ^ should be AF_UNIX + { sun_family :: !CUShort -- ^ should always be AF_UNIX , sun_path :: !BS.ByteString } deriving (Eq, Ord, Show) data InetSockAddr = InetSockAddr - { sin_family :: !CUShort -- ^ should be AF_INET - , sin_port :: !CUShort - , sin_addr :: !InetAddr + { sin_family :: !CUShort -- ^ should always be AF_INET + , sin_port :: !CUShort -- ^ port number + , sin_addr :: !InetAddr -- ^ IPv4 address } deriving (Eq, Ord, Show) data Inet6SockAddr = Inet6SockAddr - { sin6_family :: !CUShort -- ^ should be AF_INET6 + { sin6_family :: !CUShort -- ^ should always be AF_INET6 , sin6_port :: !CUShort -- ^ port number , sin6_flowinfo :: !CULong -- ^ IPv6 flow information , sin6_addr :: !Inet6Addr -- ^ IPv6 address @@ -125,21 +125,21 @@ data Inet6SockAddr = Inet6SockAddr deriving (Eq, Ord, Show) data NetlinkSockAddr = NetlinkSockAddr - { nl_family :: !CUShort - , nl_pad :: !CUShort - , nl_pid :: !CInt - , nl_groups :: !CUInt + { nl_family :: !CUShort -- ^ should always be AF_NETLINK + , nl_pad :: !CUShort -- ^ Should be Zero + , nl_pid :: !CInt -- ^ Port ID + , nl_groups :: !CUInt -- ^ Multicast groups mask } deriving (Eq, Ord, Show) data PacketSockAddr = PacketSockAddr - { sll_family :: !CUShort - , sll_protocol :: !CUShort - , sll_ifindex :: !Int - , sll_hatype :: !CUShort - , sll_pkttype :: !CUChar - , sll_halen :: !CUChar - , sll_addr :: !Word64 + { sll_family :: !CUShort -- ^ should always be AF_PACKET + , sll_protocol :: !CUShort -- ^ Physical-layer protocol + , sll_ifindex :: !Int -- ^ Interface number + , sll_hatype :: !CUShort -- ^ ARP hardware type + , sll_pkttype :: !CUChar -- ^ Packet type + , sll_halen :: !CUChar -- ^ Length of address + , sll_addr :: !Word64 -- ^ Physical-layer address } deriving (Eq, Ord, Show) diff --git a/test/HatraceSpec.hs b/test/HatraceSpec.hs index cbbd6c5..95b3ef7 100644 --- a/test/HatraceSpec.hs +++ b/test/HatraceSpec.hs @@ -583,4 +583,4 @@ spec = before_ assertNoChildren $ do nl_family sa `shouldBe` fromIntegral (afToInt AF_NETLINK) (AF_PACKET, SockAddrPacket sa) -> do sll_family sa `shouldBe` fromIntegral (afToInt AF_PACKET) - _ -> fail $ "Attribute family and code don't match. Expected: " ++ show (af code) ++ "(" ++ show code ++")" + _ -> fail $ "Attribute 'family' doesn't match. Expected: " ++ show (af code) ++ "(" ++ show code ++")" From a6f175768819f8be846e3da8b1c78d98e0d3d569 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Wed, 26 Jun 2019 22:09:42 +0200 Subject: [PATCH 11/16] Reformat connect.c and add error checks for connect sys call --- example-programs/connect.c | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index 1f5cf32..ab8262b 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -8,14 +8,17 @@ #include #include -void die_usage(void) -{ +void die_usage(void){ fprintf(stderr, "Usage: connect [FLAG]\n"); exit(1); } -void connectInet6() -{ +void error_connect(void){ + printf("\n Error: Could not connect to socket."); + exit(1); +} + +void connectInet6(){ int sockfd = socket(AF_INET6, SOCK_STREAM, 0); if(sockfd < 0){ printf("\n Error : Could not create Inet6 socket \n"); @@ -25,13 +28,14 @@ void connectInet6() addr.sin6_family = AF_INET6; addr.sin6_port = htons(5000); inet_pton(AF_INET6, "::1", &addr.sin6_addr); - connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ + error_connect(); + } close(sockfd); } -void connectInet() -{ +void connectInet(){ int sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0){ printf("\n Error : Could not create Inet socket \n"); @@ -39,12 +43,13 @@ void connectInet() } struct sockaddr_in addr; addr.sin_family = AF_INET; - connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ + error_connect(); + } close(sockfd); } -void connectNetlink() -{ +void connectNetlink(){ int sockfd = socket(PF_NETLINK, SOCK_RAW, 0); if(sockfd < 0){ printf("\n Error: Could not create netlink socket \n"); @@ -53,12 +58,13 @@ void connectNetlink() struct sockaddr_nl addr; addr.nl_family = AF_NETLINK; addr.nl_pid = getpid(); /* self pid */ - connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ + error_connect(); + } close(sockfd); } -void connectUnix() -{ +void connectUnix(){ int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); if(sockfd < 0){ printf("\n Error: Could not create unix socket \n"); @@ -68,16 +74,16 @@ void connectUnix() memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, UNIX_PATH_MAX, "./demo_socket"); - connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ + error_connect(); + } } -void connectPacket() -{ +void connectPacket(){ /* TODO: implement connect call for packet socket */ } -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]){ if (argc != 2){ die_usage(); } From ce5ffa47746c49959b9765489c6a2cdc2a9cd546 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Wed, 26 Jun 2019 22:13:53 +0200 Subject: [PATCH 12/16] Remove tab --- example-programs/connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index ab8262b..8a892b0 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -19,8 +19,8 @@ void error_connect(void){ } void connectInet6(){ - int sockfd = socket(AF_INET6, SOCK_STREAM, 0); - if(sockfd < 0){ + int sockfd = socket(AF_INET6, SOCK_STREAM, 0); + if(sockfd < 0){ printf("\n Error : Could not create Inet6 socket \n"); exit(1); } From c21998b244d2e85c3ee14993e18d368bd71cf26e Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Wed, 26 Jun 2019 22:19:11 +0200 Subject: [PATCH 13/16] Remove all tabs --- example-programs/connect.c | 98 +++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index 8a892b0..48c098c 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -9,8 +9,8 @@ #include void die_usage(void){ - fprintf(stderr, "Usage: connect [FLAG]\n"); - exit(1); + fprintf(stderr, "Usage: connect [FLAG]\n"); + exit(1); } void error_connect(void){ @@ -36,8 +36,8 @@ void connectInet6(){ void connectInet(){ - int sockfd = socket(AF_INET, SOCK_STREAM, 0); - if(sockfd < 0){ + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd < 0){ printf("\n Error : Could not create Inet socket \n"); exit(1); } @@ -50,63 +50,63 @@ void connectInet(){ } void connectNetlink(){ - int sockfd = socket(PF_NETLINK, SOCK_RAW, 0); - if(sockfd < 0){ - printf("\n Error: Could not create netlink socket \n"); - exit(1); - } - struct sockaddr_nl addr; - addr.nl_family = AF_NETLINK; + int sockfd = socket(PF_NETLINK, SOCK_RAW, 0); + if(sockfd < 0){ + printf("\n Error: Could not create netlink socket \n"); + exit(1); + } + struct sockaddr_nl addr; + addr.nl_family = AF_NETLINK; addr.nl_pid = getpid(); /* self pid */ - if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ + if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ error_connect(); } - close(sockfd); + close(sockfd); } void connectUnix(){ - int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); - if(sockfd < 0){ - printf("\n Error: Could not create unix socket \n"); - exit(1); - } - struct sockaddr_un addr; - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, UNIX_PATH_MAX, "./demo_socket"); - if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ + int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if(sockfd < 0){ + printf("\n Error: Could not create unix socket \n"); + exit(1); + } + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, UNIX_PATH_MAX, "./demo_socket"); + if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ error_connect(); } } void connectPacket(){ - /* TODO: implement connect call for packet socket */ + /* TODO: implement connect call for packet socket */ } int main(int argc, char const *argv[]){ - if (argc != 2){ - die_usage(); - } - int i = atoi(argv[1]); - switch(i){ - case AF_UNIX: - connectUnix(); - break; - case AF_INET: - connectInet(); - break; - case AF_INET6: - connectInet6(); - break; - case AF_PACKET: - connectPacket(); - break; - case AF_NETLINK: - connectNetlink(); - break; - default: - die_usage(); - } - /* code */ - return 0; + if (argc != 2){ + die_usage(); + } + int i = atoi(argv[1]); + switch(i){ + case AF_UNIX: + connectUnix(); + break; + case AF_INET: + connectInet(); + break; + case AF_INET6: + connectInet6(); + break; + case AF_PACKET: + connectPacket(); + break; + case AF_NETLINK: + connectNetlink(); + break; + default: + die_usage(); + } + /* code */ + return 0; } From f90c455cbce2375b8a4690f8f438d66146842100 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Wed, 26 Jun 2019 23:57:28 +0200 Subject: [PATCH 14/16] Add listener to unix socket --- example-programs/connect.c | 48 +++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index 48c098c..fb007b1 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -7,14 +7,16 @@ #include #include #include +#include void die_usage(void){ fprintf(stderr, "Usage: connect [FLAG]\n"); exit(1); } -void error_connect(void){ - printf("\n Error: Could not connect to socket."); +void error_connect(const char* str){ + int err = errno; + printf("\n Error: Could not connect to %s socket: %s \n", str, strerror(err)); exit(1); } @@ -29,7 +31,7 @@ void connectInet6(){ addr.sin6_port = htons(5000); inet_pton(AF_INET6, "::1", &addr.sin6_addr); if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect(); + error_connect("inet6"); } close(sockfd); } @@ -44,7 +46,7 @@ void connectInet(){ struct sockaddr_in addr; addr.sin_family = AF_INET; if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect(); + error_connect("inet"); } close(sockfd); } @@ -59,11 +61,36 @@ void connectNetlink(){ addr.nl_family = AF_NETLINK; addr.nl_pid = getpid(); /* self pid */ if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect(); + error_connect("netlink"); } close(sockfd); } +int listenUnixSocket(){ + int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if(sockfd < 0){ + printf("\n Error: Could not create unix socket \n"); + exit(1); + } + struct sockaddr_un addr; + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, UNIX_PATH_MAX, "./test_socket"); + if(unlink(addr.sun_path) != 0 && errno != ENOENT){ + printf("\n Failed to unlink."); + exit(1); + } + if(bind(sockfd, (struct sockaddr*) &addr, sizeof(addr)) != 0){ + printf("\n Failed to bind to Unix socket."); + exit(1); + } + if(listen(sockfd, 5) != 0){ + printf("\n Failed to listen to socket file descriptor."); + exit(1); + } + return sockfd; +} + void connectUnix(){ int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); if(sockfd < 0){ @@ -73,9 +100,14 @@ void connectUnix(){ struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, UNIX_PATH_MAX, "./demo_socket"); - if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect(); + snprintf(addr.sun_path, UNIX_PATH_MAX, "./test_socket"); + int listenfd = listenUnixSocket(); + if(connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) != 0){ + error_connect("unix"); + } + if(close(listenfd) != 0 || close(sockfd) != 0){ + printf("\n Failed to close Unix socket."); + exit(1); } } From 8707063568aebf05e12b3e44b153901952c6aa84 Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Thu, 27 Jun 2019 00:04:16 +0200 Subject: [PATCH 15/16] Add test --- example-programs/connect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index fb007b1..94c4e45 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -31,7 +31,7 @@ void connectInet6(){ addr.sin6_port = htons(5000); inet_pton(AF_INET6, "::1", &addr.sin6_addr); if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect("inet6"); + // fail silently, since noone is listening. } close(sockfd); } @@ -46,7 +46,7 @@ void connectInet(){ struct sockaddr_in addr; addr.sin_family = AF_INET; if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect("inet"); + // fail silently, since noone is listening. } close(sockfd); } @@ -61,7 +61,7 @@ void connectNetlink(){ addr.nl_family = AF_NETLINK; addr.nl_pid = getpid(); /* self pid */ if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){ - error_connect("netlink"); + // fail silently, since noone is listening. } close(sockfd); } From 8b729359b36b720d12f456062bdbfe199d1d7d2a Mon Sep 17 00:00:00 2001 From: Stefan Jaax Date: Thu, 27 Jun 2019 00:10:55 +0200 Subject: [PATCH 16/16] Fix indentation --- example-programs/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example-programs/connect.c b/example-programs/connect.c index 94c4e45..736718b 100644 --- a/example-programs/connect.c +++ b/example-programs/connect.c @@ -125,7 +125,7 @@ int main(int argc, char const *argv[]){ connectUnix(); break; case AF_INET: - connectInet(); + connectInet(); break; case AF_INET6: connectInet6();