diff --git a/android-x86/create.sh b/android-x86/create.sh index 3859128..cc226e3 100644 --- a/android-x86/create.sh +++ b/android-x86/create.sh @@ -4,15 +4,12 @@ cd "$(dirname "$0")" if ! [ -f android.iso ]; then ask_yn "android.iso not found, download?" \ - && bash ./download_isos.sh \ + && bash ./download_isos.sh \ || exit 1 fi -qemu-img create -f qcow2 hda.qcow2 40G +qemu-img create -f qcow2 hda.qcow2 10G -CMD=( - "${CMD[@]}" +qemu "$@" \ -drive file=android.iso,media=cdrom,readonly=on -) - -"${CMD[@]}" + #-device usb-host,vendorid=0xffff,productid=0xffff diff --git a/android-x86/run.sh b/android-x86/run.sh index 2fc768b..85fc2de 100755 --- a/android-x86/run.sh +++ b/android-x86/run.sh @@ -4,16 +4,10 @@ cd "$(dirname "$0")" if ! [ -f hda.qcow2 ]; then ask_yn "hda.qcow2 not found, create?" \ - && bash ./create.sh \ + && bash ./create.sh \ || exit 1 fi -CMD=( - "${CMD[@]}" - -nic user,model=virtio-net-pci - -vga std - # USB passthrough, might need root privileges +qemu "$@" \ + -vga std \ #-device usb-host,vendorid=0xffff,productid=0xffff -) - -"${CMD[@]}" diff --git a/arch/run.sh b/arch/run.sh index 02427cc..52adf1b 100755 --- a/arch/run.sh +++ b/arch/run.sh @@ -6,15 +6,9 @@ hda='https://geo.mirror.pkgbuild.com/images/latest/Arch-Linux-x86_64-basic.qcow2 if ! [ -f hda.qcow2 ]; then ask_yn "hda does not exist. Download?" \ - && curl -LC- -o hda.qcow2 "$hda" \ + && curl -LC- -o hda.qcow2 "$hda" \ || exit 1 fi -CMD=( - "${CMD[@]}" - -nic user,model=virtio-net-pci - # USB passthrough, might need root privileges +qemu "$@" \ #-device usb-host,vendorid=0xffff,productid=0xffff -) - -"${CMD[@]}" diff --git a/debian12/run.sh b/debian12/run.sh index 6cbe965..6cb208d 100755 --- a/debian12/run.sh +++ b/debian12/run.sh @@ -6,15 +6,9 @@ hda='https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd if ! [ -f hda.qcow2 ]; then ask_yn "hda does not exist. Download?" \ - && curl -LC- -o hda.qcow2 "$hda" \ + && curl -LC- -o hda.qcow2 "$hda" \ || exit 1 fi -CMD=( - "${CMD[@]}" - -nic user,model=virtio-net-pci - # USB passthrough, might need root privileges +qemu "$@" \ #-device usb-host,vendorid=0xffff,productid=0xffff -) - -"${CMD[@]}" diff --git a/lib.sh b/lib.sh index aa25d42..3e9adff 100644 --- a/lib.sh +++ b/lib.sh @@ -1,34 +1,56 @@ #!/bin/bash -e +DIR="$(dirname "${BASH_SOURCE[0]}")" + +BRIDGE=virbr0 function ask_yn() { local ans - printf "$1 (Y/n) " >&2 + printf '%s (Y/n) ' "$1" >&2 read -r ans case "${ans,,}" in y*|'') return 0 ;; - *) return 1 ;; + *) return 1 ;; esac } -RAM="$(free -g | awk '/^Mem:/{print $2 - 2}')" +function _getmaxram() { + local ram; ram="$(free -g | awk '/^Mem:/{print $2 - 2}')" -if [ "$RAM" -le 2 ]; then RAM=2 -elif [ "$RAM" -gt 32 ]; then RAM=32; fi + if [ "$ram" -le 2 ]; then ram=2 + elif [ "$ram" -gt 32 ]; then ram=32; fi + echo "${ram}G" +} -RAM="${RAM}G" +function _getnet() { + local net=user -CMD=( - qemu-system-x86_64 - -accel kvm - -M q35 - -cpu host - -m "2G,maxmem=$RAM" - -vga virtio - -drive if=virtio,file=hda.qcow2 - # usb - -device qemu-xhci - # shared memory - -object memory-backend-ram,id=mem,size=2G,share=on - -numa node,memdev=mem -) + if ! ip link show "$BRIDGE" | grep -q UP; then + ask_yn 'create bridge?' && sudo "$DIR/startnat.sh" "$BRIDGE" > /dev/null + fi + if ip link show "$BRIDGE" | grep -q UP; then + net="bridge,br=$BRIDGE" + fi + echo "$net" +} + +function qemu() { + local maxram; maxram="$(_getmaxram)" + local net; net="$(_getnet)" + + (set -x + qemu-system-x86_64 -accel kvm \ + -M q35 \ + -bios /usr/share/ovmf/x64/OVMF.fd \ + -cpu host \ + -m "2G,maxmem=$maxram" \ + -vga virtio \ + -drive if=virtio,file=hda.qcow2 \ + -audio pipewire,model=hda \ + -nic "model=virtio-net-pci,type=$net" \ + -device qemu-xhci \ + -object memory-backend-ram,id=mem,size=2G,share=on \ + -numa node,memdev=mem \ + "$@" + ) +} diff --git a/startnat.sh b/startnat.sh new file mode 100755 index 0000000..252d32c --- /dev/null +++ b/startnat.sh @@ -0,0 +1,56 @@ +#!/bin/bash -ex + +function _iptables() { + local table="QEMU_$1"; shift + + iptables -C "$table" "$@" 2> /dev/null || iptables -A "$table" "$@" +} + +function newtable() { + local table="$1"; shift + + iptables -N "QEMU_$table" "$@" 2> /dev/null || true + iptables -A "$table" -j "QEMU_$table" "$@" +} + +if ! command -v dnsmasq iptables-nft; then + echo 'missing 1+ dependencies: dnsmasq iptables-nft' >&2 + exit 1 +fi + +if [ "$EUID" != 0 ]; then + echo 'this script must be run as root' >&2 + exit 1 +fi + +BRIDGE="${1-virbr0}" +DEV="$(ip route | grep -Po '^default.*dev\s+\K\w+')" + +sysctl net.ipv4.conf.all.forwarding=1 + +if ! ip link show "$BRIDGE" > /dev/null; then + ip link add "$BRIDGE" type bridge +fi + +ip link set dev "$BRIDGE" up + +ip address flush dev "$BRIDGE" +ip address add 192.168.122.1/24 dev "$BRIDGE" + +newtable INPUT +newtable FORWARD +newtable OUTPUT +newtable POSTROUTING -tnat + +_iptables INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +_iptables INPUT -i virbr0 -j ACCEPT +_iptables FORWARD -i "$BRIDGE" -o "$DEV" -j ACCEPT +_iptables FORWARD -i "$DEV" -o "$BRIDGE" -m state --state RELATED,ESTABLISHED -j ACCEPT + +_iptables POSTROUTING -o "$DEV" -j MASQUERADE -tnat + +pidof dnsmasq | grep -q "$(cat /var/run/dnsmasq-virbr0.pid)" \ + || dnsmasq --bind-dynamic \ + -i "$BRIDGE" \ + -F 192.168.122.2,192.168.122.254,255.255.255.0 \ + -x /var/run/dnsmasq-virbr0.pid diff --git a/stopnat.sh b/stopnat.sh new file mode 100755 index 0000000..c8cf248 --- /dev/null +++ b/stopnat.sh @@ -0,0 +1,20 @@ +#!/bin/bash -x + +if [ "$EUID" != 0 ]; then + echo "this script must be run as root" >&2 + exit +fi + +BRIDGE="${1-virbr0}" + +sysctl net.ipv4.conf.all.forwarding=0 + +ip link del dev "$BRIDGE" + +iptables -S | sed -n '/QEMU/s/-A/iptables -D/p' | bash +iptables -S -tnat | sed -n '/QEMU/s/-A/iptables -tnat -D/p' | bash + +iptables -S | sed -n '/QEMU/s/-N/iptables -X/p' | bash +iptables -S -tnat | sed -n '/QEMU/s/-N/iptables -tnat -X/p' | bash + +kill -TERM "$(cat /var/run/dnsmasq-virbr0.pid)" diff --git a/win2k22/create.sh b/win2k22/create.sh index 44afe2b..8ae279b 100644 --- a/win2k22/create.sh +++ b/win2k22/create.sh @@ -4,17 +4,13 @@ cd "$(dirname "$0")" if ! [ -f win2k22.iso ] || ! [ -f virtio.iso ]; then ask_yn "win2k22.iso and/or virtio.iso not found, download?" \ - && bash ./download_isos.sh \ + && bash ./download_isos.sh \ || exit 1 fi qemu-img create -f qcow2 hda.qcow2 40G -CMD=( - "${CMD[@]}" - -drive file=win2k22.iso,media=cdrom,readonly=on - -drive file=virtio.iso,media=cdrom,readonly=on - -nic none # you don't want internet access for a windows installation -) - -"${CMD[@]}" +qemu "$@" \ + -drive file=win2k22.iso,media=cdrom,readonly=on \ + -drive file=virtio.iso,media=cdrom,readonly=on \ + #-device usb-host,vendorid=0xffff,productid=0xffff diff --git a/win2k22/download_isos.sh b/win2k22/download_isos.sh index a486f12..cd55f0e 100755 --- a/win2k22/download_isos.sh +++ b/win2k22/download_isos.sh @@ -3,6 +3,6 @@ win2k22='https://go.microsoft.com/fwlink/p/?LinkID=2195280' virtio='https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso' -curl -LC- \ +curl -LC- \ -o win2k22.iso "$win2k22" \ -o virtio.iso "$virtio" diff --git a/win2k22/run.sh b/win2k22/run.sh index 1993875..16930d7 100755 --- a/win2k22/run.sh +++ b/win2k22/run.sh @@ -4,15 +4,10 @@ cd "$(dirname "$0")" if ! [ -f hda.qcow2 ]; then ask_yn "hda.qcow2 not found, create?" \ - && bash ./create.sh \ + && bash ./create.sh \ || exit 1 fi -CMD=( - "${CMD[@]}" - -nic user,model=virtio-net-pci - # USB passthrough, might need root privileges +qemu "$@" \ + -drive file=virtio.iso,media=cdrom,readonly=on \ #-device usb-host,vendorid=0xffff,productid=0xffff -) - -"${CMD[@]}"