diff --git a/roles/vpn/tasks/client_configs.yml b/roles/vpn/tasks/client_configs.yml
index ea1621a..5c32ded 100644
--- a/roles/vpn/tasks/client_configs.yml
+++ b/roles/vpn/tasks/client_configs.yml
@@ -9,7 +9,6 @@
- name: Set facts for mobileconfigs
set_fact:
- proxy_enabled: false
PayloadContentCA: "{{ lookup('file' , 'configs/{{ IP_subject_alt_name }}/pki/cacert.pem')|b64encode }}"
- name: Build the mobileconfigs
diff --git a/roles/vpn/templates/mobileconfig.j2 b/roles/vpn/templates/mobileconfig.j2
index ce51ea5..b8013df 100644
--- a/roles/vpn/templates/mobileconfig.j2
+++ b/roles/vpn/templates/mobileconfig.j2
@@ -124,24 +124,12 @@
Proxies
HTTPEnable
-{% if proxy_enabled is defined and proxy_enabled == true %}
- 1
- HTTPPort
- 8118
- HTTPProxy
- {{ local_service_ip }}
- {% else %}
0
-{% endif %}
HTTPSEnable
0
UserDefinedName
-{% if proxy_enabled is defined and proxy_enabled == true %}
- Algo VPN {{ IP_subject_alt_name }} IKEv2 with proxy
- {% else %}
Algo VPN {{ IP_subject_alt_name }} IKEv2
-{% endif %}
VPNType
IKEv2
@@ -187,17 +175,9 @@
PayloadDisplayName
-{% if proxy_enabled is defined and proxy_enabled == true %}
- {{ IP_subject_alt_name }} IKEv2 with proxy
- {% else %}
{{ IP_subject_alt_name }} IKEv2
-{% endif %}
PayloadIdentifier
-{% if proxy_enabled is defined and proxy_enabled == true %}
- donut.local.{{ 600000 | random | to_uuid | upper }}
- {% else %}
donut.local.{{ 500000 | random | to_uuid | upper }}
-{% endif %}
PayloadRemovalDisallowed
PayloadType
diff --git a/roles/vpn/templates/rules.v4.j2 b/roles/vpn/templates/rules.v4.j2
index e040b18..c51568a 100644
--- a/roles/vpn/templates/rules.v4.j2
+++ b/roles/vpn/templates/rules.v4.j2
@@ -1,43 +1,95 @@
+#### The mangle table
+# This table allows us to modify packet headers
+# Packets enter this table first
+#
*mangle
+
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
+
{% if max_mss is defined %}
+# MSS is the TCP Max Segment Size
+# Setting the 'max_mss' Ansible variable can solve some issues related to packet fragmentation
+# This appears to be necessary on (at least) Google Cloud,
+# however, some routers also require a change to this parameter
+# See also:
+# - https://github.com/trailofbits/algo/issues/216
+# - https://github.com/trailofbits/algo/issues?utf8=%E2%9C%93&q=is%3Aissue%20mtu
+# - https://serverfault.com/questions/601143/ssh-not-working-over-ipsec-tunnel-strongswan
-A FORWARD -s {{ vpn_network }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ max_mss }}
{% endif %}
+
COMMIT
+
+
+#### The nat table
+# This table enables Network Address Translation
+# (This is technically a type of packet mangling)
+#
*nat
+
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
+
+# Allow traffic from the VPN network to the outside world, and replies
-A POSTROUTING -s {{ vpn_network }} -m policy --pol none --dir out -j MASQUERADE
+
COMMIT
+
+
+#### The filter table
+# The default ipfilter table
+#
*filter
+
+# By default, drop packets that are destined for this server
:INPUT DROP [0:0]
+# By default, drop packets that request to be forwarded by this server
:FORWARD DROP [0:0]
+# By default, accept any packets originating from this server
:OUTPUT ACCEPT [0:0]
+
+# Accept packets destined for localhost
-A INPUT -i lo -j ACCEPT
+# Accept any packet from an open TCP connection
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+# Accept packets using the encapsulation protocol
-A INPUT -p esp -j ACCEPT
-A INPUT -p ah -j ACCEPT
# rate limit ICMP traffic per source
-A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT
+# Accept IPSEC traffic to ports 500 (IPSEC) and 4500 (MOBIKE aka IKE + NAT traversal)
-A INPUT -p udp -m multiport --dports 500,4500 -j ACCEPT
+# Allow new traffic to port 22 (SSH)
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
+# Allow any traffic from the VPN
-A INPUT -p ipencap -m policy --dir in --pol ipsec --proto esp -j ACCEPT
+
# TODO:
# The IP of the resolver should be bound to a DUMMY interface.
# DUMMY interfaces are the proper way to install IPs without assigning them any
# particular virtual (tun,tap,...) or physical (ethernet) interface.
+
+# Accept DNS traffic to the local DNS resolver
-A INPUT -d {{ local_service_ip }} -p udp --dport 53 -j ACCEPT
--A INPUT -d {{ local_service_ip }} -p tcp -m multiport --dport 8080,8118 -j ACCEPT
+
{% if BetweenClients_DROP is defined and BetweenClients_DROP == "Y" %}
+# Drop traffic between VPN clients
-A FORWARD -s {{ vpn_network }} -d {{ vpn_network }} -j DROP
{% endif %}
+
+# Forward any packet that's part of an established connection
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+# Drop SMB/CIFS traffic that requests to be forwarded
-A FORWARD -p tcp --dport 445 -j DROP
+# Drop NETBIOS trafic that requests to be forwarded
-A FORWARD -p udp -m multiport --ports 137,138 -j DROP
-A FORWARD -p tcp -m multiport --ports 137,139 -j DROP
+
+# Forward any IPSEC traffic from the VPN network
-A FORWARD -m conntrack --ctstate NEW -s {{ vpn_network }} -m policy --pol ipsec --dir in -j ACCEPT
+
COMMIT
diff --git a/roles/vpn/templates/rules.v6.j2 b/roles/vpn/templates/rules.v6.j2
index 717b887..82ca8e1 100644
--- a/roles/vpn/templates/rules.v6.j2
+++ b/roles/vpn/templates/rules.v6.j2
@@ -1,43 +1,89 @@
+#### The mangle table
+# This table allows us to modify packet headers
+# Packets enter this table first
+#
*mangle
+
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
+
{% if max_mss is defined %}
+# MSS is the TCP Max Segment Size
+# See rules.v4 for a more complete explanation
-A FORWARD -s {{ vpn_network_ipv6 }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ max_mss }}
{% endif %}
+
COMMIT
+
+#### The nat table
+# This table enables Network Address Translation
+# (This is technically a type of packet mangling)
+#
*nat
+
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
+
+# Allow traffic from the VPN network to the outside world, and replies
-A POSTROUTING -s {{ vpn_network_ipv6 }} -m policy --pol none --dir out -j MASQUERADE
+
COMMIT
+
+#### The filter table
+# The default ipfilter table
+#
*filter
+
+# By default, drop packets that are destined for this server
:INPUT DROP [0:0]
+# By default, drop packets that request to be forwarded by this server
:FORWARD DROP [0:0]
+# By default, accept any packets originating from this server
:OUTPUT ACCEPT [0:0]
+
+# Create the ICMPV6-CHECK chain and its log chain
+# These chains are used later to prevent a type of bug that would
+# allow malicious traffic to reach over the server into the private network
+# An instance of such a bug on Cisco software is described here:
+# https://www.insinuator.net/2016/05/cve-2016-1409-ipv6-ndp-dos-vulnerability-in-cisco-software/
+# other software implementations might be at least as broken as the one in CISCO gear.
:ICMPV6-CHECK - [0:0]
:ICMPV6-CHECK-LOG - [0:0]
+
+# Accept packets destined for localhost
-A INPUT -i lo -j ACCEPT
+# Accept any packet from an open TCP connection
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+# Accept packets using the encapsulation protocol
-A INPUT -p esp -j ACCEPT
-A INPUT -m ah -j ACCEPT
# rate limit ICMP traffic per source
-A INPUT -p icmpv6 --icmpv6-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT
+# Accept IPSEC traffic to ports 500 (IPSEC) and 4500 (MOBIKE aka IKE + NAT traversal)
-A INPUT -p udp -m multiport --dports 500,4500 -j ACCEPT
+# Allow new traffic to port 22 (SSH)
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
+
+# Accept properly formatted Neighbor Discovery Protocol packets
-A INPUT -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
-A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
-A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
-A INPUT -p icmpv6 --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
+
# DHCP in AWS
-A INPUT -m conntrack --ctstate NEW -m udp -p udp --dport 546 -d fe80::/64 -j ACCEPT
+
# TODO:
# The IP of the resolver should be bound to a DUMMY interface.
# DUMMY interfaces are the proper way to install IPs without assigning them any
# particular virtual (tun,tap,...) or physical (ethernet) interface.
+
+# Accept DNS traffic to the local DNS resolver
-A INPUT -d fcaa::1 -p udp --dport 53 -j ACCEPT
+
{% if BetweenClients_DROP is defined and BetweenClients_DROP == "Y" %}
-A FORWARD -s {{ vpn_network_ipv6 }} -d {{ vpn_network_ipv6 }} -j DROP
{% endif %}
@@ -47,13 +93,13 @@ COMMIT
-A FORWARD -p tcp -m multiport --ports 137,139 -j DROP
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -m conntrack --ctstate NEW -s {{ vpn_network_ipv6 }} -m policy --pol ipsec --dir in -j ACCEPT
-# this is so potential malicious traffic can not reach anywhere over the server
-# https://www.insinuator.net/2016/05/cve-2016-1409-ipv6-ndp-dos-vulnerability-in-cisco-software/
-# other software implementations might be at least as broken as the one in CISCO gear.
+
+# Use the ICMPV6-CHECK chain, described above
-A ICMPV6-CHECK -p icmpv6 -m hl ! --hl-eq 255 --icmpv6-type router-solicitation -j ICMPV6-CHECK-LOG
-A ICMPV6-CHECK -p icmpv6 -m hl ! --hl-eq 255 --icmpv6-type router-advertisement -j ICMPV6-CHECK-LOG
-A ICMPV6-CHECK -p icmpv6 -m hl ! --hl-eq 255 --icmpv6-type neighbor-solicitation -j ICMPV6-CHECK-LOG
-A ICMPV6-CHECK -p icmpv6 -m hl ! --hl-eq 255 --icmpv6-type neighbor-advertisement -j ICMPV6-CHECK-LOG
-A ICMPV6-CHECK-LOG -j LOG --log-prefix "ICMPV6-CHECK-LOG DROP "
-A ICMPV6-CHECK-LOG -j DROP
+
COMMIT