2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2010 Michael Tremer & Christian Schmidt #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 PPP_SUPPORTED_AUTH_METHODS
="chap pap"
24 EXIT_PPPD_ERROR
=${EXIT_ERROR}
25 EXIT_PPPD_ERROR_FATAL
=$
(( ${EXIT_ERROR} + 1 ))
27 # This function monitors the pppd activity.
29 function pppd_angel
() {
33 local config_file
="${2}"
34 assert isset config_file
39 while [ $# -gt 0 ]; do
42 holdoff_time
="$(cli_get_val "${1}")"
45 warning
"Unrecognized argument: ${1}"
55 pppd_exec
"${device}" "${config_file}"
58 pppd_ret
=$
(( ${ret} % 0x0f ))
59 ret
=$
(( ${ret} >> 6 ))
61 log DEBUG
"pppd exited with error code ${pppd_ret}"
65 # pppd terminated gracefully. Propagating...
69 # pppd has a (non-fatal) error, in which case we
70 # restart it instantly, so it will try to re-establish
73 ${EXIT_PPPD_ERROR_FATAL})
74 # pppd has a fatal error. We cannot go on from here
75 # because there is either no chance to establish a connection
76 # without any user interaction, or we will damage the system.
77 log ERROR
"Fatal error. Not going to restart pppd."
81 log ERROR
"Invalid return code: ${ret}"
86 isset holdoff_time ||
continue
88 # When we got here, we need to wait a little bit and restart the
90 log INFO
"Restarting pppd in ${holdoff_time}s"
95 function pppd_exec
() {
99 local config_file
="${2}"
100 assert isset config_file
104 cmd
"pppd file ${config_file} $@"
107 # Evaluate return code.
111 # Pppd has detached, or otherwise the connection was successfully
112 # established and terminated at the peer's request.
113 log DEBUG
"pppd exited gracefully"
114 error_code
=${EXIT_OK}
117 # An immediately fatal error of some kind occurred, such as an
118 # essential system call failing, or running out of virtual memory.
119 log ERROR
"pppd crashed for an unknown reason"
120 error_code
=${EXIT_PPPD_ERROR_FATAL}
123 # An error was detected in processing the options given, such as two
124 # mutually exclusive options being used.
125 log ERROR
"pppd: Configuration error"
126 error_code
=${EXIT_PPPD_ERROR_FATAL}
129 # Pppd is not setuid-root and the invoking user is not root.
130 log ERROR
"pppd: Launched with insufficient privileges"
131 error_code
=${EXIT_PPPD_ERROR_FATAL}
134 # The kernel does not support PPP, for example, the PPP kernel driver is
135 # not included or cannot be loaded.
136 log ERROR
"pppd: Kernel does not support PPP"
137 error_code
=${EXIT_PPPD_ERROR_FATAL}
140 # Pppd terminated because it was sent a SIGINT, SIGTERM or SIGHUP signal.
141 log ERROR
"pppd: Received SIGINT, SIGTERM or SIGHUP signal"
142 error_code
=${EXIT_PPPD_ERROR}
145 # The serial port could not be locked.
146 log ERROR
"pppd: Serial port could not be locked"
147 error_code
=${EXIT_PPPD_ERROR}
150 # The serial port could not be opened.
151 log ERROR
"pppd: Serial port could not be opened"
152 error_code
=${EXIT_PPPD_ERROR}
155 # The connect script failed (returned a non-zero exit status).
156 log ERROR
"pppd: Connect script failed"
157 error_code
=${EXIT_PPPD_ERROR_FATAL}
160 # The command specified as the argument to the pty option could not be run.
161 log ERROR
"pppd: Could not run pty command"
162 error_code
=${EXIT_PPPD_ERROR_FATAL}
165 # The PPP negotiation failed, that is, it didn't reach the point where at
166 # least one network protocol (e.g. IP) was running.
167 log ERROR
"pppd: Protocol negotiation failed"
168 error_code
=${EXIT_PPPD_ERROR}
171 # The peer system failed (or refused) to authenticate itself.
172 log ERROR
"pppd: peer system failed (or refused) to authenticate itself"
173 error_code
=${EXIT_PPPD_ERROR}
176 # The link was established successfully and terminated because it was idle.
177 log ERROR
"pppd: Terminated because of idleness"
178 error_code
=${EXIT_PPPD_ERROR}
181 # The link was established successfully and terminated because the connect time
183 log ERROR
"pppd: connect time limit was reached"
184 error_code
=${EXIT_PPPD_ERROR}
187 # Callback was negotiated and an incoming call should arrive shortly.
188 # We should not be using this, so make it fatal that nobody is able to
190 error_code
=${EXIT_PPPD_ERROR_FATAL}
193 # The link was terminated because the peer is not responding to echo requests.
194 log ERROR
"pppd: Peer is not responding to echo requests"
195 error_code
=${EXIT_PPPD_ERROR}
198 # The link was terminated by the modem hanging up.
199 log ERROR
"pppd: Modem hung up"
200 error_code
=${EXIT_PPPD_ERROR}
203 # The PPP negotiation failed because serial loopback was detected.
204 log ERROR
"pppd: Serial loopback detected"
205 error_code
=${EXIT_PPPD_ERROR_FATAL}
208 # The init script failed (returned a non-zero exit status).
209 log ERROR
"pppd: Init script failed"
210 error_code
=${EXIT_PPPD_ERROR_FATAL}
213 # We failed to authenticate ourselves to the peer.
214 log ERROR
"pppd: Authentication failed"
215 error_code
=${EXIT_PPPD_ERROR_FATAL}
218 log ERROR
"pppd: Unhandled exit code: ${ret}"
219 error_code
=${EXIT_PPPD_ERROR_FATAL}
223 return $
(( (${error_code} << 6) + ${ret} ))
226 function pppd_start() {
230 # This will block until the connection has been established or
232 service_start "pppd@${device}.service"
235 function pppd_stop() {
239 service_stop "pppd@${device}.service"
242 function pppd_status() {
246 service_status "pppd@${device}.service"
249 function ppp_common_ip_pre_up() {
253 if ! zone_exists ${zone}; then
254 error "Zone '${zone}' does not exist."
258 routing_db_from_ppp ${zone} ipv4
263 function ppp_common_ipv4_up() {
267 if ! zone_exists ${zone}; then
268 error "Zone '${zone}' does not exist."
272 routing_db_set ${zone} ipv4 active 1
273 routing_update ${zone} ipv4
274 routing_default_update
279 function ppp_common_ipv4_down() {
283 if ! zone_exists ${zone}; then
284 error "Zone '${zone}' does not exist."
288 # Remove the information about this zone from the routing database
289 # and update the routing table.
290 routing_db_remove ${zone} ipv4
291 routing_update ${zone} ipv4
292 routing_default_update
294 # Save accounting information
295 ppp_accounting ${zone}
300 function ppp_common_ipv6_up() {
304 if ! zone_exists ${zone}; then
305 error "Zone '${zone}' does not exist."
309 # Add information about this zone to the routing database.
310 routing_db_from_ppp ${zone} ipv6
312 routing_db_set ${zone} ipv6 active 1
313 routing_update ${zone} ipv6
314 routing_default_update
319 function ppp_common_ipv6_down() {
323 if ! zone_exists ${zone}; then
324 error "Zone '${zone}' does not exist."
328 # Remove the information about this zone from the routing database
329 # and update the routing table.
330 routing_db_remove ${zone} ipv6
331 routing_update ${zone} ipv6
332 routing_default_update
334 # Save accounting information
335 ppp_accounting ${zone}
340 function ppp_secret() {
347 # Updateing secret file
349 while read user a secret; do
350 if [ "'${USER}'" != "${user}" ]; then
351 echo "${user} ${a} ${secret}" >> ${PPP_SECRETS}.tmp
353 done < ${PPP_SECRETS}
354 echo "'${USER}' * '${SECRET}'" >> ${PPP_SECRETS}.tmp
355 cat ${PPP_SECRETS}.tmp > ${PPP_SECRETS}
356 rm -f ${PPP_SECRETS}.tmp
359 function ppp_accounting() {
363 db_ppp_update ${zone} --duration="${CONNECT_TIME}" \
364 --rcvd="${BYTES_RCVD}" --sent="${BYTES_SENT}"
367 function pppd_write_config() {
368 local file=${1}; shift
374 local default_asyncmap="true"
377 local lcp_echo_failure=3
378 local lcp_echo_interval=20
382 local plugin plugin_options
389 while [ $# -gt 0 ]; do
392 auth=$(cli_get_val ${1})
395 baudrate=$(cli_get_val ${1})
396 assert isoneof baudrate ${SERIAL_BAUDRATES}
399 connect_cmd=$(cli_get_val ${1})
401 # Enable or disable the use of the default asyncmap.
402 --default-asyncmap=*)
403 value=$(cli_get_val ${1})
404 if enabled value; then
405 default_asyncmap="true"
407 default_asyncmap="false"
410 # The name of the created ppp interface.
412 interface=$(cli_get_val ${1})
416 ipv6="$(cli_get_val ${1})"
419 --lcr-echo-failure=*)
420 lcr_echo_failure=$(cli_get_val ${1})
422 if ! isinteger ${lcr_echo_failure}; then
423 error "--lcr-echo-failure= requires a number"
428 --lcr-echo-interval=*)
429 lcr_echo_interval=$(cli_get_val ${1})
431 if ! isinteger ${lcr_echo_failure}; then
432 error "--lcr-echo-interval= requires a number"
436 # Maximum Transmission Unit
438 mtu=$(cli_get_val ${1})
440 # Maximum Receive Unit
442 mru=$(cli_get_val ${1})
445 password=$(cli_get_val ${1})
448 plugin=$(cli_get_val ${1})
451 plugin_options=$(cli_get_val ${1})
454 pty=$(cli_get_val ${1})
456 # Refused authentication methods
458 list_append refuses "$(cli_get_val "${1}")"
459 error_log "REFUSES $refuses $1"
461 # Sets if the modem is a serial device.
463 serial=$(cli_get_val ${1})
466 serial_device=$(cli_get_val ${1})
469 username=$(cli_get_val ${1})
472 log WARNING "Unhandled argument: ${1}"
478 if [ -z "${interface}" ]; then
479 log ERROR "You need to set the interface name: ${interface}"
482 linkname="${interface}"
485 if ! isoneof ${auth} ${PPP_SUPPORTED_AUTH_METHODS}; then
486 log ERROR "Unsupported auth method: ${auth}"
491 if enabled serial; then
492 assert isset serial_device
493 assert [ -c "${serial_device}" ]
496 # Set the user credentials.
497 ppp_secret "${username}" "${password}"
499 # Write the configuration header.
500 mkdir -p $(dirname ${file}) 2>/dev/null
501 config_header "PPP daemon configuration file" > ${file}
503 # At first, set the name of the link.
504 print "linkname ${linkname}\n" >> ${file}
506 # Configure the interface/zone name.
508 print "# Interface name"
509 print "ifname ${interface}"
514 if isset plugin; then
516 print "# Plugin settings"
517 print "plugin ${plugin} ${plugin_options}"
525 print "# pty settings"
526 print "pty \"${pty}\""
531 # User authentication
532 if isset username; then
534 print "# User authentication"
535 print "user ${username}"
539 print "require-${auth}"
542 # Refused authentication methods
543 for refuse in ${refuses}; do
544 print "refuse-${refuse}"
551 if enabled ipv6; then
553 print "# IPv6 support"
561 isset mru || mru=${mtu}
564 print "# MTU/MRU settings"
571 if enabled serial; then
573 print "# Serial modem settings"
574 print "${serial_device} ${baudrate}"
582 if isset connect_cmd; then
584 print "# Connect command"
585 print "connect \"${connect_cmd}\""
592 if enabled default_asyncmap; then
594 print "# Use the default asyncmap."
595 print "default-asyncmap"
602 print "# LCP settings"
603 print "lcp-echo-failure ${lcp_echo_failure}"
604 print "lcp-echo-interval ${lcp_echo_interval}"
608 # Add the default settings.
610 print "# Disable the compression"
611 print "noccp noaccomp nodeflate nopcomp novj novjccomp nobsdcomp nomppe"
613 print "noipdefault nodetach debug"