{-# LANGUAGE
MagicHash
, RecordWildCards
, UndecidableInstances
#-}
{-# OPTIONS_GHC -Wno-duplicate-exports #-}
module Net.DNSBase.RData.SVCB
(
X_svcb(.., T_SVCB, T_HTTPS
, httpsPriority, httpsTarget, httpsParamValues
, svcPriority, svcTarget, svcParamValues)
, type XsvcbConName
, T_https
, httpsPriority, httpsTarget, httpsParamValues
, T_svcb
, svcPriority, svcTarget, svcParamValues
, KnownSVCParamValue(..)
, SPVSet(..)
, spvLookup
, module Net.DNSBase.RData.SVCB.SPV
, module Net.DNSBase.RData.SVCB.SVCParamValue
, module Net.DNSBase.RData.SVCB.SVCParamKey
) where
import qualified Data.IntMap as IM
import Data.IntMap (IntMap)
import GHC.Exts (proxy#)
import GHC.IsList(IsList(..))
import GHC.TypeLits as TL (TypeError, ErrorMessage(..))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal')
import Net.DNSBase.Internal.Util
import Net.DNSBase.Decode.Domain
import Net.DNSBase.Decode.State
import Net.DNSBase.Domain
import Net.DNSBase.Encode.Metric
import Net.DNSBase.Encode.State
import Net.DNSBase.Nat16
import Net.DNSBase.Present
import Net.DNSBase.RData
import Net.DNSBase.RData.SVCB.SPV
import Net.DNSBase.RData.SVCB.SVCParamKey
import Net.DNSBase.RData.SVCB.SVCParamValue
import Net.DNSBase.RData.SVCB.SPVSet (SPVSet(..), spvSetFromMonoList, spvLookup)
import Net.DNSBase.RRTYPE
type XsvcbConName :: Nat -> Symbol
type family XsvcbConName n where
XsvcbConName N_svcb = "T_SVCB"
XsvcbConName N_https = "T_HTTPS"
XsvcbConName n = TypeError
( ShowType n
:<>: TL.Text " is not a SVCB-based RRTYPE" )
type SPVDecoderMap = IntMap (Int -> SGet SVCParamValue)
type T_https = X_svcb N_https
type T_svcb = X_svcb N_svcb
pattern T_HTTPS :: Word16
-> Domain
-> SPVSet
-> T_https
pattern $bT_HTTPS :: Word16 -> Domain -> SPVSet -> T_https
$mT_HTTPS :: forall {r}.
T_https -> (Word16 -> Domain -> SPVSet -> r) -> ((# #) -> r) -> r
T_HTTPS { T_https -> Word16
httpsPriority, T_https -> Domain
httpsTarget, T_https -> SPVSet
httpsParamValues }
= (X_SVCB httpsPriority httpsTarget httpsParamValues :: T_https)
{-# COMPLETE T_HTTPS #-}
pattern T_SVCB :: Word16
-> Domain
-> SPVSet
-> T_svcb
pattern $bT_SVCB :: Word16 -> Domain -> SPVSet -> T_svcb
$mT_SVCB :: forall {r}.
T_svcb -> (Word16 -> Domain -> SPVSet -> r) -> ((# #) -> r) -> r
T_SVCB { T_svcb -> Word16
svcPriority, T_svcb -> Domain
svcTarget, T_svcb -> SPVSet
svcParamValues }
= (X_SVCB svcPriority svcTarget svcParamValues :: T_svcb)
{-# COMPLETE T_SVCB #-}
type X_svcb :: Nat -> Type
type role X_svcb nominal
data X_svcb n = X_SVCB
{ forall (n :: Nat). X_svcb n -> Word16
x_svcPriority :: Word16
, forall (n :: Nat). X_svcb n -> Domain
x_svcTarget :: Domain
, forall (n :: Nat). X_svcb n -> SPVSet
x_svcParamValues :: SPVSet
}
deriving instance Eq (X_svcb n)
instance (KnownSymbol (XsvcbConName n)) => Show (X_svcb n) where
showsPrec :: Int -> X_svcb n -> ShowS
showsPrec Int
p X_SVCB{Word16
Domain
SPVSet
x_svcPriority :: forall (n :: Nat). X_svcb n -> Word16
x_svcTarget :: forall (n :: Nat). X_svcb n -> Domain
x_svcParamValues :: forall (n :: Nat). X_svcb n -> SPVSet
x_svcPriority :: Word16
x_svcTarget :: Domain
x_svcParamValues :: SPVSet
..} = Int -> ShowS -> ShowS
showsP Int
p (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
String -> ShowS
showString (Proxy# (XsvcbConName n) -> String
forall (n :: Symbol). KnownSymbol n => Proxy# n -> String
symbolVal' (forall {k} (a :: k). Proxy# a
forall (a :: Symbol). Proxy# a
proxy# @(XsvcbConName n))) 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
. Word16 -> ShowS
forall a. Show a => a -> ShowS
shows' Word16
x_svcPriority 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
. Domain -> ShowS
forall a. Show a => a -> ShowS
shows' Domain
x_svcTarget 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
. SPVSet -> ShowS
forall a. Show a => a -> ShowS
shows' SPVSet
x_svcParamValues
instance Ord (X_svcb n) where
X_svcb n
a compare :: X_svcb n -> X_svcb n -> Ordering
`compare` X_svcb n
b = (X_svcb n -> Word16
forall (n :: Nat). X_svcb n -> Word16
x_svcPriority X_svcb n
a) Word16 -> Word16 -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (X_svcb n -> Word16
forall (n :: Nat). X_svcb n -> Word16
x_svcPriority X_svcb n
b)
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> (X_svcb n -> Domain
forall (n :: Nat). X_svcb n -> Domain
x_svcTarget X_svcb n
a) Domain -> Domain -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (X_svcb n -> Domain
forall (n :: Nat). X_svcb n -> Domain
x_svcTarget X_svcb n
b)
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> (X_svcb n -> [SVCParamValue]
forall {n :: Nat}. X_svcb n -> [SVCParamValue]
spvs X_svcb n
a) [SVCParamValue] -> [SVCParamValue] -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (X_svcb n -> [SVCParamValue]
forall {n :: Nat}. X_svcb n -> [SVCParamValue]
spvs X_svcb n
b)
where
spvs :: X_svcb n -> [SVCParamValue]
spvs = SPVSet -> [Item SPVSet]
SPVSet -> [SVCParamValue]
forall l. IsList l => l -> [Item l]
toList (SPVSet -> [SVCParamValue])
-> (X_svcb n -> SPVSet) -> X_svcb n -> [SVCParamValue]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. X_svcb n -> SPVSet
forall (n :: Nat). X_svcb n -> SPVSet
x_svcParamValues
instance Presentable (X_svcb n) where
present :: X_svcb n -> Builder -> Builder
present (X_SVCB Word16
p Domain
d SPVSet
vs) =
Word16 -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present Word16
p (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Domain -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp Domain
d (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder -> [SVCParamValue] -> Builder)
-> [SVCParamValue] -> Builder -> Builder
forall a b c. (a -> b -> c) -> b -> a -> c
flip ((SVCParamValue -> Builder -> Builder)
-> Builder -> [SVCParamValue] -> Builder
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr SVCParamValue -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp) (SPVSet -> [Item SPVSet]
forall l. IsList l => l -> [Item l]
toList SPVSet
vs)
instance (Nat16 n, KnownSymbol (XsvcbConName n)) => KnownRData (X_svcb n) where
type RDataExtensionVal (X_svcb n) = SPVDecoderMap
rdataExtensionVal :: forall b -> (b ~ X_svcb n) => RDataExtensionVal (X_svcb n)
rdataExtensionVal _ = SPVDecoderMap
RDataExtensionVal (X_svcb n)
baseSVCParams
rdType :: forall b -> (b ~ X_svcb n) => RRTYPE
rdType _ = Word16 -> RRTYPE
RRTYPE (Word16 -> RRTYPE) -> Word16 -> RRTYPE
forall a b. (a -> b) -> a -> b
$ natToWord16 n
rdEncode :: forall s. X_svcb n -> SPut s RData
rdEncode (X_SVCB Word16
p Domain
d SPVSet
vs) = do
SizedBuilder -> SPut s RData
forall r s. ErrorContext r => SizedBuilder -> SPut s r
putSizedBuilder (SizedBuilder -> SPut s RData) -> SizedBuilder -> SPut s RData
forall a b. (a -> b) -> a -> b
$ Word16 -> SizedBuilder
mbWord16 Word16
p SizedBuilder -> SizedBuilder -> SizedBuilder
forall a. Semigroup a => a -> a -> a
<> Domain -> SizedBuilder
mbWireForm Domain
d
(SVCParamValue -> SPut s RData) -> [SVCParamValue] -> SPut s RData
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SVCParamValue -> SPut s RData
forall {r} {s}.
(Typeable r, Show r, Eq r) =>
SVCParamValue -> SPutM s r ()
enc ([SVCParamValue] -> SPut s RData)
-> [SVCParamValue] -> SPut s RData
forall a b. (a -> b) -> a -> b
$ SPVSet -> [Item SPVSet]
forall l. IsList l => l -> [Item l]
toList SPVSet
vs
where
enc :: SVCParamValue -> SPutM s r ()
enc (SVCParamValue (a
x :: t)) = do
Word16 -> SPutM s r ()
forall r s. ErrorContext r => Word16 -> SPut s r
put16 (Word16 -> SPutM s r ()) -> Word16 -> SPutM s r ()
forall a b. (a -> b) -> a -> b
$ SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Word16) -> SVCParamKey -> Word16
forall a b. (a -> b) -> a -> b
$ spvKey t
SPutM s r () -> SPutM s r ()
forall r s a. ErrorContext r => SPutM s r a -> SPutM s r a
passLen (SPutM s r () -> SPutM s r ()) -> SPutM s r () -> SPutM s r ()
forall a b. (a -> b) -> a -> b
$ a -> SPutM s r ()
forall a r s.
(KnownSVCParamValue a, ErrorContext r) =>
a -> SPut s r
forall r s. ErrorContext r => a -> SPut s r
encodeSPV a
x
rdDecode :: forall b ->
(b ~ X_svcb n) => RDataExtensionVal (X_svcb n) -> Int -> SGet RData
rdDecode _ RDataExtensionVal (X_svcb n)
sdm Int
len = do
pos0 <- SGet Int
getPosition
x_svcPriority <- get16
x_svcTarget <- getDomainNC
pos1 <- getPosition
vals <- decodeSVCFieldValues (len - (pos1 - pos0))
let x_svcParamValues = [SVCParamValue] -> SPVSet
spvSetFromMonoList ([SVCParamValue] -> SPVSet) -> [SVCParamValue] -> SPVSet
forall a b. (a -> b) -> a -> b
$ [SVCParamValue] -> [SVCParamValue]
forall a. [a] -> [a]
reverse [SVCParamValue]
vals
pure $ RData $ (X_SVCB{..} :: X_svcb n)
where
decodeSVCFieldValues :: Int -> SGet [SVCParamValue]
decodeSVCFieldValues :: Int -> SGet [SVCParamValue]
decodeSVCFieldValues = Int -> SGet [SVCParamValue] -> SGet [SVCParamValue]
forall a. Int -> SGet a -> SGet a
fitSGet (Int -> SGet [SVCParamValue] -> SGet [SVCParamValue])
-> (Int -> Int)
-> Int
-> SGet [SVCParamValue]
-> SGet [SVCParamValue]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int
forall a. a -> a
id (Int -> SGet [SVCParamValue] -> SGet [SVCParamValue])
-> (Int -> SGet [SVCParamValue]) -> Int -> SGet [SVCParamValue]
forall a b. (Int -> a -> b) -> (Int -> a) -> Int -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [SVCParamValue] -> Word16 -> Int -> SGet [SVCParamValue]
loop [] Word16
0
where
loop :: [SVCParamValue] -> Word16 -> Int -> SGet [SVCParamValue]
loop :: [SVCParamValue] -> Word16 -> Int -> SGet [SVCParamValue]
loop [SVCParamValue]
acc !Word16
kmin !Int
n | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = do
pos0 <- SGet Int
getPosition
key <- get16
vlen <- getInt16
when (key == 0xffff) reserved
when (kmin > key) $ nonmono (kmin-1) key
spv <- case IM.lookup (fromIntegral key) sdm of
Just Int -> SGet SVCParamValue
dc -> Int -> SGet SVCParamValue -> SGet SVCParamValue
forall a. Int -> SGet a -> SGet a
fitSGet Int
vlen (SGet SVCParamValue -> SGet SVCParamValue)
-> SGet SVCParamValue -> SGet SVCParamValue
forall a b. (a -> b) -> a -> b
$ Int -> SGet SVCParamValue
dc Int
vlen
Maybe (Int -> SGet SVCParamValue)
Nothing -> Word16 -> ShortByteString -> SVCParamValue
opaqueSPV Word16
key (ShortByteString -> SVCParamValue)
-> SGet ShortByteString -> SGet SVCParamValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> SGet ShortByteString
getShortNByteString Int
vlen
used <- (subtract pos0) <$> getPosition
loop (spv : acc) (key + 1) (n - used)
loop [SVCParamValue]
acc Word16
_ Int
0 = [SVCParamValue] -> SGet [SVCParamValue]
forall a. a -> SGet a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [SVCParamValue]
acc
loop [SVCParamValue]
_ Word16
_ Int
_ = String -> SGet [SVCParamValue]
forall a. String -> SGet a
failSGet String
"internal error"
reserved :: SGet a
reserved = String -> SGet a
forall a. String -> SGet a
failSGet String
"Reserved invalid key: 65535"
nonmono :: a -> a -> SGet a
nonmono a
k1 a
k2 =
String -> SGet a
forall a. String -> SGet a
failSGet (String -> SGet a) -> String -> SGet a
forall a b. (a -> b) -> a -> b
$ String
"Non-increasing keys: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
k1 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
k2
instance (Nat16 n, KnownSymbol (XsvcbConName n))
=> TypeExtensible (X_svcb n) SPVDecoderMap where
type TypeExtensionArg (X_svcb n) b = KnownSVCParamValue b
extendByType :: forall t b ->
(t ~ X_svcb n, TypeExtensionArg t b) =>
SPVDecoderMap -> SPVDecoderMap
extendByType _ b SPVDecoderMap
m
| Int
key Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
mandatoryKey = SPVDecoderMap
m
| Bool
otherwise = Int
-> (Int -> SGet SVCParamValue) -> SPVDecoderMap -> SPVDecoderMap
forall a. Int -> a -> IntMap a -> IntMap a
IM.insert Int
key (decodeSPV b) SPVDecoderMap
m
where
key :: Int
key = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word16 (Word16 -> Int) -> (SVCParamKey -> Word16) -> SVCParamKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Int) -> SVCParamKey -> Int
forall a b. (a -> b) -> a -> b
$ spvKey b
baseSVCParams :: SPVDecoderMap
baseSVCParams :: SPVDecoderMap
baseSVCParams = [(Int, Int -> SGet SVCParamValue)] -> SPVDecoderMap
forall a. [(Int, a)] -> IntMap a
IM.fromList
[ spvMapEntry SPV_mandatory
, spvMapEntry SPV_alpn
, spvMapEntry SPV_ndalpn
, spvMapEntry SPV_port
, spvMapEntry SPV_ipv4hint
, spvMapEntry SPV_ech
, spvMapEntry SPV_ipv6hint
, spvMapEntry SPV_dohpath
, spvMapEntry SPV_tlsgroups
, spvMapEntry SPV_docpath
, spvMapEntry SPV_pvd
]
where
spvMapEntry :: forall a -> KnownSVCParamValue a
=> (Int, Int -> SGet SVCParamValue)
spvMapEntry :: forall a ->
KnownSVCParamValue a => (Int, Int -> SGet SVCParamValue)
spvMapEntry a =
( forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word16 (Word16 -> Int) -> (SVCParamKey -> Word16) -> SVCParamKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Int) -> SVCParamKey -> Int
forall a b. (a -> b) -> a -> b
$ spvKey a
, decodeSPV a)
mandatoryKey :: Int
mandatoryKey :: Int
mandatoryKey = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word16 (Word16 -> Int) -> (SVCParamKey -> Word16) -> SVCParamKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Int) -> SVCParamKey -> Int
forall a b. (a -> b) -> a -> b
$ spvKey SPV_mandatory