Skip to content

Exim_deny_filter.php Update

Dear Reader,

Because I know so many of you use it, I’ve updated my little script to maintian the exim_deny_filter described here. After being deluged with emails of congratulations, eternal thanks and feature requests[1] I finally broke down and coded the one additional feature every user I talked to[2] requested. It now has the ability to tell you how many IP addresses are in your file. Ok, technically it tells you how many lines begin with a # but since each IP address has a timestamp line before it that starts with a # you get the same info.

Anyhow, you can download it here. Full details on how to implement IP filtering in Exim can be found here.



[1] Ok, it’s the one feature I wanted to add.
[2] Ok, so I only talked to myself.

TagClouds in PHP Revisited

Dear Reader,

Yes I know TagClouds are so 2005; and yes I know TagClouds are the new Mullet; they are still fun to play with. With that having been said, I went back and re-factored the PHP code I wrote a while back for my AJAX resume. For that project, my sole purpose was just to get a TagCloud of my skills and any old TagCloud would do. This time, my purpose was to build a class to automate it as well as build an example to show how useful/useless it really is. I’ve accomplished both of those lofty goals. Here is the source code and here is the example.

Originally I was going to spend a lot of time explaining to you how I did it in an insipid tutorial. I realized though that you dear reader, fall into one of 2 classes of people.

If you are a programmer then the last thing you want is for me to explain it to you when you can read the source yourself. Therefore, if you are in this camp, just download it and read it. I’ve tried to comment it thoroughly but if you have any questions, don’t hesitate to drop me a line.

If you are in this group then you don’t really care how it works, you just want to know how to use it. First, check out the example page. The keywords on the sample page come from the last 30 entries of my blog. I’ll admit I cheated and just open the database and pull them from there instead of trying to call my blog w/curl or fopen and parse it. (Although that would have been cooler.) I then ran each blog entry against Yahoo’s Term Extraction API to get the terms. Then I pumped that array into my new TagCloud maker. The important code you can’t see from the index.php is below.

$x = TagCloud::fetch_cloud($thisArray,'...',
$o = new TagCloud($thisArray,'...','tagcloud_',
$y = $o->output_cloud;

As you can see, I used 2 different methods of creating the 2 lists. The first is just calling the object::method statically with all the necessary parameters. This is by far the easiest way to use this class and unless you need something special, it's the way I recommend. The second way it to instantiate an object. I pass all the variables into the constructor but you could just as easily use the setters to set them all. (don't know why you would but hey, I spent an extra 15 minutes creating getters and setters so use them, by all means use them!)

Then just use the contents of $y somewhere in your page. (To those of you who have worked on teams I have built, yes, I know I always preached that it's a fire-able offense to use a single letter variable name but since I don't work for you I don't care!) :)

That's it. Use it or don't. I don't care; I had fun writing it. As is my custom, I think I'll turn it into a WordPress plugin. Because god knows we need tag clouds in our blogs!

Until next time, I love you even when you piss me off.

p.s. This blog was originally titled "It's Raining Tags" which was a lot more fun but not nearly as descriptive.

p.s.s. Proof that great minds think alike I found this. The site is in (Japanese?) but the code is in...php.

Mail Server, Spam Blocking and firewalls

Dear Reader,

You may or may not know that I run a web hosting service and Internet design company in all of my spare time. This affords me the opportunity to do some interesting things like have long discussions on forums with other admins about the relative value to blocking spam at the firewall .vs the MTA. Thanks to Jeff Lasman those of us who use DirectAdmin and exim have a new SPAM fighting tool, the SpamBlocker configuration file for exim. It’s a great piece of work. If you run exim, even if you don’t run DirectAdmin, it’s worth a read just to see all the good ideas in one place.

Jeff just recently released version 2.0 of the file and while discussing it, our attention turned to blocking spam at the firewall instead of at the MTA. Obviously, it takes less resources but since a lot of spam comes from dynamic IP addresses (evil zombies) you don’t want to block those IP from your server forever or eventually no-one will be able to get to your site. Also, there are several problems that I’ve yet to overcome technically, not the least of which being that exim runs as a non-privileged user (as it should) but this precludes it from executing iptables. So, for the moment, I’m left with a less than optimal but perfectly workable solution.

1 – You need Jeff’s SpamBlocker conf file for exim. If you don’t run DirectAdmin, you will have to modify it to suit your needs but it’s well worth the effort. If however, you don’t want to start from scratch with a new conf file, this idea will work with just about any exim.conf file for 4.50 or better. (it may work with any version of exim 4.x but I’ve not tested it.)

It’s important at this point to say that before you implement this make sure exim is working 100% and then back up your conf file. if nothing else, email it to yourself. It gives you a backup AND you know it’s working! :)

2 – Ok, so you have a working exim.conf file. Now let’s tinker with it. Somewhere in your acl_smtp_rcpt (in SpamBlocker it’s the check_recipient ACL) you need to put the following:

# Blatantly stolen from
# Many props and thanks guys.
# If they added themselves to the file below, let's block them for Dict Scan!!!
deny  message       = Blocked because your address is being used for a dictionary attack.
hosts         = /etc/exim_deny
!hosts         = +relay_hosts
!authenticated = *
delay         = 150s
log_message   = Blocked because of dictionary scan.

deny  message       = Max $rcpt_fail_count failed recipients allowed
condition     = ${if > {${eval:$rcpt_fail_count}}{2}{yes}{no}}
condition     = ${run{/etc/ $sender_host_address}{1}{1}}
!hosts        = +relay_hosts
delay         = ${eval: ($rcpt_fail_count) * 30}s
log_message   = Dictionary scan! $rcpt_fail_count failed recipient attempts

If you are using SpamBlocker like me, consider putting it below:

# accept mail to hostmaster in any local domain, regardless of source
accept  local_parts = hostmaster
domains     =+local_domains

3 – Ok, save that. Now, download and save it in your /etc dir. Make sure it is executable by the user account that your exim runs under.

4 – create the file /etc/exim_deny and make sure that it is writable by the account that your exim runs under.

5 – Restart exim

At this point you should have a working solution. There are a couple of things you might want to do.

First, as Jeff pointed out, neither executables nor storage files should be in your /etc. Hey, I didn’t write it and I’ve been too lazy to change it up to this point. But he’s right and you should move the executable somewhere appropriate and the exim_deny file to somewhere in your /var directory.

Second, if you don’t watch it, exim_deny is just going to keep growing and growing. Since I hate manually editing files as much as the next guy I wrote a little php script to do it for me.

Download and save on your server as a php file. Make sure the reference to the php interpreter is correct and if you move the exim_deny file, change it here too. Now, after you run it a few times to make sure it works the way you want it to, drop it in your cron and forget it. Run it as often as you like. Hell, fire up PuTTY and run it in the middle of the day if you get bored. FWIW, I run it every night about 3 AM. (and if my boss is reading this, as far as you know I don’t run it in the middle of the day because as far as you know I’m not bored.) :)

