From 59abc641d6f5c2af46515bc917fe0474b7b3727f Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Fri, 16 Jul 2021 21:40:28 +0200 Subject: [PATCH 01/16] Implement firewall - settings in iptables_rules.json - creates a script under /tmp/iptables_raspap.sh and executes it - no installer yet - to do: deal with Bridge and VPN settings --- config/iptables_rules.json | 168 +++++++++++++++++++++++++++++++++++ includes/firewall.php | 174 +++++++++++++++++++++++++++++++++++++ installers/raspap.sudoers | 1 + templates/firewall.php | 70 +++++++++++++++ 4 files changed, 413 insertions(+) create mode 100644 config/iptables_rules.json create mode 100644 includes/firewall.php create mode 100644 templates/firewall.php diff --git a/config/iptables_rules.json b/config/iptables_rules.json new file mode 100644 index 00000000..fa23d707 --- /dev/null +++ b/config/iptables_rules.json @@ -0,0 +1,168 @@ +{ + "info": "IPTABLES rules. $...$ expressions will be replaces automatically ($INTERFACE$, $PORT$, $IPADDRESS$)", + "rules_v4_file": "/etc/iptables/rules.v4", + "rules_v6_file": "/etc/iptables/rules.v6", + "order": [ "pre_rules", "restriction_rules", "main_rules", "exception_rules" ], + "pre_rules": [ + { + "name": "firewall policies", + "fw-state": true, + "comment": "Policy rules (firewall)", + "rules": [ + "-P INPUT DROP", + "-P FORWARD ACCEPT", + "-P OUTPUT ACCEPT", + "-t nat -P PREROUTING ACCEPT", + "-t nat -P POSTROUTING ACCEPT", + "-t nat -P INPUT ACCEPT", + "-t nat -P OUTPUT ACCEPT" + ] + }, + { + "name": "policies", + "fw-state": false, + "comment": "Policy rules", + "rules": [ + "-P INPUT ACCEPT", + "-P FORWARD ACCEPT", + "-P OUTPUT ACCEPT", + "-t nat -P PREROUTING ACCEPT", + "-t nat -P POSTROUTING ACCEPT", + "-t nat -P INPUT ACCEPT", + "-t nat -P OUTPUT ACCEPT" + ] + }, + { + "name": "loopback", + "fw-state": true, + "comment": "allow loopback device", + "rules": [ + "-A INPUT -i lo -j ACCEPT", + "-A OUTPUT -o lo -j ACCEPT" + ] + }, + { + "name": "ping", + "fw-state": true, + "comment": "allow ping request and echo", + "rules": [ + "-A INPUT -p icmp --icmp-type 8/0 -j ACCEPT", + "-A INPUT -p icmp --icmp-type 0/0 -j ACCEPT" + ] + }, + { + "name": "ntp", + "fw-state": true, + "comment": "allow ntp request via udp (tcp should work w/o rule)", + "rules": [ + "-A INPUT -p udp --sport 123 -j ACCEPT" + ] + }, + { + "name": "dns", + "fw-state": true, + "comment": "allow dns request via tcp and udp", + "rules": [ + "-A INPUT -p udp -m multiport --sport 53,853 -j ACCEPT", + "-A INPUT -p tcp -m multiport --sport 53,853 -j ACCEPT" + ] + } + ], + "main_rules": [ + { + "name": "accesspoint", + "fw-state": true, + "comment": "Access point interface by default no restrictions", + "dependson": [ + { "var": "ap-device", "type": "string", "replace": "$INTERFACE$" } + ], + "rules": [ + "-A INPUT -i $INTERFACE$ -j ACCEPT", + "-A OUTPUT -o $INTERFACE$ -j ACCEPT" + ] + }, + { + "name": "clients", + "fw-state": true, + "comment": "Rules for client interfaces (includes tun device)", + "rules": [ + "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" + ] + }, + { + "name": "openvpn", + "comment": "Rules for tunnel device (tun)", + "dependson": [ + { "var": "openvpn-enable", "type": "bool" }, + { "var": "openvpn-serverip", "type": "string", "replace": "$IPADDRESS$" }, + { "var": "client-device", "type": "string", "replace": "$INTERFACE$" } + ], + "rules": [ + "-A FORWARD -i tun+ -o $INTERFACE$ -m state --state RELATED,ESTABLISHED -j ACCEPT", + "-A FORWARD -i $INTERFACE$ -o tun+ -j ACCEPT", + "-t nat -A POSTROUTING -o tun+ -j MASQUERADE" + ] + } + ], + "exception_rules": [ + { + "name": "ssh", + "fw-state": true, + "comment": "Allow ssh access to RaspAP on port 22", + "dependson": [ + { "var": "ssh-enable", "type": "bool" } + ], + "rules": [ + "-A INPUT -p tcp --dport 22 -j ACCEPT" + ] + }, + { + "name": "http", + "fw-state": true, + "comment": "Allow access to RaspAP GUI (https)", + "dependson": [ + { "var": "http-enable", "type": "bool" } + ], + "rules": [ + "-A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT" + ] + }, + { + "name": "interface", + "fw-state": true, + "comment": "Exclude interface from firewall", + "dependson": [ + { "var": "excl-devices", "type": "list", "replace": "$INTERFACE$" } + ], + "rules": [ + "-A INPUT -i $INTERFACE$ -j ACCEPT", + "-A OUTPUT -o $INTERFACE$ -j ACCEPT" + ] + }, + { + "name": "ipaddress", + "fw-state": true, + "comment": "allow access from/to IP", + "dependson": [ + { "var": "excluded-ips", "type": "list", "replace": "$IPADDRESS$" } + ], + "rules": [ + "-A INPUT -s $IPADDRESS$ -j ACCEPT", + "-A INPUT -d $IPADDRESS$ -j ACCEPT" + ] + } + ], + "restriction_rules": [ + { + "name": "ipaddress", + "fw-state": true, + "dependson": [ + { "var": "restricted-ips", "type": "list", "replace": "$IPADDRESS$" } + ], + "comment": "Block access from IP-address", + "rules": [ + "-A INPUT -s $IPADDRESS$ -j DROP" + ] + } + ] +} diff --git a/includes/firewall.php b/includes/firewall.php new file mode 100644 index 00000000..ceac3748 --- /dev/null +++ b/includes/firewall.php @@ -0,0 +1,174 @@ +"; +// print_r($ipt); + $txt = "#!/bin/bash\n"; + $txt .= "iptables -F\n"; + $txt .= "iptables -X\n"; + $txt .= "iptables -t nat -F\n"; + file_put_contents(RASPAP_IPTABLES_SCRIPT, $txt); + if ( empty($conf) || empty($ipt) ) return false; + $count=0; + foreach ( $ipt["order"] as $idx ) { + if ( isset($ipt[$idx]) ) { +// echo "Handle $idx \n"; + foreach ( $ipt[$idx] as $i => $sect ) { + if ( isRuleEnabled($sect, $conf) ) { +// echo " rule $i name ".$sect["name"]."\n"; + $str_rules= createRuleStr($sect, $conf); + if ( !empty($str_rules) ) { + file_put_contents(RASPAP_IPTABLES_SCRIPT, $str_rules, FILE_APPEND); + ++$count; + } + } + } + } + } +// echo "Firewall ON"; +//echo ""; + if ( $count > 0 ) { + exec("chmod +x ".RASPAP_IPTABLES_SCRIPT); + exec("sudo ".RASPAP_IPTABLES_SCRIPT); +// exec("sudo iptables-save > /etc/iptables/rules.v4"); +// unlink(RASPAP_IPTABLES_SCRIPT); + } + return ($count > 0); +} + +function WriteFirewallConf($conf) { + if ( is_array($conf) ) write_php_ini($conf,RASPAP_FIREWALL_CONF); +} + + +function ReadFirewallConf() { + if ( file_exists(RASPAP_FIREWALL_CONF) ) { + $conf = parse_ini_file(RASPAP_FIREWALL_CONF); + } else { + $conf = array(); + $conf["firewall-enable"] = false; + $conf["openvpn-enable"] = false; + $conf["openvpn-serverip"] = ""; + $conf["wireguard-enable"] = false; + $conf["wireguard-serverip"] = ""; + $conf["ssh-enable"] = false; + $conf["http-enable"] = false; + $conf["excl-devices"] = ""; + $conf["excluded-ips"] = ""; + $conf["ap-device"] = ""; + $conf["client-device"] = ""; + $conf["restricted-ips"] = ""; + } + return $conf; +} + +function DisplayFirewallConfig() +{ + + $status = new StatusMessages(); + + $json = file_get_contents(RASPAP_IPTABLES_CONF); + $ipt_rules = json_decode($json, true); + + getWifiInterface(); + $ap_device = $_SESSION['ap_interface']; + $clients = getClients(); + $fw_conf = ReadFirewallConf(); + $fw_conf["ap-device"] = $ap_device; + $id=findCurrentClientIndex($clients); + if ( $id >= 0 ) $fw_conf["client-device"] = $clients["device"][$id]["name"]; + if (!empty($_POST)) { + $fw_conf["ssh-enable"] = isset($_POST['ssh-enable']); + $fw_conf["http-enable"] = isset($_POST['http-enable']); + $fw_conf["firewall-enable"] = isset($_POST['firewall-enable']) || isset($_POST['apply-firewall']); + if ( isset($_POST['firewall-enable']) ) $status->addMessage(_('Firewall is now enabled'), 'success'); + if ( isset($_POST['apply-firewall']) ) $status->addMessage(_('Firewall settings changed'), 'success'); + if ( isset($_POST['firewall-disable']) ) $status->addMessage(_('Firewall is now disabled'), 'warning'); + if ( isset($_POST['save-firewall']) ) $status->addMessage(_('Firewall settings saved. Firewall is still disabled.'), 'success'); + WriteFirewallConf($fw_conf); + setFirewall(); + } + echo renderTemplate("firewall", compact( + "status", + "ap_device", + "clients", + "fw_conf", + "ipt_rules") + ); +} diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index 7ce40f28..ae737910 100644 --- a/installers/raspap.sudoers +++ b/installers/raspap.sudoers @@ -62,3 +62,4 @@ www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wireguard/*.conf www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wireguard/wg-*.key www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/wireguard/*.conf www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/wireguard/wg-*.key +www-data ALL=(ALL) NOPASSWD:/tmp/iptables_raspap.sh diff --git a/templates/firewall.php b/templates/firewall.php new file mode 100644 index 00000000..39e41b71 --- /dev/null +++ b/templates/firewall.php @@ -0,0 +1,70 @@ +
+
+
+
+
+
+ +
+
+
+
+ showMessages(); ?> +

