Skip to content

Commit

Permalink
version 0.6.4
Browse files Browse the repository at this point in the history
  • Loading branch information
corrad1nho committed Aug 12, 2018
1 parent 030a5f2 commit db4a3e0
Show file tree
Hide file tree
Showing 8 changed files with 439 additions and 386 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
##Changelog

version 0.6.4:
- [change] added new firewall options
- [change] code cleanup
- [change] WireGuard connections now honor DNS override
- [bugfix] Proton api url updated
- [bugfix] added all local ipv4 ranges

version 0.6.3:
- [change] bypass mode supports ipv6 now
- [change] alternative DNS servers are used for bypass
Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,18 @@ qomui-cli --help
Qomui has been my first ever programming experience and a practical challenge for myself to learn a bit of Python. Hence, I'm aware that there is a lot of code that could probably be improved, streamlined and made more beautiful. I might have made some horrible mistakes, too. I'd appreciate any feedback as well as suggestions for new features.

### Changelog
version 0.6.4:
- [change] added new firewall options
- [change] code cleanup
- [change] WireGuard connections now honor DNS override
- [bugfix] Proton api url updated
- [bugfix] added all local ipv4 ranges

version 0.6.3:
- [change] bypass mode supports ipv6 now
- [change] alternative DNS servers are used for bypass
- [change] WireGuard is now written correctly (pull request from zx2c4) - requires all WireGuard configs to be readded
- [change] exit dialog has a 5 sec timeout now
- [change] umask set before chmod to avoid race conditions (pull request from zx2c4)
- [bugfix] bypass should now work properly with WireGuard connections

version 0.6.2:
- [change] api-url for ProtonVPN updated - the one introduced in last update was out of date
- [change] added support for Windscribe's stealth feature (OpenVPN over SSL)
- [change] postrm functions added to deb/rpm/aur packages
- [change] automatic reconnections for double hop if first hop fails/disconnects
- [change] adjusted OpenVPN configs of Mullvad and Windscribe to match official ones
- [bugfix] tray icon not always updated after establishing double hop connection
- [bugfix] qomui crashes while performing latency checks when server(s) are deleted

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.6.3
0.6.4
85 changes: 44 additions & 41 deletions qomui/bypass.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import os
import logging
from subprocess import check_call, Popen, CalledProcessError
from subprocess import check_call, CalledProcessError

from qomui import firewall

cgroup_path = "/sys/fs/cgroup/net_cls/bypass_qomui"
Expand All @@ -14,27 +15,28 @@ def create_cgroup(user, group, default_interface, default_gateway, default_inter

delete_cgroup(default_interface, default_interface_6)

cgroup_iptables = [["-t", "mangle", "-A", "OUTPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "MARK", "--set-mark", "11"],
["-t", "nat", "-A", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface , "-j", "MASQUERADE"],
["-I", "OUTPUT", "1", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-I", "INPUT", "1", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-t", "nat", "-A", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "tcp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"],
["-t", "nat", "-A", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "udp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"]
]
cgroup_iptables = [
["-t", "mangle", "-A", "OUTPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "MARK", "--set-mark", "11"],
["-t", "nat", "-A", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface, "-j", "MASQUERADE"],
["-I", "OUTPUT", "1", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-I", "INPUT", "1", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-t", "nat", "-A", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "tcp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"],
["-t", "nat", "-A", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "udp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"]
]

if not os.path.exists(cgroup_path):
os.makedirs(cgroup_path)
with open("%s/net_cls.classid" % cgroup_path, 'w') as setcid:
setcid.write(cls_id)
setcid.close()

try:
try:
check_call(["ip", "route", "show", "table", "bypass_qomui"])
logging.debug("No routing table added - table bypass_qomui already exists")
except CalledProcessError:
Expand All @@ -47,17 +49,17 @@ def create_cgroup(user, group, default_interface, default_gateway, default_inter

if default_gateway_6 != "None":
cgroup_iptables.pop(1)
cgroup_iptables.insert(1, ["-t", "nat", "-A", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface_6 , "-j", "MASQUERADE"])
cgroup_iptables.insert(1, ["-t", "nat", "-A", "POSTROUTING", "-m", "cgroup", "--cgroup",
"0x00110011", "-o", "%s" %default_interface_6, "-j", "MASQUERADE"])

for rule in cgroup_iptables:
firewall.add_rule_6(rule)

else:
logging.debug("Blocking ipv6 via bypass_qomui")
cgroup_iptables.pop(1)
cgroup_iptables.insert(1, ["-t", "nat", "-A", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface , "-j", "MASQUERADE"])
cgroup_iptables.insert(1, ["-t", "nat", "-A", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface, "-j", "MASQUERADE"])
cgroup_iptables.pop(2)
cgroup_iptables.insert(2, ["-I", "OUTPUT", "1", "-m", "cgroup", "--cgroup", "0x00110011", "-j", "DROP"])
cgroup_iptables.pop(3)
Expand All @@ -79,15 +81,15 @@ def create_cgroup(user, group, default_interface, default_gateway, default_inter
try:
check_call(["ip", "route", "flush", "table", "bypass_qomui"])
check_call(["ip", "rule", "add", "fwmark", "11", "table", "bypass_qomui"])
check_call(["ip", "route", "add", "default", "via",
check_call(["ip", "route", "add", "default", "via",
"%s" %default_gateway, "dev", "%s" %default_interface, "table", "bypass_qomui"])
except CalledProcessError:
logging.error("Could not set ipv4 routes for cgroup")

try:
check_call(["ip", "-6", "route", "flush", "table", "bypass_qomui"])
check_call(["ip", "-6", "rule", "add", "fwmark", "11", "table", "bypass_qomui"])
check_call(["ip", "-6", "route", "add", "default", "via",
check_call(["ip", "-6", "route", "add", "default", "via",
"%s" %default_gateway_6, "dev", "%s" %default_interface_6, "table", "bypass_qomui"])
except CalledProcessError:
logging.error("Could not set ipv6 routes for cgroup")
Expand All @@ -97,32 +99,33 @@ def create_cgroup(user, group, default_interface, default_gateway, default_inter
except CalledProcessError:
logging.error("Creating cgroup failed")

with open ("/proc/sys/net/ipv4/conf/all/rp_filter", 'w') as rp_edit_all:
with open("/proc/sys/net/ipv4/conf/all/rp_filter", 'w') as rp_edit_all:
rp_edit_all.write("2")
with open ("/proc/sys/net/ipv4/conf/%s/rp_filter" %default_interface, 'w') as rp_edit_int:
with open("/proc/sys/net/ipv4/conf/%s/rp_filter" %default_interface, 'w') as rp_edit_int:
rp_edit_int.write("2")

logging.info("Succesfully created cgroup to bypass OpenVPN tunnel")

def delete_cgroup(default_interface, default_interface_6):

cgroup_iptables_del = [["-t", "mangle", "-D", "OUTPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "MARK", "--set-mark", "11"],
["-t", "nat", "-D", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface , "-j", "MASQUERADE"],
["-D", "OUTPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-D", "INPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-t", "nat", "-D", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "tcp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"],
["-t", "nat", "-D", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "udp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"]
]

with open ("/proc/sys/net/ipv4/conf/all/rp_filter", 'w') as rp_edit_all:
cgroup_iptables_del = [
["-t", "mangle", "-D", "OUTPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "MARK", "--set-mark", "11"],
["-t", "nat", "-D", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface, "-j", "MASQUERADE"],
["-D", "OUTPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-D", "INPUT", "-m", "cgroup",
"--cgroup", "0x00110011", "-j", "ACCEPT"],
["-t", "nat", "-D", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "tcp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"],
["-t", "nat", "-D", "OUTPUT", "-m", "cgroup", "--cgroup",
"0x00110011", "-p", "udp", "--dport", "53", "-j", "REDIRECT", "--to-ports", "5354"]
]

with open("/proc/sys/net/ipv4/conf/all/rp_filter", 'w') as rp_edit_all:
rp_edit_all.write("1")
with open ("/proc/sys/net/ipv4/conf/%s/rp_filter" %default_interface, 'w') as rp_edit_int:
with open("/proc/sys/net/ipv4/conf/%s/rp_filter" %default_interface, 'w') as rp_edit_int:
rp_edit_int.write("1")

try:
Expand All @@ -135,8 +138,8 @@ def delete_cgroup(default_interface, default_interface_6):
firewall.add_rule(rule)

cgroup_iptables_del.pop(1)
cgroup_iptables_del.insert(1, ["-t", "nat", "-D", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface_6 , "-j", "MASQUERADE"])
cgroup_iptables_del.insert(1, ["-t", "nat", "-D", "POSTROUTING", "-m", "cgroup",
"--cgroup", "0x00110011", "-o", "%s" %default_interface_6, "-j", "MASQUERADE"])

for rule in cgroup_iptables_del:
firewall.add_rule_6(rule)
Expand Down
94 changes: 47 additions & 47 deletions qomui/firewall.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
saved_rules_6 = []
ip_cmd = ["iptables", "--wait",]
ip6_cmd = ["ip6tables", "--wait",]
devnull = open(os.devnull, 'w')
devnull = open(os.devnull, 'w')

def add_rule(rule):
a = 1
Expand All @@ -24,21 +24,21 @@ def add_rule(rule):
check.pop(2)
elif check[2] == "-A":
check[2] = "-C"
apply_rule = check_call(ip_cmd + check, stdout=devnull, stderr=devnull)
check_call(ip_cmd + check, stdout=devnull, stderr=devnull)
logging.debug("iptables: %s already exists" %rule)
a = 0
except (IndexError, CalledProcessError):
pass

try:
if a == 1:
apply_rule = check_call(ip_cmd + rule, stdout=devnull, stderr=devnull)
check_call(ip_cmd + rule, stdout=devnull, stderr=devnull)
logging.debug("iptables: applied %s" %rule)

except CalledProcessError:
if "-D" not in rule:
logging.warning("iptables: failed to apply %s" %rule)

def add_rule_6(rule):
a = 1
try:
Expand All @@ -51,112 +51,112 @@ def add_rule_6(rule):
check.pop(2)
elif check[2] == "-A":
check[2] = "-C"
apply_rule = check_call(ip6_cmd + check, stdout=devnull, stderr=devnull)
check_call(ip6_cmd + check, stdout=devnull, stderr=devnull)
logging.debug("ipt6ables: %s already exists" %rule)
a = 0
except (IndexError, CalledProcessError):
pass

try:
if a == 1:
apply_rule = check_call(ip6_cmd + rule, stdout=devnull, stderr=devnull)
check_call(ip6_cmd + rule, stdout=devnull, stderr=devnull)
logging.debug("ip6tables: applied %s" %rule)

except CalledProcessError:
if "-D" not in rule:
logging.warning("ip6tables: failed to apply %s" %rule)

def apply_rules(opt, block_lan=0, preserve=0):
firewall_rules = get_config()
save_existing_rules(firewall_rules)
save_existing_rules_6(firewall_rules)
for rule in firewall_rules["flush"]:
fw_rules = get_config()
save_existing_rules(fw_rules)
save_existing_rules_6(fw_rules)

for rule in fw_rules["flush"]:
add_rule(rule)
for rule in firewall_rules["flushv6"]:

for rule in fw_rules["flushv6"]:
add_rule_6(rule)

logging.info("iptables: flushed existing rules")

for rule in saved_rules:
if preserve == 1:
add_rule(rule)

for rule in saved_rules_6:
if preserve == 1:
add_rule_6(rule)

if opt == 1:
for rule in firewall_rules["defaults"]:
for rule in fw_rules["defaults"]:
add_rule(rule)

if block_lan == 0:
for rule in firewall_rules["ipv4local"]:
for rule in fw_rules["ipv4local"]:
add_rule(rule)
for rule in firewall_rules["ipv6local"]:

for rule in fw_rules["ipv6local"]:
add_rule_6(rule)

for rule in firewall_rules["defaultsv6"]:
for rule in fw_rules["defaultsv6"]:
add_rule_6(rule)
for rule in firewall_rules["ipv4rules"]:

for rule in fw_rules["ipv4rules"]:
add_rule(rule)

for rule in firewall_rules["ipv6rules"]:
for rule in fw_rules["ipv6rules"]:
add_rule_6(rule)

logging.info("iptables: activated firewall")

elif opt == 0:
for rule in firewall_rules["unsecure"]:
for rule in fw_rules["unsecure"]:
add_rule(rule)
for rule in firewall_rules["unsecurev6"]:

for rule in fw_rules["unsecurev6"]:
add_rule_6(rule)

logging.info("iptables: deactivated firewall")
def save_existing_rules(firewall_rules):

def save_existing_rules(fw_rules):
existing_rules = check_output(["iptables", "-S"]).decode("utf-8")
for line in existing_rules.split('\n'):
rpl = line.replace("/32", "")
rule = shlex.split(rpl)
if len(rule) != 0:
match = 0
omit = firewall_rules["ipv4rules"] + firewall_rules["flush"] + firewall_rules["ipv4local"]
omit = fw_rules["ipv4rules"] + fw_rules["flush"] + fw_rules["ipv4local"]
for x in omit:
if Counter(x) == Counter(rule):
match = 1
if match == 0 and rule not in saved_rules:
saved_rules.append(rule)
match = 0
def save_existing_rules_6(firewall_rules):

def save_existing_rules_6(fw_rules):
existing_rules = check_output(["ip6tables", "-S"]).decode("utf-8")
for line in existing_rules.split('\n'):
rpl = line.replace("/32", "")
rule = shlex.split(rpl)
if len(rule) != 0:
match = 0
omit = firewall_rules["ipv6rules"] + firewall_rules["flushv6"] + firewall_rules["ipv6local"]
omit = fw_rules["ipv6rules"] + fw_rules["flushv6"] + fw_rules["ipv6local"]
for x in omit:
if Counter(x) == Counter(rule):
match = 1
if match == 0 and rule not in saved_rules_6:
saved_rules_6.append(rule)
match = 0

def get_config():
try:
with open ("%s/firewall.json" %(ROOTDIR), "r") as f:
return json.load(f)
with open("%s/firewall.json" %ROOTDIR, "r") as f:
return json.load(f)
except (FileNotFoundError, json.decoder.JSONDecodeError) as e:
logging.debug("Loading default firewall configuration")
try:
with open ("%s/firewall_default.json" %(ROOTDIR), "r") as f:
return json.load(f)
with open("%s/firewall_default.json" %ROOTDIR, "r") as f:
return json.load(f)
except (FileNotFoundError, json.decoder.JSONDecodeError) as e:
logging.debug("Failed to load firewall configuration")
return None
logging.debug("Failed to load firewall configuration")
return None

0 comments on commit db4a3e0

Please sign in to comment.