#!/bin/bash
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2012 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 . #
# #
###############################################################################
. /usr/lib/network/header-zone
HOOK_SETTINGS="HOOK ACCESS_CONCENTRATOR AUTH USERNAME PASSWORD"
HOOK_SETTINGS="${HOOK_SETTINGS} SERVICE_NAME MTU IPV6 PREFIX_DELEGATION"
# User credentials for the dialin.
USERNAME=""
PASSWORD=""
# Set the authentication mechanism.
AUTH=
# Access Concentrator.
ACCESS_CONCENTRATOR=""
# Service name.
SERVICE_NAME=""
# Maximum Transmission Unit.
MTU=
# This hook can work with all authentication methods supported by pppd.
PPPOE_SUPPORTED_AUTH_METHODS="${PPP_SUPPORTED_AUTH_METHODS}"
PPPOE_PLUGIN="rp-pppoe.so"
# Request an IPv6 address.
IPV6="true"
# Use IPv6 prefix delegation.
PREFIX_DELEGATION="true"
hook_check_settings() {
assert isset USERNAME
assert isset PASSWORD
isset AUTH && assert isoneof AUTH ${PPPOE_SUPPORTED_AUTH_METHODS}
assert isset IPV6
assert isset PREFIX_DELEGATION
}
hook_parse_cmdline() {
while [ $# -gt 0 ]; do
case "${1}" in
--access-concentrator=*)
ACCESS_CONCENTRATOR=$(cli_get_val "${1}")
;;
--auth=*)
AUTH=$(cli_get_val "${1}")
;;
--ipv6=*)
local value="$(cli_get_val "${1}")"
if enabled value; then
IPV6="true"
else
IPV6="false"
fi
;;
--mtu=*)
MTU=$(cli_get_val "${1}")
;;
--password=*)
PASSWORD=$(cli_get_val "${1}")
;;
--prefix-delegation=*)
PREFIX_DELEGATION="$(cli_get_bool "${1}")"
;;
--service-name=*)
SERVICE_NAME=$(cli_get_val "${1}")
;;
--username=*)
USERNAME=$(cli_get_val "${1}")
;;
*)
warning "Unknown argument: ${1}" >&2
;;
esac
shift
done
}
hook_up() {
local zone=${1}
assert isset zone
# If this zone's port is not set, we will return
# with EXIT_OK so that this zone will remain active,
# but we cannot start pppd.
local port=$(__hook_get_port "${zone}")
if ! isset port || ! port_exists "${port}"; then
log WARNING "Could not bring up zone '${zone}' because no port is attached"
exit ${EXIT_OK}
fi
zone_settings_read "${zone}"
# Load the pppoe kernel module
module_load "pppoe"
# Bring up the port.
port_up "${port}"
# Start the ppp daemon.
pppd_start ${zone}
exit ${EXIT_OK}
}
hook_down() {
local zone=${1}
assert isset zone
zone_settings_read "${zone}"
# Stop the ppp daemon.
pppd_stop ${zone}
# Bring down the port.
local port=$(__hook_get_port "${zone}")
if isset port; then
log DEBUG "Bringing down port '${port}'"
port_down "${port}"
fi
exit ${EXIT_OK}
}
hook_hotplug() {
local zone="${1}"
case "$(hotplug_action)" in
add)
if hotplug_event_interface_is_port_of_zone "${zone}"; then
# Bring up the zone if it is enabled but not active, yet.
zone_start_auto "${zone}"
exit ${EXIT_OK}
fi
;;
remove)
# PPPoE cannot work if the ethernet device has been removed
if hotplug_event_interface_is_port_of_zone "${zone}"; then
if zone_is_active "${zone}"; then
zone_stop "${zone}"
fi
exit ${EXIT_OK}
fi
;;
esac
exit ${EXIT_NOT_HANDLED}
}
hook_discover() {
local device=${1}
# This obviously only works on ethernet (or compatible) devices
if ! device_is_ethernet_compatible "${device}"; then
exit ${EXIT_ERROR}
fi
local output
output=$(pppoe-discovery -I ${device} -U $(uuid) 2>&1)
# Exit if there was not output
[ -z "${output}" ] && exit ${DISCOVER_ERROR}
# Exit if PADI timed out
grep -q "Timeout" <<<${output} && exit ${DISCOVER_ERROR}
local ac
while read line; do
case "${line}" in
Access-Concentrator:*)
ac="${line#Access-Concentrator: }"
;;
esac
done <<<"${output}"
echo "ACCESS_CONCENTRATOR=\"$ac\""
exit ${DISCOVER_OK}
}
hook_status() {
local zone=${1}
assert isset zone
cli_device_headline ${zone}
zone_settings_read "${zone}"
cli_headline 2 "Configuration"
cli_print_fmt1 2 "Username" "${USERNAME}"
cli_print_fmt1 2 "Password" ""
local port=$(__hook_get_port "${zone}")
if isset port; then
cli_print_fmt1 2 "Port" "${port}"
fi
cli_space
# Exit if zone is down
if ! zone_is_up ${zone}; then
echo # Empty line
exit ${EXIT_ERROR}
fi
# XXX display time since connection started
cli_headline 2 "Point-to-Point-over-Ethernet protocol"
cli_print_fmt1 2 "MAC-Remote" "$(db_get "${zone}/remote-address")"
cli_space
local proto
for proto in ${IP_SUPPORTED_PROTOCOLS}; do
db_exists "${zone}/${proto}" || continue
local headline
case "${proto}" in
ipv6)
headline="Internet Protocol Version 6"
;;
ipv4)
headline="Internet Protocol Version 4"
;;
*)
headline="Unkown protocol"
;;
esac
cli_headline 3 "${headline}"
cli_print_fmt1 3 "IP address" "$(db_get "${zone}/${proto}/local-ip-address")"
cli_print_fmt1 3 "Gateway" "$(db_get "${zone}/${proto}/remote-ip-address")"
cli_print_fmt1 3 "DNS servers" "$(db_get "${zone}/${proto}/domain-name-servers")"
cli_space
done
exit ${EXIT_OK}
}
hook_ppp_write_config() {
local zone=${1}
assert isset zone
local file=${2}
assert isset file
# Read in the configuration files.
zone_settings_read "${zone}"
# A port has to be assigned for this action
local port=$(__hook_get_port "${zone}")
if ! isset port; then
error "No port assigned to pppoe hook of zone '${zone}'"
exit ${EXIT_ERROR}
fi
# Prepare the command line options for the pppoe plugin.
local plugin_options
# Add the access concentrator (if any).
if isset ACCESS_CONCENTRATOR; then
plugin_options="${plugin_options} rp_pppoe_ac '${ACCESS_CONCENTRATOR}'"
fi
# Add the service name (if any).
if isset SERVICE_NAME; then
plugin_options="${plugin_options} rp_pppoe_service '${SERVICE_NAME}'"
fi
# The last argument must be the interface.
plugin_options="${plugin_options} ${port}"
pppd_write_config ${file} \
--interface="${zone}" \
--username="${USERNAME}" \
--password="${PASSWORD}" \
--mtu="${MTU}" \
--auth="${AUTH}" \
--ipv6="${IPV6}" \
\
--plugin="${PPPOE_PLUGIN}" \
--plugin-options="${plugin_options}"
exit ${EXIT_OK}
}
__hook_get_port() {
local zone="${1}"
local port
for port in $(zone_get_ports "${zone}"); do
echo "${port}"
return ${EXIT_OK}
done
return ${EXIT_ERROR}
}
hook_port_attach() {
# Excepting at least two arguments here
assert [ $# -ge 2 ]
local zone="${1}"
local port="${2}"
shift 2
# PPPoE can only use one port
local ports_num="$(zone_get_ports_num "${zone}")"
if [ ${ports_num} -ge 1 ]; then
local ports="$(zone_get_ports "${zone}")"
error "The pppoe zone hook only supports assigning one port"
error " port '${ports}' has already been assigned to zone '${zone}'"
return ${EXIT_ERROR}
fi
if ! zone_port_settings_write "${zone}" "${port}"; then
exit ${EXIT_ERROR}
fi
exit ${EXIT_OK}
}
hook_port_detach() {
assert [ $# -eq 2 ]
local zone="${1}"
local port="${2}"
# Shut down the entire zone here, because it cannot
# run without a port any way and removing the port would
# create a hotplug event which will be processed after the
# port has already been detached...
zone_stop "${zone}"
if ! zone_port_settings_remove "${zone}" "${port}"; then
exit ${EXIT_ERROR}
fi
exit ${EXIT_OK}
}
hook_port_up() {
assert [ $# -eq 2 ]
local zone="${1}"
local port="${2}"
# Try bringing up the port if it has not been brought up before
if ! device_exists "${port}"; then
port_create "${port}"
fi
# Make sure that the port is up
port_up "${port}"
exit ${EXIT_OK}
}
hook_port_down() {
assert [ $# -eq 2 ]
local zone="${1}"
local port="${2}"
if device_exists "${port}"; then
port_down "${port}"
fi
exit ${EXIT_OK}
}
hook_ppp_ipv6_up() {
local zone="${1}"
ppp_common_ipv6_up "${zone}"
# Read configuration
zone_settings_read "${zone}"
if enabled PREFIX_DELEGATION; then
dhclient_start "${zone}" ipv6
fi
exit ${EXIT_OK}
}
hook_ppp_ipv6_down() {
local zone="${1}"
ppp_common_ipv6_down "${zone}"
# Read configuration
zone_settings_read "${zone}"
if enabled PREFIX_DELEGATION; then
dhclient_stop "${zone}" ipv6
fi
exit ${EXIT_OK}
}