rem

.co

Iptables: Creating Persistent Bans From Fail2Ban

| Comments

On my servers I use the nifty program Fail2Ban to perform logbased automatic firewalling of ‘bad’ ip’s.

The idea behind this is easy: Some IP performs an action I don’t approve of. This can be any number of things, e.g. requesting pages in Apache that are commonly accessed by bots and/or scanners, or trying to log in to SSH with accounts that do not exist on the system. This bad behavior gets logged, and Fail2Ban keeps tabs on those logs, and using a number of rules it determines if a host is ‘bad’ enough to temporarily or permanently ban all access to the server. It does so by adding a few chains to Iptables (one for each thing it checks for), and dynamically adding/removing IP’s to/from these chains.

This all works perfectly. However, there’s one issue; When Iptables gets reloaded, it restores its default rules, removing the Fail2Ban chains and all the rules they contain, even if the ip’s in the chain were marked as permanent.

I created a workaround for this problem, consisting of two simple steps:

  • When a ‘bad’ ip gets banned, it’s added to the Iptables chain, but also written to a file, containing all collected ‘bad’ ip’s. (I use /etc/shitlist for this purpose).

  • Whenever Iptables gets reloaded, I run a PHP script that checks the /etc/shitlist file for ‘safe’ and duplicate ip’s, and writes all other ip’s to the permanent Blocklist chain. (The checking for ‘safe’ ip’s might be a bit unneeded, but with my Fail2Ban rules it’s possible that one of my own ip’s gets banned for 10 minutes if a SSH login attempt fails for 5 times. Though it’s a temporary ban, the ip will still get written to the shitlist, and would end up in the permanent Blocklist).

To make this work, I made the following changes:

Every jail in Fail2Ban uses an action.d script to perform (un)banning. I defaulted all actions to an action script called iptables-allports.conf. Basically this action drops everything in Iptables if a package originates from the ‘bad’ IP.

I updated the ban action such that:

1
2
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
echo <ip> >> /etc/shitlist

After that I created a PHP script that updates Iptables with the ip’s contained in the shitlist:

shitlist.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
/** script that loads a shitlist file into iptables */
//CONFIG 
$shitlists = array("/root/list.txt","/etc/shitlist");
$chain = "Blocklist";
$safelist = array("x.x.x.x", "y.y.y.y", "z.z.z.z");

echo "Reading current IPTABLES state\r\n";
$data = shell_exec('iptables -S '.$chain);
$iparr = explode(' ',$data);
$j = 0;
$ref = array();
for($i=0;$i<sizeof($iparr);$i++) {
  if(substr_count($iparr[$i],".")==3) {
      $ref[$j] = $iparr[$i];
       $j++;
   }
}
sort($ref);
$total = 0;
foreach($shitlists as $shitlist) {
  echo "Reading shitlist at $shitlist\r\n";
  //READ FILE
  $fh = fopen($shitlist,'r');
  if($fh) {
      $itt = 0;
      $iparr = array();
      while(!feof($fh)) {
          $ip = trim(fgets($fh));
          if(strlen($ip)>6) {
              if(array_search($ip,$iparr)===false&&array_search($ip,$safelist)===false&&array_search($ip."/32",$ref)===false) {
                  $iparr[] = $ip;
                  echo "Now adding $ip to $chain\r\n";
                  $ins = 18+$itt;
                  shell_exec("iptables -I ".$chain." ".$ins." -s ".$ip."/32 -j DROP");
                  $itt++;
              }
          }
      }
      fclose($fh);
      echo "Finished adding $itt ip's from list $shitlist to chain $chain . Bye!\r\n";
      $total = $total + $itt;
  } else {
      echo "Could not open shitlist file $shitlist . Skipping this list\r\n";
  }
}
echo "Finished adding $total ip's to chain $chain from ".sizeof($shitlists)." shitlists.\r\n";
?> 

You can run the script from the commandline (as root!) simply by stating php shitlist.php, or add it to the startup script of your Iptables installation.

Hope this helps keeping your NIC’s available for VALID traffic!

Update:

Made some changes to the script to check for already existing bans, to keep your chains clean!

Update 2:

Little tweak to the script so it now loads an array of lists, in case you have various sources.

CSS: Overlapping Flash Content With CSS

| Comments

By default, flash movies are always shown on the top-level of a display tree.

However, it can be very useful to be able to move the flash content to the background, and having it overlapped by other content; e.g. You have a flash movie in the header of your website, but there’s a sidebar menu which should be displayed over the header.

This is easily achieved by following these steps:

  1. Add wmode="transparent" to your object and embed tags which include the flash movie
  2. Wrap the object and embed tags by a div and assign a CSS class to it.
  3. Define a z-index for this class in your stylesheet.
  4. Assign a higher z-index for all items that should overlay the flash movie.
  5. Refresh and enjoy.

Example:

HTML Flash Include
1
2
3
4
5
6
7
8
9
10
11
12
<div class="flashheader"> <object id="header" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="1024" height="202" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0">
 <param name="data" value="fileadmin/template/header.swf" /> <param name="wmode" value="transparent" />
 <param name="allowScriptAccess" value="sameDomain" />
 <param name="allowFullScreen" value="false" />
 <param name="quality" value="high" />
 <param name="bgcolor" value="#ffffff" />
 <param name="src" value="fileadmin/template/header.swf" />
 <param name="name" value="header" /><param name="allowfullscreen" value="false" />
 <embed id="header" type="application/x-shockwave-flash" width="1024" height="202" src="fileadmin/template/header.swf" name="header" bgcolor="#ffffff" quality="high" allowfullscreen="false" allowscriptaccess="sameDomain" wmode="transparent" data="fileadmin/template/header.swf">
 </embed>
 </object>
</div>
CSS for Flash
1
2
3
4
5
6
7
8
div.flashheader {
 display: block;
 width: 1024px;
 left:0;
 margin-top:-260px;
 position: relative;
 z-index: 1;
}
CSS for Overlap
1
2
3
4
5
6
7
8
9
10
div.side{
 height:578px;
 width:372px;
 float:left;
 background-image:url('../img/rightbar.png');
 position: absolute;
 top:114px;
 left: 612px;
 z-index: 100;
}

PHP: Testing the Pseudo Random Number Generator

| Comments

Every programmer uses them.. PRNG’s, better known as Pseudo-Random Number Generators; in PHP represented by the rand(min,max) function.

Unlike True Random Number Generators (TRNG’s) that use true random data like atmospheric noise to create their numbers, PRNG’s rely on software algorithms to come up with seemingly random numbers.. but are they?

And is there a difference between Linux and Windows PRNG results?

MySQL: The Complete FULLTEXT Checklist

| Comments

In an effort to help a colleague with FULLTEXT search troubles today, I tried to find out everything that could go wrong with setting up this search method on a table. My short research resulted in this checklist. Failure to comply with these checks will result in catastrophic failure :P

  1. Make sure the table you’re trying to FULLTEXT on has MyISAM type! Currently, FULLTEXT searches do NOT work on InnoDB types. If you are bound to using InnoDB for various reasons, you could create a duplicate table in MyISAM to perform your searches on.

MySQL: Boolean Substitution

| Comments

Today I faced a quite interesting problem, that originated from pure laziness. I’m developing a backend system for a quite complex database structure. Within this backend, an almost limitless amount of table views have to be created for the end user. Because I’m extremely lazy, and didn’t want to develop the html view code for each table view, I created a PHP html-table-generator-class, which takes a mysql_result_set as parameter, and outputs the html table in string format.

This method works great, unless for some cases, where a value in the query has to be substituted by a user readable value. A boolean is a good example of such a value.