summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog2
-rw-r--r--helpers/bitmask-root76
2 files changed, 69 insertions, 9 deletions
diff --git a/debian/changelog b/debian/changelog
index 55e1f6b..cb996ed 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-riseup-vpn (0.21.2.5) groovy; urgency=medium
+riseup-vpn (0.21.2.6) groovy; urgency=medium
* Initial Release.
diff --git a/helpers/bitmask-root b/helpers/bitmask-root
index 6615d3b..f105bfc 100644
--- a/helpers/bitmask-root
+++ b/helpers/bitmask-root
@@ -43,6 +43,7 @@ The `openvpn start` action is special: it calls exec on openvpn and replaces
the current process. If the `restart` parameter is passed, the firewall will
not be teared down in the case of an error during launch.
"""
+import ipaddress
import os
import re
import signal
@@ -83,7 +84,7 @@ def get_no_group_name():
def tostr(s):
return s.decode('utf-8')
-VERSION = "12"
+VERSION = "13"
SCRIPT = "bitmask-root"
NAMESERVER_TCP = "10.41.0.1"
NAMESERVER_UDP = "10.42.0.1"
@@ -275,6 +276,29 @@ def get_process_list():
return filter(None, res)
+def getIPv4AllowAddresses():
+ lines = []
+ try:
+ with open("/etc/bitmask/ipv4.allow", 'r') as f:
+ lines = [l.strip() for l in f.readlines()]
+ except FileNotFoundError:
+ return lines
+
+ lines = filter(lambda x: ipaddress.ip_address(x).version == 4, lines)
+ return list(filter(lambda x: ipaddress.ip_address(x).is_private, lines))
+
+def getIPv6AllowAddresses():
+ lines = []
+ try:
+ with open("/etc/bitmask/ipv6.allow", 'r') as f:
+ lines = [l.strip() for l in f.readlines()]
+ except FileNotFoundError:
+ return lines
+
+ lines = filter(lambda x: ipaddress.ip_address(x).version == 6, lines)
+ return list(filter(lambda x: ipaddress.ip_address(x).is_private, lines))
+
+
def run(command, *args, **options):
"""
Run an external command.
@@ -655,6 +679,16 @@ def firewall_start(args):
local_network_ipv6 = get_local_network_ipv6(default_device)
gateways = get_gateways(args)
+ # allow local address in listed exception list
+ # this will allow all ports and both tcp and udp.
+ def allow4(ip):
+ ip4tables("--append", BITMASK_CHAIN, "--destination", ip,
+ "-o", default_device, "--jump", "ACCEPT")
+
+ def allow6(ip):
+ ip6tables("--append", BITMASK_CHAIN, "--destination", ip,
+ "-o", default_device, "--jump", "ACCEPT")
+
# add custom chain "bitmask" to front of OUTPUT chain for both
# the 'filter' and the 'nat' tables.
if not ipv4_chain_exists(BITMASK_CHAIN):
@@ -707,11 +741,14 @@ def firewall_start(args):
"--protocol", "tcp", "--dport", "53", "--jump", "MASQUERADE")
# allow local network traffic
+
+ ipv4_exceptions = getIPv4AllowAddresses()
if local_network_ipv4:
- # allow local network destinations
- ip4tables("--append", BITMASK_CHAIN,
- "--destination", local_network_ipv4, "-o", default_device,
- "--jump", "ACCEPT")
+ if len(ipv4_exceptions) == 0:
+ # allow all local network destinations if no explicit allow rules defined
+ ip4tables("--append", BITMASK_CHAIN,
+ "--destination", local_network_ipv4, "-o", default_device,
+ "--jump", "ACCEPT")
# allow local network sources for DNS
# (required to allow local network DNS that gets rewritten by NAT
# to get passed through so that MASQUERADE can set correct source IP)
@@ -731,10 +768,15 @@ def firewall_start(args):
"--protocol", "udp",
"--destination", "224.0.0.251", "--dport", "5353",
"-o", default_device, "--jump", "RETURN")
+
+
+ ipv6_exceptions = getIPv6AllowAddresses()
if local_network_ipv6:
- ip6tables("--append", BITMASK_CHAIN,
- "--destination", local_network_ipv6, "-o", default_device,
- "--jump", "ACCEPT")
+ if len(ipv6_exceptions) == 0:
+ # allow all local network destinations if no explicit allow rules defined
+ ip6tables("--append", BITMASK_CHAIN,
+ "--destination", local_network_ipv6, "-o", default_device,
+ "--jump", "ACCEPT")
# allow multicast Simple Service Discovery Protocol
ip6tables("--append", BITMASK_CHAIN,
"--protocol", "udp",
@@ -751,12 +793,29 @@ def firewall_start(args):
ip4tables("--append", BITMASK_CHAIN, "--destination", gateway,
"-o", default_device, "--jump", "ACCEPT")
+ # TODO allow ipv6 traffic to gws too
+
# log rejected packets to syslog
if DEBUG:
iptables("--append", BITMASK_CHAIN, "-o", default_device,
"--jump", "LOG", "--log-prefix", "iptables denied: ",
"--log-level", "7")
+ # allow explicit private exceptions
+ if len(ipv4_exceptions) != 0:
+ for ip in ipv4_exceptions:
+ allow4(ip)
+ ip4tables("--append", BITMASK_CHAIN,
+ "--destination", local_network_ipv4, "-o", default_device,
+ "--jump", "REJECT")
+
+ if len(ipv6_exceptions) != 0:
+ for ip in ipv6_exceptions:
+ allow6(ip)
+ ip6tables("--append", BITMASK_CHAIN,
+ "--destination", local_network_ipv6, "-o", default_device,
+ "--jump", "REJECT")
+
# for now, ensure all other ipv6 packets get rejected (regardless of
# device). not sure why, but "-p any" doesn't work.
ip6tables("--append", BITMASK_CHAIN, "-p", "tcp", "--jump", "REJECT")
@@ -766,6 +825,7 @@ def firewall_start(args):
ip4tables("--append", BITMASK_CHAIN, "-o",
default_device, "--jump", "REJECT")
+
# On Qubes OS, add anti-leak rules for proxyVM qubes-firewall.service
# Must stay on 'top' of chain!
if QUBES_PROXY and QUBES_VER >= 3 and run("grep", "installed\ by\ " +