Skip to content

Instantly share code, notes, and snippets.

@vshabanov
Created October 2, 2017 12:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vshabanov/04b394e1cddad942c67357ad287f1552 to your computer and use it in GitHub Desktop.
Save vshabanov/04b394e1cddad942c67357ad287f1552 to your computer and use it in GitHub Desktop.
Some utilities to work with dns package
resolveA :: DNSCache -> String -> IO (Either T.Text HostAddress)
resolveA c d =
handle Left $ checkDomain id d $ fmap errorStr $ resolve c (B.pack d)
resolveCachedA :: DNSCache -> String -> IO (Maybe (Either T.Text HostAddress))
resolveCachedA c d =
handle (Just . Left) $ checkDomain Just d $ fmap (fmap errorStr) $ resolveCache c (B.pack d)
handle f a = a `E.catch` handleError f
handleError :: (T.Text -> a) -> E.SomeException -> IO a
handleError f e = return $ f $ T.concat ["Exception (badly configured or non-working local BIND?): ", T.pack (show e)]
checkDomain f domain act
| any (`elem` (":/" :: [Char])) domain =
return $ f $ Left "Invalid domain name"
| length domain > 253 = return $ f $ Left "Domain name too long"
| any (\ t -> T.length t > 63) (T.split (== '.') $ T.pack domain) =
return $ f $ Left "Domain name or component too long"
| any (\ t -> T.length t == 0) (T.split (== '.') $ T.pack domain) =
return $ f $ Left "Illegal domain name (empty label)"
| isIPAddr domain = return $ f $ Right $ ipToWord32 domain
| otherwise = act
isIPAddr :: HostName -> Bool
isIPAddr hn = length groups == 4 && all ip groups
where groups = T.split (== '.') $ T.pack hn
ip x = T.length x <= 3 && T.length x > 0 &&
T.all (\ e -> e >= '0' && e <= '9') x &&
read (T.unpack x) <= (255 :: Int)
ipToWord32 :: String -> HostAddress
ipToWord32 = toHostAddress . read
errorStr (Left e) = Left $ case e of
SequenceNumberMismatch -> "Sequence number mismatch?"
TimeoutExpired -> "Timeout"
UnexpectedRDATA -> "Unexpected RDATA (no domain found?)"
IllegalDomain -> "Illegal domain name"
FormatError -> "Name server was unable to interpret the query"
ServerFailure -> "Name server returned failure"
NameError -> "No such domain"
NotImplemented -> "Not implemented (name server failuer)"
OperationRefused -> "Name server refused operaion"
BadOptRecord -> "Bad OPT record"
RetryLimitExceeded -> "Retry limit exceeded"
errorStr (Right x) = Right $ case x of
Hit a -> a
Resolved a -> a
Numeric a -> a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment