aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/store-api.cc35
-rw-r--r--src/libutil/url-parts.hh3
2 files changed, 36 insertions, 2 deletions
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 27be66cac..7bf9235b2 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -10,6 +10,8 @@
#include "archive.hh"
#include "callback.hh"
+#include <regex>
+
namespace nix {
@@ -1091,6 +1093,34 @@ std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Para
}
}
+// The `parseURL` function supports both IPv6 URIs as defined in
+// RFC2732, but also pure addresses. The latter one is needed here to
+// connect to a remote store via SSH (it's possible to do e.g. `ssh root@::1`).
+//
+// This function now ensures that a usable connection string is available:
+// * If the store to be opened is not an SSH store, nothing will be done.
+// * If the URL looks like `root@[::1]` (which is allowed by the URL parser and probably
+// needed to pass further flags), it
+// will be transformed into `root@::1` for SSH (same for `[::1]` -> `::1`).
+// * If the URL looks like `root@::1` it will be left as-is.
+// * In any other case, the string will be left as-is.
+static std::string extractConnStr(const std::string &proto, const std::string &connStr)
+{
+ if (proto.rfind("ssh") != std::string::npos) {
+ std::smatch result;
+ std::regex v6AddrRegex("^((.*)@)?\\[(.*)\\]$");
+
+ if (std::regex_match(connStr, result, v6AddrRegex)) {
+ if (result[1].matched) {
+ return result.str(1) + result.str(3);
+ }
+ return result.str(3);
+ }
+ }
+
+ return connStr;
+}
+
ref<Store> openStore(const std::string & uri_,
const Store::Params & extraParams)
{
@@ -1099,7 +1129,10 @@ ref<Store> openStore(const std::string & uri_,
auto parsedUri = parseURL(uri_);
params.insert(parsedUri.query.begin(), parsedUri.query.end());
- auto baseURI = parsedUri.authority.value_or("") + parsedUri.path;
+ auto baseURI = extractConnStr(
+ parsedUri.scheme,
+ parsedUri.authority.value_or("") + parsedUri.path
+ );
for (auto implem : *Implementations::registered) {
if (implem.uriSchemes.count(parsedUri.scheme)) {
diff --git a/src/libutil/url-parts.hh b/src/libutil/url-parts.hh
index 68be15cb0..5d21b8d1a 100644
--- a/src/libutil/url-parts.hh
+++ b/src/libutil/url-parts.hh
@@ -8,7 +8,8 @@ namespace nix {
// URI stuff.
const static std::string pctEncoded = "(?:%[0-9a-fA-F][0-9a-fA-F])";
const static std::string schemeRegex = "(?:[a-z][a-z0-9+.-]*)";
-const static std::string ipv6AddressRegex = "(?:\\[[0-9a-fA-F:]+\\])";
+const static std::string ipv6AddressSegmentRegex = "[0-9a-fA-F:]+";
+const static std::string ipv6AddressRegex = "(?:\\[" + ipv6AddressSegmentRegex + "\\]|" + ipv6AddressSegmentRegex + ")";
const static std::string unreservedRegex = "(?:[a-zA-Z0-9-._~])";
const static std::string subdelimsRegex = "(?:[!$&'\"()*+,;=])";
const static std::string hostnameRegex = "(?:(?:" + unreservedRegex + "|" + pctEncoded + "|" + subdelimsRegex + ")*)";