Browse Source
Implement firewall
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 settingspull/1087/head
4 changed files with 413 additions and 0 deletions
-
168config/iptables_rules.json
-
174includes/firewall.php
-
1installers/raspap.sudoers
-
70templates/firewall.php
@ -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" |
|||
] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,174 @@ |
|||
<?php |
|||
|
|||
require_once 'includes/status_messages.php'; |
|||
require_once 'includes/functions.php'; |
|||
|
|||
define(RASPAP_FIREWALL_CONF,"/tmp/iptables.conf"); |
|||
define(RASPAP_IPTABLES_CONF,"/etc/raspap/networking/firewall/iptables_rules.json"); |
|||
define(RASPAP_IPTABLES_SCRIPT,"/tmp/iptables_raspap.sh"); |
|||
|
|||
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; |
|||
} |
|||
|
|||
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; |
|||
} |
|||
|
|||
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) ) { |
|||
//echo "replace $repl $val \n"; //print_r( $val); echo "\n";
|
|||
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 .= "iptables ".$r."\n"; |
|||
} |
|||
return $str; |
|||
} |
|||
|
|||
function setFirewall() { |
|||
$json = file_get_contents(RASPAP_IPTABLES_CONF); |
|||
$ipt = json_decode($json, true); |
|||
$conf = ReadFirewallConf(); |
|||
|
|||
//echo "<pre>";
|
|||
// 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 "</pre>";
|
|||
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") |
|||
); |
|||
} |
@ -0,0 +1,70 @@ |
|||
<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 allow only outgoing and already established traffic. No UDP traffic is allowed.") ?></small></p>
|
|||
</div> |
|||
</div> |
|||
|
|||
<form id="frm-firewall" action="firewall_conf" method="POST" > |
|||
<?php echo CSRFTokenFieldTag(); ?>
|
|||
<h5><?php echo _("Exceptions for Services"); ?></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="exceptions-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") ?></label>
|
|||
</div> |
|||
<p class="mb-0" id="exceptions-description"> |
|||
<small><?php echo _("Allow access for some services from the client side.") ?></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"); ?>" 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 if($fw_conf["firewall-enable"]) echo _("Disable the firewall ..."); else echo _("Enable the Firewall ..."); ?>
|
|||
</div> |
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue