From: Michael Tremer Date: Sat, 23 Jun 2012 20:38:11 +0000 (+0000) Subject: pppoe-server: New (client) hook. X-Git-Tag: 004~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=999d659bc956ef2a57c0d3d6c359fd712fcdc9da;p=network.git pppoe-server: New (client) hook. --- diff --git a/Makefile b/Makefile index 0fb47447..e118ae86 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,9 @@ install: ln -svf ip-updown $(DESTDIR)$(sysconfdir)/ppp/ipv6-down install -m 755 -v ppp/dialer $(DESTDIR)$(sysconfdir)/ppp + # Install pppoe-server wrapper. + install -m 755 ppp/pppoe-server $(DESTDIR)$(libdir)/network/ + # Create the version file. : > $(VERSION_FILE) echo "# This file is automatically generated." >> $(VERSION_FILE) diff --git a/functions.ipv4 b/functions.ipv4 index aada214a..a3b3ce46 100644 --- a/functions.ipv4 +++ b/functions.ipv4 @@ -133,3 +133,147 @@ function ipv4_prefix2netmask() { ;; esac } + +function ipv4_get_network() { + local net=${1} + + local prefix=$(ip_get_prefix ${net}) + isset prefix || prefix=32 + + local mask=0 + if [ ${prefix} -ne 0 ]; then + mask=$(( -1 << $(( 32 - ${prefix} )) )) + fi + + local addr=$(ip_split_prefix ${net}) + addr=$(ipv4_encode ${addr}) + + ipv4_decode $(( ${addr} & ${mask} )) +} + +function ipv4_get_broadcast() { + local net=${1} + + local prefix=$(ip_get_prefix ${net}) + assert isset prefix + + prefix=$(( 32 - ${prefix} )) + + local netmask=0 + local broadcast=-1 + if [ ${prefix} -eq 32 ]; then + : + else + netmask=$(( -1 << ${prefix} )) + broadcast=$(( $(( 1 << ${prefix} )) - 1)) + fi + + local addr=$(ip_split_prefix ${net}) + addr=$(ipv4_encode ${addr}) + + ipv4_decode $(( $(( ${addr} & ${netmask} )) | ${broadcast} )) +} + +function ipv4_encode() { + local addr=${1} + local int=0 + + local field + for field in ${addr//./ }; do + int=$(( $(( ${int} << 8 )) | ${field} )) + done + + print "${int}" +} + +function ipv4_decode() { + local int=${1} + + local addr=$(( ${int} & 255 )) + + local i + for i in 1 2 3; do + int=$(( ${int} >> 8 )) + addr="$(( ${int} & 255 )).${addr}" + done + + print "${addr}" +} + +function ipv4_range() { + local range=${1} + + local first=${1%-*} + local last=${1#*-} + + _ipv4_range "$(ipv4_encode ${first})" "$(ipv4_encode ${last})" +} + +function _ipv4_range() { + local first=${1} + local last=${2} + + if [ ${first} -gt ${last} ]; then + local range="$(ipv4_decode ${first})-$(ipv4_decode ${last})" + + error "Invalid IPv4 address range: ${range}" + return ${EXIT_ERROR} + fi + + last=$(( ${last} + 1 )) + + local prefix + local x y z + while [ ${last} -gt ${first} ]; do + prefix= + x=31 + y=2 + z=1 + + while [ $(( ${first} % ${y} )) -eq 0 ] && [ ${last} -gt $(( ${first} + ${y} )) ]; do + prefix="/${x}" + x=$(( ${x} - 1 )) + z=${y} + y=$(( ${y} * 2 )) + done + + print "$(ipv4_decode ${first})${prefix}" + first=$(( ${first} + ${z} )) + done +} + +function ipv4_range_explicit() { + local range=${1} + + local first last + + case "${range}" in + *.*.*.*-*.*.*.*) + first=${range%-*} + last=${range#*-} + ;; + *.*.*.*/*) + first=$(ipv4_get_network ${range}) + last=$(ipv4_get_broadcast ${range}) + ;; + esac + + _ipv4_range_explicit "$(ipv4_encode ${first})" "$(ipv4_encode ${last})" +} + +function _ipv4_range_explicit() { + local first=${1} + local last=${2} + + if [ ${first} -gt ${last} ]; then + local range="$(ipv4_decode ${first})-$(ipv4_decode ${last})" + + error "Invalid IPv4 address range: ${range}" + return ${EXIT_ERROR} + fi + + while [ ${first} -le ${last} ]; do + ipv4_decode ${first} + first=$(( ${first} + 1 )) + done +} diff --git a/functions.pppoe-server b/functions.pppoe-server new file mode 100644 index 00000000..fa1f2835 --- /dev/null +++ b/functions.pppoe-server @@ -0,0 +1,183 @@ +#!/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 . # +# # +############################################################################### + +function pppoe_server_start() { + local zone=${1} + assert isset zone + + service_start "pppoe-server@${zone}" +} + +function pppoe_server_stop() { + local zone=${1} + assert isset zone + + service_stop "pppoe-server@${zone}" +} + +function pppoe_server_status() { + local zone=${1} + assert isset zone + + service_status "pppoe-server@${zone}" +} + +function pppoe_server_options() { + local file=${1} + assert isset file + + local zone=${2} + assert isset zone + + shift 2 + + local auth="false" + local default_asyncmap="true" + local dns_servers + local lcp_echo_failure=5 + local lcp_echo_interval=60 + local proxyarp="true" + local required_auths + local value + + while [ $# -gt 0 ]; do + case "${1}" in + --auth=*) + auth=$(cli_get_val ${1}) + ;; + --default-asyncmap=*) + default_asyncmap=$(cli_get_val ${1}) + ;; + --dns-server=*) + dns_servers="${dns_servers} $(cli_get_val ${1})" + ;; + --lcp-echo-failure=*) + lcp_echo_failure=$(cli_get_val ${1}) + assert isinteger ${lcp_echo_failure} + ;; + --lcp-echo-interval=*) + lcp_echo_interval=$(cli_get_val ${1}) + assert isinteger ${lcp_echo_interval} + ;; + --proxyarp=*) + proxyarp=$(cli_get_val ${1}) + ;; + --require-auth=*) + required_auths="${required_auths} $(cli_get_val ${1})" + ;; + esac + shift + done + + mkdir -p $(dirname ${file}) 2>/dev/null + config_header "pppoe-server options configuration file" > ${file} + + # Authentication + ( + print "# Authentication" + if enabled auth; then + print "auth" + else + print "noauth" + fi + print + ) >> ${file} + + # If there are only a number of auth algorithms allowed, we + # define them here. + if isset required_auths; then + print "# Required authentication methods" >> ${file} + local method + for method in ${required_auths}; do + print "require-${method}" + done >> ${file} + print >> ${file} + fi + + # DNS servers + if isset dns_servers; then + print "# DNS servers" >> ${file} + local server + for server in ${dns_servers}; do + print "ms-dns ${server}" + done >> ${file} + print >> ${file} + fi + + # Default asyncmap + if enabled default_asyncmap; then + ( + print "# Default asyncmap" + print "default-asyncmap" + print + ) >> ${file} + fi + + # LCP settings. + ( + print "# LCP settings" + print "lcp-echo-failure ${lcp_echo_failure}" + print "lcp-echo-interval ${lcp_echo_interval}" + print + ) >> ${file} + + # Proxy ARP + ( + print "# Proxy ARP" + if enabled proxyarp; then + print "proxyarp" + else + print "noproxyarp" + fi + print + ) >> ${file} + + # Default options, we always set. + ( + print "debug" + print "nodefaultroute" + print "noipdefault" + print "noipx" + ) >> ${file} + + return ${EXIT_OK} +} + +function pppoe_server_poolfile() { + local file=${1} + assert isset file + + local subnet=${2} + assert isset subnet + + config_header "PPPoE server IP address pool file" > ${file} + + # The network address will be the gateway address. + local netaddr=$(ipv4_get_network ${subnet}) + + local addr + for addr in $(ipv4_range_explicit ${subnet}); do + [ "${addr}" = "${netaddr}" ] && continue + print "${addr}" + done >> ${file} + + return ${EXIT_OK} +} diff --git a/hooks/zones/bridge.configs/pppoe-server b/hooks/zones/bridge.configs/pppoe-server new file mode 100755 index 00000000..a3727f0f --- /dev/null +++ b/hooks/zones/bridge.configs/pppoe-server @@ -0,0 +1,113 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2010 Michael Tremer & Christian Schmidt # +# # +# 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-config + +HOOK_SETTINGS="HOOK MTU SERVICE_NAME SUBNET" + +# Maximum Transmission Unit. +MTU=1492 + +# Service Name. +SERVICE_NAME= + +# A subnet. Addresses from this subnet will be given to the remote hosts. +# The net address will be the gateway address for the PPPoE server. +SUBNET= + +function _check() { + assert isset MTU + assert isset SUBNET +} + +function _create() { + local zone=${1} + shift + + while [ $# -gt 0 ]; do + case "${1}" in + --mtu=*) + MTU=$(cli_get_val ${1}) + ;; + --service-name=*) + SERVICE_NAME=$(cli_get_val ${1}) + ;; + --subnet=*) + SUBNET=$(cli_get_val ${1}) + ;; + esac + shift + done + + config_write $(zone_dir ${zone})/configs/${HOOK} ${HOOK_SETTINGS} + + exit ${EXIT_OK} +} + +function _up() { + local zone=${1} + local config=${2} + shift 2 + + # Start the PPPoE server. + pppoe_server_start ${zone} + + exit ${EXIT_OK} +} + +function _down() { + local zone=${1} + local config=${2} + shift 2 + + if ! device_exists ${zone}; then + error "Zone '${zone}' doesn't exist." + exit ${EXIT_ERROR} + fi + + # Stop the PPPoE server. + pppoe_server_stop ${zone} + + exit ${EXIT_OK} +} + +function _status() { + local zone=${1} + local config=${2} + shift 2 + + if ! device_exists ${zone}; then + error "Zone '${zone}' doesn't exist." + exit ${EXIT_ERROR} + fi + + config_read $(zone_dir ${zone})/configs/${config} + + local status + if pppoe_server_status ${zone}; then + status="${MSG_HOOK_UP}" + else + status="${MSG_HOOK_DOWN}" + fi + cli_statusline 3 "PPPoE server" "${status}" + + exit ${EXIT_OK} +} diff --git a/ppp/pppoe-server b/ppp/pppoe-server new file mode 100644 index 00000000..a3bc9966 --- /dev/null +++ b/ppp/pppoe-server @@ -0,0 +1,89 @@ +#!/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 . # +# # +############################################################################### + +# This is a wrapper script which does some on-the-fly configuration of the +# pppoe-server daemon, which does not support any configuration files. + +LOG_FACILITY="pppoe-server" +. /usr/lib/network/functions + +zone=${1} +assert zone_exists ${zone} + +action=${2} + +# Read the configuration file of this hook. +config_read $(zone_dir ${zone})/configs/pppoe-server +assert isset SUBNET + +pppd_options="${RUN_DIR}/${zone}/pppoe-server-options" +pool_file="${RUN_DIR}/${zone}/pppoe-server-pool" + +case "${action}" in + cleanup) + # Cleanup all temporary files. + rm -f ${pppd_options} ${pool_file} + + exit ${EXIT_OK} + ;; + + *) + # Don't let the server fork to background. + pppoe_cmdline="-F" + + # Add the interface to listen to. + pppoe_cmdline="${pppoe_cmdline} -I ${zone}" + + # Enable kernel-mode PPPoE. + pppoe_cmdline="${pppoe_cmdline} -k" + + # Randomize session IDs. + pppoe_cmdline="${pppoe_cmdline} -r" + + # Add the service name. + if isset SERVICE_NAME; then + pppoe_cmdline="${pppoe_cmdline} -S ${SERVICE_NAME// /_}" + fi + + # Create the pppoe-server-options file. + pppoe_server_options ${pppd_options} ${zone} + pppoe_cmdline="${pppoe_cmdline} -O ${pppd_options}" + + # Configure the IP addresses. + local_address=$(ipv4_get_network ${SUBNET}) + pppoe_cmdline="${pppoe_cmdline} -L ${local_address}" + + # Create the address pool. + pppoe_server_poolfile ${pool_file} ${SUBNET} + pppoe_cmdline="${pppoe_cmdline} -p ${pool_file}" + + log INFO "Starting pppoe-server daemon..." + log DEBUG "pppoe-server options: ${pppoe_cmdline}" + + # Now exec the actual pppoe-server binary. + exec pppoe-server ${pppoe_cmdline} + + error "Could not execute pppoe-server. Exiting." + exit ${EXIT_ERROR} + ;; +esac + +exit ${EXIT_ERROR}