Procházet zdrojové kódy

[Web] add manage f2b external option

FreddleSpl0it před 2 roky
rodič
revize
65cbc478b8

+ 48 - 31
data/Dockerfiles/netfilter/server.py

@@ -96,6 +96,7 @@ def verifyF2boptions(f2boptions):
   verifyF2boption(f2boptions,'netban_ipv4', 32)
   verifyF2boption(f2boptions,'netban_ipv4', 32)
   verifyF2boption(f2boptions,'netban_ipv6', 128)
   verifyF2boption(f2boptions,'netban_ipv6', 128)
   verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4()))
   verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4()))
+  verifyF2boption(f2boptions,'manage_external', 0)
 
 
 def verifyF2boption(f2boptions, f2boption, f2bdefault):
 def verifyF2boption(f2boptions, f2boption, f2bdefault):
   f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
   f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
@@ -158,6 +159,7 @@ def mailcowChainOrder():
             exit_code = 2
             exit_code = 2
 
 
 def ban(address):
 def ban(address):
+  global f2boptions
   global lock
   global lock
   refreshF2boptions()
   refreshF2boptions()
   BAN_TIME = int(f2boptions['ban_time'])
   BAN_TIME = int(f2boptions['ban_time'])
@@ -199,7 +201,7 @@ def ban(address):
     cur_time = int(round(time.time()))
     cur_time = int(round(time.time()))
     NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter']
     NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter']
     logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 ))
     logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 ))
-    if type(ip) is ipaddress.IPv4Address:
+    if type(ip) is ipaddress.IPv4Address and int(f2boptions['manage_external']) != 1:
       with lock:
       with lock:
         chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
         chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
         rule = iptc.Rule()
         rule = iptc.Rule()
@@ -208,7 +210,7 @@ def ban(address):
         rule.target = target
         rule.target = target
         if rule not in chain.rules:
         if rule not in chain.rules:
           chain.insert_rule(rule)
           chain.insert_rule(rule)
-    else:
+    elif int(f2boptions['manage_external']) != 1:
       with lock:
       with lock:
         chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
         chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
         rule = iptc.Rule6()
         rule = iptc.Rule6()
@@ -253,37 +255,52 @@ def unban(net):
     bans[net]['ban_counter'] += 1
     bans[net]['ban_counter'] += 1
 
 
 def permBan(net, unban=False):
 def permBan(net, unban=False):
+  global f2boptions
   global lock
   global lock
   if type(ipaddress.ip_network(net, strict=False)) is ipaddress.IPv4Network:
   if type(ipaddress.ip_network(net, strict=False)) is ipaddress.IPv4Network:
-    with lock:
-      chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
-      rule = iptc.Rule()
-      rule.src = net
-      target = iptc.Target(rule, "REJECT")
-      rule.target = target
-      if rule not in chain.rules and not unban:
-        logCrit('Add host/network %s to blacklist' % net)
-        chain.insert_rule(rule)
-        r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
-      elif rule in chain.rules and unban:
-        logCrit('Remove host/network %s from blacklist' % net)
-        chain.delete_rule(rule)
-        r.hdel('F2B_PERM_BANS', '%s' % net)
+    if int(f2boptions['manage_external']) != 1:
+      with lock:
+        chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW')
+        rule = iptc.Rule()
+        rule.src = net
+        target = iptc.Target(rule, "REJECT")
+        rule.target = target
+        if rule not in chain.rules and not unban:
+          logCrit('Add host/network %s to blacklist' % net)
+          chain.insert_rule(rule)
+          r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
+        elif rule in chain.rules and unban:
+          logCrit('Remove host/network %s from blacklist' % net)
+          chain.delete_rule(rule)
+          r.hdel('F2B_PERM_BANS', '%s' % net)
+    elif not unban:
+      logCrit('Add host/network %s to blacklist' % net)
+      r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
+    elif unban:
+      logCrit('Remove host/network %s from blacklist' % net)
+      r.hdel('F2B_PERM_BANS', '%s' % net)
   else:
   else:
-    with lock:
-      chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
-      rule = iptc.Rule6()
-      rule.src = net
-      target = iptc.Target(rule, "REJECT")
-      rule.target = target
-      if rule not in chain.rules and not unban:
-        logCrit('Add host/network %s to blacklist' % net)
-        chain.insert_rule(rule)
-        r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
-      elif rule in chain.rules and unban:
-        logCrit('Remove host/network %s from blacklist' % net)
-        chain.delete_rule(rule)
-        r.hdel('F2B_PERM_BANS', '%s' % net)
+    if int(f2boptions['manage_external']) != 1:
+      with lock:
+        chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
+        rule = iptc.Rule6()
+        rule.src = net
+        target = iptc.Target(rule, "REJECT")
+        rule.target = target
+        if rule not in chain.rules and not unban:
+          logCrit('Add host/network %s to blacklist' % net)
+          chain.insert_rule(rule)
+          r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
+        elif rule in chain.rules and unban:
+          logCrit('Remove host/network %s from blacklist' % net)
+          chain.delete_rule(rule)
+          r.hdel('F2B_PERM_BANS', '%s' % net)
+    elif not unban:
+      logCrit('Add host/network %s to blacklist' % net)
+      r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
+    elif unban:
+      logCrit('Remove host/network %s from blacklist' % net)
+      r.hdel('F2B_PERM_BANS', '%s' % net)
 
 
 def quit(signum, frame):
 def quit(signum, frame):
   global quit_now
   global quit_now
@@ -555,7 +572,7 @@ def initChain():
       chain.insert_rule(rule)
       chain.insert_rule(rule)
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
-
+  refreshF2boptions()
   # In case a previous session was killed without cleanup
   # In case a previous session was killed without cleanup
   clear()
   clear()
   # Reinit MAILCOW chain
   # Reinit MAILCOW chain

+ 6 - 3
data/web/inc/functions.fail2ban.inc.php

@@ -247,6 +247,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
         $netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']);
         $netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']);
         $wl = (isset($_data['whitelist'])) ? $_data['whitelist'] : $is_now['whitelist'];
         $wl = (isset($_data['whitelist'])) ? $_data['whitelist'] : $is_now['whitelist'];
         $bl = (isset($_data['blacklist'])) ? $_data['blacklist'] : $is_now['blacklist'];
         $bl = (isset($_data['blacklist'])) ? $_data['blacklist'] : $is_now['blacklist'];
+        $manage_external = (isset($_data['manage_external'])) ? intval($_data['manage_external']) : 0;
       }
       }
       else {
       else {
         $_SESSION['return'][] = array(
         $_SESSION['return'][] = array(
@@ -266,6 +267,8 @@ function fail2ban($_action, $_data = null, $_extra = null) {
       $f2b_options['netban_ipv6'] = ($netban_ipv6 > 128) ? 128 : $netban_ipv6;
       $f2b_options['netban_ipv6'] = ($netban_ipv6 > 128) ? 128 : $netban_ipv6;
       $f2b_options['max_attempts'] = ($max_attempts < 1) ? 1 : $max_attempts;
       $f2b_options['max_attempts'] = ($max_attempts < 1) ? 1 : $max_attempts;
       $f2b_options['retry_window'] = ($retry_window < 1) ? 1 : $retry_window;
       $f2b_options['retry_window'] = ($retry_window < 1) ? 1 : $retry_window;
+      $f2b_options['banlist_id'] = $is_now['banlist_id'];
+      $f2b_options['manage_external'] = ($manage_external > 0) ? 1 : 0;
       try {
       try {
         $redis->Set('F2B_OPTIONS', json_encode($f2b_options));
         $redis->Set('F2B_OPTIONS', json_encode($f2b_options));
         $redis->Del('F2B_WHITELIST');
         $redis->Del('F2B_WHITELIST');
@@ -351,8 +354,8 @@ function fail2ban($_action, $_data = null, $_extra = null) {
       switch ($_data) {
       switch ($_data) {
         case 'get':
         case 'get':
           try {
           try {
-            $bl = $redis->hGetAll('F2B_BLACKLIST');
-            $active_bans = $redis->hGetAll('F2B_ACTIVE_BANS');
+            $bl = $redis->hKeys('F2B_BLACKLIST');
+            $active_bans = $redis->hKeys('F2B_ACTIVE_BANS');
           } 
           } 
           catch (RedisException $e) {
           catch (RedisException $e) {
             $_SESSION['return'][] = array(
             $_SESSION['return'][] = array(
@@ -362,7 +365,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
             );
             );
             return false;
             return false;
           }
           }
-          $banlist = implode("\n", array_merge(array_keys($bl), array_keys($active_bans)));
+          $banlist = implode("\n", array_merge($bl, $active_bans));
           return $banlist;
           return $banlist;
         break;
         break;
         case 'refresh':
         case 'refresh':

+ 2 - 0
data/web/lang/lang.de-de.json

@@ -181,6 +181,8 @@
         "f2b_blacklist": "Blacklist für Netzwerke und Hosts",
         "f2b_blacklist": "Blacklist für Netzwerke und Hosts",
         "f2b_filter": "Regex-Filter",
         "f2b_filter": "Regex-Filter",
         "f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
         "f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
+        "f2b_manage_external": "Fail2Ban extern verwalten",
+        "f2b_manage_external_info": "Fail2ban wird die Banlist weiterhin pflegen, jedoch werden keine aktiven Regeln zum blockieren gesetzt. Die unten generierte Banlist, kann verwendet werden, um den Datenverkehr extern zu blockieren.",
         "f2b_max_attempts": "Max. Versuche",
         "f2b_max_attempts": "Max. Versuche",
         "f2b_max_ban_time": "Maximale Bannzeit in Sekunden",
         "f2b_max_ban_time": "Maximale Bannzeit in Sekunden",
         "f2b_netban_ipv4": "Netzbereich für IPv4-Banns (8-32)",
         "f2b_netban_ipv4": "Netzbereich für IPv4-Banns (8-32)",

+ 2 - 0
data/web/lang/lang.en-gb.json

@@ -185,6 +185,8 @@
         "f2b_blacklist": "Blacklisted networks/hosts",
         "f2b_blacklist": "Blacklisted networks/hosts",
         "f2b_filter": "Regex filters",
         "f2b_filter": "Regex filters",
         "f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. <b>List updates will take a few seconds to be applied.</b>",
         "f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. <b>List updates will take a few seconds to be applied.</b>",
+        "f2b_manage_external": "Manage Fail2Ban externally",
+        "f2b_manage_external_info": "Fail2ban will still maintain the banlist, but it will not actively set rules to block traffic. Use the generated banlist below to externally block the traffic.",
         "f2b_max_attempts": "Max. attempts",
         "f2b_max_attempts": "Max. attempts",
         "f2b_max_ban_time": "Max. ban time (s)",
         "f2b_max_ban_time": "Max. ban time (s)",
         "f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",
         "f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)",

+ 7 - 0
data/web/templates/admin/tab-config-f2b.twig

@@ -42,6 +42,13 @@
             <input type="number" class="form-control" id="f2b_netban_ipv6" name="netban_ipv6" value="{{ f2b_data.netban_ipv6 }}" required>
             <input type="number" class="form-control" id="f2b_netban_ipv6" name="netban_ipv6" value="{{ f2b_data.netban_ipv6 }}" required>
           </div>
           </div>
         </div>
         </div>
+        <div class="mb-4">
+          <div class="form-check form-switch">
+            <input class="form-check-input" type="checkbox" id="f2b_manage_external" value="1" name="manage_external" {% if f2b_data.manage_external == 1 %}checked{% endif %}>
+            <label class="form-check-label" for="f2b_manage_external">{{ lang.admin.f2b_manage_external }}</label>
+          </div>
+          <p class="text-muted">{{ lang.admin.f2b_manage_external_info }}</p>
+        </div>
         <hr>
         <hr>
         <p class="text-muted">{{ lang.admin.f2b_list_info|raw }}</p>
         <p class="text-muted">{{ lang.admin.f2b_list_info|raw }}</p>
         <div class="mb-2">
         <div class="mb-2">