Skip to content

Commit

Permalink
first step towards a revamped vmcloak
Browse files Browse the repository at this point in the history
  • Loading branch information
jbremer committed Sep 18, 2015
1 parent 31dde88 commit 7eaf0be
Show file tree
Hide file tree
Showing 12 changed files with 462 additions and 382 deletions.
23 changes: 4 additions & 19 deletions bin/vmcloak
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import sys
import tempfile
import time

from vmcloak.conf import vboxmanage_path
from vmcloak.deps import DependencyManager, DependencyWriter
from vmcloak.exceptions import CommandError
from vmcloak.misc import add_bird, shared_parameters, register_cuckoo
from vmcloak.misc import wait_for_host, resolve_parameters
from vmcloak.winxp import WindowsXP
Expand Down Expand Up @@ -89,12 +87,7 @@ def main():
exit(1)

if s.vm.lower() == 'virtualbox':
vboxmanage = vboxmanage_path(s)
if not vboxmanage:
exit(1)

m = VirtualBox(s.vmname, s.vm_dir, s.data_dir,
vboxmanage=vboxmanage, temp_dir=s.temp_dirpath)
m = VirtualBox(s.vmname, s.vm_dir, s.data_dir)
else:
log.error('Only the VirtualBox --vm is supported as of now.')
exit(1)
Expand Down Expand Up @@ -156,7 +149,6 @@ def main():
GUEST_IP=s.host_init_ip if s.bird else s.hostonly_ip,
GUEST_MASK=s.host_init_mask if s.bird else s.hostonly_mask,
GUEST_GATEWAY=s.host_init_gateway if s.bird else s.hostonly_gateway,
VMMODE='bird' if s.bird else 'normal',
DEBUG='yes' if s.debug else 'no',
)

Expand All @@ -172,7 +164,7 @@ def main():
else:
settings_bat['RUNEXEC'] = ''

bootstrap = tempfile.mkdtemp(dir=s.temp_dirpath)
bootstrap = tempfile.mkdtemp(dir=s.tempdir)

vmcloak_dir = os.path.join(bootstrap, 'vmcloak')
os.mkdir(vmcloak_dir)
Expand Down Expand Up @@ -218,7 +210,7 @@ def main():
# Create the ISO file.
log.debug('Creating ISO file.')
if not h.buildiso(s.iso_mount or h.mount, m.iso_path, bootstrap,
s.temp_dirpath):
s.tempdir):
shutil.rmtree(bootstrap)
exit(1)

Expand All @@ -245,14 +237,7 @@ def main():
guest.close()
else:
# Wait until the Virtual Machine is shutdown.
while True:
try:
if m.vminfo('VMState') == 'poweroff':
break
except CommandError:
pass

time.sleep(1)
m.wait_for_state(shutdown=True)

log.debug('It took %d seconds to install Windows!', time.time() - t)

Expand Down
8 changes: 3 additions & 5 deletions bin/vmcloak-clone
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
# See the file 'docs/LICENSE.txt' for copying permission.

import logging
import os.path
import json
import socket
import sys

from vmcloak.conf import vboxmanage_path
from vmcloak.misc import read_bird, shared_parameters, register_cuckoo
from vmcloak.misc import wait_for_host, resolve_parameters
from vmcloak.winxp import WindowsXP
Expand Down Expand Up @@ -51,8 +51,6 @@ def main():
log.error('A name for the Virtual Machine is required.')
exit(1)

vboxmanage = vboxmanage_path(s)

bird = read_bird(s.bird)
if not bird:
log.critical('Specified bird not found! Please verify its name.')
Expand All @@ -63,8 +61,8 @@ def main():
exit(1)

# Only VirtualBox support at the moment.
m = VirtualBox(s.vmname, s.vm_dir, s.data_dir,
vboxmanage=vboxmanage, temp_dir=s.temp_dirpath)
m = VirtualBox(s.vmname, os.path.join(s.data_dir, '%s.vdi' % s.vmname),
tempdir=s.tempdir)

if bird['vmtype'] == 'winxp':
h = WindowsXP()
Expand Down
122 changes: 122 additions & 0 deletions bin/vmcloak-init
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env python
# Copyright (C) 2014-2015 Jurriaan Bremer.
# This file is part of VMCloak - http://www.vmcloak.org/.
# See the file 'docs/LICENSE.txt' for copying permission.

import argparse
import logging
import os.path
import shutil
import tempfile

from vmcloak.winxp import WindowsXP
from vmcloak.win7 import Windows7
from vmcloak.repository import image_path, Database, Image
from vmcloak.vm import VirtualBox

log = logging.getLogger("vmcloak")
db = Database()

def main():
parser = argparse.ArgumentParser()
parser.add_argument("name", type=str, help="Name of the new instance.")
parser.add_argument("--winxp", action="store_true", help="This is a Windows XP instance.")
parser.add_argument("--win7", action="store_true", help="This is a Windows 7 instance.")
parser.add_argument("--x64", action="store_true", help="This is a 64-bit OS.")
parser.add_argument("--win7x64", action="store_true", help="This is a Windows 7 64-bit instance.")
parser.add_argument("--vm", type=str, default="virtualbox", help="Virtual Machinery.")
parser.add_argument("--iso-mount", type=str, help="Mounted ISO Windows installer image.")
parser.add_argument("--serial-key", type=str, help="Windows Serial Key.")
parser.add_argument("--ip", type=str, default="192.168.56.2", help="Guest IP address.")
parser.add_argument("--port", type=int, default=8000, help="Port to run the Agent on.")
parser.add_argument("--netmask", type=str, default="255.255.255.0", help="Guest IP address.")
parser.add_argument("--gateway", type=str, default="192.168.56.1", help="Guest IP address.")
parser.add_argument("--tempdir", type=str, default=tempfile.gettempdir(), help="Temporary directory to build the ISO file.")
parser.add_argument("--vm-visible", action="store_true", default=None, help="Start the Virtual Machine in GUI mode.")
parser.add_argument("-d", "--debug", action="store_true", default=None, help="Install Virtual Machine in debug mode.")
parser.add_argument("-v", "--verbose", action="store_true", default=None, help="Verbose logging.")
args = parser.parse_args()

