#!/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=( "ACCESS_CONCENTRATOR" "AUTH" "USERNAME" "PASSWORD" "SERVICE_NAME" "MTU" "IPV6" "PREFIX_DELEGATION" ) # 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. DEFAULT_IPV6="true" # Use IPv6 prefix delegation. DEFAULT_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} }