Archive for the 'Squid' Category

SquidGuard, Content Filtering, Password bypass integrated with a windows domain

At home, I installed SquidGuard in order to protect my children againt suspicious sites. For that purpose I just installed squid as a transparent proxy on my linux router and configured SquidGuard using some well known blacklist rules. This setup was running quite well, with only one small problem, I had no way to bypass the system, when the rules were a little bit too strict.

I wanted to show a login page instead of an error page. And by login on the page, using my windows username/password (checked against my windows domain), be able to bypass the blocking rules.
I searched on the internet for a solution, but I did not really find one which was working with a transparent proxy. So I developed mine :)

Note: If you want to re-use my solution, you first need a working version of squid and squidguard. There are a lot of tutorials which will guide you to do that. You also require to have a working configuration of winbind, that is to say that your samba installation needs to be integrated with you windows domain ( wbinfo –a USER%PASS must work ! ).

Here is my solution.

Squidguard configuration and related pages

First, when the destination matches the rules, I redirect to a login page instead of the usual error page.

Excerpt from /etc/squid/squidGuard.conf

dest adult {
       domainlist      adult/domains
       urllist         adult/urls
       expressionlist  adult/expressions
       redirect         https://squid.dgconsulting.local/adultcheck/login.php?rurl=%u

This login page is asking the user and password of the user. And it useq winbind to check if the user/password is correct. If it is correct, it adds the client ip to the ip database with the current date.

Https is mandatory since the password is passed as clear text within the http request

File: /var/www/adultcheck/login.php

Adult check

quote($user).", ".$db->quote($ip).", CURRENT_TIMESTAMP + INTERVAL ".$db->quote($time)." MINUTE )"; $result = $db->query( $query ); return $result; } } $ip = getIP(); $username=$_POST['username']; $password=$_POST['password']; $authtime=30; if ( isset( $username ) ) { $return_var = 0; $output = array(); exec('/usr/bin/wbinfo -K '.$username.'%'.$password, $output, $return_var); if ( $return_var == 0 ) { echo $ip." Authoriser pour ".$authtime." minutes
\n"; $db = DB::connect('mysql://adultcheck:adultcheck@localhost/adultcheck'); $db->setFetchMode(DB_FETCHMODE_ASSOC); AdultHost::authorize($username,$ip,$authtime); echo "continuer
"; echo " \n "; } else { echo "Password Invalide
\n"; } } ?>

Squid configuration and related tools

Secondly, I need to tell squid in which case the rules apply, and in which case they must be bypassed. The configuration option external_acl_type allows me to do that. I can receive the ip of the http client, check if the ip has recently been added in the database, and either I allow to go directly or through the filter if the ip is not found.

Here is the relevant configuration I my squig.conf

Excerpt from /var/www/adultcheck/squid_acl.php

acl adults external checkip
external_acl_type checkip ttl=5 negative_ttl=5 %SRC /var/www/adultcheck/squid_acl.php
url_rewrite_access deny adults

At each request, the ip of the requestor is checked against the database. If the IP is found in the database, the request is marked as adult. Any request which is marked as adult does not get into the url redirector ( squigguard )

Here is the other relevant code

File: /var/www/adultcheck/squid_acl.php


class AdultHost
    function getId($ip)
        global $db;
        $query = "SELECT ID FROM ADULT_HOST where IP=".$db->quote($ip)." and END > CURRENT_TIMESTAMP ";
        $result = $db->getOne( $query );
        return $result;

class logfile
  function info($the_string )
    $this->write( "I: ".$the_string."\n" );

  function write($the_string )
    if( $fh = @fopen( "/tmp/adultcheck.log", "a+" ) )
      fputs( $fh, $the_string, strlen($the_string) );
      fclose( $fh );
      return( true );
      return( false );

  $log = new logfile();

  while (!0)
    $IP = trim(fgets(STDIN));
    if (feof(STDIN)) {
    $log->info( "IP: $IP" );
    $id = AdultHost::getId( $IP );
    if ( isset( $id ) ) {
      echo ( "OK\n" );
    } else
      echo ( "ERR\n" );


The database table where the ip are stored

  ID int(11) NOT NULL auto_increment,
  USER varchar(20) NOT NULL,
  IP varchar(20) NOT NULL,
  END timestamp NOT NULL default '0000-00-00 00:00:00',


This solution is working at home for more than 1 year now. It is working fine. The only small problem is that sometimes you get redirected twice to the login page.
This is due to the fact that squid is not really rechecking the acl at each request, but only each 5 seconds ( as defined in the ttl parameter of external_acl_type )
There are also other improvements that can be useful if not mandatory for a production installation.

  • Checking if the user against is member of a special windows group
  • The username and password are passed as parameters to the winbind application. This may cause a security breach. With the appropriate access to the server you may find the password. But to be honest, I already know the password of all users of my windows domain ! The solution would be to use NTLM authentication, but I do not want to spend too much time just for that.