{-# LANGUAGE RecordWildCards #-}
module Net.DNSBase.Resolver.Internal.Types
(
ResolverConf(..)
, NameserverConf(..)
, NameserverSpec(..)
, Nameserver(..)
, ResolvSeed(..)
, Resolver(..)
, withResolver
, RDataMap
, OptionMap
, EdnsControls
, QueryControls(
QctlFlags
, EdnsEnabled
, EdnsDisabled
, EdnsVersion
, EdnsUdpSize
, EdnsOptionCtl
)
, DNSIO
, runDNSIO
, liftDNS
, makeQueryFlags
) where
import qualified Crypto.Random as C
import qualified Data.IORef as I
import Data.List (intercalate)
import Network.Socket (AddrInfo(..), PortNumber)
import Net.DNSBase.Decode.Internal.Option
import Net.DNSBase.EDNS.Internal.Option
import Net.DNSBase.Internal.EDNS
import Net.DNSBase.Internal.Error
import Net.DNSBase.Internal.Flags
import Net.DNSBase.Internal.RData
import Net.DNSBase.Internal.Util
type DNSIO = ExceptT DNSError IO
runDNSIO :: DNSIO a -> IO (Either DNSError a)
runDNSIO :: forall a. DNSIO a -> IO (Either DNSError a)
runDNSIO = ExceptT DNSError IO a -> IO (Either DNSError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT
liftDNS :: IO (Either DNSError a) -> DNSIO a
liftDNS :: forall a. IO (Either DNSError a) -> DNSIO a
liftDNS = IO (Either DNSError a) -> ExceptT DNSError IO a
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT
data ResolverConf = ResolverConf
{ ResolverConf -> NameserverConf
rcSource :: NameserverConf
, ResolverConf -> Int
rcTimeout :: Int
, ResolverConf -> Int
rcRetries :: Int
, ResolverConf -> QueryControls
rcQryCtls :: QueryControls
, ResolverConf -> RDataMap
rcRDataMap :: RDataMap
, ResolverConf -> OptionMap
rcOptionMap :: OptionMap
}
data NameserverConf = SourceFile FilePath
| HostList (NonEmpty NameserverSpec)
data NameserverSpec = NameserverSpec
{ NameserverSpec -> String
nameserverName :: String
, NameserverSpec -> Maybe PortNumber
nameserverPort :: Maybe PortNumber
}
data Nameserver = Nameserver
{ Nameserver -> Maybe String
nsName :: Maybe String
, Nameserver -> AddrInfo
nsAddr :: AddrInfo
}
instance Show Nameserver where
showsPrec :: Int -> Nameserver -> ShowS
showsPrec Int
_ (Nameserver {Maybe String
AddrInfo
nsName :: Nameserver -> Maybe String
nsAddr :: Nameserver -> AddrInfo
nsName :: Maybe String
nsAddr :: AddrInfo
..}) =
ShowS -> (String -> ShowS) -> Maybe String -> ShowS
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ShowS
forall a. a -> a
id String -> ShowS
showString Maybe String
nsName
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
'['
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SockAddr -> ShowS
forall a. Show a => a -> ShowS
shows (AddrInfo -> SockAddr
addrAddress AddrInfo
nsAddr)
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
']'
data ResolvSeed = ResolvSeed
{ ResolvSeed -> ResolverConf
seedConfig :: ResolverConf
, ResolvSeed -> RDataMap
seedRDataMap :: RDataMap
, ResolvSeed -> OptionMap
seedOptionMap :: OptionMap
, ResolvSeed -> NonEmpty Nameserver
seedServers :: NonEmpty Nameserver
}
data Resolver = Resolver
{ Resolver -> ResolvSeed
resolvSeed :: ResolvSeed
, Resolver -> IO Word64
resolvRng :: IO Word64
}
withResolver :: ResolvSeed -> (Resolver -> IO a) -> IO a
withResolver :: forall a. ResolvSeed -> (Resolver -> IO a) -> IO a
withResolver ResolvSeed
resolvSeed Resolver -> IO a
f = do
resolvRng <- IORef ChaChaDRG -> IO Word64
getRandom (IORef ChaChaDRG -> IO Word64)
-> IO (IORef ChaChaDRG) -> IO (IO Word64)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (IO ChaChaDRG
forall (randomly :: * -> *).
MonadRandom randomly =>
randomly ChaChaDRG
C.drgNew IO ChaChaDRG
-> (ChaChaDRG -> IO (IORef ChaChaDRG)) -> IO (IORef ChaChaDRG)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ChaChaDRG -> IO (IORef ChaChaDRG)
forall a. a -> IO (IORef a)
I.newIORef)
f Resolver{..}
where
getRandom :: I.IORef C.ChaChaDRG -> IO Word64
getRandom :: IORef ChaChaDRG -> IO Word64
getRandom IORef ChaChaDRG
ref = do
gen <- IORef ChaChaDRG -> IO ChaChaDRG
forall a. IORef a -> IO a
I.readIORef IORef ChaChaDRG
ref
let (bs, gen') = C.randomBytesGenerate 8 gen
!w = ByteString -> Word64
word64be ByteString
bs
w <$ I.writeIORef ref gen'
data QueryControls = QueryControls (FlagOps -> FlagOps) EdnsControls
instance Show QueryControls where
showsPrec :: Int -> QueryControls -> ShowS
showsPrec Int
p (QueryControls FlagOps -> FlagOps
fctl EdnsControls
ectl) = Int -> ShowS -> ShowS
showsP Int
p (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
String -> ShowS
showString String
"QueryControls "
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FlagOps -> ShowS
forall a. Show a => a -> ShowS
shows' (FlagOps -> FlagOps
fctl FlagOps
emptyFlagOps) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EdnsControls -> ShowS
forall a. Show a => a -> ShowS
shows' EdnsControls
ectl
instance Semigroup QueryControls where
(QueryControls FlagOps -> FlagOps
fl1 EdnsControls
edns1) <> :: QueryControls -> QueryControls -> QueryControls
<> (QueryControls FlagOps -> FlagOps
fl2 EdnsControls
edns2) =
(FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls (FlagOps -> FlagOps
fl1 (FlagOps -> FlagOps) -> (FlagOps -> FlagOps) -> FlagOps -> FlagOps
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FlagOps -> FlagOps
fl2) (EdnsControls
edns1 EdnsControls -> EdnsControls -> EdnsControls
forall a. Semigroup a => a -> a -> a
<> EdnsControls
edns2)
instance Monoid QueryControls where
mempty :: QueryControls
mempty = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
forall a. a -> a
id EdnsControls
forall a. Monoid a => a
mempty
pattern QctlFlags :: (FlagOps -> FlagOps)
-> QueryControls
pattern $mQctlFlags :: forall {r}.
QueryControls -> ((FlagOps -> FlagOps) -> r) -> ((# #) -> r) -> r
$bQctlFlags :: (FlagOps -> FlagOps) -> QueryControls
QctlFlags fl <- QueryControls fl _ where
QctlFlags FlagOps -> FlagOps
fl = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
fl EdnsControls
forall a. Monoid a => a
mempty
{-# COMPLETE QctlFlags #-}
makeQueryFlags :: QueryControls -> DNSFlags
makeQueryFlags :: QueryControls -> DNSFlags
makeQueryFlags (QctlFlags FlagOps -> FlagOps
op) = FlagOps -> DNSFlags -> DNSFlags
applyFlagOps (FlagOps -> FlagOps
op FlagOps
emptyFlagOps) DNSFlags
defaultQueryFlags
data EdnsControls = EdnsControls
(Maybe Bool)
(Maybe Word8)
(Maybe Word16)
(OptionCtl -> OptionCtl)
instance Semigroup EdnsControls where
(EdnsControls Maybe Bool
en1 Maybe Word8
vn1 Maybe Word16
sz1 OptionCtl -> OptionCtl
od1) <> :: EdnsControls -> EdnsControls -> EdnsControls
<> (EdnsControls Maybe Bool
en2 Maybe Word8
vn2 Maybe Word16
sz2 OptionCtl -> OptionCtl
od2) =
Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls (Maybe Bool
en1 Maybe Bool -> Maybe Bool -> Maybe Bool
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe Bool
en2) (Maybe Word8
vn1 Maybe Word8 -> Maybe Word8 -> Maybe Word8
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe Word8
vn2) (Maybe Word16
sz1 Maybe Word16 -> Maybe Word16 -> Maybe Word16
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe Word16
sz2) (OptionCtl -> OptionCtl
od1 (OptionCtl -> OptionCtl)
-> (OptionCtl -> OptionCtl) -> OptionCtl -> OptionCtl
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OptionCtl -> OptionCtl
od2)
instance Monoid EdnsControls where
mempty :: EdnsControls
mempty = Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls Maybe Bool
forall a. Maybe a
Nothing Maybe Word8
forall a. Maybe a
Nothing Maybe Word16
forall a. Maybe a
Nothing OptionCtl -> OptionCtl
forall a. a -> a
id
instance Show EdnsControls where
show :: EdnsControls -> String
show (EdnsControls Maybe Bool
en Maybe Word8
vn Maybe Word16
sz OptionCtl -> OptionCtl
od) =
[String] -> String
_showOpts
[ String -> Maybe Bool -> String
forall a. Show a => String -> Maybe a -> String
_showWord String
"edns.enabled" Maybe Bool
en
, String -> Maybe Word8 -> String
forall a. Show a => String -> Maybe a -> String
_showWord String
"edns.version" Maybe Word8
vn
, String -> Maybe Word16 -> String
forall a. Show a => String -> Maybe a -> String
_showWord String
"edns.udpsize" Maybe Word16
sz
, String -> ShowS
_showOdOp String
"edns.options" ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ OptionCtl -> String
forall a. Show a => a -> String
show
(OptionCtl -> String) -> OptionCtl -> String
forall a b. (a -> b) -> a -> b
$ OptionCtl -> OptionCtl
od OptionCtl
emptyOptionCtl ]
where
_showOpts :: [String] -> String
_showOpts :: [String] -> String
_showOpts [String]
os = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) [String]
os
_showWord :: Show a => String -> Maybe a -> String
_showWord :: forall a. Show a => String -> Maybe a -> String
_showWord String
nm Maybe a
w = String -> (a -> String) -> Maybe a -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (\a
s -> String
nm String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
":" String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
s) Maybe a
w
_showOdOp :: String -> String -> String
_showOdOp :: String -> ShowS
_showOdOp String
nm String
os = case String
os of
String
"" -> String
""
String
_ -> String
nm String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
":" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
os
pattern EdnsEnabled :: QueryControls
pattern $mEdnsEnabled :: forall {r}. QueryControls -> ((# #) -> r) -> ((# #) -> r) -> r
$bEdnsEnabled :: QueryControls
EdnsEnabled <-
QueryControls _ (EdnsControls (Just True) _ _ _) where
EdnsEnabled = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
forall a. a -> a
id (Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls (Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True) Maybe Word8
forall a. Maybe a
Nothing Maybe Word16
forall a. Maybe a
Nothing OptionCtl -> OptionCtl
forall a. a -> a
id)
pattern EdnsDisabled :: QueryControls
pattern $mEdnsDisabled :: forall {r}. QueryControls -> ((# #) -> r) -> ((# #) -> r) -> r
$bEdnsDisabled :: QueryControls
EdnsDisabled <-
QueryControls _ (EdnsControls (Just False) _ _ _) where
EdnsDisabled = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
forall a. a -> a
id (Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls (Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False) Maybe Word8
forall a. Maybe a
Nothing Maybe Word16
forall a. Maybe a
Nothing OptionCtl -> OptionCtl
forall a. a -> a
id)
pattern EdnsVersion :: Word8
-> QueryControls
pattern $mEdnsVersion :: forall {r}. QueryControls -> (Word8 -> r) -> ((# #) -> r) -> r
$bEdnsVersion :: Word8 -> QueryControls
EdnsVersion vn <-
QueryControls _ (EdnsControls _ (Just vn) _ _) where
EdnsVersion Word8
vn = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
forall a. a -> a
id (Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls Maybe Bool
forall a. Maybe a
Nothing (Word8 -> Maybe Word8
forall a. a -> Maybe a
Just Word8
vn) Maybe Word16
forall a. Maybe a
Nothing OptionCtl -> OptionCtl
forall a. a -> a
id)
pattern EdnsUdpSize :: Word16
-> QueryControls
pattern $mEdnsUdpSize :: forall {r}. QueryControls -> (Word16 -> r) -> ((# #) -> r) -> r
$bEdnsUdpSize :: Word16 -> QueryControls
EdnsUdpSize sz <-
QueryControls _ (EdnsControls _ _ (Just sz) _) where
EdnsUdpSize Word16
sz = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
forall a. a -> a
id (Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls Maybe Bool
forall a. Maybe a
Nothing Maybe Word8
forall a. Maybe a
Nothing (Word16 -> Maybe Word16
forall a. a -> Maybe a
Just Word16
capped) OptionCtl -> OptionCtl
forall a. a -> a
id)
where
!capped :: Word16
capped = Word16 -> Word16 -> Word16
forall a. Ord a => a -> a -> a
max Word16
minUdpSize (Word16 -> Word16) -> (Word16 -> Word16) -> Word16 -> Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> Word16 -> Word16
forall a. Ord a => a -> a -> a
min Word16
maxUdpSize (Word16 -> Word16) -> Word16 -> Word16
forall a b. (a -> b) -> a -> b
$ Word16
sz
pattern EdnsOptionCtl :: (OptionCtl -> OptionCtl)
-> QueryControls
pattern $mEdnsOptionCtl :: forall {r}.
QueryControls
-> ((OptionCtl -> OptionCtl) -> r) -> ((# #) -> r) -> r
$bEdnsOptionCtl :: (OptionCtl -> OptionCtl) -> QueryControls
EdnsOptionCtl omod <-
QueryControls _ (EdnsControls _ _ _ omod) where
EdnsOptionCtl OptionCtl -> OptionCtl
omod = (FlagOps -> FlagOps) -> EdnsControls -> QueryControls
QueryControls FlagOps -> FlagOps
forall a. a -> a
id (Maybe Bool
-> Maybe Word8
-> Maybe Word16
-> (OptionCtl -> OptionCtl)
-> EdnsControls
EdnsControls Maybe Bool
forall a. Maybe a
Nothing Maybe Word8
forall a. Maybe a
Nothing Maybe Word16
forall a. Maybe a
Nothing OptionCtl -> OptionCtl
omod)
{-# COMPLETE EdnsOptionCtl #-}