Introduces a hook that can connect to 6rd border relay servers.
###############################################################################
# #
# IPFire.org - A linux based firewall #
-# Copyright (C) 2012 IPFire Network Development Team #
+# Copyright (C) 2012-2013 IPFire Network Development Team #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
while [ $# -gt 0 ]; do
case "${1}" in
--mode=*)
- mode=$(cli_get_val ${1})
+ mode="$(cli_get_val ${1})"
;;
--ttl=*)
- ttl=$(cli_get_val ${1})
+ ttl="$(cli_get_val ${1})"
;;
--remote-address=*)
- remote_address=$(cli_get_val ${1})
+ remote_address="$(cli_get_val ${1})"
;;
--local-address=*)
- local_address=$(cli_get_val ${1})
+ local_address="$(cli_get_val ${1})"
;;
esac
shift
# If TTL is set, make sure it is an integer.
isset ttl && assert isinteger ttl
- assert isset remote_address
assert isset local_address
local cmd_args
cmd_args="${cmd_args} ttl ${ttl}"
fi
+ # Apply remote address if a value has been set.
+ if isset remote_address; then
+ cmd_args="${cmd_args} remote ${remote_address}"
+ fi
+
log DEBUG "Creating tunnel device '${device}' (mode=${mode})..."
# Create the device.
cmd ip tunnel add ${device} mode ${mode} \
- remote ${remote_address} local ${local_address} ${cmd_args}
+ local ${local_address} ${cmd_args}
assert [ $? -eq 0 ]
}
-
function ip_tunnel_del() {
local device=${1}
assert device_exists ${device}
ip tunnel del ${device}
assert [ $? -eq 0 ]
}
+
+function ip_tunnel_6rd_set_prefix() {
+ local device="${1}"
+ assert isset device
+
+ local prefix="${2}"
+ assert isset prefix
+
+ # Validate the prefix.
+ assert ipv6_is_valid "${prefix}"
+
+ log INFO "Setting 6rd-prefix ${prefix} on ${device}"
+
+ # Set the prefix.
+ cmd ip tunnel 6rd dev "${device}" 6rd-prefix "${prefix}"
+ assert [ $? -eq 0 ]
+}
return ${EXIT_TRUE}
}
+function ipv6_get_prefix() {
+ ip_get_prefix "$@"
+}
+
+function ipv6_split_prefix() {
+ ip_split_prefix "$@"
+}
+
function ipv6_implode() {
local address=${1}
assert isset address
print "${PREFIX6}/${prefix}"
}
+
+function ipv6_6rd_format_address() {
+ local isp_prefix="${1}"
+ assert ipv6_is_valid "${isp_prefix}"
+
+ local client_address="${2}"
+ assert ipv4_is_valid "${client_address}"
+
+ local prefix="$(ipv6_get_prefix "${isp_prefix}")"
+ isp_prefix="$(ipv6_split_prefix "${isp_prefix}")"
+
+ # This only works for prefix lengths up to 32 bit.
+ assert [ "${prefix}" -le 32 ]
+ assert [ "${prefix}" -gt 0 ]
+
+ # Explode the address and throw away the second 32 bit.
+ local address="$(ipv6_explode "${isp_prefix}")"
+
+ client_address="$(ipv6_6rd_format_client_address ${client_address})"
+ assert isset client_address
+
+ local block1="0x${address:0:4}"
+ local block2="0x${address:5:4}"
+ local block3="0x${address:10:4}"
+ local block4="0x${address:15:4}"
+
+ address="$(( (${block1} << 48) + (${block2} << 32) + (${block3} << 16) + ${block4} ))"
+ assert [ "${address}" -gt 0 ]
+
+ block1="0x${client_address:0:4}"
+ block2="0x${client_address:5:4}"
+
+ client_address="$(( (${block1} << 48) + (${block2} << 32) ))"
+
+ # Fix for numbers that are interpreted by bash as negative
+ # numbers and therefore filled up with ones when shifted to
+ # the right. Weird.
+ if [ "${client_address}" -gt 0 ]; then
+ client_address="$(( ${client_address} >> ${prefix} ))"
+ else
+ local bitmask="$(( 1 << 63 ))"
+ client_address="$(( ${client_address} >> 1 ))"
+ client_address="$(( ${client_address} ^ ${bitmask} ))"
+ client_address="$(( ${client_address} >> $(( ${prefix} - 1 )) ))"
+ fi
+ assert [ "${client_address}" -gt 0 ]
+
+ # XOR everything together
+ address="$(( ${address} ^ ${client_address} ))"
+ prefix="$(( ${prefix} + 32 ))"
+
+ local block formatted_address=":"
+ while [ ${address} -gt 0 ]; do
+ printf -v block "%x" "$(( ${address} & 0xffff ))"
+ formatted_address="${block}:${formatted_address}"
+
+ address="$(( ${address} >> 16 ))"
+ done
+
+ assert ipv6_is_valid "${formatted_address}"
+
+ # Implode the output IP address.
+ formatted_address="$(ipv6_implode "${formatted_address}")"
+
+ print "${formatted_address}/${prefix}"
+}
+
+function ipv6_6rd_format_client_address() {
+ local address="${1}"
+ assert isset address
+
+ print "%02x%02x:%02x%02x" ${address//\./ }
+}
--- /dev/null
+#!/bin/bash
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2013 IPFire Network Development Team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+. /usr/lib/network/header-zone
+
+HOOK_SETTINGS="HOOK SIX_RD_PREFIX LOCAL_ADDRESS PUBLIC_ADDRESS SERVER_ADDRESS"
+
+# The address that is assigned to the tunnel device (with prefix).
+SIX_RD_PREFIX=""
+
+# The local IPv4 address of the tunnel endpoint.
+# For usage if the endpoint is in a pre-routed network.
+LOCAL_ADDRESS=""
+
+# The IPv4 address of the tunnel endpoint where to connect to.
+SERVER_ADDRESS=""
+
+# The public IPv4 address of the tunnel client.
+PUBLIC_ADDRESS=""
+
+function _check() {
+ assert isset SIX_RD_PREFIX
+ assert isset PUBLIC_ADDRESS
+ assert isset SERVER_ADDRESS
+
+ # Check if an optional local address has been specified or use the public address instead.
+ if [ -z "${LOCAL_ADDRESS}" ]; then
+ LOCAL_ADDRESS="${PUBLIC_ADDRESS}"
+ fi
+
+ assert isset LOCAL_ADDRESS
+
+ # Check input.
+ if ! ipv6_is_valid "${SIX_RD_PREFIX}"; then
+ log ERROR "Invalid 6rd prefix. Please use a valid IPv6 prefix."
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipv4_is_valid "${SERVER_ADDRESS}"; then
+ log ERROR "Invalid server address. Please use a valid IPv4 address."
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipv4_is_valid "${PUBLIC_ADDRESS}"; then
+ log ERROR "Invalid public address. Please use a valid IPv4 address."
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipv4_is_valid "${LOCAL_ADDRESS}"; then
+ log ERROR "Invalid local address. Please use a valid IPv4 address."
+ return ${EXIT_ERROR}
+ fi
+}
+
+function _parse_cmdline() {
+ local value
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --6rd-prefix=*)
+ SIX_RD_PREFIX=$(cli_get_val ${1})
+ ;;
+ --server-address=*)
+ SERVER_ADDRESS=$(cli_get_val ${1})
+ ;;
+ --local-ipv4-address=*)
+ LOCAL_ADDRESS=$(cli_get_val ${1})
+ ;;
+ --public-address=*)
+ PUBLIC_ADDRESS=$(cli_get_val ${1})
+ ;;
+ *)
+ echo "Unknown option: ${1}" >&2
+ exit ${EXIT_ERROR}
+ ;;
+ esac
+ shift
+ done
+}
+
+function _up() {
+ local zone="${1}"
+ assert isset zone
+
+ # Read configuration options.
+ zone_config_read "${zone}"
+
+ # Configure the tunnel.
+ if ! device_exists "${zone}"; then
+ ip_tunnel_add "${zone}" \
+ --ttl=64 \
+ --local-address="${LOCAL_ADDRESS}"
+ fi
+
+ # Set 6rd prefix.
+ ip_tunnel_6rd_set_prefix "${zone}" "${SIX_RD_PREFIX}"
+
+ # Bring up the device.
+ device_set_up "${zone}"
+
+ # Update routing information.
+ routing_db_set "${zone}" ipv6 "type" "${HOOK}"
+ routing_db_set "${zone}" ipv6 "local-ip-address" "::${LOCAL_ADDRESS}"
+ routing_db_set "${zone}" ipv6 "remote-ip-address" "::${SERVER_ADDRESS}"
+ routing_db_set "${zone}" ipv6 "active" 1
+
+ # Update the routing database.
+ routing_update ${zone} ipv6
+ routing_default_update
+
+ exit ${EXIT_OK}
+}
+
+function _down() {
+ local zone=${1}
+ assert isset zone
+
+ # Remove everything from the routing db.
+ routing_db_remove ${zone} ipv6
+ routing_update ${zone} ipv6
+ routing_default_update
+
+ # Remove the tunnel device.
+ ip_tunnel_del ${zone}
+
+ exit ${EXIT_OK}
+}
+
+function _status() {
+ local zone=${1}
+ assert isset zone
+
+ cli_device_headline ${zone}
+
+ zone_config_read ${zone}
+
+ local server_line="${SERVER_ADDRESS}"
+ local server_hostname=$(dns_get_hostname ${SERVER_ADDRESS})
+ if [ -n "${server_hostname}" ]; then
+ server_line="${server_line} (Hostname: ${server_hostname})"
+ fi
+
+ cli_headline 2 "Configuration"
+ cli_print_fmt1 2 "Server" "${server_line}"
+ cli_print_fmt1 2 "6rd Prefix" "${SIX_RD_PREFIX}"
+ cli_space
+
+ # Generate the IPv6 prefix from the given 6rd Prefix and the Public IPv4 Address.
+ local six_rd_address="$(ipv6_6rd_format_address "${SIX_RD_PREFIX}" "${PUBLIC_ADDRESS}")"
+
+ cli_headline 2 "Tunnel properties"
+ cli_print_fmt1 2 "IPv6 Subnet" "${six_rd_address}"
+ cli_space
+
+ exit ${EXIT_OK}
+}