mirror of
				https://github.com/billz/raspap-webgui.git
				synced 2025-03-01 10:31:47 +00:00 
			
		
		
		
	Merge pull request #49 from RaspAP/feature-firewall
Feature: firewall settings
This commit is contained in:
		| @@ -24,12 +24,14 @@ define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf'); | ||||
| define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf'); | ||||
| define('RASPI_WIREGUARD_PATH', '/etc/wireguard/'); | ||||
| define('RASPI_WIREGUARD_CONFIG', RASPI_WIREGUARD_PATH.'wg0.conf'); | ||||
| define('RASPI_FIREWALL_CONF', RASPI_CONFIG.'/networking/firewall/firewall.conf'); | ||||
| define('RASPI_IPTABLES_CONF', RASPI_CONFIG.'/networking/firewall/iptables_rules.json'); | ||||
| define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc'); | ||||
| define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf'); | ||||
| define('RASPI_ACCESS_CHECK_IP', '1.1.1.1'); | ||||
| define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one'); | ||||
| define('RASPI_CLIENT_CONFIG_PATH', '/etc/raspap/networking/client_udev_prototypes.json'); | ||||
| define('RASPI_MOBILEDATA_CONFIG', '/etc/raspap/networking/mobiledata.ini'); | ||||
| define('RASPI_CLIENT_CONFIG_PATH', RASPI_CONFIG.'/networking/client_udev_prototypes.json'); | ||||
| define('RASPI_MOBILEDATA_CONFIG', RASPI_CONFIG.'/networking/mobiledata.ini'); | ||||
| define('RASPI_CLIENT_SCRIPT_PATH', '/usr/local/sbin'); | ||||
|  | ||||
| // Constant for the 5GHz wireless regulatory domain | ||||
| @@ -44,6 +46,7 @@ define('RASPI_DHCP_ENABLED', true); | ||||
| define('RASPI_ADBLOCK_ENABLED', false); | ||||
| define('RASPI_OPENVPN_ENABLED', false); | ||||
| define('RASPI_WIREGUARD_ENABLED', false); | ||||
| define('RASPI_FIREWALL_ENABLED', true); | ||||
| define('RASPI_TORPROXY_ENABLED', false); | ||||
| define('RASPI_CONFAUTH_ENABLED', true); | ||||
| define('RASPI_CHANGETHEME_ENABLED', true); | ||||
|   | ||||
							
								
								
									
										205
									
								
								config/iptables_rules.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								config/iptables_rules.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | ||||
