about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libmain/common-args.cc11
-rw-r--r--src/nix/main.cc55
2 files changed, 55 insertions, 11 deletions
diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc
index 0486932b20..9e1d7cee60 100644
--- a/src/libmain/common-args.cc
+++ b/src/libmain/common-args.cc
@@ -1,6 +1,5 @@
 #include "common-args.hh"
 #include "globals.hh"
-#include "download.hh"
 
 namespace nix {
 
@@ -45,16 +44,6 @@ MixCommonArgs::MixCommonArgs(const string & programName)
             settings.set("max-jobs", s);
         });
 
-    mkFlag()
-        .longName("no-net")
-        .description("disable substituters and consider all previously downloaded files up-to-date")
-        .handler([]() {
-            settings.useSubstitutes = false;
-            settings.tarballTtl = std::numeric_limits<unsigned int>::max();
-            downloadSettings.tries = 0;
-            downloadSettings.connectTimeout = 1;
-        });
-
     std::string cat = "config";
     globalConfig.convertToArgs(*this, cat);
 
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 19bb7a5431..73c4b8db11 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -8,19 +8,52 @@
 #include "shared.hh"
 #include "store-api.hh"
 #include "progress-bar.hh"
+#include "download.hh"
 #include "finally.hh"
 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+
 extern std::string chrootHelperName;
 
 void chrootHelper(int argc, char * * argv);
 
 namespace nix {
 
+/* Check if we have a non-loopback/link-local network interface. */
+static bool haveInternet()
+{
+    struct ifaddrs * addrs;
+
+    if (getifaddrs(&addrs))
+        return true;
+
+    Finally free([&]() { freeifaddrs(addrs); });
+
+    for (auto i = addrs; i; i = i->ifa_next) {
+        if (!i->ifa_addr) continue;
+        if (i->ifa_addr->sa_family == AF_INET) {
+            if (ntohl(((sockaddr_in *) i->ifa_addr)->sin_addr.s_addr) != INADDR_LOOPBACK) {
+                return true;
+            }
+        } else if (i->ifa_addr->sa_family == AF_INET6) {
+            if (!IN6_IS_ADDR_LOOPBACK(((sockaddr_in6 *) i->ifa_addr)->sin6_addr.s6_addr) &&
+                !IN6_IS_ADDR_LINKLOCAL(((sockaddr_in6 *) i->ifa_addr)->sin6_addr.s6_addr))
+                return true;
+        }
+    }
+
+    return false;
+}
+
 std::string programPath;
 
 struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
 {
     bool printBuildLogs = false;
+    bool useNet = true;
 
     NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix")
     {
@@ -53,6 +86,11 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
             .longName("version")
             .description("show version information")
             .handler([&]() { printVersion(programName); });
+
+        mkFlag()
+            .longName("no-net")
+            .description("disable substituters and consider all previously downloaded files up-to-date")
+            .handler([&]() { useNet = false; });
     }
 
     void printFlags(std::ostream & out) override
@@ -108,6 +146,23 @@ void mainWrapped(int argc, char * * argv)
 
     startProgressBar(args.printBuildLogs);
 
+    if (args.useNet && !haveInternet()) {
+        warn("you don't have Internet access; disabling some network-dependent features");
+        args.useNet = false;
+    }
+
+    if (!args.useNet) {
+        // FIXME: should check for command line overrides only.
+        if (!settings.useSubstitutes.overriden)
+            settings.useSubstitutes = false;
+        if (!settings.tarballTtl.overriden)
+            settings.tarballTtl = std::numeric_limits<unsigned int>::max();
+        if (!downloadSettings.tries.overriden)
+            downloadSettings.tries = 0;
+        if (!downloadSettings.connectTimeout.overriden)
+            downloadSettings.connectTimeout = 1;
+    }
+
     args.command->prepare();
     args.command->run();
 }