Distributing IPv6 addresses accross your web server's users

If you have a dedicated web server you're most likely IPv6-ready today. Although you're propably hosting multiple domains and users, they share one IP. For some use cases (e.g. SSL for web sites) users should have their own IP.

While this is difficult due to the limited numbers of IPs in the v4-world, you can give each user its own IPv6 address. In the near future most visitors will us IPv6 anyway.

The idea

The basic idea is to give each user an IP address which represent its system user-ID (UID). Therefore I invented a quasi-subnet which is simply made by my definition. In this 'subnet' all user IPs are in. I tried to avoid using all the last 64 bits because usually network interfaces use them to create their IPs (derived from MAC).

Since you need to configure all your Virtual Hosts by hand anyway (apache2: VirtualHost, ServerName etc.), at least you can automate the available IPv6 adresses on your machine. As one interface can be set up to serve an unlimited number of IPs you don't need to have multiple interfaces. But you still have to add those addresses to the interface's config. This may be dozens of addresses but can be done by automagic.

I decided to use scripts which add the IPv6 addresses to the interface eth0 programmatically. The IPv6s itselves are generated from a virtual prefix (the 'quasi-subnet') and use users' UID as last 16 bytes to create valid IPv6 addresses. The system is ubuntu/debian based and uses traditional network management with ifup and ifdown.

The following examples assume that...

  • all your web users are all members of one group (e.g. www-users) which has the GID 33,
  • the example user has the UID 1001 which is in hex 3e9,
  • you have received a /64-prefix (you're on one single machine no 'virtual' subnet), 
  • your prefix is 2001:db8:10:20 (actually that's beneath the documentation prefix, rfc 3849),
  • and your quasi-subnet's prefix is therefore 2001:db8:10:20::80 (I chose ::80 because it is easy to remember in context of web servers).

Given the above details your users' IPs will be within the range of 2001:db8:10:20::80:0000 to 2001:db8:10:20::80:ffff. You just defined - more or less - your own subnet

Your apache2 will most likely listen to all IPs by default

Most installations I have seen are preconfigured to listen to all addresses of all interfaces regardless they are IPv6 or traditional. Usually httpd.conf only care about the ports 80 and 443 (see for debain/ubuntu: /etc/apache2/ports.conf):

NameVirtualHost *:80
Listen 80

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
    Listen 443
</IfModule>

<IfModule mod_gnutls.c>
    Listen 443
</IfModule>

It is your task to set the correct IPs for every user within the site's configuration file. Acknowledge the last bits "3e9" as hex representation of UID 1001!

<VirtualHost 1.2.3.4:80 [2001:db8:10:20::80:3e9]:80>
        ServerName example.com
...
AssignUserId wwwuser1 www-users
...
</VirtualHost>

So far the (manual) configuration of apache.

Automate address allocation for interface

To enable apache2 listening on the IPs you need to make them known to the interface. You can use the following scripts which have to be made executable before.

chmod +x /etc/network/if-up.d/userIPs
chmod +x /etc/network/if-down.d/userIPs

1) To add IPv6s on startup

/etc/network/if-up.d/userIPs:

#!/bin/bash

#
# Going UP only for inet6 (not inet) || invoked by console
#

if [ "$1" == "add" ]; then
 ADDRFAM=inet6
 IFACE=`cat /etc/network/interfaces | grep iface | grep inet6 | cut -d ' ' -f 2`
 METHOD=static
 MODE=start
 PHASE=manually
fi

[[ "$ADDRFAM" != "inet6" ]] && exit 0;

#
# Setting of users' group and ip-prefix (last bit will be user)
#

WWWGROUPID=33
IPPREFIX=2001:db8:10:20::80:

#
# Add only IPs which aren't set already
#

WWWUSERS=`cat /etc/passwd | cut -d ':' -f 1,3,4 | grep ":$WWWGROUPID"`
EXISTING=`ifconfig $IFACE | tr -s ' ' | cut -d ' ' -f 3 | grep $IPPREFIX`
COUNTER=0

for I in $WWWUSERS; do
 WWWUID=`echo $I | cut -d ':' -f 2`
 ## convert to hex
GENIP=$IPPREFIX`echo "ibase=10;obase=16;$WWWUID" | bc`
 if [[ "${EXISTING[@]}" == *"$GENIP"* ]]; then
  echo Cannot add IP $GENIP for user `echo $I | cut -d ':' -f 1` - this IP is already in use.
 else
  ip -6 addr add $GENIP/64 dev $IFACE
  let COUNTER=COUNTER+1
 fi
done

#
# Show Result
#

bold=`tput -T xterm bold`
normal=`tput -T xterm sgr0`
echo ${bold}$IFACE \($METHOD\):${normal} Added $COUNTER user-IPv6s for apache2 ${bold}$MODE/$PHASE${normal}

2) To delete IPv6s before shutting down the interface

/etc/network/if-down.d/userIPs:

#!/bin/bash

#
# Setting of ip-prefix (last bit will be user)
#

IPPREFIX=2001:db8:10:20::80:

#
# Delete only IPs which are already set
#

EXISTING=`ifconfig $IFACE | tr -s ' ' | cut -d ' ' -f 4 | grep $IPPREFIX`
COUNTER=0

for I in $EXISTING; do
 ip -6 addr del $I dev $IFACE
 let COUNTER=COUNTER+1
done

#
# Show Result
#

bold=`tput -T xterm bold`
normal=`tput -T xterm sgr0`

echo ${bold}$IFACE \($METHOD\):${normal} Deleted $COUNTER user-IPv6s for apache2 ${bold}$MODE/$PHASE${normal}

3) Manually complete addresses after adding new users

If you just have added another user you can run the script 1) with the parameter add:

# /etc/network/if-up.d/userIPs add

Conclusion

Although you can't automate apache2 config (who wants that?), you can at least make sure that apache2 gets its IPs to listen on. You can make sure that all IPv6 are active by invoking:

# ifconfig eth0

Please diskuss this approach below.

Geben Sie einen Kommentar ab

Kommentare

Bisher hat niemand diese Seite kommentiert.

RSS Feed für die Kommentare auf dieser Seite | RSS feed für alle Kommentare