-
Notifications
You must be signed in to change notification settings - Fork 696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement DNS-based mirror bootstrap protocol #3947
Conversation
For reference, here's how
|
@@ -0,0 +1,134 @@ | |||
module Distribution.Client.Security.DNS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't hackage-security
a more appropriate place for this functionality?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
75dbee7
to
d23b1e3
Compare
where | ||
ns = take (length s - 8) s | ||
|
||
-- | Parse output of @nslookup -query=TXT $HOSTNAME@ tolerantly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you really sure you don't want to use a parser combinator for this? ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, what's the benefit? :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...well, ideally you would have written it with parser combinators to begin with :P
-- | ||
queryBootstrapMirrors :: Verbosity -> URI -> IO [URI] | ||
queryBootstrapMirrors verbosity repoUri | ||
| uriScheme repoUri `elem` ["http:","https:"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this test. Whether or not the hostname component of a URI is DNS resolvable has nothing to do with the scheme; e.g., ftp also does DNS. file is not a good excuse because these have a blank hostname, e.g. file:///foo
(that's why there's three slashes!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...what kind of test are you suggesting instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test if uriAuthority is Just.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
evaluate (force $ extractMirrors mirrorsDnsName out) | ||
|
||
mirrors <- case mirrors' of | ||
Left e -> (e::SomeException) `seq` return [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you don't want to warn in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I do so implicitly when null mirrors
a few lines below... or do you want to see e
displayed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to see e. If the code is doing something weird that e could have critical information for debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
requiresBootstrap <- Sec.requiresBootstrap r | ||
requiresBootstrap <- withRepo [] Sec.requiresBootstrap | ||
|
||
mirrors <- if requiresBootstrap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems worth mentioning (in info) that we're querying DNS to get some mirrors. And it'll only happen once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered that, but I didn't want to have to duplicate the detection in queryBootstrapMirrors
for when a DNS query is going to occur at all...
So what about:
if requiresBootstrap
then do
info verbosity $ "Trying to locate mirrors via DNS for initial bootstrap of secure repository (" ++ show remoteRepoURI ++ ") ..."
Sec.DNS.queryBootstrapMirrors verbosity remoteRepoURI
else ...
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is what I had in mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Seems reasonable. |
I'm absolutely not an expert on these matters, but can this be vulnerable to DNS spoofing/cache poisoning or some similar attack? |
@23Skidoo we don't rely on DNS to be trustworthy; the trust is established via the signatures inside |
d23b1e3
to
7bc11c6
Compare
This way `cabal` can bootstrap secure repos even if the primary Hackage instance is currently unreachable, as long as there's at least one reachable and working secure mirror available. NB: This new code-path is only used for the initial bootstrap. Once the repository cache has been bootstrapped, its `mirrors.json` meta-data is used instead. See also haskell/hackage-security#171
176ff86
to
ae24c5c
Compare
/cc @edsko |
Commenting on the idea, not on the code: it seems reasonable to me. Like @hvr says, we don't rely on DNS information to be accurate to guard against attacks; as long as we get pointed to a server and that server has metadata signed by the root keys we expect, we're fine (of course, the distribution of those root keys is a different matter but that's orthogonal to this PR). |
I havn't reviewed the code yet, but I concur with edsko about the security. |
Merged, thanks! |
This way
cabal
can bootstrap secure repos even if the primary Hackageinstance is currently unreachable, as long as there's at least one
reachable and working secure mirror available.
NB: This new code-path is only used for the initial bootstrap. Once the
repository cache has been bootstrapped, its @mirrors.json@ meta-data is
used instead.
See also haskell/hackage-security#171