if args.verbose:
log.setLevel(logging.DEBUG)

if args.vm != "virtualbox":
log.error("Only the VirtualBox Machinery is supported at this point.")
exit(1)

if args.winxp:
h = WindowsXP()
osversion = "winxp"
elif args.win7 or args.win7x64:
h = Windows7()
if args.x64 or args.win7x64:
osversion = "win7x64"
args.x64 = True
else:
osversion = "win7"
else:
log.error("Please provide either --winxp or --win7.")
exit(1)

if not os.path.isdir(args.iso_mount or h.mount):
log.error("Please specify --iso-mount to a directory containing the "
"mounted Windows Installer ISO image.")
log.info("Refer to the documentation on mounting an .iso image.")
exit(1)

if not h.set_serial_key(args.serial_key):
exit(1)

h.configure(args)

settings = dict(
GUEST_IP=args.ip,
AGENT_PORT=args.port,
GUEST_MASK=args.netmask,
GUEST_GATEWAY=args.gateway,
DEBUG="yes" if args.debug else "no",
)

bootstrap = tempfile.mkdtemp(dir=args.tempdir)

vmcloak_dir = os.path.join(bootstrap, "vmcloak")
os.mkdir(vmcloak_dir)

# Write the configuration values for bootstrap.bat.
with open(os.path.join(vmcloak_dir, "settings.bat"), "wb") as f:
for key, value in settings.items():
print>>f, "set %s=%s" % (key, value)

hdd_path = os.path.join(image_path, "%s.vdi" % args.name)
m = VirtualBox(name=args.name, tempdir=args.tempdir, hdd_path=hdd_path)

if not h.buildiso(args.iso_mount or h.mount, m.iso_path, bootstrap,
args.tempdir):
shutil.rmtree(bootstrap)
exit(1)

shutil.rmtree(bootstrap)

m.create_vm()
m.os_type(os=h.name, sp=h.service_pack)
m.create_hd()
m.attach_iso(m.iso_path)
m.hostonly(nictype=h.nictype)

log.info("Starting the Virtual Machine %r to install Windows.", args.name)
m.start_vm(visible=args.vm_visible)

m.wait_for_state(shutdown=True)

m.detach_iso()
os.unlink(m.iso_path)

m.remove_hd()
m.compact_hd()
m.remove_vm()

log.info("Added image %r to the repository.", args.name)
db.add(Image(name=args.name, path=hdd_path, osversion=osversion))

if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
],
scripts=[
'bin/vmcloak',
'bin/vmcloak-init',
'bin/vmcloak-bird',
'bin/vmcloak-clone',
'bin/vmcloak-deps',
Expand All @@ -45,5 +46,8 @@

# Required on BSD systems for unknown reasons.
'jinja2',

# For interaction with the Agent.
'requests',
],
)
25 changes: 2 additions & 23 deletions vmcloak/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,10 @@ class Machinery(object):
vm_dir_required = True
data_dir_required = True

def __init__(self, name, vm_dir=None, data_dir=None, temp_dir=None):
def __init__(self, name, tempdir):
self.name = name
self.vm_dir = vm_dir
self.data_dir = data_dir

self.network_idx = 0

if self.vm_dir_required and not vm_dir:
log.error('Please provide --vm-dir a directory for the '
'associated VM files.')
log.info('Optionally this directory can be put into tmpfs for '
'improved speed.')
exit(1)

if self.data_dir_required and not data_dir:
log.error('Please provide --data-dir a directory for the '
'harddisk and .iso files for the virtual machine.')
log.info('It is recommended to store this directory on a regular '
'harddisk or SSD - not in tmpfs.')
exit(1)

if data_dir:
self.iso_path = os.path.join(self.data_dir, '%s.iso' % self.name)
else:
_, self.iso_path = tempfile.mkstemp(suffix='.iso', dir=temp_dir)
self.iso_path = os.path.join(tempdir, '%s.iso' % self.name)

def vminfo(self, element=None):
"""Returns a dictionary with all available information for the
Expand Down
22 changes: 22 additions & 0 deletions vmcloak/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright (C) 2014-2015 Jurriaan Bremer.
# This file is part of VMCloak - http://www.vmcloak.org/.
# See the file 'docs/LICENSE.txt' for copying permission.

import requests

class Agent(object):
def __init__(self, ipaddr, port):
self.ipaddr = ipaddr
self.port = port

def get(self, method, *args, **kwargs):
url = "http://%s:%s%s" % (self.ipaddr, self.port, method)
return requests.get(url, *args, **kwargs)

def post(self, method, **kwargs):
url = "http://%s:%s%s" % (self.ipaddr, self.port, method)
return requests.post(url, data=kwargs)

def postfile(self, method, files, **kwargs):
url = "http://%s:%s%s" % (self.ipaddr, self.port, method)
return requests.post(url, files=files, data=kwargs)
Loading

0 comments on commit 7eaf0be

Please sign in to comment.