Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 202 lines (177 sloc) 6 KB
#!/bin/sh
# vim:tw=80:tabstop=2:shiftwidth=2:expandtab
# Copyright (c) 2012-present, Phil Dibowitz <phil@ipom.com>
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in
# binary form must reproduce the above copyright notice, this list of
# conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
# * Neither the name of the author nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# You can find the latest version of this at:
# https://github.com/jaymzh/v6-gw-scripts
#
# Will, given a 'dhclient -6 -P ...' on $EXT_IFACE and assign the prefix
# given to the $INT_IFACE, and twiddle radvd.
#
# For radvd, it takes /etc/radvd.conf.tmpl, replaces "__PREFIX__" with your
# prefix, and "__IFACE__" with your internal interface, and - if it's different
# from /etc/radvd.conf - replaces the config file and restarts the daemon.
#
# Change INT_IFACE or EXT_IFACE by setting them in the config file
CONF='/etc/ipv6_prefix_dhclient.conf'
EXT_IFACE='eth0'
INT_IFACE='eth1'
OTHER_IFACES=''
RADVD_TEMPLATE='/etc/radvd.conf.tmpl'
[ -r $CONF ] && . $CONF
STATE_DIR=/var/lib/dhcp/dhclient-ipv6-mapping
set_iaid_mapping() {
local iaid="$1"
local iface="$2"
echo $iface > "$STATE_DIR/iaid_$iaid"
}
get_interface() {
local iaid=$1
if [ ! -d $STATE_DIR ]; then
mkdir -p $STATE_DIR
set_iaid_mapping "$iaid" "$INT_IFACE"
echo $INT_IFACE
return
fi
ls $STATE_DIR/iaid_* >/dev/null 2>/dev/null
if [ $? -eq 2 ]; then
echo $INT_IFACE
set_iaid_mapping "$iaid" "$INT_IFACE"
fi
# if we've mapped this iaid to an interface, just cat it out
if [ -e "$STATE_DIR/iaid_$iaid" ]; then
iface=`cat "$STATE_DIR/iaid_$iaid"`
# we're not changing the mapping, but we call update anyway mostly
# as a `touch` for the code below that checks the time
echo $iface
set_iaid_mapping "$iaid" "$iface"
return
fi
# we haven't - so let's see if we have an interfaces not-yet-mapped
known=""
for file in $STATE_DIR/iaid_*; do
known="$known `cat $file`"
done
for iface in $INT_IFACE $OTHER_IFACES; do
for kface in $known; do
if [ "$kface" = "$iface" ]; then
continue 2
fi
done
# This interface is not yet mapped, return it
echo $iface
set_iaid_mapping "$iaid" "$iface"
return
done
# OK, all of our interfaces are mapped, but none of them is this one, so we'll
# just return the least-recently touched file. This is a bit odd, because
# we'll end up populating them in the reverse order, but we won't just end up
# re-doing one we just did
last=`ls -t $STATE_DIR/iaid_* | tail -n 1`
iface=`cat "$last"`
rm -f "$last"
echo $iface
set_iaid_mapping "$iaid" "$iface"
}
get_prefix() {
local iface="$1"
current_ip=`/sbin/ip -6 addr show dev $iface scope global |\
/usr/bin/awk '/inet6/ {print $2}'`
echo $current_ip | /bin/sed -e 's@::1/64@::/64@'
}
update_radvd() {
local iface="$1"
local prefix="$2"
tmpfile="/tmp/radvd.conf.$$"
rm -f "$tmpfile"
for tface in $INT_IFACE $OTHER_IFACES; do
if [ "$iface" = "$tface" ]; then
sed -e "s@__PREFIX__@$prefix@g" \
-e "s@__IFACE__@$iface@g" $RADVD_TEMPLATE \
>> $tmpfile
else
tprefix=`get_prefix $tface`
if [ -z "$tprefix" ]; then
continue
fi
sed -e "s@__PREFIX__@$tprefix@g" \
-e "s@__IFACE__@$tface@g" $RADVD_TEMPLATE \
>> $tmpfile
fi
done
diff $tmpfile /etc/radvd.conf >/dev/null 2>/dev/null
if [ $? -ne 0 ]; then
# Update config and restart radvd
mv $tmpfile /etc/radvd.conf
service radvd restart
else
rm $tmpfile
# ensure it's running anyway
service radvd start
fi
}
ipv6_prefix_setup() {
local iface=`get_interface "$new_iaid"`
local current_prefix=`get_prefix $iface`
if [ -z "$current_prefix" ] || \
! [ "$current_prefix" = "$new_ip6_prefix" ] ; then
# Setup the new IP
new_ip=`echo $new_ip6_prefix | /bin/sed -e 's@::/64@::1/64@g'`
if [ ! -z "$current_ip" ] ; then
ip -6 addr del $current_ip dev $iface
fi
ip -6 addr add $new_ip dev $iface
# Ensure we'll get router advertisements
sysctl -w "net.ipv6.conf.$EXT_IFACE.accept_ra=2"
# Needed for kernels before 2.6.37, don't worry,
# forwarding will still work as long as you have it set
# on your other interface.
sysctl -w "net.ipv6.conf.$EXT_IFACE.forwarding=0"
fi
update_radvd "$iface" "$new_ip6_prefix"
}
if [ "$interface" != "$EXT_IFACE" ] ; then
return
fi
case "$reason" in
BOUND6|REBIND6)
# We will get called twice here - once for the temp address
# and once for the prefix. We only care about the prefix.
if [ ! -z "$new_ip6_prefix" ] ; then
ipv6_prefix_setup
fi
;;
RELEASE)
if [ -e /var/run/dhclient6.eth0.pid ]; then
echo 'Shutting down dhclient6'
kill `cat /var/run/dhclient6.eth0.pid`
fi
;;
esac
You can’t perform that action at this time.