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