Start porting VM to Windows

This commit is contained in:
Micah Lee 2021-08-09 12:04:17 -07:00
parent b82ffa2cac
commit 173f31ff41
6 changed files with 166 additions and 35 deletions

View file

@ -31,7 +31,13 @@ Create a .deb:
Install dependencies: Install dependencies:
```sh ```sh
sudo dnf install -y rpm-build podman python3 python3-setuptools python3-pyside2 python3-appdirs python3-click python3-pyxdg python3-requests python3-colorama sudo dnf install -y rpm-build podman python3 python3-setuptools python3-pyside2 python3-appdirs python3-click python3-pyxdg python3-requests python3-colorama python3-psutil
```
Build the latest container:
```sh
./install/linux/build-container.py
``` ```
Run from source tree: Run from source tree:
@ -62,7 +68,9 @@ If you don't have it already, install poetry (`pip3 install --user poetry`). The
poetry install poetry install
``` ```
Make sure [Docker Desktop](https://www.docker.com/products/docker-desktop) and vagrant (`brew install vagrant`) are installed and run this to collect the binaries from Docker Desktop and then build a custom Alpine Linux ISO for Dangerzone, and copy them into the `share` folder: Make sure [Docker Desktop](https://www.docker.com/products/docker-desktop) and vagrant (`brew install vagrant`) are installed.
Run this to build a custom Alpine Linux ISO for Dangerzone, and copy it into the `share` folder:
```sh ```sh
./install/macos/make-vm.sh ./install/macos/make-vm.sh
@ -97,8 +105,6 @@ The output is in the `dist` folder.
## Windows ## Windows
Install [Docker Desktop](https://www.docker.com/products/docker-desktop).
These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH. These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
Download Python 3.9.0, 32-bit (x86) from https://www.python.org/downloads/release/python-390/. I downloaded python-3.9.0.exe. When installing it, make sure to check the "Add Python 3.9 to PATH" checkbox on the first page of the installer. Download Python 3.9.0, 32-bit (x86) from https://www.python.org/downloads/release/python-390/. I downloaded python-3.9.0.exe. When installing it, make sure to check the "Add Python 3.9 to PATH" checkbox on the first page of the installer.
@ -115,6 +121,31 @@ Change to the `dangerzone` folder, and install the poetry dependencies:
poetry install poetry install
``` ```
Make sure these are installed:
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
- [Vagrant](https://www.vagrantup.com/downloads)
- [VirtualBox](https://www.virtualbox.org/wiki/Downloads)
- [Chocolatey](https://chocolatey.org/install)
Open an administrator PowerShell and run:
```
choco install vcbuildtools
```
Build OpenSSH:
```
powershell.exe -executionpolicy remotesigned -File .\install\windows\make-openssh.ps1
```
Run this to build a custom Alpine Linux ISO for Dangerzone, and copy it (and some binaries from Docker) into the `share` folder:
```
.\install\windows\make-vm.bat
```
After that you can launch dangerzone during development with: After that you can launch dangerzone during development with:
``` ```

View file

@ -1,5 +1,4 @@
import os import os
import sys
import subprocess import subprocess
import uuid import uuid
import pipes import pipes
@ -10,6 +9,7 @@ import getpass
import json import json
import psutil import psutil
import time import time
import platform
from PySide2 import QtCore from PySide2 import QtCore
@ -32,6 +32,22 @@ class Vm(QtCore.QObject):
self.sshd_port = None self.sshd_port = None
self.sshd_tunnel_port = None self.sshd_tunnel_port = None
# Folder to hold temporary files related to the VM
self.state_dir = tempfile.TemporaryDirectory()
self.ssh_host_key_path = os.path.join(self.state_dir.name, "host_ed25519")
self.ssh_host_pubkey_path = os.path.join(
self.state_dir.name, "host_ed25519.pub"
)
self.ssh_client_key_path = os.path.join(self.state_dir.name, "client_ed25519")
self.ssh_client_pubkey_path = os.path.join(
self.state_dir.name, "client_ed25519.pub"
)
self.sshd_pid_path = os.path.join(self.state_dir.name, "sshd.pid")
self.sshd_log_path = os.path.join(self.state_dir.name, "sshd.log")
self.vm_info_path = os.path.join(self.state_dir.name, "info.json")
self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img")
if platform.system() == "Darwin":
# Processes # Processes
self.vpnkit_p = None self.vpnkit_p = None
self.hyperkit_p = None self.hyperkit_p = None
@ -46,22 +62,9 @@ class Vm(QtCore.QObject):
"vm/initramfs.img" "vm/initramfs.img"
) )
# Folder to hold temporary files related to the VM # Temporary files related to the VM
self.state_dir = tempfile.TemporaryDirectory()
self.vpnkit_sock_path = os.path.join(self.state_dir.name, "vpnkit.eth.sock") self.vpnkit_sock_path = os.path.join(self.state_dir.name, "vpnkit.eth.sock")
self.hyperkit_pid_path = os.path.join(self.state_dir.name, "hyperkit.pid") self.hyperkit_pid_path = os.path.join(self.state_dir.name, "hyperkit.pid")
self.ssh_host_key_path = os.path.join(self.state_dir.name, "host_ed25519")
self.ssh_host_pubkey_path = os.path.join(
self.state_dir.name, "host_ed25519.pub"
)
self.ssh_client_key_path = os.path.join(self.state_dir.name, "client_ed25519")
self.ssh_client_pubkey_path = os.path.join(
self.state_dir.name, "client_ed25519.pub"
)
self.sshd_pid_path = os.path.join(self.state_dir.name, "sshd.pid")
self.sshd_log_path = os.path.join(self.state_dir.name, "sshd.log")
self.vm_info_path = os.path.join(self.state_dir.name, "info.json")
self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img")
# UDID for VM # UDID for VM
self.vm_uuid = str(uuid.uuid4()) self.vm_uuid = str(uuid.uuid4())
@ -69,6 +72,9 @@ class Vm(QtCore.QObject):
"earlyprintk=serial console=ttyS0 modules=loop,squashfs,sd-mod" "earlyprintk=serial console=ttyS0 modules=loop,squashfs,sd-mod"
) )
if platform.system() == "Windows":
pass
# Threads # Threads
self.wait_t = None self.wait_t = None
@ -78,9 +84,6 @@ class Vm(QtCore.QObject):
def start(self): def start(self):
print("Starting VM\n") print("Starting VM\n")
self.state = self.STATE_STARTING
self.vm_state_change.emit(self.state)
# Delete keys if they already exist # Delete keys if they already exist
for filename in [ for filename in [
self.ssh_host_key_path, self.ssh_host_key_path,
@ -91,6 +94,10 @@ class Vm(QtCore.QObject):
if os.path.exists(filename): if os.path.exists(filename):
os.remove(filename) os.remove(filename)
# Find an open port
self.sshd_port = self.find_open_port()
self.sshd_tunnel_port = self.find_open_port()
# Generate new keys # Generate new keys
subprocess.run( subprocess.run(
[ [
@ -127,10 +134,6 @@ class Vm(QtCore.QObject):
with open(self.ssh_client_pubkey_path) as f: with open(self.ssh_client_pubkey_path) as f:
ssh_client_pubkey = f.read() ssh_client_pubkey = f.read()
# Find an open port
self.sshd_port = self.find_open_port()
self.sshd_tunnel_port = self.find_open_port()
# Start an sshd service on this port # Start an sshd service on this port
args = [ args = [
"/usr/sbin/sshd", "/usr/sbin/sshd",
@ -162,6 +165,13 @@ class Vm(QtCore.QObject):
print("> " + args_str) print("> " + args_str)
subprocess.run(args, stdout=self.devnull, stderr=self.devnull) subprocess.run(args, stdout=self.devnull, stderr=self.devnull)
if platform.system() == "Darwin":
self.start_macos()
def start_macos(self):
self.state = self.STATE_STARTING
self.vm_state_change.emit(self.state)
# Create a JSON object to pass into the VM # Create a JSON object to pass into the VM
# This is a 512kb file that starts with a JSON object, followed by null bytes # This is a 512kb file that starts with a JSON object, followed by null bytes
guest_vm_info = { guest_vm_info = {
@ -257,6 +267,10 @@ class Vm(QtCore.QObject):
self.vm_state_change.emit(self.state) self.vm_state_change.emit(self.state)
def stop(self): def stop(self):
if platform.system() == "Darwin":
self.stop_macos()
def stop_macos(self):
# Kill existing processes # Kill existing processes
self.kill_sshd() self.kill_sshd()
if self.vpnkit_p is not None: if self.vpnkit_p is not None:

View file

@ -1,2 +0,0 @@
set DANGERZONE_MODE=container
poetry run python .\dev_scripts\dangerzone %*

View file

@ -0,0 +1,12 @@
#!/bin/sh
VAGRANT_FILES=$(find /vagrant -type f | grep -v /vagrant/.vagrant | grep -v /vagrant/vm)
DANGERZONE_CONVERTER_FILES=$(find /opt/dangerzone-converter -type f)
for FILE in $VAGRANT_FILES; do dos2unix $FILE; done
for FILE in $DANGERZONE_CONVERTER_FILES; do dos2unix $FILE; done
/vagrant/build-iso.sh
for FILE in $VAGRANT_FILES; do unix2dos $FILE; done
for FILE in $DANGERZONE_CONVERTER_FILES; do unix2dos $FILE; done

View file

@ -0,0 +1,65 @@
import os
import sys
import inspect
import requests
import hashlib
import zipfile
import shutil
def main():
zip_url = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/V8.6.0.0p1-Beta/OpenSSH-Win32.zip"
expected_zip_sha256 = (
"0221324212413a6caf260f95e308d22f8c141fc37727b622a6ad50998c46d226"
)
# Figure out the paths
root_path = os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
)
zip_path = os.path.join(root_path, "build", "OpenSSH-Win32.zip")
extracted_path = os.path.join(root_path, "build", "OpenSSH-Win32")
bin_path = os.path.join(root_path, "share", "bin")
os.makedirs(os.path.join(root_path, "build"), exist_ok=True)
os.makedirs(os.path.join(bin_path), exist_ok=True)
# Make sure openssh is downloaded
if not os.path.exists(zip_path):
print(f"Downloading {zip_url}")
r = requests.get(zip_url)
open(zip_path, "wb").write(r.content)
zip_sha256 = hashlib.sha256(r.content).hexdigest()
else:
zip_data = open(zip_path, "rb").read()
zip_sha256 = hashlib.sha256(zip_data).hexdigest()
# Compare the hash
if zip_sha256 != expected_zip_sha256:
print("ERROR! The sha256 doesn't match:")
print("expected: {}".format(expected_zip_sha256))
print(" actual: {}".format(zip_sha256))
sys.exit(-1)
# Extract the zip
with zipfile.ZipFile(zip_path, "r") as z:
z.extractall(os.path.join(root_path, "build"))
# Copy binaries to share
shutil.copy(os.path.join(extracted_path, "libcrypto.dll"), bin_path)
shutil.copy(os.path.join(extracted_path, "moduli"), bin_path)
shutil.copy(os.path.join(extracted_path, "scp.exe"), bin_path)
shutil.copy(os.path.join(extracted_path, "ssh-agent.exe"), bin_path)
shutil.copy(os.path.join(extracted_path, "ssh-keygen.exe"), bin_path)
shutil.copy(os.path.join(extracted_path, "ssh.exe"), bin_path)
shutil.copy(os.path.join(extracted_path, "sshd.exe"), bin_path)
shutil.copyfile(
os.path.join(extracted_path, "LICENSE.txt"),
os.path.join(bin_path, "LICENSE-OpenSSH.txt"),
)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,11 @@
REM Build ISO
cd install\vm-builder
vagrant up
vagrant ssh -- dos2unix /vagrant/windows.sh
vagrant ssh -- /vagrant/windows.sh
vagrant halt
cd ..\..
REM Copy the ISO to resources
if not exists share\vm mkdir share\vm
cp install\vm-builder\vm\* share\vm