Table of Contents
This is my personal note for the qemu-system
. I decided to write this post in order to shorten my time to make and use the qemu image.
Recently, I had to use QEMU for my personal project and there are too many interesting(and useless) features to know and I can't even catch up countless resources swimming on the internet.
HONESTLY, I HAD TO WRITE THIS POST. I DON'T WANT TO TAKE ALL DAY LEARNING UP THE MANUAL.
I hope this post helps other people who are planning to use the qemu-system
for the first time.
I'm going to use latest debian image in this example.
The following steps will be valid even on future releases. (yes I'm certain!)
wget https://cdimage.debian.org/debian-cd/current/i386/iso-cd/debian-9.4.0-i386-netinst.iso
qemu-img create -f qcow2 debian.qcow 5G
qemu-system-i386 -cdrom debian-9.4.0-i386-netinst.iso -hda debian.qcow -m 1G -boot d -curses
ESC
buttoninstall vga=normal fb=false
After the installation, boot with -nographic
to disable the monitor and remove -boot d
, -curses
and -cdrom
arguments to make the system fully functional.
Assuming that you want the Host's port 1234
forwarded to VM's port 5555
, the most preferred command for you will be -redir tcp:1234::5555
.
if you don't want to plan to open your port worldwide, the problem can be solve with tcp:127.0.0.1:1234-:5555
.
However, the manual says that the -redir
option is deprecated (as of 2018) and will be removed soon.
The qemu-system manual suggests that using -netdev user
is highly encouraged.
So the encouraged method should be using arguments like the following:
qemu-system-i386 -netdev user,hostfwd=tcp:1234::1337,id=alicenet,hostname=alice,net=1.3.3.0/24 -device e1000,netdev=alicenet ...
Setting MAC address is very easy. you just need to add one more option on the -device
argument.
To assign a specific MAC address, You can write -device e1000,netdev=alicenet,mac=11:22:33:44:55:66
.
Remember, the -device
option should be used with -netdev
option to make a functional networking interface.
It works, but generally it's not preferred and generally not recommneded.
Please don't use the nested virtualization on AWS, conoha or digitalocean.
You can get suspended/banned by the hosting company. It's better to install QEMU and use them on barebone servers.
Please don't even try qemu-system on VPS. you have been warned.
You can make multiple snapshots on qcow2
format and rewind features seems to be available.
But if you're planning to run the current image multiple times and don't want the changes to be commited at all, you can just go ahead with the -snapshot
feature.
-snapshot
basically keeps your original image and changes done will be written on a temporary space.
From the tips above, you can now use qemu-system
like this:
qemu-system-x86_64 -nographic -snapshot \
-hda image.qcow2 -m 512 \
-netdev user,id=alicenet,hostname=alice,net=172.10.1.0/24 \
-device e1000,netdev=alicenet,mac=$(openssl rand -hex 6 | sed 's/\(..\)/\1:/g; s/.$//')
The command above boots image.qcow2
with 512MB memory space without the graphic, having a network card assigning random MAC address on every run and an IP allocated on 172.10.1.0/24
.
The following script runs multiple qemu-system-x86_64
instances with different ports assigned respectively. When one of these instances is killed or terminated, the runner starts another QEMU instances, until the user kills the runner.
You can customize the script to develop it further. In my project, I also made the status checker for running qemu instances.
It's not pythonic, and I know it. I don't have enough time to sincerely develop a lot of code. Please consider this one as a concept script.
If you like it, go refactor and customize the code! 😉
Tested on Ubuntu 17.10.
#!/usr/bin/python -u
#-*- coding:utf-8 -*-
# Developer: Harold Kim ([email protected])
import time
import os
import sys
import random
class QEMURunner:
''' QEMU runner class for debian/ubuntu '''
qemu_binary = '/usr/bin/qemu-system-x86_64'
qemu_opt = " -snapshot -nographic -hda image.qcow2 -m 256 "
qemu_opt += "-netdev user,hostfwd=tcp:127.0.0.1:%s-:8080,id=vnet%s,hostname=vulnhost%s,net=10.1.3.0/24 "
qemu_opt += "-device e1000,netdev=vnet%s"
qemu_opt += ",mac=%s &"
#-redir [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport
def __init__(self, maximum_instance):
self.maximum_instance_count = maximum_instance
self.kill() # reset instances
self.running_instance = []
def count(self):
''' count running (ret int) '''
c = os.popen("ps aux | grep %s | grep -v grep" % (self.qemu_binary,)).read()
c = c.split("\n")[:-1]
return len(c)
def kill(self, ps=None):
if ps is None:
c = os.popen("killall -9 %s 2>/dev/null" % (self.qemu_binary,)).read()
else:
c = os.popen("ps aux | grep %s | grep %s | grep -v grep | awk '{print $2}'" % (self.qemu_binary, ps,)).read()
def run(self):
c = 0
while self.count() < self.maximum_instance_count:
c += 1
count = self.count()
# generate MAC
mac = [ random.randint(0, 255) for x in range(0, 5) ]
mac[0] = (mac[0] & 0xfc) | 0x02
mac = '37:' + (':'.join(['{0:02x}'.format(x) for x in mac ]))
# port starts from 2300. (e.g. 2301, 2302, 2303, ...)
port = str(2301 + c)
run = self.qemu_binary + self.qemu_opt % (port, count, count, count, mac)
os.system(run)
self.running_instance.append(mac)
time.sleep(1)
print(self.count())
return True
def run_infinite(self):
while True:
self.run()
time.sleep(5)
if __name__ == "__main__":
# Run 3 QEMU instances, forever.
qemu = QEMURunner(3)
qemu.run_infinite()
Added docker runner which does similar thing for docker: https://gist.github.com/stypr/ffe28c8262a8a362be0fd7b1558dc2b4