Archive for the 'Linux' Category

Building a new kernel for the raspberry pi, including support for i2c, spi and working version of the driver rtl8192cu.

This guide will show you the entire step that I had to do in order to produce my custom kernel. I wanted to have the latest kernel of Chris boot, which include support for spi and i2c, but I also need to include the latest realtek driver for my wifi dongle.

The Chris Boot’s website contains a lot of information, but it does not contains this information required to build his kernel from scratch by real beginner. I will try to fill the gap.

Prerequisits

First install Ubuntu 12.04 LTS

Since I have a mac, I installed it on Parallels and it is working like a charm.

install the cross compiler and the dev tools

sudo apt-get install git-core gcc-4.6-arm-linux-gnueabi
sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-4.6 /usr/bin/arm-linux-gnueabi-gcc
sudo apt-get install git-core gcc-4.6-arm-linux-gnueabi

Build the kernel

Download the source code

cd
mkdir rpi-3.2.20
cd rpi-3.2.20
git clone https://github.com/raspberrypi/firmware
git clone -b rpi-3.2.20 https://github.com/bootc/linux.git

Download the realtek driver RTL819xCU, and copy it ro the rpi-3.2.20 directory

Copy the default config from the previous kernel.

There are several way of doing that, you can start simply download the Chris Boot images, and install his latest kernel.
The config is located in /boot/config-3.2.20-rpi1+, or you can simply download it from my site config-3.2.20-rpi1+
Copy this to your ubuntu system as .config

cd ~/rpi-3.2.20/linux
wget http://www.gallot.be/resources/config-3.2.20-rpi1+
cp config-3.2.20-rpi1+ .config

Change the kernel name, so it will not conflict with any other one.

Edit the Makefile and change the first line from :

EXTRAVERSION =
To :
EXTRAVERSION=-spi-i2c-rpi1

Import the config and disable the old rlt8192 module

make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- oldconfig
make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- menuconfig

Open the following menu :
Device Drivers
Network device support
Wireless LAN
And unselect the driver by typing [space]
Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter
Hit [Tab] to select exit multiple time, and save the configuration.

Build the kernel.

make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- -k -j5

Prepare the file to be copied to the system.

mkdir -p ~/rpi-3.2.20/install/boot
make ARCH=arm INSTALL_MOD_PATH=~/rpi-3.2.20/install CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- modules_install
make INSTALL_PATH=~/rpi-3.2.20/install/boot ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- INSTALLKERNEL=none install

Build the 8192cu kernel driver.

Copy and unpack the driver.

cd ~/rpi-3.2.20
wget http://www.gallot.be/resources/RTL819xCU_USB_linux_v3.4.2_3727.20120404.zip
unzip RTL819xCU_USB_linux_v3.4.2_3727.20120404.zip
cd RTL8188C_8192C_8192D_USB_linux_v3.4.2_3727.20120404/driver
tar -xvzf rtl8188C_8192C_8192D_usb_linux_v3.4.2_3727.20120404.tar.gz

Build the 8192cu kernel driver.

cd ~/rpi-3.2.20/RTL8188C_8192C_8192D_USB_linux_v3.4.2_3727.20120404/driver/rtl8188C_8192C_8192D_usb_linux_v3.4.2_3727.20120404
make KSRC=~/rpi-3.2.20/linux ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- -k -j5

Copy the 8192cu to the modules tree.

cp 8192cu.ko ~/rpi-3.2.20/install/lib/modules/3.2.20-spi-i2c-rpi1+/kernel/drivers/net/wireless

Install the new kernel

Now you simply need to install the new files to you sd card.
Plug you sd card, and if you are working from a virtual machine connect the sd card reader to the ubuntu vm.
The boot partition will be the fat partition, on my system it is mount into /media/00D7-4C15
The system partition is the ext2 partition, on my system it is mount into /media/1bee6d88-1731-433f-8f74-49a7c1ce1035

df -T
/dev/sdb1      vfat        102182   41764     60418  41% /media/00D7-4C15
/dev/sdb2      ext4       1824112 1054740    677980  61% /media/1bee6d88-1731-433f-8f74-49a7c1ce1035

Copy the new firmware

cp ~/rpi-3.2.20/firmware/boot/* /media/00D7-4C15

Copy the kernel and the modules

I really do not know if it is required to install the kernel in the boot partition and in the system partition ( in the /boot ).
But since it does not harm, I copy it on both location.

cp ~/rpi-3.2.20/install/boot/* /media/00D7-4C15
cp ~/rpi-3.2.20/install/boot/* /media/1bee6d88-1731-433f-8f74-49a7c1ce1035/boot
cp -R ~/rpi-3.2.20/install/lib/modules/* /media/1bee6d88-1731-433f-8f74-49a7c1ce1035/lib/modules

Activate the kernel

The latest firmware is not able to directly start the linux image, you do not need to create a disk image anymore.
So to activate it, simply override the kernel.img file with the new kernel.

cp /media/00D7-4C15/vmlinux-3.2.20-spi-i2c-rpi1+ /media/00D7-4C15/kernel.img

Final step

The only remaining step required to start you raspberry pi, and connect a keybord and a screen to it !

And issue a simple depmod command and reboot.

depmod -a
Reboot

I delibered choosed to not merge the RTL819x driver to the kernel source tree.
Doing so slighly complicate the process, but if you want to do it check the website of lumux which explain how to do it.
If you do so, this step is not required :)

The next article will explain how to modify this image make it usable without a keyboard by doing

  • Run the depmod -a on the first boot
  • Do an offline configuration of the wifi
  • Unattented installation of the required package like ssh

Credits:

http://blog.kmp.or.at/2012/05/build-your-own-raspberry-pi-image/
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=28&t=7585
http://www.bootc.net/archives/2012/05/11/updated-raspberry-pi-wheezy-image/
http://www.bootc.net/projects/raspberry-pi-kernel/
http://lumux.co.uk/2012/06/07/realtek-rtl8192curtl8192c-wifi-on-raspberrypi/
http://elinux.org/RPi_Kernel_Compilation

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

Username:
Password:
Url:
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

#!/usr/bin/php
setFetchMode(DB_FETCHMODE_ASSOC);

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 );
    }
    else
    {
      return( false );
    }
  }
}

  $log = new logfile();

  set_time_limit(0);
  define('STDIN',fopen("php://stdin","r"));
  while (!0)
  {
    $IP = trim(fgets(STDIN));
    if (feof(STDIN)) {
      break;
    }
    $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

CREATE TABLE ADULT_HOST (
  ID int(11) NOT NULL auto_increment,
  USER varchar(20) NOT NULL,
  IP varchar(20) NOT NULL,
  START timestamp NOT NULL default CURRENT_TIMESTAMP,
  END timestamp NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (ID)
)

Conclusion

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.