]> git.ipfire.org Git - network.git/commitdiff
pppoe-server: New (client) hook.
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 23 Jun 2012 20:38:11 +0000 (20:38 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 23 Jun 2012 20:38:11 +0000 (20:38 +0000)
Makefile
functions.ipv4
functions.pppoe-server [new file with mode: 0644]
hooks/zones/bridge.configs/pppoe-server [new file with mode: 0755]
ppp/pppoe-server [new file with mode: 0644]

index 0fb47447d5b802546c98ccce22e1b6df7c9a7e33..e118ae86b783dac6ae4fec5513ec4cf2980e8fe2 100644 (file)
--- 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)
index aada214a90fd490f19b0a8e48bbd5c47ba78625b..a3b3ce46acb9d6eeb9b6b684ed99969de57d2112 100644 (file)
@@ -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 (file)
index 0000000..fa1f283
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+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 (executable)
index 0000000..a3727f0
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+. /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 (file)
index 0000000..a3bc996
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+# 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}