That’s it. Like I said, it’s not a perfect solution. Blocking the IP addresses at the firewall is a much more efficient solution. Especially if you have a busy server that gets attacked a lot. But I present it here for you because it worked for me. I encourage you to drop me a line with any improvements. I’ll make sure and share them.

Until next time,



Fade Anything Technique Extended Edition 2.0

Dear Reader,

Ok, it’s finally done. Sorry it took so long but life intervenes. Here is my take on the wonderful code to fade things. You may have seen this technique in my previous blog entries. Or in some of the lesser known places like basecamp (who inspired the original author) or the original author’s page. No matter where you saw it, here is the WordPress plugin to let you use and abuse this effect in your blog.

A sample of the effects that can be used to annoy can be found here. The official project page can be found here. You can download the tar file here.

To install:

  1. Download the tarball to your wp-content directory.
  2. Untar. This will place wp-fatter.php in your plugins directory and fatter2.js in your wp-content directory.
  3. Move fatter2.js into your javascript directory. (Or wherever you keep your javascript files.)
  4. Activate the plugin
  5. From the Admin section of WordPress go to Options->FATtER. Check the options listed making sure they have the values you want. Pay careful attention to the location of the script. If this isn’t right, the effect won’t work. Once everything is correct, Click Update to commit the values to the database.
  6. Start using the effect. There are several examples in the .js file of how to call it, the easiest is to wrap a piece of text in a span tag with a unique ID (anything as long as it’s unique for the PAGE) and a class of “fade”.

I hope you enjoy using this as much as I did creating it. For those curious, I originaly wrote this because when I would encode secret messages of undying love into blogs for wife v1.22 – the lovely and talented Kathy – she sometimes didn’t see them. So I had to make them a little less secret and a little more obvious.Until next time,



Front-end .vs Back-end

Dear Reader,

I was reminded yesterday of a truth that I think too many developers forget. “The best back-end in the world is useless without a good front-end.”

I’m the first to admin that I’m a middle-tier and back-end programmer. I don’t do front-end interfaces well at all. So it’s natural for me assume that the back-end is the most imortant part of the application. Let’s face it, a well executed calss library is a thing of beauty. Everybody should be able to appreciate that; right? However, being married to a graphic designer (The lovely and talented Kathy) I am constantly reminded that this is only true when I’m writing shell-scripts. (and possibly not even then)
Well coded back-ends are great but without a usable interface, they just won’t get used.

I know it’s not a unique thought, I know I’m not the first one to have it. I also know that developers need to be reminded of it regularly.

Until next time,