]> git.ipfire.org Git - people/stevee/network.git/blob - src/hooks/zones/pppoe
cd3913b62034ff38a474d2a711070fcd3f0f059c
[people/stevee/network.git] / src / hooks / zones / pppoe
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012 IPFire Network Development Team #
6 # #
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. #
11 # #
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. #
16 # #
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/>. #
19 # #
20 ###############################################################################
21
22 . /usr/lib/network/header-zone
23
24 HOOK_SETTINGS="HOOK ACCESS_CONCENTRATOR AUTH USERNAME PASSWORD"
25 HOOK_SETTINGS="${HOOK_SETTINGS} SERVICE_NAME MTU IPV6 PREFIX_DELEGATION"
26
27 # This hook can work with all authentication methods supported by pppd.
28 PPPOE_SUPPORTED_AUTH_METHODS="${PPP_SUPPORTED_AUTH_METHODS}"
29 PPPOE_PLUGIN="rp-pppoe.so"
30
31 # Request an IPv6 address.
32 DEFAULT_IPV6="true"
33
34 # Use IPv6 prefix delegation.
35 DEFAULT_PREFIX_DELEGATION="true"
36
37 hook_check_settings() {
38 assert isset USERNAME
39 assert isset PASSWORD
40
41 isset AUTH && assert isoneof AUTH ${PPPOE_SUPPORTED_AUTH_METHODS}
42
43 assert isset IPV6
44 assert isset PREFIX_DELEGATION
45 }
46
47 hook_parse_cmdline() {
48 while [ $# -gt 0 ]; do
49 case "${1}" in
50 --access-concentrator=*)
51 ACCESS_CONCENTRATOR=$(cli_get_val "${1}")
52 ;;
53 --auth=*)
54 AUTH=$(cli_get_val "${1}")
55 ;;
56 --ipv6=*)
57 local value="$(cli_get_val "${1}")"
58 if enabled value; then
59 IPV6="true"
60 else
61 IPV6="false"
62 fi
63 ;;
64 --mtu=*)
65 MTU=$(cli_get_val "${1}")
66 ;;
67 --password=*)
68 PASSWORD=$(cli_get_val "${1}")
69 ;;
70 --prefix-delegation=*)
71 PREFIX_DELEGATION="$(cli_get_bool "${1}")"
72 ;;
73 --service-name=*)
74 SERVICE_NAME=$(cli_get_val "${1}")
75 ;;
76 --username=*)
77 USERNAME=$(cli_get_val "${1}")
78 ;;
79 *)
80 warning "Unknown argument: ${1}" >&2
81 ;;
82 esac
83 shift
84 done
85 }
86
87 hook_up() {
88 local zone=${1}
89 assert isset zone
90
91 # If this zone's port is not set, we will return
92 # with EXIT_OK so that this zone will remain active,
93 # but we cannot start pppd.
94 local port=$(__hook_get_port "${zone}")
95 if ! isset port || ! port_exists "${port}"; then
96 log WARNING "Could not bring up zone '${zone}' because no port is attached"
97 exit ${EXIT_OK}
98 fi
99
100 zone_settings_read "${zone}"
101
102 # Load the pppoe kernel module
103 module_load "pppoe"
104
105 # Bring up the port.
106 port_up "${port}"
107
108 # Start the ppp daemon.
109 pppd_start ${zone}
110
111 exit ${EXIT_OK}
112 }
113
114 hook_down() {
115 local zone=${1}
116 assert isset zone
117
118 zone_settings_read "${zone}"
119
120 # Stop the ppp daemon.
121 pppd_stop ${zone}
122
123 # Bring down the port.
124 local port=$(__hook_get_port "${zone}")
125 if isset port; then
126 log DEBUG "Bringing down port '${port}'"
127 port_down "${port}"
128 fi
129
130 exit ${EXIT_OK}
131 }
132
133 hook_hotplug() {
134 local zone="${1}"
135
136 case "$(hotplug_action)" in
137 add)
138 if hotplug_event_interface_is_port_of_zone "${zone}"; then
139 # Bring up the zone if it is enabled but not active, yet.
140 zone_start_auto "${zone}"
141
142 exit ${EXIT_OK}
143 fi
144 ;;
145 remove)
146 # PPPoE cannot work if the ethernet device has been removed
147 if hotplug_event_interface_is_port_of_zone "${zone}"; then
148 if zone_is_active "${zone}"; then
149 zone_stop "${zone}"
150 fi
151
152 exit ${EXIT_OK}
153 fi
154 ;;
155 esac
156
157 exit ${EXIT_NOT_HANDLED}
158 }
159
160 hook_discover() {
161 local device=${1}
162
163 # This obviously only works on ethernet (or compatible) devices
164 if ! device_is_ethernet_compatible "${device}"; then
165 exit ${EXIT_ERROR}
166 fi
167
168 local output
169 output=$(pppoe-discovery -I ${device} -U $(uuid) 2>&1)
170
171 # Exit if there was not output
172 [ -z "${output}" ] && exit ${DISCOVER_ERROR}
173
174 # Exit if PADI timed out
175 grep -q "Timeout" <<<${output} && exit ${DISCOVER_ERROR}
176
177 local ac
178 while read line; do
179 case "${line}" in
180 Access-Concentrator:*)
181 ac="${line#Access-Concentrator: }"
182 ;;
183 esac
184 done <<<"${output}"
185
186 echo "ACCESS_CONCENTRATOR=\"$ac\""
187
188 exit ${DISCOVER_OK}
189 }
190
191 hook_status() {
192 local zone=${1}
193 assert isset zone
194
195 cli_device_headline ${zone}
196
197 zone_settings_read "${zone}"
198
199 cli_headline 2 "Configuration"
200 cli_print_fmt1 2 "Username" "${USERNAME}"
201 cli_print_fmt1 2 "Password" "<hidden>"
202
203 local port=$(__hook_get_port "${zone}")
204 if isset port; then
205 cli_print_fmt1 2 "Port" "${port}"
206 fi
207 cli_space
208
209 # Exit if zone is down
210 if ! zone_is_up ${zone}; then
211 echo # Empty line
212 exit ${EXIT_ERROR}
213 fi
214
215 # XXX display time since connection started
216
217 cli_headline 2 "Point-to-Point-over-Ethernet protocol"
218 cli_print_fmt1 2 "MAC-Remote" "$(db_get "${zone}/remote-address")"
219 cli_space
220
221 local proto
222 for proto in ${IP_SUPPORTED_PROTOCOLS}; do
223 db_exists "${zone}/${proto}" || continue
224
225 local headline
226 case "${proto}" in
227 ipv6)
228 headline="Internet Protocol Version 6"
229 ;;
230 ipv4)
231 headline="Internet Protocol Version 4"
232 ;;
233 *)
234 headline="Unkown protocol"
235 ;;
236 esac
237 cli_headline 3 "${headline}"
238
239 cli_print_fmt1 3 "IP address" "$(db_get "${zone}/${proto}/local-ip-address")"
240 cli_print_fmt1 3 "Gateway" "$(db_get "${zone}/${proto}/remote-ip-address")"
241 cli_print_fmt1 3 "DNS servers" "$(db_get "${zone}/${proto}/domain-name-servers")"
242 cli_space
243 done
244
245 exit ${EXIT_OK}
246 }
247
248 hook_ppp_write_config() {
249 local zone=${1}
250 assert isset zone
251
252 local file=${2}
253 assert isset file
254
255 # Read in the configuration files.
256 zone_settings_read "${zone}"
257
258 # A port has to be assigned for this action
259 local port=$(__hook_get_port "${zone}")
260 if ! isset port; then
261 error "No port assigned to pppoe hook of zone '${zone}'"
262 exit ${EXIT_ERROR}
263 fi
264
265 # Prepare the command line options for the pppoe plugin.
266 local plugin_options
267
268 # Add the access concentrator (if any).
269 if isset ACCESS_CONCENTRATOR; then
270 plugin_options="${plugin_options} rp_pppoe_ac '${ACCESS_CONCENTRATOR}'"
271 fi
272
273 # Add the service name (if any).
274 if isset SERVICE_NAME; then
275 plugin_options="${plugin_options} rp_pppoe_service '${SERVICE_NAME}'"
276 fi
277
278 # The last argument must be the interface.
279 plugin_options="${plugin_options} ${port}"
280
281 pppd_write_config ${file} \
282 --interface="${zone}" \
283 --username="${USERNAME}" \
284 --password="${PASSWORD}" \
285 --mtu="${MTU}" \
286 --auth="${AUTH}" \
287 --ipv6="${IPV6}" \
288 \
289 --plugin="${PPPOE_PLUGIN}" \
290 --plugin-options="${plugin_options}"
291
292 exit ${EXIT_OK}
293 }
294
295 __hook_get_port() {
296 local zone="${1}"
297
298 local port
299 for port in $(zone_get_ports "${zone}"); do
300 echo "${port}"
301 return ${EXIT_OK}
302 done
303
304 return ${EXIT_ERROR}
305 }
306
307 hook_port_attach() {
308 # Excepting at least two arguments here
309 assert [ $# -ge 2 ]
310
311 local zone="${1}"
312 local port="${2}"
313 shift 2
314
315 # PPPoE can only use one port
316 local ports_num="$(zone_get_ports_num "${zone}")"
317 if [ ${ports_num} -ge 1 ]; then
318 local ports="$(zone_get_ports "${zone}")"
319 error "The pppoe zone hook only supports assigning one port"
320 error " port '${ports}' has already been assigned to zone '${zone}'"
321 return ${EXIT_ERROR}
322 fi
323
324 if ! zone_port_settings_write "${zone}" "${port}"; then
325 exit ${EXIT_ERROR}
326 fi
327
328 exit ${EXIT_OK}
329 }
330
331 hook_port_detach() {
332 assert [ $# -eq 2 ]
333
334 local zone="${1}"
335 local port="${2}"
336
337 # Shut down the entire zone here, because it cannot
338 # run without a port any way and removing the port would
339 # create a hotplug event which will be processed after the
340 # port has already been detached...
341 zone_stop "${zone}"
342
343 if ! zone_port_settings_remove "${zone}" "${port}"; then
344 exit ${EXIT_ERROR}
345 fi
346
347 exit ${EXIT_OK}
348 }
349
350 hook_port_up() {
351 assert [ $# -eq 2 ]
352
353 local zone="${1}"
354 local port="${2}"
355
356 # Try bringing up the port if it has not been brought up before
357 if ! device_exists "${port}"; then
358 port_create "${port}"
359 fi
360
361 # Make sure that the port is up
362 port_up "${port}"
363
364 exit ${EXIT_OK}
365 }
366
367 hook_port_down() {
368 assert [ $# -eq 2 ]
369
370 local zone="${1}"
371 local port="${2}"
372
373 if device_exists "${port}"; then
374 port_down "${port}"
375 fi
376
377 exit ${EXIT_OK}
378 }
379
380 hook_ppp_ipv6_up() {
381 local zone="${1}"
382
383 ppp_common_ipv6_up "${zone}"
384
385 # Read configuration
386 zone_settings_read "${zone}"
387
388 if enabled PREFIX_DELEGATION; then
389 dhclient_start "${zone}" ipv6
390 fi
391
392 exit ${EXIT_OK}
393 }
394
395 hook_ppp_ipv6_down() {
396 local zone="${1}"
397
398 ppp_common_ipv6_down "${zone}"
399
400 # Read configuration
401 zone_settings_read "${zone}"
402
403 if enabled PREFIX_DELEGATION; then
404 dhclient_stop "${zone}" ipv6
405 fi
406
407 exit ${EXIT_OK}
408 }