# #
###############################################################################
+PPP_SUPPORTED_AUTH_METHODS="chap pap"
+
+EXIT_PPPD_ERROR=${EXIT_ERROR}
+EXIT_PPPD_ERROR_FATAL=$(( ${EXIT_ERROR} + 1 ))
+
+# This function monitors the pppd activity.
+
+function pppd_angel() {
+ local device="${1}"
+ assert isset device
+
+ local config_file="${2}"
+ assert isset config_file
+ shift 2
+
+ local holdoff_time
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --holdoff-time=*)
+ holdoff_time="$(cli_get_val "${1}")"
+ ;;
+ *)
+ warning "Unrecognized argument: ${1}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+ shift
+ done
+
+ local pppd_ret ret
+ while :; do
+ # Execute ppp daemon.
+ pppd_exec "${device}" "${config_file}"
+ ret=$?
+
+ pppd_ret=$(( ${ret} % 0x0f ))
+ ret=$(( ${ret} >> 6 ))
+
+ log DEBUG "pppd exited with error code ${pppd_ret}"
+
+ case "${ret}" in
+ ${EXIT_OK})
+ # pppd terminated gracefully. Propagating...
+ return ${EXIT_OK}
+ ;;
+ ${EXIT_PPPD_ERROR})
+ # pppd has a (non-fatal) error, in which case we
+ # restart it instantly, so it will try to re-establish
+ # the connection.
+ ;;
+ ${EXIT_PPPD_ERROR_FATAL})
+ # pppd has a fatal error. We cannot go on from here
+ # because there is either no chance to establish a connection
+ # without any user interaction, or we will damage the system.
+ log ERROR "Fatal error. Not going to restart pppd."
+ return ${pppd_ret}
+ ;;
+ *)
+ log ERROR "Invalid return code: ${ret}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+
+ isset holdoff_time || continue
+
+ # When we got here, we need to wait a little bit and restart the
+ # ppp daemon soon.
+ log INFO "Restarting pppd in ${holdoff_time}s"
+ sleep ${holdoff_time}
+ done
+}
+
+function pppd_exec() {
+ local device="${1}"
+ assert isset device
+
+ local config_file="${2}"
+ assert isset config_file
+ shift 2
+
+ # Execute pppd.
+ cmd "pppd file ${config_file} $@"
+ local ret=$?
+
+ # Evaluate return code.
+ local error_code
+ case "${ret}" in
+ 0)
+ # Pppd has detached, or otherwise the connection was successfully
+ # established and terminated at the peer's request.
+ log DEBUG "pppd exited gracefully"
+ error_code=${EXIT_OK}
+ ;;
+ 1)
+ # An immediately fatal error of some kind occurred, such as an
+ # essential system call failing, or running out of virtual memory.
+ log ERROR "pppd crashed for an unknown reason"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 2)
+ # An error was detected in processing the options given, such as two
+ # mutually exclusive options being used.
+ log ERROR "pppd: Configuration error"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 3)
+ # Pppd is not setuid-root and the invoking user is not root.
+ log ERROR "pppd: Launched with insufficient privileges"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 4)
+ # The kernel does not support PPP, for example, the PPP kernel driver is
+ # not included or cannot be loaded.
+ log ERROR "pppd: Kernel does not support PPP"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 5)
+ # Pppd terminated because it was sent a SIGINT, SIGTERM or SIGHUP signal.
+ log ERROR "pppd: Received SIGINT, SIGTERM or SIGHUP signal"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 6)
+ # The serial port could not be locked.
+ log ERROR "pppd: Serial port could not be locked"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 7)
+ # The serial port could not be opened.
+ log ERROR "pppd: Serial port could not be opened"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 8)
+ # The connect script failed (returned a non-zero exit status).
+ log ERROR "pppd: Connect script failed"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 9)
+ # The command specified as the argument to the pty option could not be run.
+ log ERROR "pppd: Could not run pty command"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 10)
+ # The PPP negotiation failed, that is, it didn't reach the point where at
+ # least one network protocol (e.g. IP) was running.
+ log ERROR "pppd: Protocol negotiation failed"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 11)
+ # The peer system failed (or refused) to authenticate itself.
+ log ERROR "pppd: peer system failed (or refused) to authenticate itself"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 12)
+ # The link was established successfully and terminated because it was idle.
+ log ERROR "pppd: Terminated because of idleness"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 13)
+ # The link was established successfully and terminated because the connect time
+ # limit was reached.
+ log ERROR "pppd: connect time limit was reached"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 14)
+ # Callback was negotiated and an incoming call should arrive shortly.
+ # We should not be using this, so make it fatal that nobody is able to
+ # abuse the feature.
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 15)
+ # The link was terminated because the peer is not responding to echo requests.
+ log ERROR "pppd: Peer is not responding to echo requests"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 16)
+ # The link was terminated by the modem hanging up.
+ log ERROR "pppd: Modem hung up"
+ error_code=${EXIT_PPPD_ERROR}
+ ;;
+ 17)
+ # The PPP negotiation failed because serial loopback was detected.
+ log ERROR "pppd: Serial loopback detected"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 18)
+ # The init script failed (returned a non-zero exit status).
+ log ERROR "pppd: Init script failed"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ 19)
+ # We failed to authenticate ourselves to the peer.
+ log ERROR "pppd: Authentication failed"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ *)
+ log ERROR "pppd: Unhandled exit code: ${ret}"
+ error_code=${EXIT_PPPD_ERROR_FATAL}
+ ;;
+ esac
+
+ return $(( (${error_code} << 6) + ${ret} ))
+}
+
+function pppd_start() {
+ local device="${1}"
+ assert isset device
+
+ # This will block until the connection has been established or
+ # pppd exited.
+ service_start "pppd@${device}.service"
+}
+
+function pppd_stop() {
+ local device="${1}"
+ assert isset device
+
+ service_stop "pppd@${device}.service"
+}
+
+function pppd_status() {
+ local device="${1}"
+ assert isset device
+
+ service_status "pppd@${device}.service"
+}
+
function ppp_common_ip_pre_up() {
local zone=${1}
shift
routing_db_from_ppp ${zone} ipv4
- # Request firewall reload
- event_firewall_reload
-
return ${EXIT_OK}
}
-function ppp_common_ip_up() {
+function ppp_common_ipv4_up() {
local zone=${1}
shift
routing_db_set ${zone} ipv4 active 1
routing_update ${zone} ipv4
-
- # Emit interface-up event
- event_interface_up ${zone}
+ routing_default_update
return ${EXIT_OK}
}
-function ppp_common_ip_down() {
+function ppp_common_ipv4_down() {
local zone=${1}
shift
# and update the routing table.
routing_db_remove ${zone} ipv4
routing_update ${zone} ipv4
+ routing_default_update
# Save accounting information
ppp_accounting ${zone}
- # Emit interface-up event
- event_interface_down ${zone}
-
return ${EXIT_OK}
}
routing_db_set ${zone} ipv6 active 1
routing_update ${zone} ipv6
-
- # Emit interface-up event
- event_interface_up ${zone}
+ routing_default_update
return ${EXIT_OK}
}
# and update the routing table.
routing_db_remove ${zone} ipv6
routing_update ${zone} ipv6
+ routing_default_update
# Save accounting information
ppp_accounting ${zone}
- # Emit interface-up event
- event_interface_down ${zone}
-
return ${EXIT_OK}
}
--rcvd="${BYTES_RCVD}" --sent="${BYTES_SENT}"
}
-function pppd_exec() {
- log DEBUG "Running pppd with parameters '$@'."
+function pppd_write_config() {
+ local file=${1}; shift
+ assert isset file
+
+ local auth
+ local baudrate
+ local connect_cmd
+ local default_asyncmap="true"
+ local interface
+ local ipv6="true"
+ local lcp_echo_failure=3
+ local lcp_echo_interval=20
+ local linkname
+ local mtu mru
+ local password
+ local plugin plugin_options
+ local pty
+ local refuses
+ local serial="false"
+ local username
+ local value
+
+ while [ $# -gt 0 ]; do
+ case "${1}" in
+ --auth=*)
+ auth=$(cli_get_val ${1})
+ ;;
+ --baudrate=*)
+ baudrate=$(cli_get_val ${1})
+ assert isoneof baudrate ${SERIAL_BAUDRATES}
+ ;;
+ --connect-command=*)
+ connect_cmd=$(cli_get_val ${1})
+ ;;
+ # Enable or disable the use of the default asyncmap.
+ --default-asyncmap=*)
+ value=$(cli_get_val ${1})
+ if enabled value; then
+ default_asyncmap="true"
+ else
+ default_asyncmap="false"
+ fi
+ ;;
+ # The name of the created ppp interface.
+ --interface=*)
+ interface=$(cli_get_val ${1})
+ ;;
+ # IPv6
+ --ipv6=*)
+ ipv6="$(cli_get_val ${1})"
+ ;;
+ # LCP echo failure.
+ --lcr-echo-failure=*)
+ lcr_echo_failure=$(cli_get_val ${1})
+
+ if ! isinteger ${lcr_echo_failure}; then
+ error "--lcr-echo-failure= requires a number"
+ return ${EXIT_ERROR}
+ fi
+ ;;
+ # LCP echo interval.
+ --lcr-echo-interval=*)
+ lcr_echo_interval=$(cli_get_val ${1})
+
+ if ! isinteger ${lcr_echo_failure}; then
+ error "--lcr-echo-interval= requires a number"
+ return ${EXIT_ERROR}
+ fi
+ ;;
+ # Maximum Transmission Unit
+ --mtu=*)
+ mtu=$(cli_get_val ${1})
+ ;;
+ # Maximum Receive Unit
+ --mru=*)
+ mru=$(cli_get_val ${1})
+ ;;
+ --password=*)
+ password=$(cli_get_val ${1})
+ ;;
+ --plugin=*)
+ plugin=$(cli_get_val ${1})
+ ;;
+ --plugin-options=*)
+ plugin_options=$(cli_get_val ${1})
+ ;;
+ --pty=*)
+ pty=$(cli_get_val ${1})
+ ;;
+ # Refused authentication methods
+ --refuse=*)
+ list_append refuses "$(cli_get_val "${1}")"
+ error_log "REFUSES $refuses $1"
+ ;;
+ # Sets if the modem is a serial device.
+ --serial=*)
+ serial=$(cli_get_val ${1})
+ ;;
+ --serial-device=*)
+ serial_device=$(cli_get_val ${1})
+ ;;
+ --username=*)
+ username=$(cli_get_val ${1})
+ ;;
+ *)
+ log WARNING "Unhandled argument: ${1}"
+ ;;
+ esac
+ shift
+ done
+
+ if [ -z "${interface}" ]; then
+ log ERROR "You need to set the interface name: ${interface}"
+ return ${EXIT_ERROR}
+ fi
+ linkname="${interface}"
- pppd $@ > /dev/null
+ if isset auth; then
+ if ! isoneof ${auth} ${PPP_SUPPORTED_AUTH_METHODS}; then
+ log ERROR "Unsupported auth method: ${auth}"
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if enabled serial; then
+ assert isset serial_device
+ assert [ -c "${serial_device}" ]
+ fi
+
+ # Set the user credentials.
+ ppp_secret "${username}" "${password}"
+
+ # Write the configuration header.
+ mkdir -p $(dirname ${file}) 2>/dev/null
+ config_header "PPP daemon configuration file" > ${file}
+
+ # At first, set the name of the link.
+ print "linkname ${linkname}\n" >> ${file}
+
+ # Configure the interface/zone name.
+ (
+ print "# Interface name"
+ print "ifname ${interface}"
+ print
+ ) >> ${file}
+
+ # Plugin settings
+ if isset plugin; then
+ (
+ print "# Plugin settings"
+ print "plugin ${plugin} ${plugin_options}"
+ print
+ ) >> ${file}
+ fi
+
+ # pty settings
+ if isset pty; then
+ (
+ print "# pty settings"
+ print "pty \"${pty}\""
+ print
+ ) >> ${file}
+ fi
+
+ # User authentication
+ if isset username; then
+ (
+ print "# User authentication"
+ print "user ${username}"
+
+ print "noauth"
+ if isset auth; then
+ print "require-${auth}"
+ fi
+
+ # Refused authentication methods
+ for refuse in ${refuses}; do
+ print "refuse-${refuse}"
+ done
+ print
+ ) >> ${file}
+ fi
+
+ # IPv6
+ if enabled ipv6; then
+ (
+ print "# IPv6 support"
+ print "+ipv6"
+ print
+ ) >> ${file}
+ fi
+
+ # MTU/MRU settings
+ if isset mtu; then
+ isset mru || mru=${mtu}
+
+ (
+ print "# MTU/MRU settings"
+ print "mtu ${mtu}"
+ print "mru ${mru}"
+ print
+ ) >> ${file}
+ fi
+
+ if enabled serial; then
+ (
+ print "# Serial modem settings"
+ print "${serial_device} ${baudrate}"
+ print "crtscts"
+ print "lock"
+ print "modem"
+ print
+ ) >> ${file}
+
+ # Connect command
+ if isset connect_cmd; then
+ (
+ print "# Connect command"
+ print "connect \"${connect_cmd}\""
+ print
+ ) >> ${file}
+ fi
+ fi
+
+ # Default asyncmap.
+ if enabled default_asyncmap; then
+ (
+ print "# Use the 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}
+
+ # Add the default settings.
+ (
+ print "# Disable the compression"
+ print "noccp noaccomp nodeflate nopcomp novj novjccomp nobsdcomp nomppe"
+
+ print "noipdefault nodetach debug"
+ ) >> ${file}
+
+ return ${EXIT_OK}
}