diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 65431a3..7f69165 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,5 +1,5 @@ on: [workflow_call] -name: "Check" +name: "Shellcheck" permissions: {} jobs: diff --git a/Dockerfile b/Dockerfile index 7ec80c4..d87e65d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,15 +17,16 @@ RUN apt-get update && apt-get -y upgrade && \ fdisk \ unzip \ procps \ - dnsmasq \ + xz-utils \ iptables \ iproute2 \ - xz-utils \ + dnsmasq \ net-tools \ btrfs-progs \ bridge-utils \ - netcat-openbsd \ ca-certificates \ + isc-dhcp-client \ + netcat-openbsd \ qemu-system-x86 \ && apt-get clean diff --git a/agent/agent.sh b/agent/agent.sh index 397877f..7532930 100644 --- a/agent/agent.sh +++ b/agent/agent.sh @@ -134,9 +134,17 @@ fi # Display message in docker log output -echo "-------------------------------------------" -echo " You can now login to DSM at port 5000 " -echo "-------------------------------------------" +IP=$(ip address show dev eth0 | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/) + +if [[ "$IP" == "20.20"* ]]; then + MSG="port 5000" +else + MSG="http://${IP}:5000" +fi + +echo "--------------------------------------------------------" +echo " You can now login to DSM at ${MSG}" +echo "--------------------------------------------------------" # Wait for NMI interrupt as a shutdown signal diff --git a/readme.md b/readme.md index ab2c3ad..febe0b9 100644 --- a/readme.md +++ b/readme.md @@ -128,10 +128,22 @@ docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-ti --ip-range=192.168.0.100/28 \ -o parent=eth0 vdsm ``` - Modify these values to match your local subnet. And change the docker network of the container from `bridged` to `vdsm` in your run command or compose file: + Modify these values to match your local subnet. + + Now change the containers configuration in your compose file: ``` - --network vdsm --ip=192.168.0.100 + networks: + vdsm: + ipv4_address: 192.168.0.100 + ``` + + And add the network to the very bottom of your compose file: + + ``` + networks: + vdsm: + external: true ``` This also has the advantage that you don't need to do any portmapping anymore, because all ports will be fully exposed this way. diff --git a/run/disk.sh b/run/disk.sh index 26c1fea..4eb4e27 100644 --- a/run/disk.sh +++ b/run/disk.sh @@ -3,9 +3,9 @@ set -eu # Docker environment variabeles -: ${DISK_IO:='native'} # I/O Mode -: ${DISK_ROTATION:='1'} # Rotation rate -: ${DISK_CACHE:='none'} # Caching mode +: ${DISK_IO:='native'} # I/O Mode, can be set to 'native', 'threads' or 'io_turing' +: ${DISK_ROTATION:='1'} # Rotation rate, set to 1 for SSD storage and increase for HDD +: ${DISK_CACHE:='none'} # Caching mode, can be set to 'writeback' for better performance BOOT="$STORAGE/$BASE.boot.img" SYSTEM="$STORAGE/$BASE.system.img" diff --git a/run/install.sh b/run/install.sh index 7cb6354..5a05ffd 100644 --- a/run/install.sh +++ b/run/install.sh @@ -103,7 +103,7 @@ BOOT=$(find $TMP -name "*.bin.zip") BOOT=$(echo "$BOOT" | head -c -5) unzip -q -o "$BOOT".zip -d $TMP - [ "$ALLOCATE" != "Z" ] && echo "Install: Allocating diskspace..." +[ "$ALLOCATE" != "Z" ] && echo "Install: Allocating diskspace..." SYSTEM="$TMP/sys.img" SYSTEM_SIZE=4954537983 @@ -121,10 +121,8 @@ if ! fallocate -l "${SYSTEM_SIZE}" "${SYSTEM}"; then fi if [ "$ALLOCATE" = "Z" ]; then - echo "Install: Preallocating 4 GB of diskspace..." dd if=/dev/urandom of="${SYSTEM}" count="${SYSTEM_SIZE}" bs=1M iflag=count_bytes status=none - fi # Check if file exists diff --git a/run/network.sh b/run/network.sh index dad2de8..b4a6301 100644 --- a/run/network.sh +++ b/run/network.sh @@ -3,22 +3,85 @@ set -eu # Docker environment variabeles -: ${VM_NET_TAP:=''} -: ${VM_NET_IP:='20.20.20.21'} : ${VM_NET_HOST:='VirtualDSM'} : ${VM_NET_MAC:='02:11:32:AA:BB:CC'} +: ${DHCP:='N'} : ${DNS_SERVERS:=''} -: ${DNSMASQ:='/usr/sbin/dnsmasq'} : ${DNSMASQ_OPTS:=''} +: ${DNSMASQ:='/usr/sbin/dnsmasq'} : ${DNSMASQ_CONF_DIR:='/etc/dnsmasq.d'} # ###################################### # Functions # ###################################### -# Setup macvtap device to connect later the VM and setup a new macvlan device to connect the host machine to the network -configureNatNetworks () { +configureDHCP() { + + # Create /dev/vhost-net + if [ ! -c /dev/vhost-net ]; then + mknod /dev/vhost-net c 10 238 + chmod 660 /dev/vhost-net + fi + + if [ ! -c /dev/vhost-net ]; then + echo -n "Error: VHOST interface not available. Please add the following " + echo "docker variable to your container: --device=/dev/vhost-net" && exit 85 + fi + + VM_NET_TAP="_VmMacvtap" + echo "Info: Retrieving IP via DHCP using MAC ${VM_NET_MAC}..." + + ip l add link eth0 name ${VM_NET_TAP} address ${VM_NET_MAC} type macvtap mode bridge || true + ip l set ${VM_NET_TAP} up + + ip a flush eth0 + ip a flush ${VM_NET_TAP} + + DHCP_IP=$( dhclient -v ${VM_NET_TAP} 2>&1 | grep ^bound | cut -d' ' -f3 ) + + if [[ "${DHCP_IP}" == [0-9.]* ]]; then + echo "Info: Retrieved IP ${DHCP_IP} via DHCP" + else + echo "ERROR: Cannot retrieve IP from DHCP using MAC ${VM_NET_MAC}" && exit 16 + fi + + ip a flush ${VM_NET_TAP} + + TAP_PATH="/dev/tap$(>$TAP_PATH; then + echo -n "ERROR: Please add the following docker variables to your container: " + echo "--device=/dev/vhost-net --device-cgroup-rule='c ${MAJOR}:* rwm'" && exit 21 + fi + + if ! exec 40>>/dev/vhost-net; then + echo -n "ERROR: VHOST can not be found. Please add the following docker " + echo "variable to your container: --device=/dev/vhost-net" && exit 22 + fi + + NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30" +} + +configureNAT () { + + VM_NET_IP='20.20.20.21' + VM_NET_TAP="_VmNatTap" #Create bridge with static IP for the VM guest brctl addbr dockerbridge @@ -34,6 +97,9 @@ configureNatNetworks () { iptables -t nat -A PREROUTING -i eth0 -p tcp -j DNAT --to $VM_NET_IP iptables -t nat -A PREROUTING -i eth0 -p udp -j DNAT --to $VM_NET_IP + # Hack for guest VMs complaining about "bad udp checksums in 5 packets" + iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill + #Enable port forwarding flag [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]] && sysctl -w net.ipv4.ip_forward=1 @@ -43,6 +109,33 @@ configureNatNetworks () { # Create lease file for faster resolve echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:${VM_NET_MAC}" > /var/lib/misc/dnsmasq.leases chmod 644 /var/lib/misc/dnsmasq.leases + + NET_OPTS="-netdev tap,ifname=${VM_NET_TAP},script=no,downscript=no,id=hostnet0" + + # Build DNS options from container /etc/resolv.conf + nameservers=($(grep '^nameserver' /etc/resolv.conf | sed 's/nameserver //')) + searchdomains=$(grep '^search' /etc/resolv.conf | sed 's/search //' | sed 's/ /,/g') + domainname=$(echo $searchdomains | awk -F"," '{print $1}') + + for nameserver in "${nameservers[@]}"; do + if ! [[ $nameserver =~ .*:.* ]]; then + [[ -z $DNS_SERVERS ]] && DNS_SERVERS=$nameserver || DNS_SERVERS="$DNS_SERVERS,$nameserver" + fi + done + + [[ -z $DNS_SERVERS ]] && DNS_SERVERS="1.1.1.1" + + DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,$DNS_SERVERS --dhcp-option=option:router,${VM_NET_IP%.*}.1" + + if [ -n "$searchdomains" -a "$searchdomains" != "." ]; then + DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-search,$searchdomains --dhcp-option=option:domain-name,$domainname" + else + [[ -z $(hostname -d) ]] || DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-name,$(hostname -d)" + fi + + [ "$DEBUG" = "Y" ] && echo && echo "$DNSMASQ $DNSMASQ_OPTS" + + $DNSMASQ $DNSMASQ_OPTS } # ###################################### @@ -58,47 +151,34 @@ fi [ ! -c /dev/net/tun ] && echo "Error: TUN network interface not available..." && exit 85 -if [ "$DEBUG" = "Y" ]; then - ifconfig - ip link - ip route -fi - update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null -VM_NET_TAP="_VmNatTap" -configureNatNetworks -NET_OPTS="-netdev tap,ifname=${VM_NET_TAP},script=no,downscript=no,id=hostnet0" - -# Build DNS options from container /etc/resolv.conf -nameservers=($(grep '^nameserver' /etc/resolv.conf | sed 's/nameserver //')) -searchdomains=$(grep '^search' /etc/resolv.conf | sed 's/search //' | sed 's/ /,/g') -domainname=$(echo $searchdomains | awk -F"," '{print $1}') - -for nameserver in "${nameservers[@]}"; do - if ! [[ $nameserver =~ .*:.* ]]; then - [[ -z $DNS_SERVERS ]] && DNS_SERVERS=$nameserver || DNS_SERVERS="$DNS_SERVERS,$nameserver" - fi -done - -[[ -z $DNS_SERVERS ]] && DNS_SERVERS="1.1.1.1" - -DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,$DNS_SERVERS --dhcp-option=option:router,${VM_NET_IP%.*}.1" - -if [ -n "$searchdomains" -a "$searchdomains" != "." ]; then - DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-search,$searchdomains --dhcp-option=option:domain-name,$domainname" -else - [[ -z $(hostname -d) ]] || DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:domain-name,$(hostname -d)" -fi +GATEWAY=$(ip r | grep default | awk '{print $3}') if [ "$DEBUG" = "Y" ]; then - echo "$DNSMASQ $DNSMASQ_OPTS" + + IP=$(ip address show dev eth0 | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/) + echo "Info: Container IP is ${IP} with gateway {GATEWAY}" + ifconfig + ip route fi -$DNSMASQ $DNSMASQ_OPTS +if [ "$DHCP" != "Y" ]; then + + # Configuration for static IP + configureNAT + +else + + if [[ "$GATEWAY" == "172."* ]]; then + echo -n "ERROR: You cannot enable DHCP while the container is " + echo "in a bridge network, only on a macvlan network!" && exit 86 + fi + + # Configuration for DHCP IP + configureDHCP + +fi NET_OPTS="${NET_OPTS} -device virtio-net-pci,romfile=,netdev=hostnet0,mac=${VM_NET_MAC},id=net0" - -# Hack for guest VMs complaining about "bad udp checksums in 5 packets" -iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill