mod_miserable: Apache module for sadists

Those of you who admin busy web forums (vBulletin in particular) may well have come across so called 'miserable' plugins/mods. This is an Apache module which does something very similar, but with a few extra handy features.

The idea behind a miserable forum plugin is that certain users/usergroups are inconvenienced when using the forum. Pages will take longer to load, 404 or Internal Server Errors will sporadically occur etc. Using the forum will become a frustrating experience for these users. The reasoning goes that this can be more effective than banning the user because a banned user will invariably just register a new account, through a proxy if necessary. A miserable user will not be aware that they have been made miserable, will hopefully put the problems down to an overloaded or poorly administrated web server, and in frustration will start trolling somewhere else. Of course, it's also gives the forum admin some sadistic pleasure.

There are several miserable implementations, but they typically suffer several shortcomings:

As you'll see, mod_miserable addresses all of these, and is very flexible to use.

Implementation

My first thought was that Apache should read a list of IP addresses from a file, and inflict misery on the client if its address matched. Ideally we'd need to be able to use domain names and wildcards thought too (eg *.aol.com 192.168.*.*), and suddenly things are getting more complicated. Why re-invent the wheel though when the core module mod_setenvif can already do this.

mod_setenvif

The chances are that you already have mod_setenvif installed, but have never needed to use it. It basically allows you to set environmental variables based on characteristics of the client. These env vars can be used in other Apache directives, in server-side code (in PHP they are exposed via the $_SERVER array), or - crucially - in other Apache modules.

So the basic idea is this. We use setenvif to set a 'miserable' env var based on certain criteria (most likely client IP). mod_miserable looks for the presence of this env var, and if set, inflicts misery on the client.

Misery

Inflicting misery is pretty straightforward. We generate a random number between 0 and 100. If the number is between 0 and 5, we send back a 404 (Not Found) response, if it's between 6 and 10 we send back a 500 (Internal Server Error), etc etc. Around 75% of the time though, mod_miserable does not send back a response - the key to making the experience frustrating is regular random errors, not constant errors. Just for good measure, mod_miserable also sleeps for a random period between 0 and 10 seconds, causing pages to take longer to load.

If mod_miserable only kicking in 25% of the time seems low, don't forget that a typical page view will consist of a handful of requests: as well as the html/php page, there may be external css/js files and images (although often these will be cached by the browser). One of the advantages of using setenvif is that we can limit mod_miserable to only operating on certain requests - resources in a particular directory, resources of a particular type (eg images) etc.

Here's a list of the status codes generated by mod_miserable:

The last of these is rarely seen in use, so should cause of a bit of confusion. If you're happy editing some very simple C in the mod_miserable source code (which is less than 100 lines in total), the weighting of each of these status codes can be changed, as can the random sleep time.

Installing

Downloading and Building

The source code for mod_miserable is available here. Unpack it, then issue the following commands to build the module:

gcc -fPIC -DSHARED_MODULE -I/usr/include/apache2 -I/usr/include/apr-1.0  -c mod_miserable.c
ld -Bshareable -o mod_miserable.so mod_miserable.o

Then copy mod_miserable.so into your Apache modules directory (if you're unsure where this is, look in your Apache config files, or find the directory containing things like mod_alias.so, mod_info.so etc).

Configure Apache

Somewhere in your Apache config add the line after the LoadModule setenvif_module directive (order is important):

LoadModule miserable_module /usr/lib/apache2/modules/mod_miserable.so

, to load the module (don't forget to change /usr/lib/apache2/modules to your modules directory. While you're at it, check that mod_setenvif is installed (look for something like LoadModule setenvif_module /usr/lib/apache2/modules/mod_setenvif.so) - we'll need it in a minute.

Now it's time to write your first setenvif rule...


<IfModule mod_setenvif.c>
SetEnvIf Remote_Addr 1.2.3.4 miserable=1
</IfModule>

This causes the miserable env var to be set to 1 if the client IP is 1.2.3.4. Try changing it to your own IP, restarting apache, then browsing your site. As previously mentioned, setenvif can match the client hostname, file extensions, directories etc. Check out the Apache setenvif docs for more examples

Linux Services

Books

Code

vBulletin

Fun Stuff

Blog

Pete's Shed




linux support email pete@linuxbox.co.uk
(+44) 07890 592198