Verifying web server content with checksums

While setting up monit to monitor several services I support, I decided to look for an in-depth HTTP monitoring solution to compliment the monitoring capabilities provided by monit. To be more exact, I wanted to find a monitoring solution that would validate the authenticity of the content returned by a web server. Several monitoring solutions (including monit) will issue a GET request to a web server, and check that the server replied with a 200 OK status code. This works for most situations, but it doesn’t detect content deployment snafus, or server misconfigurations (the ones that don’t generate 500 status codes). I couldn’t find an opensource software package that provided this level of in-depth monitoring, so I decided to write content-check.

Content-check is written in Bourne shell, and provides in-depth HTTP monitoring by comparing a saved SHA1 hash with a SHA1 hash generated from the content returned by a web server. If the two hashes don’t match, content-check will generate a syslog entry (which can be picked up by monit) with the logger utility, and E-mail the website administrator to let them know that the content did not hash to a known value.

To configure content-check, you first need to generate a hash for the webpage you want to monitor. This can be accomplished by passing an absolute URL to content-check’s “-g” (generate hash) option:

$ content-check -g

After you generate the hash, you will need to place the hash and the absolute URL to monitor in a text file. This file can contain multiple site / hash values, but only one site / hash pair is allowed per line. Once the file is populated with one or more sites to monitor, content-check can be invoked with the “-f” option and the file that contains the list of sites to monitor:

$ cat sites da39a3ee5e6b4b0d3255bfef95601890afd80709 da39a3ee5e6b4b0d3255bfef95601890afd80709

$ content-check -f sites

If one of the sites listed in the file doesn’t hash to the value stored in the file, an E-mail is sent to the address passed to the “-e” option (or root), and a syslog message similar to the following is generated:

Jul 21 16:27:01 neutron matty: [ID 702911 daemon.notice] Content from \ did not hash to da39a3ee5e6b4b0d3255bfef95601890afd80709

Since it is possible for web servers to break in ways that allow them to still serve content, validating the content they return is the only way to know for sure that your site is working optimally.

domain-check update

I received a few emails about domain-check not producing correct output for some domains. After some poking around, it looks like a few registrars don’t publish expiration data. To address this, I added an if statement to domain-check to print “Unknown” if it is unable to locate expiration data:

$ cat domains

$ domain-check -f domains -h

Domain                              Registrar         Status   Expires     Days Left
----------------------------------- ----------------- -------- ----------- ---------                         INTERCOSMOS MEDIA Valid    13-feb-2007   313                          Unknown           Unknown  Unknown     Unknown                          GANDI             Valid    03-dec-2006   241  

I wish I could get domain-check to work with all domains, but unfortunately it wasn’t meant to be.

ssl-cert-check update

Based on some feedback I received through email, I modified the ssl-cert-check “-f” option to allow it to process files in addition to hosts/ports:

$ cat ssldomains 443 443 443
/etc/ca/cacert.pem FILE

$ ssl-cert-check -f ssldomains

Host                                            Status       Expires      Days Left
----------------------------------------------- ------------ ------------ ----------                                   Valid        May 23 2006  51                            Valid        Jun 7 2006   66                                 Valid        Dec 1 2007   608   
FILE:/etc/ca/cacert.pem                         Valid        Jan 2 2008   640   

Hopefully folks find this useful.

Is a tty?

While reading some documentation today, I came across the libc isatty() and ttyname() functions. I was curious to see how they worked, so I decided to write a little test program:

$ cat tty.c


int main(int argc, char**argv)
   if ( argc != 2) {
      printf("Usage: tty fd\n");

   int fd = atoi(argv[1]);

   if (isatty(fd)) {
       printf("File descriptor %d is a terminal %s\n",fd, ttyname(fd));
   } else {
       printf("File descriptor %d is not a terminal\n",fd);


$ gcc -o tty tty.c

$ ./tty
Usage: tty fd

$ ./tty 0
File descriptor 0 is a terminal /dev/pts/4

$ ./tty 1
File descriptor 1 is a terminal /dev/pts/4

$ ./tty 4
File descriptor 4 is not a terminal

Even though this is a small meaningless program, programming in C is fun! Shibby!

StartTLS support for ssl-cert-check

Marco Amrein sent me a StartTLS patch for ssl-cert-check this week. This nifty patch allows ssl-cert-check to query servers that setup the TLS connection after the initial protocol handshake, which can be helpful for checking the certificate expiration on SMTP and POP3 servers:

$ ssl-cert-check -s -p 25

Host                                            Status       Expires      Days Left
----------------------------------------------- ------------ ------------ ----------                             Valid        Jun 20 2006  179   

Thanks Marco!