+ + + + + +
+
+

+
+
+ +
+ +
+
+
+
+ > + +
+
+ > + +
+

+ +

+
+
+ + " name="apply-firewall" /> + " name="firewall-disable" data-toggle="modal" data-target="#firewallModal"/> + + " name="save-firewall" /> + " name="firewall-enable" data-toggle="modal" data-target="#firewallModal"/> + +
+
+ +
+
+
+ + + +
+
+
+ + " aria-describedby="exclusion-description" > +

+ Current client devices: $str_clients
The access point ". $ap_device ." is per default excluded.") ?>
+

+
+
" name="apply-firewall" /> " name="firewall-disable" data-toggle="modal" data-target="#firewallModal"/> From 393292f8722f95de11d752e6939d25d6d1dd20e2 Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Wed, 21 Jul 2021 16:02:21 +0200 Subject: [PATCH 09/16] Add VPN server IPs to Firewall GUI --- includes/firewall.php | 80 +++++++++++++++++++++++++++--------------- templates/firewall.php | 25 +++++++++---- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/includes/firewall.php b/includes/firewall.php index dc2397cf..6839a264 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -39,7 +39,7 @@ function createRuleStr(&$sect, &$conf) { $repl=$val=""; switch ( $dep["type"] ) { case "list": - if ( isset($dep["var"]) && !empty($conf[$dep["var"]]) ) $val = explode(',', $conf[$dep["var"]]); + if ( isset($dep["var"]) && !empty($conf[$dep["var"]]) ) $val = explode(' ', $conf[$dep["var"]]); if ( !empty($val) && isset($dep["replace"]) ) $repl=$dep["replace"]; break; case "string": @@ -103,9 +103,9 @@ function configureFirewall() { } function WriteFirewallConf($conf) { - $ret = false; - if ( is_array($conf) ) write_php_ini($conf,RASPAP_FIREWALL_CONF); - return $ret; + $ret = false; + if ( is_array($conf) ) write_php_ini($conf,RASPAP_FIREWALL_CONF); + return $ret; } @@ -115,10 +115,6 @@ function ReadFirewallConf() { } else { $conf = array(); $conf["firewall-enable"] = false; - $conf["openvpn-enable"] = false; - $conf["openvpn-serverip"] = ""; - $conf["wireguard-enable"] = false; - $conf["wireguard-serverip"] = ""; $conf["ssh-enable"] = false; $conf["http-enable"] = false; $conf["excl-devices"] = ""; @@ -127,26 +123,32 @@ function ReadFirewallConf() { $conf["client-device"] = ""; $conf["restricted-ips"] = ""; } - -# get openvpn server IP (if existing) - if ( RASPI_OPENVPN_ENABLED && file_exists(RASPI_OPENVPN_CLIENT_CONFIG) ) { - exec('cat '.RASPI_OPENVPN_CLIENT_CONFIG.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_]*)\s*([0-9]*).*$/\1/ip" ', $ret); - if ( !empty($ret) ) { - $ip = $ret[0]; - $ip = ( filter_var($ip, FILTER_VALIDATE_IP) !== false ) ? $ip : gethostbyname($ip); - if ( !empty($ip) ) { - $conf["openvpn-serverip"] = "$ip"; - $conf["openvpn-enable"] = true; - } - } - } -# get wireguard server IP (if existing) - if ( RASPI_WIREGUARD_ENABLED && file_exists(RASPI_WIREGUARD_CONFIG) ) { -# search for endpoint - } return $conf; } +function getVPN_IPs() { + $ips = ""; + # get openvpn server IPs for UDP (if existing) + if ( RASPI_OPENVPN_ENABLED && ($fconf = glob(RASPI_OPENVPN_CLIENT_PATH ."/*.conf")) !== false && !empty($fconf) ) { + foreach ( $fconf as $f ) { + exec('cat '.$f.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_]*)\s*([0-9]*).*$/\1/ip" ', $result); + $ip = (isset($result[0])) ? $result[0] : ""; + unset($result); + exec('cat '.$f.' | sed -rn "s/^proto\s*([a-z]*).*$/\1/ip" ', $result); + $proto = (isset($result[0])) ? $result[0] : ""; + if ( !empty($ip) && trim(strtolower($proto)) === "udp" ) { + $ip = gethostbyname($ip); + if ( filter_var($ip,FILTER_VALIDATE_IP) && strpos($ips, $ip) === false ) $ips .= " $ip"; + } + } + } + # get wireguard server IPs for UDP (if existing) + if ( RASPI_WIREGUARD_ENABLED && ($fconf = glob(RASPI_WIREGUARD_PATH ."/*.conf")) !== false && !empty($fconf) ) { + } + return trim($ips); +} + + function DisplayFirewallConfig() { @@ -154,7 +156,6 @@ function DisplayFirewallConfig() $json = file_get_contents(RASPAP_IPTABLES_CONF); $ipt_rules = json_decode($json, true); - getWifiInterface(); $ap_device = $_SESSION['ap_interface']; $clients = getClients(); @@ -179,20 +180,41 @@ function DisplayFirewallConfig() if ( isset($_POST['save-firewall']) ) $status->addMessage(_('Firewall settings saved. Firewall is still disabled.'), 'success'); if ( isset($_POST['excl-devices']) ) { $excl = filter_var($_POST['excl-devices'], FILTER_SANITIZE_STRING); - $excl = str_replace(' ', '', $excl); - if ( !empty($excl) && $fw_conf["excl-devices"] != $excl ) { + $excl = str_replace(',', ' ', $excl); + $excl = trim(preg_replace('/\s+/', ' ', $excl)); + if ( $fw_conf["excl-devices"] != $excl ) { $status->addMessage(_('Exclude devices '. $excl), 'success'); $fw_conf["excl-devices"] = $excl; } } + if ( isset($_POST['excluded-ips']) ) { + $excl = filter_var($_POST['excluded-ips'], FILTER_SANITIZE_STRING); + $excl = str_replace(',', ' ', $excl); + $excl = trim(preg_replace('/\s+/', ' ', $excl)); + if ( !empty($excl) ) { + $excl = explode(' ',$excl); + $str_excl = ""; + foreach ( $excl as $ip ) { + if ( filter_var($ip,FILTER_VALIDATE_IP) ) $str_excl .= "$ip "; + else $status->addMessage(_('Exclude IP address '. $ip . ' failed - not a valid IP address'), 'warning'); + } + } + $str_excl = trim($str_excl); + if ( $fw_conf["excluded-ips"] != $str_excl ) { + $status->addMessage(_('Exclude IP address(es) '. $str_excl ), 'success'); + $fw_conf["excluded-ips"] = $str_excl; + } + } WriteFirewallConf($fw_conf); configureFirewall(); } + $vpn_ips = getVPN_IPs(); echo renderTemplate("firewall", compact( "status", "ap_device", "str_clients", "fw_conf", - "ipt_rules") + "ipt_rules", + "vpn_ips") ); } diff --git a/templates/firewall.php b/templates/firewall.php index e20217e4..e2b1ec6b 100644 --- a/templates/firewall.php +++ b/templates/firewall.php @@ -18,34 +18,45 @@
-

+

No incoming UDP traffic is allowed.
There are no restrictions for the access point $ap_device.") ?>

-
+
- > + >
> - +

- +

-
+
" aria-describedby="exclusion-description" >

- Current client devices: $str_clients
The access point ". $ap_device ." is per default excluded.") ?>
+ Current client devices: $str_clients
The access point ". $ap_device ." is per default excluded.") ?>
+

+
+
+
+
+
+ + " aria-describedby="excl-ips-description" > +

+ This is required for an OpenVPN via UDP or Wireguard connection.") ?> + The list of configured VPN server IP addresses: ". $vpn_ips. "") ?>

From 0a6e48a953bba13163cad1e1477aeb85cb52bc0d Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Wed, 21 Jul 2021 17:56:01 +0200 Subject: [PATCH 10/16] Fix display of VPN IPs --- includes/firewall.php | 1 + templates/firewall.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/firewall.php b/includes/firewall.php index 6839a264..90713d34 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -131,6 +131,7 @@ function getVPN_IPs() { # get openvpn server IPs for UDP (if existing) if ( RASPI_OPENVPN_ENABLED && ($fconf = glob(RASPI_OPENVPN_CLIENT_PATH ."/*.conf")) !== false && !empty($fconf) ) { foreach ( $fconf as $f ) { + unset($result); exec('cat '.$f.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_]*)\s*([0-9]*).*$/\1/ip" ', $result); $ip = (isset($result[0])) ? $result[0] : ""; unset($result); diff --git a/templates/firewall.php b/templates/firewall.php index e2b1ec6b..478ed652 100644 --- a/templates/firewall.php +++ b/templates/firewall.php @@ -56,7 +56,7 @@ " aria-describedby="excl-ips-description" >

This is required for an OpenVPN via UDP or Wireguard connection.") ?> - The list of configured VPN server IP addresses: ". $vpn_ips. "") ?> + The list of configured VPN server IP addresses: ". $vpn_ips. "") ?>

From 1855f40f9dc36c1326a01efe6f156aaee6ebf30f Mon Sep 17 00:00:00 2001 From: zbchristian <33725910+zbchristian@users.noreply.github.com> Date: Sat, 24 Jul 2021 15:04:01 +0200 Subject: [PATCH 11/16] Add masquerade rule for NAT Add default NAT POSTROUTING rule to masquerade addresses --- config/iptables_rules.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/iptables_rules.json b/config/iptables_rules.json index 0e6618ec..df2b126b 100644 --- a/config/iptables_rules.json +++ b/config/iptables_rules.json @@ -81,6 +81,13 @@ "-A OUTPUT -o $INTERFACE$ -j ACCEPT" ] }, + { + "name": "NAT for access point", + "comment": "Masquerading needed for access point", + "rules": [ + "-t nat -A POSTROUTING -j MASQUERADE" + ] + }, { "name": "clients", "fw-state": true, From 2f1a6af0baad75be9bc880b58412569e3d7aafbd Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Sun, 25 Jul 2021 15:42:46 +0200 Subject: [PATCH 12/16] Add IPv6 to Firewall --- config/iptables_rules.json | 15 +++++++++++++++ includes/firewall.php | 29 ++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/config/iptables_rules.json b/config/iptables_rules.json index df2b126b..d9b6f5f9 100644 --- a/config/iptables_rules.json +++ b/config/iptables_rules.json @@ -44,12 +44,23 @@ { "name": "ping", "fw-state": true, + "ip-version": 4, "comment": "allow ping request and echo", "rules": [ "-A INPUT -p icmp --icmp-type 8/0 -j ACCEPT", "-A INPUT -p icmp --icmp-type 0/0 -j ACCEPT" ] }, + { + "name": "ping IPv6", + "fw-state": true, + "ip-version": 6, + "comment": "allow ping request and echo for IPv6", + "rules": [ + "-A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT", + "-A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT" + ] + }, { "name": "ntp", "fw-state": true, @@ -99,6 +110,7 @@ { "name": "openvpn", "comment": "Rules for tunnel device (tun)", + "ip-version": 4, "dependson": [ { "var": "openvpn-enable", "type": "bool" }, { "var": "openvpn-serverip", "type": "string", "replace": "$IPADDRESS$" }, @@ -114,6 +126,7 @@ { "name": "wireguard", "comment": "Rules for wireguard device (wg)", + "ip-version": 4, "dependson": [ { "var": "wireguard-enable", "type": "bool" }, { "var": "wireguard-serverip", "type": "string", "replace": "$IPADDRESS$" }, @@ -164,6 +177,7 @@ { "name": "ipaddress", "fw-state": true, + "ip-version": 4, "comment": "allow access from/to IP", "dependson": [ { "var": "excluded-ips", "type": "list", "replace": "$IPADDRESS$" } @@ -178,6 +192,7 @@ { "name": "ipaddress", "fw-state": true, + "ip-version": 4, "dependson": [ { "var": "restricted-ips", "type": "list", "replace": "$IPADDRESS$" } ], diff --git a/includes/firewall.php b/includes/firewall.php index 90713d34..1b763622 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -4,6 +4,7 @@ require_once 'includes/status_messages.php'; require_once 'includes/functions.php'; define('RASPAP_IPTABLES_SCRIPT',"/tmp/iptables_raspap.sh"); +define('RASPAP_IP6TABLES_SCRIPT',"/tmp/ip6tables_raspap.sh"); function getDependson(&$rule, &$conf) { if ( isset($rule["dependson"][0]) ) { @@ -64,20 +65,33 @@ function createRuleStr(&$sect, &$conf) { } $str=""; foreach ( $rs as $r ) { - if ( !preg_match('/\$[a-z0-9]*\$/i',$r) ) $str .= "iptables ".$r."\n"; + if ( !preg_match('/\$[a-z0-9]*\$/i',$r) ) $str .= '$IPT '.$r."\n"; } return $str; } +function isIPv4(&$rule) { + return !isset($rule["ip-version"]) || strstr($rule["ip-version"],"4") !== false; +} + +function isIPv6(&$rule) { + return !isset($rule["ip-version"]) || strstr($rule["ip-version"],"6") !== false; +} + function configureFirewall() { $json = file_get_contents(RASPAP_IPTABLES_CONF); $ipt = json_decode($json, true); $conf = ReadFirewallConf(); $txt = "#!/bin/bash\n"; - $txt .= "iptables -F\n"; - $txt .= "iptables -X\n"; - $txt .= "iptables -t nat -F\n"; file_put_contents(RASPAP_IPTABLES_SCRIPT, $txt); + file_put_contents(RASPAP_IP6TABLES_SCRIPT, $txt); + file_put_contents(RASPAP_IPTABLES_SCRIPT, 'IPT="iptables"'."\n", FILE_APPEND); + file_put_contents(RASPAP_IP6TABLES_SCRIPT, 'IPT="ip6tables"'."\n", FILE_APPEND); + $txt = "\$IPT -F\n"; + $txt .= "\$IPT -X\n"; + $txt .= "\$IPT -t nat -F\n"; + file_put_contents(RASPAP_IPTABLES_SCRIPT, $txt, FILE_APPEND); + file_put_contents(RASPAP_IP6TABLES_SCRIPT, $txt, FILE_APPEND); if ( empty($conf) || empty($ipt) ) return false; $count=0; foreach ( $ipt["order"] as $idx ) { @@ -86,7 +100,8 @@ function configureFirewall() { if ( isRuleEnabled($sect, $conf) ) { $str_rules= createRuleStr($sect, $conf); if ( !empty($str_rules) ) { - file_put_contents(RASPAP_IPTABLES_SCRIPT, $str_rules, FILE_APPEND); + if ( isIPv4($sect) ) file_put_contents(RASPAP_IPTABLES_SCRIPT, $str_rules, FILE_APPEND); + if ( isIPv6($sect) ) file_put_contents(RASPAP_IP6TABLES_SCRIPT, $str_rules, FILE_APPEND); ++$count; } } @@ -98,6 +113,10 @@ function configureFirewall() { exec("sudo ".RASPAP_IPTABLES_SCRIPT); // exec("sudo iptables-save > /etc/iptables/rules.v4"); // unlink(RASPAP_IPTABLES_SCRIPT); + exec("chmod +x ".RASPAP_IP6TABLES_SCRIPT); + exec("sudo ".RASPAP_IP6TABLES_SCRIPT); +// exec("sudo iptables-save > /etc/iptables/rules.v6"); +// unlink(RASPAP_IP6TABLES_SCRIPT); } return ($count > 0); } From 882535b1309fc4fe8fcc2e29502c0bd8ed600559 Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Sun, 25 Jul 2021 17:27:31 +0200 Subject: [PATCH 13/16] Get VPN state from active tun/wg device --- includes/firewall.php | 37 ++++++++++++++++++++++++++++--------- installers/raspap.sudoers | 1 + 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/includes/firewall.php b/includes/firewall.php index 1b763622..d6699866 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -142,28 +142,47 @@ function ReadFirewallConf() { $conf["client-device"] = ""; $conf["restricted-ips"] = ""; } + exec('ifconfig | grep -E -i "tun+"', $ret); + $conf["openvpn-enable"] = !empty($ret); + unset($ret); + exec('ifconfig | grep -E -i "wg+"', $ret); + $conf["wireguard-enable"] = !empty($ret); return $conf; } function getVPN_IPs() { $ips = ""; - # get openvpn server IPs for UDP (if existing) + # get openvpn and wireguard server IPs if ( RASPI_OPENVPN_ENABLED && ($fconf = glob(RASPI_OPENVPN_CLIENT_PATH ."/*.conf")) !== false && !empty($fconf) ) { foreach ( $fconf as $f ) { - unset($result); - exec('cat '.$f.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_]*)\s*([0-9]*).*$/\1/ip" ', $result); - $ip = (isset($result[0])) ? $result[0] : ""; - unset($result); - exec('cat '.$f.' | sed -rn "s/^proto\s*([a-z]*).*$/\1/ip" ', $result); - $proto = (isset($result[0])) ? $result[0] : ""; - if ( !empty($ip) && trim(strtolower($proto)) === "udp" ) { + unset($result); + exec('cat '.$f.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_]*)\s*([0-9]*).*$/\1 \2/ip" ', $result); + if ( !empty($result) ) { + $result = explode(" ",$result[0]); + $ip = (isset($result[0])) ? $result[0] : ""; + $port = (isset($result[1])) ? $result[1] : ""; + if ( !empty($ip) ) { $ip = gethostbyname($ip); if ( filter_var($ip,FILTER_VALIDATE_IP) && strpos($ips, $ip) === false ) $ips .= " $ip"; + } } } } - # get wireguard server IPs for UDP (if existing) + # get wireguard server IPs if ( RASPI_WIREGUARD_ENABLED && ($fconf = glob(RASPI_WIREGUARD_PATH ."/*.conf")) !== false && !empty($fconf) ) { + foreach ( $fconf as $f ) { + unset($result); + exec('sudo /bin/cat '.$f.' | sed -rn "s/^endpoint\s*=\s*([a-z0-9\.\-\_]*:[0-9]*).*$/\1/ip" ', $result); + if ( !empty($result) ) { + $result = explode(":",$result[0]); + $ip = (isset($result[0])) ? $result[0] : ""; + $port = (isset($result[1])) ? $result[1] : ""; + if ( !empty($ip) ) { + $ip = gethostbyname($ip); + if ( filter_var($ip,FILTER_VALIDATE_IP) && strpos($ips, $ip) === false ) $ips .= " $ip"; + } + } + } } return trim($ips); } diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index ae737910..b85fe487 100644 --- a/installers/raspap.sudoers +++ b/installers/raspap.sudoers @@ -63,3 +63,4 @@ www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wireguard/wg-*.key www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/wireguard/*.conf www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/wireguard/wg-*.key www-data ALL=(ALL) NOPASSWD:/tmp/iptables_raspap.sh +www-data ALL=(ALL) NOPASSWD:/tmp/ip6tables_raspap.sh From 088699905527b1f3a7b8879dc249955c0c29b6aa Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Mon, 26 Jul 2021 15:42:14 +0200 Subject: [PATCH 14/16] Improve active VPN detection --- includes/firewall.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/firewall.php b/includes/firewall.php index d6699866..3f4ef8b7 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -142,10 +142,10 @@ function ReadFirewallConf() { $conf["client-device"] = ""; $conf["restricted-ips"] = ""; } - exec('ifconfig | grep -E -i "tun+"', $ret); + exec('ifconfig | grep -E -i "^tun[0-9]"', $ret); $conf["openvpn-enable"] = !empty($ret); unset($ret); - exec('ifconfig | grep -E -i "wg+"', $ret); + exec('ifconfig | grep -E -i "^wg[0-9]"', $ret); $conf["wireguard-enable"] = !empty($ret); return $conf; } From 3d4b710492fdc5ac19195d4e96b759ba6b4f182e Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Tue, 27 Jul 2021 10:09:36 +0200 Subject: [PATCH 15/16] Allow IPv6 addresses for VPN server --- includes/firewall.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/firewall.php b/includes/firewall.php index 3f4ef8b7..9a61f304 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -142,10 +142,10 @@ function ReadFirewallConf() { $conf["client-device"] = ""; $conf["restricted-ips"] = ""; } - exec('ifconfig | grep -E -i "^tun[0-9]"', $ret); + exec('ifconfig | grep -E -i "tun+"', $ret); $conf["openvpn-enable"] = !empty($ret); unset($ret); - exec('ifconfig | grep -E -i "^wg[0-9]"', $ret); + exec('ifconfig | grep -E -i "wg+"', $ret); $conf["wireguard-enable"] = !empty($ret); return $conf; } @@ -156,7 +156,7 @@ function getVPN_IPs() { if ( RASPI_OPENVPN_ENABLED && ($fconf = glob(RASPI_OPENVPN_CLIENT_PATH ."/*.conf")) !== false && !empty($fconf) ) { foreach ( $fconf as $f ) { unset($result); - exec('cat '.$f.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_]*)\s*([0-9]*).*$/\1 \2/ip" ', $result); + exec('cat '.$f.' | sed -rn "s/^remote\s*([a-z0-9\.\-\_:]*)\s*([0-9]*)\s*$/\1 \2/ip" ', $result); if ( !empty($result) ) { $result = explode(" ",$result[0]); $ip = (isset($result[0])) ? $result[0] : ""; @@ -172,9 +172,9 @@ function getVPN_IPs() { if ( RASPI_WIREGUARD_ENABLED && ($fconf = glob(RASPI_WIREGUARD_PATH ."/*.conf")) !== false && !empty($fconf) ) { foreach ( $fconf as $f ) { unset($result); - exec('sudo /bin/cat '.$f.' | sed -rn "s/^endpoint\s*=\s*([a-z0-9\.\-\_]*:[0-9]*).*$/\1/ip" ', $result); + exec('sudo /bin/cat '.$f.' | sed -rn "s/^endpoint\s*=\s*\[?([a-z0-9\.\-\_:]*)\]?:([0-9]*)\s*$/\1 \2/ip" ', $result); if ( !empty($result) ) { - $result = explode(":",$result[0]); + $result = explode(" ",$result[0]); $ip = (isset($result[0])) ? $result[0] : ""; $port = (isset($result[1])) ? $result[1] : ""; if ( !empty($ip) ) { From f572fdd39e59fc63e7c98fd6006b3d5cda577759 Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Tue, 27 Jul 2021 11:25:42 +0200 Subject: [PATCH 16/16] Improve search for tun and wg device --- includes/firewall.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/firewall.php b/includes/firewall.php index 9a61f304..1f05c9fe 100644 --- a/includes/firewall.php +++ b/includes/firewall.php @@ -142,10 +142,10 @@ function ReadFirewallConf() { $conf["client-device"] = ""; $conf["restricted-ips"] = ""; } - exec('ifconfig | grep -E -i "tun+"', $ret); + exec('ifconfig | grep -E -i "^tun[0-9]"', $ret); $conf["openvpn-enable"] = !empty($ret); unset($ret); - exec('ifconfig | grep -E -i "wg+"', $ret); + exec('ifconfig | grep -E -i "^wg[0-9]"', $ret); $conf["wireguard-enable"] = !empty($ret); return $conf; }