packages feed

moesocks-1.0.0.41: src/Network/MoeSocks/Common.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module Network.MoeSocks.Common where

import Control.Lens
import Control.Monad.Writer hiding (listen)
import Data.IP
import Data.Maybe
import Data.Text.Lens
import Network.MoeSocks.Helper
import Network.MoeSocks.Type
import Network.Socket hiding (send, recv, recvFrom, sendTo)
import Prelude hiding ((-), take)


makePrisms ''IPRange

check_IP_List :: AddressType -> [IPRange] -> Bool
check_IP_List _address@(IPv4_Address _) a_IP_List =
  isJust -
    do
      _ip <- show _address  ^? _Show
      findOf (each . _IPv4Range) (isMatchedTo _ip) a_IP_List

check_IP_List _address@(IPv6_Address _) a_IP_List =
  isJust -
    do
      _ip <- show _address ^? _Show
      findOf (each . _IPv6Range) (isMatchedTo _ip) a_IP_List

check_IP_List _ _ = False

withChecked_IP_List :: AddressType -> ([IPRange], Maybe [IPRange])
                        -> IO a -> IO ()
withChecked_IP_List aAddressType (aDenyList, aAllowList) aIO =
  if check_IP_List aAddressType aDenyList
    then error_ - show aAddressType
                <> " is in the denied list"
    else
      case aAllowList of
        Nothing -> () <$ aIO
        Just _allowList ->
          if not - check_IP_List aAddressType _allowList
            then error_ - show aAddressType
                    <> " is NOT in the allowed list"
            else
              () <$ aIO

getIPLists :: Env -> ([IPRange], Maybe [IPRange])
getIPLists aEnv = (aEnv ^. denyList <> aEnv ^. forbidden_IPs, mempty)

showConnectionType :: ConnectionType -> String
showConnectionType TCP_IP_StreamConnection = "TCP_Stream"
-- showConnectionType TCP_IP_PortBinding      = "TCP_Bind  "
showConnectionType UDP_Port                = "UDP       "

showRequest :: ClientRequest -> String
showRequest _r =
                   _r ^. addressType . to show
                <> ":"
                <> _r ^. portNumber . to show

showRelay :: SockAddr -> ClientRequest -> String
showRelay aSockAddr aClientRequest =
      show aSockAddr <> " -> " <> showRequest aClientRequest

addressType_To_Family :: AddressType -> Family
addressType_To_Family (IPv4_Address _) = AF_INET
addressType_To_Family (IPv6_Address _) = AF_INET6
addressType_To_Family _                = AF_UNSPEC

_SocketType :: Prism' SocketType ConnectionType
_SocketType = prism' connectionType_To_SocketType socketType_To_connectionType
  where
    connectionType_To_SocketType :: ConnectionType -> SocketType
    connectionType_To_SocketType TCP_IP_StreamConnection = Stream
    {-connectionType_To_SocketType TCP_IP_PortBinding      = NoSocketType-}
    connectionType_To_SocketType UDP_Port                = Datagram

    socketType_To_connectionType :: SocketType -> Maybe ConnectionType
    socketType_To_connectionType Stream = Just TCP_IP_StreamConnection
    socketType_To_connectionType Datagram = Just UDP_Port
    socketType_To_connectionType _ = Nothing


initTarget :: ClientRequest -> IO (Socket, SockAddr)
initTarget _clientRequest = do
  let
      _socketType = _clientRequest ^. connectionType . re _SocketType
      _hostName   = _clientRequest ^. addressType . to show . re _Text
      _port       = _clientRequest ^. portNumber
      _family     = _clientRequest ^. addressType . to addressType_To_Family

  getSocketWithHint _family _hostName _port _socketType


setSocketConfig:: Env -> Socket -> IO ()
setSocketConfig aEnv aSocket = do
  setSocketOption aSocket NoDelay 1
  when (aEnv ^. socketOption_TCP_NOTSENT_LOWAT) - do
    tryIO "setSocket_TCP_NOTSENT_LOWAT" - setSocket_TCP_NOTSENT_LOWAT aSocket
    pure ()