mirror of
https://github.com/Rudd-O/qubes-network-server.git
synced 2025-03-01 14:22:35 +01:00
Bump version and prepare to package.
This commit is contained in:
parent
4e522c56a7
commit
efdda01dd0
1
Makefile
1
Makefile
@ -20,3 +20,4 @@ srpm: dist
|
||||
install:
|
||||
install -Dm 755 src/usr/bin/qvm-static-ip -t $(DESTDIR)/$(BINDIR)/
|
||||
install -Dm 644 src/usr/lib64/python2.7/site-packages/qubes/modules/*.py -t $(DESTDIR)/$(LIBDIR)/python2.7/site-packages/qubes/modules
|
||||
install -Dm 644 src/usr/lib64/python2.7/site-packages/qubes/modules/qubes-appvm-firewall -t $(DESTDIR)/$(LIBDIR)/python2.7/site-packages/qubes/modules
|
||||
|
@ -3,7 +3,7 @@
|
||||
%define mybuildnumber %{?build_number}%{?!build_number:1}
|
||||
|
||||
Name: qubes-network-server
|
||||
Version: 0.0.6
|
||||
Version: 0.0.7
|
||||
Release: %{mybuildnumber}%{?dist}
|
||||
Summary: Turn your Qubes OS into a network server
|
||||
BuildArch: noarch
|
||||
@ -38,6 +38,7 @@ make install DESTDIR=$RPM_BUILD_ROOT BINDIR=%{_bindir} LIBDIR=%{_libdir}
|
||||
%files
|
||||
%attr(0755, root, root) %{_bindir}/qvm-static-ip
|
||||
%attr(0644, root, root) %{_libdir}/python2.7/site-packages/qubes/modules/*.py*
|
||||
%attr(0644, root, root) %{_libdir}/python2.7/site-packages/qubes/modules/qubes-appvm-firewall
|
||||
%doc README.md TODO
|
||||
|
||||
%changelog
|
||||
|
@ -104,15 +104,13 @@ class QubesVm(OriginalQubesVm):
|
||||
else:
|
||||
return None
|
||||
|
||||
def start(self, verbose = False, preparing_dvm = False, start_guid = True,
|
||||
notify_function = None, mem_required = None):
|
||||
if dry_run:
|
||||
return
|
||||
xid = OriginalQubesVm.start(self, verbose, preparing_dvm, start_guid, notify_function, mem_required)
|
||||
if not preparing_dvm:
|
||||
self.adjust_proxy_arp(verbose=verbose, notify_function=notify_function)
|
||||
self.adjust_own_firewall_rules()
|
||||
return xid
|
||||
def start_qrexec_daemon(self, verbose=False, notify_function=None):
|
||||
ret = OriginalQubesVm.start_qrexec_daemon(self, verbose=verbose, notify_function=notify_function)
|
||||
if self.type not in ['AppVM', 'HVM']:
|
||||
self.deploy_appvm_firewall(verbose=verbose, notify_function=notify_function)
|
||||
self.adjust_proxy_arp(verbose=verbose, notify_function=notify_function)
|
||||
self.adjust_own_firewall_rules()
|
||||
return ret
|
||||
|
||||
def unpause(self):
|
||||
self.log.debug('unpause()')
|
||||
@ -397,4 +395,42 @@ class QubesVm(OriginalQubesVm):
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def deploy_appvm_firewall(self, verbose = False, notify_function=None):
|
||||
def n(msg):
|
||||
if notify_function:
|
||||
notify_function("info", msg)
|
||||
elif verbose:
|
||||
print >> sys.stderr, "-->", msg
|
||||
|
||||
n("Deploying AppVM firewall...")
|
||||
|
||||
appvm_firewall_path = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"qubes-appvm-firewall"
|
||||
)
|
||||
pill = textwrap.dedent(
|
||||
"""
|
||||
set -e
|
||||
tmp=$(mktemp)
|
||||
trap 'rm -f "$tmp"' EXIT
|
||||
cat > "$tmp" << "EOF"
|
||||
%s
|
||||
EOF
|
||||
chmod +x "$tmp"
|
||||
"$tmp" deploy
|
||||
"""
|
||||
) % open(appvm_firewall_path).read()
|
||||
|
||||
try:
|
||||
p = self.run("bash", user="root", gui=False, wait=True, passio_popen=True, autostart=False)
|
||||
p.stdin.write(pill)
|
||||
p.stdin.close()
|
||||
out = p.stdout.read()
|
||||
retcode = p.wait()
|
||||
except Exception as e:
|
||||
n("Could not deploy the AppVM firewall on the VM: %s" % e)
|
||||
if retcode != 0:
|
||||
n("Could not deploy the AppVM firewall on the VM (return status %s): %s" % (retcode, out))
|
||||
|
||||
|
||||
register_qubes_vm_class(QubesVm)
|
||||
|
217
src/usr/lib64/python2.7/site-packages/qubes/modules/qubes-appvm-firewall
Executable file
217
src/usr/lib64/python2.7/site-packages/qubes/modules/qubes-appvm-firewall
Executable file
@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
UNITPATH = "/usr/lib/systemd/system/qubes-appvm-firewall.service"
|
||||
DEPPATH = "/run/fortress/qubes-appvm-firewall"
|
||||
KEY = '/qubes-fortress-iptables-rules'
|
||||
CHAIN = 'FORTRESS-INPUT'
|
||||
|
||||
|
||||
class ReadError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def watch(key):
|
||||
subprocess.check_call(['qubesdb-watch', key])
|
||||
|
||||
|
||||
def read(key):
|
||||
try:
|
||||
return subprocess.check_output(['qubesdb-read', '-r', key])
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.error("error reading key %s: %s", key, e)
|
||||
raise ReadError()
|
||||
|
||||
|
||||
class Table(object):
|
||||
|
||||
header = None
|
||||
chains = None
|
||||
rules = None
|
||||
footer = None
|
||||
original_chains = None
|
||||
original_rules = None
|
||||
|
||||
def __init__(self, text):
|
||||
lines = text.splitlines(True)
|
||||
self.header = ''
|
||||
self.chains = collections.OrderedDict()
|
||||
self.rules = []
|
||||
self.footer = ''
|
||||
mode = "header"
|
||||
for line in lines:
|
||||
if mode == "header":
|
||||
if line.startswith(":"):
|
||||
self.chains.update([line[1:].split(" ", 1)])
|
||||
mode = "chains"
|
||||
else:
|
||||
self.header += line
|
||||
elif mode == "chains":
|
||||
if line.startswith("-"):
|
||||
self.rules.append(line)
|
||||
mode = "rules"
|
||||
else:
|
||||
self.chains.update([line[1:].split(" ", 1)])
|
||||
elif mode == "rules":
|
||||
if line.startswith("COMMIT"):
|
||||
self.footer += line
|
||||
mode = "footer"
|
||||
else:
|
||||
self.rules.append(line)
|
||||
else: # mode == "footer":
|
||||
self.footer += line
|
||||
self.original_chains = collections.OrderedDict(self.chains.items())
|
||||
self.original_rules = list(self.rules)
|
||||
|
||||
def __str__(self):
|
||||
return self.render()
|
||||
|
||||
def render(self, old=False):
|
||||
if old:
|
||||
chains = self.original_chains
|
||||
rules = self.original_rules
|
||||
else:
|
||||
chains = self.chains
|
||||
rules = self.rules
|
||||
return (
|
||||
self.header
|
||||
+ "".join(":%s %s" % x for x in chains.items())
|
||||
+ "".join(rules)
|
||||
+ self.footer
|
||||
)
|
||||
|
||||
def dirty(self):
|
||||
return self.render() != self.render(True)
|
||||
|
||||
def ensure_chain_present(self, name):
|
||||
if name not in self.chains:
|
||||
logging.info("Adding chain %s", name)
|
||||
self.chains[name] = '- [0:0]\n'
|
||||
|
||||
def clear_chain(self, name):
|
||||
for n, rule in reversed(list(enumerate(self.rules))):
|
||||
if rule.startswith("-A %s " % name):
|
||||
self.rules.pop(n)
|
||||
|
||||
def add_rule(self, rule, after_rule):
|
||||
original_after_rule = after_rule
|
||||
if not rule.endswith("\n"):
|
||||
rule += "\n"
|
||||
if not after_rule.endswith("\n"):
|
||||
after_rule += "\n"
|
||||
inserted = False
|
||||
if rule in self.rules:
|
||||
return
|
||||
for n, exrule in enumerate(self.rules):
|
||||
if exrule == after_rule:
|
||||
logging.info("Inserting rule %s", rule.strip())
|
||||
self.rules.insert(n + 1, rule)
|
||||
inserted = True
|
||||
break
|
||||
if not inserted:
|
||||
logging.error("Could not insert rule %s", rule.strip())
|
||||
raise KeyError(original_after_rule)
|
||||
|
||||
def replace_rules(self, chain, ruletext):
|
||||
for rule in ruletext.splitlines():
|
||||
if not rule.strip(): continue
|
||||
if not rule.startswith("-A %s " % chain):
|
||||
raise ValueError(
|
||||
"rule %s is not for chain %s" % (
|
||||
rule.strip(),
|
||||
chain,
|
||||
)
|
||||
)
|
||||
self.ensure_chain_present(chain)
|
||||
self.clear_chain(chain)
|
||||
for rule in ruletext.splitlines():
|
||||
if rule.startswith("-A %s " % chain):
|
||||
self.rules.append(rule + "\n")
|
||||
|
||||
def commit(self):
|
||||
if not self.dirty():
|
||||
return
|
||||
text = self.render()
|
||||
cmd = ['iptables-restore']
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
out, _ = p.communicate(text)
|
||||
w = p.wait()
|
||||
if w != 0:
|
||||
logging.error("Rule changes commit failed with status %s: %s", w, out)
|
||||
raise subprocess.CalledProcessError(w, cmd, out)
|
||||
self.original_chains = collections.OrderedDict(self.chains.items())
|
||||
self.original_rules = list(self.rules)
|
||||
logging.info("Rule changes committed")
|
||||
|
||||
@classmethod
|
||||
def filter_from_iptables(klass):
|
||||
r = subprocess.check_output(['iptables-save', '-t', 'filter'])
|
||||
t = klass(r)
|
||||
return t
|
||||
|
||||
def deploy():
|
||||
if not os.path.isdir(os.path.dirname(DEPPATH)):
|
||||
os.makedirs(os.path.dirname(DEPPATH))
|
||||
shutil.copyfile(__file__, DEPPATH)
|
||||
os.chmod(DEPPATH, 0755)
|
||||
service = '''[Unit]
|
||||
Description=Qubes AppVM firewall updater
|
||||
After=qubes-iptables.service qubes-firewall.service
|
||||
Before=qubes-network.service network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=%s main
|
||||
''' % DEPPATH
|
||||
if not os.path.isfile(UNITPATH) or open(UNITPATH, "rb").read() != service:
|
||||
open(UNITPATH, "wb").write(service)
|
||||
subprocess.check_call(['systemctl', '--system', 'daemon-reload'])
|
||||
subprocess.check_call(['systemctl', 'restart', os.path.basename(UNITPATH)])
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
t = Table.filter_from_iptables()
|
||||
t.ensure_chain_present(CHAIN)
|
||||
t.add_rule('-A INPUT -j %s' % CHAIN, '-A INPUT -i lo -j ACCEPT')
|
||||
try:
|
||||
newrules = read(KEY)
|
||||
t.replace_rules(CHAIN, newrules)
|
||||
except ReadError:
|
||||
# Key may not exist at this time.
|
||||
logging.warning("Qubes DB key %s does not yet exist", KEY)
|
||||
t.commit()
|
||||
logging.info("Startup complete")
|
||||
while True:
|
||||
watch(KEY)
|
||||
try:
|
||||
newrules = read(KEY)
|
||||
except ReadError:
|
||||
# Key may have been deleted.
|
||||
logging.warning("Qubes DB key %s could not be read", KEY)
|
||||
continue
|
||||
logging.info("Rule changes detected")
|
||||
try:
|
||||
t.replace_rules(CHAIN, newrules)
|
||||
t.commit()
|
||||
except Exception:
|
||||
logging.exception("Rule changes could not be committed")
|
||||
|
||||
|
||||
try:
|
||||
cmd = sys.argv[1]
|
||||
except IndexError:
|
||||
cmd = 'main'
|
||||
cmd = locals()[cmd]
|
||||
sys.exit(cmd())
|
Loading…
x
Reference in New Issue
Block a user