| { | ||||
|     "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, | ||||
|             "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, | ||||
|             "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": "NAT for access point", | ||||
|             "comment": "Masquerading needed for access point", | ||||
|             "rules": [ | ||||
|                 "-t nat -A POSTROUTING -j MASQUERADE" | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "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)", | ||||
|             "ip-version": 4, | ||||
|             "dependson": [ | ||||
|                   { "var": "openvpn-enable", "type": "bool" }, | ||||
|                   { "var": "openvpn-serverip", "type": "string", "replace": "$IPADDRESS$" }, | ||||
|                   { "var": "ap-device", "type": "string", "replace": "$INTERFACE$" } | ||||
|             ], | ||||
|             "rules": [ | ||||
|                 "-A INPUT -p udp -s $IPADDRESS$ -j ACCEPT", | ||||
|                 "-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" | ||||
|             ] | ||||
|         }, | ||||
|         { | ||||
|             "name": "wireguard", | ||||
|             "comment": "Rules for wireguard device (wg)", | ||||
|             "ip-version": 4, | ||||
|             "dependson": [ | ||||
|                   { "var": "wireguard-enable", "type": "bool" }, | ||||
|                   { "var": "wireguard-serverip", "type": "string", "replace": "$IPADDRESS$" }, | ||||
|                   { "var": "client-device", "type": "string", "replace": "$INTERFACE$" } | ||||
|             ], | ||||
|             "rules": [ | ||||
|                 "-A INPUT -p udp -s $IPADDRESS$ -j ACCEPT", | ||||
|                 "-A FORWARD -i wg+ -j ACCEPT", | ||||
|                 "-t nat -A POSTROUTING -o $INTERFACE$ -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, | ||||
|             "ip-version": 4, | ||||
|             "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, | ||||
|             "ip-version": 4, | ||||
|             "dependson": [ | ||||
|                 { "var": "restricted-ips", "type": "list", "replace": "$IPADDRESS$" } | ||||
|             ], | ||||
|             "comment": "Block access from IP-address", | ||||
|             "rules": [ | ||||
|                 "-A INPUT -s $IPADDRESS$ -j DROP" | ||||
|             ] | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										368
									
								
								includes/firewall.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								includes/firewall.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,368 @@ | ||||
| <?php | ||||
|  | ||||
| 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"); | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param  array $rule | ||||
|  * @param  array $conf | ||||
|  * @return array $don | ||||
|  */ | ||||
| function getDependson(&$rule, &$conf) | ||||
| { | ||||
|     if (isset($rule["dependson"][0]) ) { | ||||
|         $don = &$rule["dependson"]; | ||||
|         if (!empty($don[0]) && isset($conf[$don[0]["var"]]) ) { | ||||
|             if (!isset($don[0]["type"]) ) { $don[0]["type"]="bool"; | ||||
|             } | ||||
|             return $don; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param  array $sect | ||||
|  * @param  array $conf | ||||
|  * @return boolean $active | ||||
|  */ | ||||
| function isRuleEnabled(&$sect, &$conf) | ||||
| { | ||||
|     $fw_on = isset($conf["firewall-enable"]) && $conf["firewall-enable"]; | ||||
|     $active = isset($sect["fw-state"]) && $sect["fw-state"]==1; | ||||
|     $active = $fw_on ? $active : !$active; | ||||
|     $active = $active || !isset($sect["fw-state"]); | ||||
|     if (($don = getDependson($sect, $conf)) !== false  | ||||
|         && $don[0]["type"] == "bool" && !$conf[$don[0]["var"]]  | ||||
|     ) {  $active = false; | ||||
|     } | ||||
|     return $active; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param  array $sect | ||||
|  * @param  array $conf | ||||
|  * @return string $str | ||||
|  */ | ||||
| function createRuleStr(&$sect, &$conf) | ||||
| { | ||||
|     if (!is_array($sect["rules"]) ) { return ""; | ||||
|     } | ||||
|     $rules = $sect["rules"]; | ||||
|     $depon = getDependson($sect, $conf); | ||||
|     $rs = array(); | ||||
|     foreach ( $rules as $rule ) { | ||||
|         if (preg_match('/\$[a-z0-9]*\$/i', $rule) ) { | ||||
|             $r = array($rule); | ||||
|             foreach ( $depon as $dep ) { | ||||
|                 $rr = array(); | ||||
|                 $repl=$val=""; | ||||
|                 switch ( $dep["type"] ) { | ||||
|                 case "list": | ||||
|                     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": | ||||
|                     if (isset($dep["var"]) ) { $val=$conf[$dep["var"]]; | ||||
|                     } | ||||
|                     if (!empty($val) && isset($dep["replace"]) ) { $repl=$dep["replace"]; | ||||
|                     } | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|                 } | ||||
|                 if (!empty($repl) && !empty($val) ) { | ||||
|                     if (is_array($val) ) { | ||||
|                         foreach ( $val as $v ) { $rr = array_merge($rr, str_replace($repl, $v, $r)); | ||||
|                         } | ||||
|                     } | ||||
|                     else { $rr = array_merge($rr, str_replace($repl, $val, $r)); | ||||
|                     } | ||||
|                 } | ||||
|                 $r = !empty($rr) ? $rr : $r; | ||||
|             } | ||||
|             $rs = array_merge($rs, $rr); | ||||
|         } else { | ||||
|             $rs[] = $rule; | ||||
|         } | ||||
|     } | ||||
|     $str=""; | ||||
|     foreach ( $rs as $r ) { | ||||
|         if (!preg_match('/\$[a-z0-9]*\$/i', $r) ) { $str .= '$IPT '.$r."\n"; | ||||
|         } | ||||
|     } | ||||
|     return $str; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param  array $rule | ||||
|  * @return boolean | ||||
|  */ | ||||
| function isIPv4(&$rule) | ||||
| { | ||||
|     return !isset($rule["ip-version"]) || strstr($rule["ip-version"], "4") !== false;  | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param  array $rule | ||||
|  * @return boolean | ||||
|  */ | ||||
| function isIPv6(&$rule) | ||||
| { | ||||
|     return !isset($rule["ip-version"]) || strstr($rule["ip-version"], "6") !== false;  | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @return boolean  | ||||
|  */ | ||||
| function configureFirewall() | ||||
| { | ||||
|     $json = file_get_contents(RASPI_IPTABLES_CONF); | ||||
|     $ipt  = json_decode($json, true); | ||||
|     $conf = ReadFirewallConf(); | ||||
|     $txt = "#!/bin/bash\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 ) { | ||||
|         if (isset($ipt[$idx]) ) { | ||||
|             foreach ( $ipt[$idx] as $i => $sect ) { | ||||
|                 if (isRuleEnabled($sect, $conf) ) { | ||||
|                     $str_rules= createRuleStr($sect, $conf); | ||||
|                     if (!empty($str_rules) ) { | ||||
|                         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; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if ($count > 0 ) { | ||||
|         exec("chmod +x ".RASPAP_IPTABLES_SCRIPT); | ||||
|         exec("sudo ".RASPAP_IPTABLES_SCRIPT); | ||||
|         exec("sudo iptables-save | sudo tee /etc/iptables/rules.v4"); | ||||
|         unlink(RASPAP_IPTABLES_SCRIPT); | ||||
|         exec("chmod +x ".RASPAP_IP6TABLES_SCRIPT); | ||||
|         exec("sudo ".RASPAP_IP6TABLES_SCRIPT); | ||||
|         exec("sudo ip6tables-save | sudo tee /etc/iptables/rules.v6"); | ||||
|         unlink(RASPAP_IP6TABLES_SCRIPT); | ||||
|     } | ||||
|     return ($count > 0); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @param array $conf | ||||
|  * @return string $ret | ||||
|  */ | ||||
| function WriteFirewallConf($conf) | ||||
| { | ||||
|     $ret = false; | ||||
|     if (is_array($conf) ) { write_php_ini($conf, RASPI_FIREWALL_CONF); | ||||
|     } | ||||
|     return $ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @return array $conf | ||||
|  */ | ||||
| function ReadFirewallConf() | ||||
| { | ||||
|     $conf = array(); | ||||
|     if (file_exists(RASPI_FIREWALL_CONF) ) { | ||||
|         $conf = parse_ini_file(RASPI_FIREWALL_CONF); | ||||
|     } | ||||
|     if ( !isset($conf["firewall-enable"]) ) { | ||||
|         $conf["firewall-enable"] = false; | ||||
|         $conf["ssh-enable"] = false; | ||||
|         $conf["http-enable"] = false; | ||||
|         $conf["excl-devices"] = ""; | ||||
|         $conf["excluded-ips"] = ""; | ||||
|         $conf["ap-device"] = ""; | ||||
|         $conf["client-device"] = ""; | ||||
|         $conf["restricted-ips"] = ""; | ||||
|     } | ||||
|     exec('ifconfig | grep -E -i "^tun[0-9]"', $ret); | ||||
|     $conf["openvpn-enable"] = !empty($ret); | ||||
|     unset($ret); | ||||
|     exec('ifconfig | grep -E -i "^wg[0-9]"', $ret); | ||||
|     $conf["wireguard-enable"] = !empty($ret); | ||||
|     return $conf; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @return string $ips | ||||
|  */ | ||||
| function getVPN_IPs() | ||||
| { | ||||
|     $ips = ""; | ||||
|     // 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]*)\s*$/\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 | ||||
|     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]*)\s*$/\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"; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return trim($ips); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @return array $fw_conf | ||||
|  */ | ||||
| function getFirewallConfiguration()  | ||||
| { | ||||
|     $fw_conf = ReadFirewallConf(); | ||||
|      | ||||
|     $json = file_get_contents(RASPI_IPTABLES_CONF); | ||||
|     getWifiInterface(); | ||||
|     $ap_device = $_SESSION['ap_interface']; | ||||
|     $clients = getClients(); | ||||
|     $str_clients = ""; | ||||
|     foreach( $clients["device"] as $dev ) { | ||||
|         if (!$dev["isAP"] ) { | ||||
|             if (!empty($str_clients) ) { $str_clients .= ", "; | ||||
|             } | ||||
|             $str_clients .= $dev["name"]; | ||||
|         } | ||||
|     } | ||||
|     $fw_conf["ap-device"] = $ap_device; | ||||
|     $fw_conf["client-list"] = $str_clients; | ||||
|     $id=findCurrentClientIndex($clients); | ||||
|     if ($id >= 0 ) { $fw_conf["client-device"] = $clients["device"][$id]["name"]; | ||||
|     } | ||||
|     return $fw_conf; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  */ | ||||
| function updateFirewall()  | ||||
| { | ||||
|     $fw_conf = getFirewallConfiguration(); | ||||
|     if ( isset($fw_conf["firewall-enable"]) ) { | ||||
|         WriteFirewallConf($fw_conf); | ||||
|         configureFirewall(); | ||||
|     } | ||||
|     return; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  */ | ||||
| function DisplayFirewallConfig() | ||||
| { | ||||
|     $status = new StatusMessages(); | ||||
|  | ||||
|     $fw_conf = getFirewallConfiguration(); | ||||
|     $ap_device = $fw_conf["ap-device"]; | ||||
|     $str_clients = $fw_conf["client-list"]; | ||||
|  | ||||
|     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'); | ||||
|         } | ||||
|         if (isset($_POST['excl-devices'])  ) { | ||||
|             $excl = filter_var($_POST['excl-devices'], FILTER_SANITIZE_STRING); | ||||
|             $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", | ||||
|             "vpn_ips" | ||||
|         ) | ||||
|     ); | ||||
| } | ||||
|  | ||||
| @@ -41,6 +41,7 @@ require_once 'includes/system.php'; | ||||
| require_once 'includes/sysstats.php'; | ||||
| require_once 'includes/configure_client.php'; | ||||
| require_once 'includes/networking.php'; | ||||
| require_once 'includes/firewall.php'; | ||||
| require_once 'includes/themes.php'; | ||||
| require_once 'includes/data_usage.php'; | ||||
| require_once 'includes/about.php'; | ||||
| @@ -175,6 +176,11 @@ $bridgedEnabled = getBridgedState(); | ||||
|           <?php if (RASPI_TORPROXY_ENABLED) : ?> | ||||
|         <li class="nav-item"> | ||||
|            <a class="nav-link" href="torproxy_conf"><i class="fas fa-eye-slash fa-fw mr-2"></i><span class="nav-label"><?php echo _("TOR proxy"); ?></a> | ||||
|         </li> | ||||
|           <?php endif; ?> | ||||
|           <?php if (RASPI_FIREWALL_ENABLED) : ?> | ||||
|         <li class="nav-item"> | ||||
|           <a class="nav-link" href="firewall_conf"><i class="fas fa-shield-alt fa-fw mr-2"></i><span class="nav-label"><?php echo _("Firewall"); ?></a> | ||||
|         </li> | ||||
|           <?php endif; ?> | ||||
|           <?php if (RASPI_CONFAUTH_ENABLED) : ?> | ||||
| @@ -274,6 +280,9 @@ $bridgedEnabled = getBridgedState(); | ||||
|         case "/torproxy_conf": | ||||
|             DisplayTorProxyConfig(); | ||||
|             break; | ||||
|         case "/firewall_conf": | ||||
|             DisplayFirewallConfig(); | ||||
|             break; | ||||
|         case "/auth_conf": | ||||
|             DisplayAuthConfig($config['admin_user'], $config['admin_pass']); | ||||
|             break; | ||||
|   | ||||
							
								
								
									
										20
									
								
								installers/install_feature_firewall.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								installers/install_feature_firewall.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # RaspAP feature installation: Firewall | ||||
| # to be sources by the RaspAP installer script | ||||
| # Author: @zbchristian <christian@zeitnitz.eu> | ||||
| # Author URI: https://github.com/zbchristian/ | ||||
| # License: GNU General Public License v3.0 | ||||
| # License URI: https://github.com/raspap/raspap-webgui/blob/master/LICENSE | ||||
|  | ||||
| function _install_feature_firewall() { | ||||
|     name="feature firewall" | ||||
|  | ||||
|     _install_log "Install $name" | ||||
| 	# create config dir | ||||
| 	sudo mkdir "$raspap_network/firewall" || _install_status 1 "Unable to create firewall config directory"  | ||||
|     # copy firewall configuration  | ||||
|     sudo cp "$webroot_dir/config/iptables_rules.json" "$raspap_network/firewall/" || _install_status 1 "Unable to copy iptables templates" | ||||
| 	sudo chown $raspap_user:$raspap_user -R "$raspap_network/firewall" || _install_status 1 "Unable to change ownership of firewall directory and files " | ||||
|     _install_status 0 | ||||
| } | ||||
| @@ -62,3 +62,9 @@ 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 | ||||
| www-data ALL=(ALL) NOPASSWD:/tmp/ip6tables_raspap.sh | ||||
| www-data ALL=(ALL) NOPASSWD:/usr/sbin/iptables-save | ||||
| www-data ALL=(ALL) NOPASSWD:/usr/sbin/ip6tables-save | ||||
| www-data ALL=(ALL) NOPASSWD:/usr/bin/tee /etc/iptables/rules.v4 | ||||
| www-data ALL=(ALL) NOPASSWD:/usr/bin/tee /etc/iptables/rules.v6 | ||||
|   | ||||
							
								
								
									
										29
									
								
								installers/update_firewall.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								installers/update_firewall.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #!/bin/bash | ||||
| # include the raspap helper functions | ||||
| source /usr/local/sbin/raspap_helpers.sh | ||||
|  | ||||
| _getWebRoot | ||||
|  | ||||
| echo -n "Update firewall ... " | ||||
|  | ||||
| cat << EOF > /tmp/updateFirewall.php | ||||
| <?php | ||||
| //set_include_path('/var/www/html/'); | ||||
| \$_SESSION['locale']="en_GB.UTF-8"; | ||||
|  | ||||
| require_once 'includes/config.php'; | ||||
| require_once 'includes/defaults.php'; | ||||
| require_once RASPI_CONFIG.'/raspap.php'; | ||||
| require_once 'includes/locale.php'; | ||||
| require_once 'includes/wifi_functions.php'; | ||||
| require_once 'includes/get_clients.php'; | ||||
| require_once 'includes/firewall.php'; | ||||
|  | ||||
| updateFirewall(); | ||||
|  | ||||
| ?> | ||||
| EOF | ||||
|  | ||||
| sudo php -d include_path=$raspap_webroot /tmp/updateFirewall.php | ||||
| rm /tmp/updateFirewall.php | ||||
| echo "done." | ||||
| @@ -1140,3 +1140,74 @@ msgstr "WireGuard configuration updated successfully" | ||||
| msgid "WireGuard configuration failed to be updated" | ||||
| msgstr "WireGuard configuration failed to be updated" | ||||
|  | ||||
| #: templates/firewall.php | ||||
|  | ||||
| msgid "Client Firewall" | ||||
| msgstr "Client Firewall" | ||||
|  | ||||
| msgid "Firewall is ENABLED" | ||||
| msgstr "Firewall is ENABLED" | ||||
|  | ||||
| msgid "Firewall is OFF" | ||||
| msgstr "Firewall is OFF" | ||||
|  | ||||
| msgid "The default firewall will only allow outgoing and already established traffic." | ||||
| msgstr "The default firewall will only allow outgoing and already established traffic." | ||||
|  | ||||
| msgid "No incoming UDP traffic is allowed." | ||||
| msgstr "No incoming UDP traffic is allowed." | ||||
|  | ||||
| msgid "There are no restrictions for the access point <code>%s</code>." | ||||
| msgstr "There are no restrictions for the access point <code>%s</code>." | ||||
|  | ||||
| msgid "Exception: Service" | ||||
| msgstr "Exception: Service" | ||||
|  | ||||
| msgid "allow SSH access on port 22" | ||||
| msgstr "allow SSH access on port 22" | ||||
|  | ||||
| msgid "allow access to the RaspAP GUI on port 80 or 443" | ||||
| msgstr "allow access to the RaspAP GUI on port 80 or 443" | ||||
|  | ||||
| msgid "Allow incoming connections for some services from the internet side." | ||||
| msgstr "Allow incoming connections for some services from the internet side." | ||||
|  | ||||
| msgid "Exception: network device" | ||||
| msgstr "Exception: network device" | ||||
|  | ||||
| msgid "Exclude device(s)" | ||||
| msgstr "Exclude device(s)" | ||||
|  | ||||
| msgid "Exclude the given network device(s) (separated by a blank or comma) from firewall rules." | ||||
| msgstr "Exclude the given network device(s) (separated by a blank or comma) from firewall rules." | ||||
|  | ||||
| msgid "Current client devices: <code>%s</code>" | ||||
| msgstr "Current client devices: <code>%s</code>" | ||||
|  | ||||
| msgid "The access point <code>%s</code> is per default excluded." | ||||
| msgstr "The access point <code>%s</code> is per default excluded." | ||||
|  | ||||
| msgid "Exception: IP-Address" | ||||
| msgstr "Exception: IP-Address" | ||||
|  | ||||
| msgid "Allow incoming connections from" | ||||
| msgstr "Allow incoming connections from" | ||||
|  | ||||
| msgid "For the given IP-addresses (separated by a blank or comma) the incoming connection (via TCP and UDP) is accepted." | ||||
| msgstr "For the given IP-addresses (separated by a blank or comma) the incoming connection (via TCP and UDP) is accepted." | ||||
|  | ||||
| msgid "This is required for an OpenVPN via UDP or Wireguard connection." | ||||
| msgstr "This is required for an OpenVPN via UDP or Wireguard connection." | ||||
|  | ||||
| msgid "The list of configured VPN server IP addresses: <code><b>%s</b></code>" | ||||
| msgstr "The list of configured VPN server IP addresses: <code><b>%s</b></code>" | ||||
|  | ||||
| msgid "Disable Firewall" | ||||
| msgstr "Disable Firewall" | ||||
|  | ||||
| msgid "Enable Firewall" | ||||
| msgstr "Enable Firewall" | ||||
|  | ||||
| msgid "Apply changes" | ||||
| msgstr "Apply changes" | ||||
| : | ||||
|   | ||||
							
								
								
									
										110
									
								
								templates/firewall.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										110
									
								
								templates/firewall.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| <div class="row"> | ||||
|   <div class="col-lg-12"> | ||||
|     <div class="card"> | ||||
|       <div class="card-header"> | ||||
|         <div class="row"> | ||||
|           <div class="col"> | ||||
|             <i class="fas fa-shield-alt mr-2"></i><?php echo _("Firewall"); ?> | ||||
|           </div> | ||||
|         </div><!-- /.row --> | ||||
|       </div><!-- /.card-header --> | ||||
|       <div class="card-body"> | ||||
|         <?php $status->showMessages(); ?> | ||||
|         <h4><?php echo _("Client Firewall"); ?></h4> | ||||
|         <?php if ( $fw_conf["firewall-enable"]) : ?> | ||||
|            <i class="fas fa-circle mr-2 service-status-up"></i><?php echo _("Firewall is ENABLED"); ?> | ||||
|         <?php else : ?> | ||||
|            <i class="fas fa-circle mr-2 service-status-down"></i><?php echo _("Firewall is OFF"); ?> | ||||
|         <?php endif ?> | ||||
|         <div class="row"> | ||||
|           <div class="col-md-6"> | ||||
|             <p class="mr-2"> | ||||
|               <small> | ||||
|                 <?php echo _("The default firewall will only allow outgoing and already established traffic."); ?><br /> | ||||
|                 <?php echo _("No incoming UDP traffic is allowed."); ?><br /> | ||||
|                 <?php printf(_("There are no restrictions for the access point <code>%s</code>."), $ap_device); ?> | ||||
|               </small> | ||||
|             </p> | ||||
|           </div> | ||||
|         </div> | ||||
|         <form id="frm-firewall" action="firewall_conf" method="POST" > | ||||
|           <?php echo CSRFTokenFieldTag(); ?> | ||||
|           <h5><?php echo _("Exception: Service"); ?></h4> | ||||
|           <div class="row"> | ||||
|             <div class="form-group col-md-6"> | ||||
|                 <div class="custom-control custom-switch"> | ||||
|                     <input class="custom-control-input" id="ssh-enable" type="checkbox" name="ssh-enable" value="1" aria-describedby="exception-description" <?php if ($fw_conf["ssh-enable"]) echo "checked"; ?> > | ||||
|                     <label class="custom-control-label" for="ssh-enable"><?php echo _("allow SSH access on port 22") ?></label> | ||||
|                 </div> | ||||
|                 <div class="custom-control custom-switch"> | ||||
|                     <input class="custom-control-input" id="http-enable" type="checkbox" name="http-enable" value="1" aria-describedby="exceptions-description" <?php if ($fw_conf["http-enable"]) echo "checked"; ?> > | ||||
|                     <label class="custom-control-label" for="http-enable"><?php echo _("allow access to the RaspAP GUI on port 80 or 443") ?></label> | ||||
|                 </div> | ||||
|                 <p class="mb-0" id="exceptions-description"> | ||||
|                     <small><?php echo _("Allow incoming connections for some services from the internet side.") ?></small> | ||||
|                 </p> | ||||
|             </div> | ||||
|           </div> | ||||
|           <h5><?php echo _("Exception: network device"); ?></h4> | ||||
|           <div class="row"> | ||||
|             <div class="form-group col-md-6"> | ||||
|                 <label for="excl-device"><?php echo _("Exclude device(s)") ?></label> | ||||
|                 <input class="form-control" id="excl-devices" type="text" name="excl-devices" value="<?php echo $fw_conf["excl-devices"] ?>" aria-describedby="exclusion-description"  > | ||||
|                 <p class="mb-0" id="exclusion-description"> | ||||
|                   <small> | ||||
|                     <?php echo _("Exclude the given network device(s) (separated by a blank or comma) from firewall rules."); ?><br /> | ||||
|                     <?php printf(_("Current client devices: <code>%s</code>"), $str_clients); ?><br /> | ||||
|                     <?php printf(_("The access point <code>%s</code> is per default excluded."), $ap_device); ?> | ||||
|                   </small> | ||||
|                 </p> | ||||
|             </div> | ||||
|           </div> | ||||
|           <h5><?php echo _("Exception: IP-Address"); ?></h4> | ||||
|           <div class="row"> | ||||
|             <div class="form-group col-md-6"> | ||||
|                 <label for="excluded-ips"><?php echo _("Allow incoming connections from") ?></label> | ||||
|                 <input class="form-control" id="excluded-ips" type="text" name="excluded-ips" value="<?php echo $fw_conf["excluded-ips"] ?>" aria-describedby="excl-ips-description"  > | ||||
|                 <p class="mb-0" id="excl-ips-description"> | ||||
|                   <small> | ||||
|                     <?php echo _("For the given IP-addresses (separated by a blank or comma) the incoming connection (via TCP and UDP) is accepted."); ?><br /> | ||||
|                     <?php echo _("This is required for an OpenVPN via UDP or Wireguard connection."); ?><br /> | ||||
|                     <?php if ( !empty($vpn_ips) ) printf (_("The list of configured VPN server IP addresses: <code><b>%s</b></code>"), $vpn_ips); ?> | ||||
|                   </small> | ||||
|                 </p> | ||||
|             </div> | ||||
|           </div> | ||||
|           <?php if ($fw_conf["firewall-enable"]) : ?> | ||||
|               <input type="submit" class="btn btn-outline btn-primary" value="<?php echo _("Apply changes"); ?>" name="apply-firewall" /> | ||||
|               <input type="submit" class="btn btn-warning firewall-apply" value="<?php echo _("Disable Firewall") ?>"  name="firewall-disable" data-toggle="modal" data-target="#firewallModal"/> | ||||
|           <?php else : ?> | ||||
|               <input type="submit" class="btn btn-outline btn-primary" value="<?php echo _("Save settings"); ?>" name="save-firewall" /> | ||||
|               <input type="submit" class="btn btn-success firewall-apply" value="<?php echo _("Enable Firewall") ?>" name="firewall-enable" data-toggle="modal" data-target="#firewallModal"/> | ||||
|           <?php endif ?> | ||||
|         </form> | ||||
|       </div><!-- /.card-body --> | ||||
|       <div class="card-footer"></div> | ||||
|     </div><!-- /.card --> | ||||
|   </div><!-- /.col-lg-12 --> | ||||
| </div><!-- /.row --> | ||||
|  | ||||
| <!-- Modal --> | ||||
| <div class="modal fade" id="firewallModal" tabindex="-1" role="dialog" aria-labelledby="ModalLabel" aria-hidden="true"> | ||||
|   <div class="modal-dialog" role="document"> | ||||
|     <div class="modal-content"> | ||||
|       <div class="modal-header"> | ||||
|         <div class="modal-title" id="ModalLabel"> | ||||
|           <i class="fas fa-sync-alt mr-2"></i><?php echo _("Executing firewall option") ?> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="modal-body"> | ||||
|         <div class="col-md-12 mb-3 mt-1"> | ||||
|           <?php if($fw_conf["firewall-enable"]) echo _("Disabling firewall").'...'; else echo _("Enabling firewall").'...'; ?> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="modal-footer"> | ||||
|         <button type="button" class="btn btn-outline btn-primary" data-dismiss="modal"><?php echo _("Close"); ?></button> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
|  | ||||
							
								
								
									
										0
									
								
								templates/torproxy.php
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								templates/torproxy.php
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										0
									
								
								templates/wireguard.php
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								templates/wireguard.php
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
		Reference in New Issue
	
	Block a user