summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
authorrnhmjoj <rnhmjoj@inventati.org>2021-06-23 17:24:29 +0200
committerrnhmjoj <rnhmjoj@inventati.org>2021-09-18 16:47:12 +0200
commitb8bfc81d5b2d88b734a311f712fc0ba2b267f9e0 (patch)
tree6d4a9c543a651514f83ffb4a027cac1265dfc683 /nixos/modules
parent44d95b773b0998d5db577c7a856b4d8af2aeec19 (diff)
downloadnixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.tar
nixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.tar.gz
nixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.tar.bz2
nixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.tar.lz
nixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.tar.xz
nixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.tar.zst
nixpkgs-b8bfc81d5b2d88b734a311f712fc0ba2b267f9e0.zip
nixos/qemu: add option to forward ports
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix115
1 files changed, 110 insertions, 5 deletions
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index bf65c7f3d89..9a26e328e4d 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -411,6 +411,75 @@ in
           '';
       };
 
+    virtualisation.forwardPorts = mkOption {
+      type = types.listOf
+        (types.submodule {
+          options.from = mkOption {
+            type = types.enum [ "host" "guest" ];
+            default = "host";
+            description =
+              ''
+                Controls the direction in which the ports are mapped:
+
+                - <literal>"host"</literal> means traffic from the host ports
+                is forwarded to the given guest port.
+
+                - <literal>"guest"</literal> means traffic from the guest ports
+                is forwarded to the given host port.
+              '';
+          };
+          options.proto = mkOption {
+            type = types.enum [ "tcp" "udp" ];
+            default = "tcp";
+            description = "The protocol to forward.";
+          };
+          options.host.address = mkOption {
+            type = types.str;
+            default = "";
+            description = "The IPv4 address of the host.";
+          };
+          options.host.port = mkOption {
+            type = types.port;
+            description = "The host port to be mapped.";
+          };
+          options.guest.address = mkOption {
+            type = types.str;
+            default = "";
+            description = "The IPv4 address on the guest VLAN.";
+          };
+          options.guest.port = mkOption {
+            type = types.port;
+            description = "The guest port to be mapped.";
+          };
+        });
+      default = [];
+      example = lib.literalExample
+        ''
+        [ # forward local port 2222 -> 22, to ssh into the VM
+          { from = "host"; host.port = 2222; guest.port = 22; }
+
+          # forward local port 80 -> 10.0.2.10:80 in the VLAN
+          { from = "guest";
+            guest.address = "10.0.2.10"; guest.port = 80;
+            host.address = "127.0.0.1"; host.port = 80;
+          }
+        ]
+        '';
+      description =
+        ''
+          When using the SLiRP user networking (default), this option allows to
+          forward ports to/from the host/guest.
+
+          <warning><para>
+            If the NixOS firewall on the virtual machine is enabled, you also
+            have to open the guest ports to enable the traffic between host and
+            guest.
+          </para></warning>
+
+          <note><para>Currently QEMU supports only IPv4 forwarding.</para></note>
+        '';
+    };
+
     virtualisation.vlans =
       mkOption {
         type = types.listOf types.ints.unsigned;
@@ -480,7 +549,7 @@ in
       consoles = mkOption {
         type = types.listOf types.str;
         default = let
-          consoles = [ "${qemuSerialDevice},115200n8" "tty0" ];
+          consoles = [ "${qemu-flags.qemuSerialDevice},115200n8" "tty0" ];
         in if cfg.graphics then consoles else reverseList consoles;
         example = [ "console=tty1" ];
         description = ''
@@ -496,17 +565,18 @@ in
 
       networkingOptions =
         mkOption {
-          default = [
+          type = types.listOf types.str;
+          default = [ ];
+          example = [
             "-net nic,netdev=user.0,model=virtio"
-            "-netdev user,id=user.0\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
+            "-netdev user,id=user.0,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
           ];
-          type = types.listOf types.str;
           description = ''
             Networking-related command-line options that should be passed to qemu.
             The default is to use userspace networking (SLiRP).
 
             If you override this option, be advised to keep
-            ''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS} (as seen in the default)
+            ''${QEMU_NET_OPTS:+,$QEMU_NET_OPTS} (as seen in the example)
             to keep the default runtime behaviour.
           '';
         };
@@ -590,6 +660,25 @@ in
 
   config = {
 
+    assertions =
+      lib.concatLists (lib.flip lib.imap cfg.forwardPorts (i: rule:
+        [
+          { assertion = rule.from == "guest" -> rule.proto == "tcp";
+            message =
+              ''
+                Invalid virtualisation.forwardPorts.<entry ${toString i}>.proto:
+                  Guest forwarding supports only TCP connections.
+              '';
+          }
+          { assertion = rule.from == "guest" -> lib.hasPrefix "10.0.2." rule.guest.address;
+            message =
+              ''
+                Invalid virtualisation.forwardPorts.<entry ${toString i}>.guest.address:
+                  The address must be in the default VLAN (10.0.2.0/24).
+              '';
+          }
+        ]));
+
     # Note [Disk layout with `useBootLoader`]
     #
     # If `useBootLoader = true`, we configure 2 drives:
@@ -676,6 +765,22 @@ in
       shared    = { source = ''"''${SHARED_DIR:-$TMPDIR/xchg}"''; target = "/tmp/shared"; };
     };
 
+    virtualisation.qemu.networkingOptions =
+      let
+        forwardingOptions = flip concatMapStrings cfg.forwardPorts
+          ({ proto, from, host, guest }:
+            if from == "host"
+              then "hostfwd=${proto}:${host.address}:${toString host.port}-" +
+                   "${guest.address}:${toString guest.port},"
+              else "'guestfwd=${proto}:${guest.address}:${toString guest.port}-" +
+                   "cmd:${pkgs.netcat}/bin/nc ${host.address} ${toString host.port}',"
+          );
+      in
+      [
+        "-net nic,netdev=user.0,model=virtio"
+        "-netdev user,id=user.0,${forwardingOptions}\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}"
+      ];
+
     # FIXME: Consolidate this one day.
     virtualisation.qemu.options = mkMerge [
       (mkIf (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [