Sebastian Nohn

Weblog

Using Net_DNSBL and Nagios to check if your SMTP server is listed in a RBL

RBLs are a great way to get rid of a lot of SPAM (if you choose the right ones). On the other hand you (and users of your mail server) get in big trouble if your SMTP server gets listed on a common RBL.

Checking this manually is a job that sucks a lot, checking this automatically is an easy job with Nagios, PHP, Net_DNSBL and Console_Getopt.

I assume, you have Nagios up and running and installed according to FHS.

Install the required PEAR packages via

# pear install -a Net_DNSBL Console_Getopt

The code for a non-idiot proof, but working RBL checker is simple:

#!/opt/php/bin/php
<?php

define
('SERVICE_STATUS''Service Status:');

require_once 
'Console/Getopt.php';
require_once 
'Net/DNSBL.php';

$dnsbl = new Net_DNSBL();

$shortoptions 'H:V::r:';
$longoptions = array('hostname=''version==''rbls=');

$con = new Console_Getopt;
$args $con->readPHPArgv();
array_shift($args);
$options $con->getopt2($args$shortoptions$longoptions);

foreach(
$options[0] as $option) {
  if (
$option[0] == 'H' || $option[0] == '--hostname') {
    
$hostname $option[1];
  }
  if (
$option[0] == 'r' || $option[0] == '--rbls') {
    
$rbls_temp $option[1];
  }
}

if (!isset(
$hostname) || !isset($rbls_temp)) {
  echo 
SERVICE_STATUS.' Unknown'."\n";
  exit(
3);
} else {
  
$rbls explode(','$rbls_temp);
  
$dnsbl->setBlacklists($rbls);
  if (
$dnsbl->isListed($hostname)) {
    echo 
SERVICE_STATUS.' Critical - Listed in '.$dnsbl->getListingBl($hostname)."\n";
    exit(
2);
  } else {
    echo 
SERVICE_STATUS.' OK - Not Listed in supplied DNSBLs'."\n";
    exit(
0);
  }
}
?>

Put this into your Nagios plugin directory (/opt/nagios/libexec) and add this to /etc/opt/nagios/checkcommands.cfg:

define command{
        command_name    check_dnsbl
        command_line    $USER1$/check_dnsbl -H $HOSTADDRESS$ -r $ARG1$
        }

As well as this to /etc/opt/nagios/services.cfg:

define service{
        use                             generic-service
        host_name                       your.mail.server
        service_description             DNSBL
        is_volatile                     0
        check_period                    24x7
        max_check_attempts              3
        normal_check_interval           3
        retry_check_interval            1
        contact_groups                  nohn
        notification_interval           120
        notification_period             24x7
        notification_options            w,u,c,r
        check_command                   check_dnsbl!bl.spamcop.net,some.other.comma.separated.rbls
        }

Finally you have to restart Nagios:

# /etc/init.d/nagios restart

Posted Apr 18, 2006
Tagged as: Console_Getopt, Nagios, Net_DNSBL, PEAR, PHP, RBL, SMTP, SPAM

GD graphics library becomes a PHP project

Some years ago, the GD library was forked by the PHP project for easier building PHP with graphics support. Building GD library and PHP with GD support was always a hassle and this fork has made life much easier for PHP people.

Unfortunately, the author of the original project, Thomas Boutell, ran out of time and so had not the time to backport improvements and fixes done by the PHP development team nor do his own improvements and fixes to the library.

The consequence: Thomas has proposed to make the GD library an official PHP project and have the development of that library moved over to php.net. It seems that Pierre is going to be the new GD lead.

Congratulations to that - in my eyes perfect - decision of Thomas to propose the move, Rasmus to "accepting" GD as a PHP project and Pierre to volunteer being project lead of this well known and quite common library.

Posted Apr 02, 2006
Tagged as: GD graphics library, PHP

Continuous Builds with CruiseControl, Ant and PHPUnit

Let me start with a quote:

An important part of any software development process is getting reliable builds of the software. Despite it's importance, we are often surprised when this isn't done. We stress a fully automated and reproducible build, including testing, that runs many times a day. This allows each developer to integrate daily thus reducing integration problems.

This blog posting will show you how to enable continuous builds with CruiseControl, Ant and PHPUnit. But be warned: Continuous builds are addicting.

Install the required packages

First you need to get the required tools (like always). This guide refers to JRE 5.0 Update 6, CruiseControl 2.4.1 and PHPUnit 2.2.1. CruiseControl 2.4.1 includes ANT 1.6.5, so we don't need to think further about this.

You already have installed PHPUnit (pear install -a phpunit2). CruiseControl and Ant are still missing. I assume, you install them according to the FHS in /opt:

$ unzip cruisecontrol-bin-2.4.1.zip -d /opt

For convenience in case of upgrades, you should create this symlink:

$ ln -s /opt/cruisecontrol-bin-2.4.1 /opt/cruisecontrol
Getting started with Ant

Ant may be new to you. If you know Make, this is cool, because you already know some build tool. Ant is Make with all that Java bloat you hate about Java. If you know Phing, this is even cooler, because Phing is Ant written in PHP, so you are already familiar with that bloat.

I have two reasons for choosing Ant over Phing or Make:

The disadvantage is, that PHPUnit does not integrate into Ant out of the box. This integration issue is the one point of this posting.

The main thing you need to know about Ant is a file called build.xml. Locate it where you like. For a good start, it does (1) Delete the old CVS checkout. (2) Checkout a clean new version:

<project name="my-project" default="build" basedir="checkout">
  <target name="build">
    <delete dir="My_Project" />
    <cvs cvsRoot=":ext:cruise@cvs:/var/opt/cvs"
         command="co My_Project" reallyquiet="true" />
  </target>
</project>

The ones of you that are known to build tools may ask why I put the "checkout" task into the build task. The answer is simple: I like to keep this little howto simple, so I do not introduce dependencies here.

Start to cruise

Like for Ant, for CruiseControl everything is configured in an XML file. This time it's called config.xml:

<cruisecontrol>
  <project name="my-project">

    <bootstrappers>
      <currentbuildstatusbootstrapper file="logs/my-project/buildstatus.txt" />
    </bootstrappers>

    <modificationset quietperiod="60">
      <cvs localworkingcopy="checkout/My_Project"/>
    </modificationset>

    <schedule interval="60">
      <ant buildfile="build.xml"
           target="build"
           uselogger="true"
           usedebug="false" />
    </schedule>

    <log dir="logs/my-project/" />

    <publishers>
      <currentbuildstatuspublisher file="logs/my-project/buildstatus.txt" />
      <email mailhost="localhost"
           returnaddress="cruise@mailserver"
           buildresultsurl="http://cruisecontrol:8080/buildresults/my-project"
           skipusers="true" spamwhilebroken="true">
        <always address="developer@mailserver" />
      </email>
    </publishers>

  </project>
</cruisecontrol>

Forget about the bootstrappers. The most interesting part is modificationset and schedule. The scheduler looks every 60 seconds, if something has changed in CVS and if so it would start Ant with our well know build.xml. I said, it would and I meant it would if there were not that modification set:

CVS commits are not atomic, this means, you can't be sure to have a working checkout, because there may be still some - yet uncommited - files in the commit pipeline. Our modification set tries to workaround that problem by only starting the build if the last commit was 60 seconds ago.

The publisher does what you most likely think, it publishes the build report into various channels.

So far so senseless: We do a regular checkout. Nevertheless, management may like the results, because we do a successful build after every commit.

Just start cruisecontrol in your cwd to get it working:

$ /opt/cruisecontrol/cruisecontrol.sh

The output should look something like this:

[cc]Mar-07 11:34:29 Main          - CruiseControl Version 2.4.1 Compiled on February 28 2006 1809
[cc]Mar-07 11:34:30 HttpServer    - Version Jetty/5.1.3
[cc]Mar-07 11:34:30 Credential    - Checking Resource aliases
[cc]Mar-07 11:34:30 LConfigManager- reading settings from config file [/my/path/config.xml]
[cc]Mar-07 11:34:30 usBootstrapper- CurrentBuildStatusBootstrapper was obsoleted by CurrentBuildStatusListener
[cc]Mar-07 11:34:30 tatusPublisher- CurrentBuildStatusPublisher was obsoleted by CurrentBuildStatusListener
[cc]Mar-07 11:34:30 trolController- projectName = [my-project]
[cc]Mar-07 11:34:30 LConfigManager- using settings from config file [/my/path/config.xml]
[cc]Mar-07 11:34:30 Project       - Project PEAR_Net_DNSBL: starting
[cc]Mar-07 11:34:30 Project       - Project PEAR_Net_DNSBL:  idle
[cc]Mar-07 11:34:30 Project       - Project PEAR_Net_DNSBL: started
[cc]Mar-07 11:34:30 Project       - Project PEAR_Net_DNSBL:  next build in 1 minutes 
[cc]Mar-07 11:34:30 Project       - Project PEAR_Net_DNSBL:  waiting for next time to build
Integrate PHPUnit

The goal is to integrate PHPUnit into build.xml and config.xml so that a build fails when the unit tests fail and some nice lists (sorry, no graphs so far) are included to the CruiseControl results (remember the management).

Achieving this is very easy. Integrate this into your build.xml, just before the </target> tag:

    <exec dir="${basedir}/My_Project/test/" executable="phpunit" failonerror="true">
        <arg line="--log-xml ${basedir}/logs/phpunit_all.xml AllTest" />
    </exec>

Replace the <log />-Part in your config.xml with this:

    <log dir="logs/my-project/" />
      <merge dir="checkout/logs/" />
    </log>

To get the changes working you need to stip CruiseControl (CTRL-C) and start it again like before.

Start to SPAM

Finally we modify our publishers to notify the management anytime, the developers on build failures and QA on successful builds:

    <publishers>
      <currentbuildstatuspublisher file="logs/my-project/buildstatus.txt" />
      <email mailhost="localhost"
           returnaddress="cruise@mailserver"
           buildresultsurl="http://cruisecontrol:8080/buildresults/my-project"
           skipusers="true" spamwhilebroken="true">
        <map alias="management" address="management@mailserver" />
        <map alias="qa" address="qa@mailserver" />
        <map alias="developer" address="developer@mailserver" />
        <always address="management" />
        <success address="qa" />
        <failure address="developer" reportWhenFixed="true" />
      </email>
    </publishers>
Next Steps

Posted Mar 07, 2006
Tagged as: Ant, CruiseControl, PHP, PHPUnit, Software Development, Software Quality

Playing around with the Zend Framework

Today I found some time to play around a bit with the Zend Framework. My first experiences are that it is very easy to use and very well documented unlike most other PHP Frameworks. Adding a photo page to my site was easy to do with only 6 lines of code using the Framework:

Note: Flickr is actively promoting censorship, so you should not use it anymore. Treat the following as an example of the Zend Framework.

<?php
require_once('../includes/config.php');
require_once(
'Zend/Service/Flickr.php');

$page = new org_nohn_SmartyRenderer();
$page->setTitle('Photos');

$flickr = new Zend_Service_Flickr($flickr_api_key);
$results $flickr->userSearch($flickr_user_id);

foreach (
$results as $result) {
  
$page->addSimpleTextBlock($result->title
            
'<a href="'.$result->Large->clickUri.'"><img
                src="'
.$result->Medium->uri.'" 
                alt="'
.$result->title.'" 
                width="'
.$result->Medium->width.'" 
                height="'
.$result->Medium->height.'"></a>');
}

$page->render();
?>

Of course, there's also stuff I don't like. To get it working, I had to patch some files, there are warnings with E_ALL and it is not a PEAR package and can't be installed and upgraded with the PEAR installer, which would have been very easy with the (not so new) PEAR channels.

Posted Mar 05, 2006
Tagged as: PHP, Software Development

PHP Security battle

There are two big names in the PHP Security world. Stefan Esser, member of Hardened PHP Project. And Chris Shifflet, Member of the PHP Security Consortium.

While Stefan has proven his expertise with tons of security advisories, Chris is proven to do the better marketing.

Both are offering paid security consulting, and that's where their battle starts.

I don't want to hold forth about deciding wether expertise or marketing is better - that's up to you, I'd just like to point you to a a (marketing-wise bad) posting by Stefan, claiming that Chris is just once more unfair by making him look better than he is while talking down Hardened PHP and let you decide, who you let audit your software.

Posted Feb 18, 2006
Tagged as: PHP, Security

<<< Page 2 of 3 >>>