]>
Commit | Line | Data |
---|---|---|
8ae238a5 | 1 | #!/bin/bash |
66c36198 PM |
2 | ############################################################################### |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
5 | # Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> # | |
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 | ############################################################################### | |
71ea0d68 | 21 | |
71ea0d68 SS |
22 | eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings) |
23 | eval $(/usr/local/bin/readhash /var/ipfire/dns/settings) | |
24 | ||
3f863ee7 MT |
25 | ip2bin() { |
26 | local address="${1}" | |
27 | ||
28 | local IFS='.' | |
29 | local octet | |
30 | ||
31 | local n=0 | |
32 | ||
33 | for octet in ${address}; do | |
34 | # Shift n | |
35 | (( n <<= 8 )) | |
36 | ||
37 | # Apply the octet | |
38 | (( n |= octet )) | |
39 | done | |
40 | ||
41 | echo "${n}" | |
42 | } | |
43 | ||
44 | bin2ip() { | |
45 | local n="${1}" | |
46 | ||
47 | local IFS='.' | |
48 | local address=() | |
49 | ||
50 | for i in {3..0}; do | |
51 | address+=( $(( n >> (8 * i) & 0xff )) ) | |
52 | done | |
53 | ||
54 | echo "${address[*]}" | |
55 | } | |
56 | ||
db151ad7 | 57 | network_get_intfs() { |
79cce701 MT |
58 | local zone="${1}" |
59 | ||
d99826dc | 60 | case "${zone^^}" in |
79cce701 MT |
61 | RED) |
62 | # For PPPoE, the RED interface is called ppp0 (unless we use QMI) | |
63 | if [ "${RED_TYPE}" = "PPPOE" ] && [ "${RED_DRIVER}" != "qmi_wwan" ]; then | |
64 | echo "ppp0" | |
65 | return 0 | |
66 | ||
67 | # Otherwise we return RED_DEV | |
68 | elif [ -n "${RED_DEV}" ]; then | |
69 | echo "${RED_DEV}" | |
70 | return 0 | |
71 | fi | |
72 | ;; | |
73 | ||
74 | GREEN) | |
75 | if [ -n "${GREEN_DEV}" ]; then | |
76 | echo "${GREEN_DEV}" | |
77 | return 0 | |
78 | fi | |
79 | ;; | |
80 | ||
81 | ORANGE) | |
82 | if [ -n "${ORANGE_DEV}" ]; then | |
83 | echo "${ORANGE_DEV}" | |
84 | return 0 | |
85 | fi | |
86 | ;; | |
87 | ||
88 | BLUE) | |
89 | if [ -n "${BLUE_DEV}" ]; then | |
90 | echo "${BLUE_DEV}" | |
91 | return 0 | |
92 | fi | |
93 | ;; | |
94 | ||
d99826dc MT |
95 | IPSEC) |
96 | local VARS=( | |
97 | id status x1 x2 type x3 x4 x5 x6 x7 x8 x9 x10 | |
98 | x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 | |
99 | x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 | |
100 | x31 x32 x33 x34 interface_mode rest | |
101 | ) | |
102 | ||
103 | while IFS="," read -r "${VARS[@]}"; do | |
104 | # Check if the connection is enabled | |
105 | [ "${status}" = "on" ] || continue | |
106 | ||
107 | # Check if this a net-to-net connection | |
108 | [ "${type}" = "net" ] || continue | |
109 | ||
110 | # Determine the interface name | |
111 | case "${interface_mode}" in | |
112 | gre|vti) | |
113 | echo "${interface_mode}${id}" | |
114 | ;; | |
115 | esac | |
116 | done < /var/ipfire/vpn/config | |
117 | ||
118 | return 0 | |
119 | ;; | |
120 | ||
1b7d1abd MT |
121 | WIREGUARD|WG) |
122 | echo "wg+" | |
123 | return 0 | |
124 | ;; | |
125 | ||
79cce701 MT |
126 | OPENVPN|OVPN) |
127 | # OpenVPN is using all tun devices | |
128 | echo "tun+" | |
1b7d1abd | 129 | return 0 |
79cce701 MT |
130 | ;; |
131 | esac | |
132 | ||
133 | # Not found | |
134 | return 1 | |
135 | } | |
136 | ||
3f863ee7 MT |
137 | network_get_address() { |
138 | local network="${1}" | |
139 | ||
140 | # Return everything before the slash | |
141 | echo "${network%%/*}" | |
142 | } | |
143 | ||
144 | network_get_prefix() { | |
145 | local network="${1}" | |
146 | ||
147 | # Consider everything after the / the prefix | |
148 | local prefix="${network##*/}" | |
149 | ||
150 | # If the prefix is valid, return it | |
151 | if network_prefix_is_valid "${prefix}"; then | |
152 | echo "${prefix}" | |
153 | ||
154 | # Otherwise it might be a subnet mask | |
155 | else | |
156 | network_netmask_to_prefix "${prefix}" | |
157 | fi | |
158 | } | |
159 | ||
160 | network_get_netmask() { | |
161 | local network="${1}" | |
162 | ||
163 | # Consider everything after the / the netmask | |
164 | local netmask="${network##*/}" | |
165 | ||
166 | # If we have a prefix, we need to convert | |
167 | if network_prefix_is_valid "${netmask}"; then | |
168 | network_prefix_to_netmask "${netmask}" | |
169 | ||
170 | # Otherwise return what we got | |
171 | else | |
172 | echo "${netmask}" | |
173 | fi | |
174 | } | |
175 | ||
176 | network_prefix_is_valid() { | |
177 | local prefix="${1}" | |
178 | ||
179 | # The prefix must be numbers only | |
180 | if ! [[ "${prefix}" =~ ^[0-9]+$ ]]; then | |
181 | return 1 | |
182 | fi | |
183 | ||
184 | # Must be a number between 0 and 32 (inclusive) | |
185 | [ "${prefix}" -ge 0 -a "${prefix}" -le 32 ] | |
186 | } | |
187 | ||
188 | network_prefix_to_netmask() { | |
189 | local prefix="${1}" | |
190 | ||
191 | # Set n with all bits set | |
192 | local n=0xffffffff | |
193 | ||
194 | # Shift | |
195 | (( n <<= (32 - prefix) )) | |
196 | ||
197 | # Convert back | |
198 | bin2ip "${n}" | |
199 | } | |
200 | ||
201 | network_netmask_to_prefix() { | |
202 | local netmask="${1}" | |
203 | ||
204 | local prefix=0 | |
205 | ||
206 | # Convert to binary | |
207 | local n="$(ip2bin "${netmask}")" | |
208 | ||
209 | while [ "${n}" -gt 0 ]; do | |
210 | # If the highest bit is not set, we are done | |
211 | [ "$(( n & (1 << 31) ))" -eq 0 ] && break | |
212 | ||
213 | # Increment prefix & shift n | |
214 | (( prefix++ )) | |
215 | (( n <<= 1 )) | |
216 | done | |
217 | ||
218 | echo "${prefix}" | |
219 | } | |
220 | ||
221 | network_address_in_network() { | |
222 | local address="${1}" | |
223 | local network="${2}" | |
224 | ||
225 | # Split the network into its address & mask | |
226 | local netaddr="$(network_get_address "${network}")" | |
227 | local netmask="$(network_get_netmask "${network}")" | |
228 | ||
229 | # Abort if we could not parse the network | |
230 | if [ -z "${netaddr}" -o -z "${netmask}" ]; then | |
231 | return 1 | |
232 | fi | |
233 | ||
234 | # Convert everything to binary | |
235 | address="$(ip2bin "${address}")" | |
236 | netaddr="$(ip2bin "${netaddr}")" | |
237 | netmask="$(ip2bin "${netmask}")" | |
238 | ||
239 | # Ensure the network address is the first address | |
240 | (( netaddr &= netmask )) | |
241 | ||
242 | # Compute broadcast | |
243 | local broadcast=$(( netaddr | (~netmask & 0xffffffff) )) | |
244 | ||
245 | # Return true if address is in the network | |
246 | [ "${address}" -ge "${netaddr}" -a "${address}" -le "${broadcast}" ] | |
247 | } | |
248 | ||
76ea485d MT |
249 | # Takes a network and list of IP addresses and will return the first IP address |
250 | # that is in the given network. | |
251 | first_address_in_network() { | |
252 | local network="${1}" | |
253 | shift | |
254 | ||
255 | local addr | |
256 | for addr in $@; do | |
257 | if network_address_in_network "${addr}" "${network}"; then | |
258 | echo "${addr}" | |
259 | return 0 | |
260 | fi | |
261 | done | |
262 | ||
263 | return 1 | |
264 | } | |
265 | ||
266 | # Returns the first of IPFire's own IP addresses that is in any of the given networks | |
267 | ipfire_address_in_networks() { | |
268 | local addresses=() | |
269 | ||
270 | local var | |
271 | for var in GREEN_ADDRESS BLUE_ADDRESS ORANGE_ADDRESS; do | |
272 | if [ -n "${!var}" ]; then | |
273 | addresses+=( "${!var}" ) | |
274 | fi | |
275 | done | |
276 | ||
277 | local network | |
278 | for network in $@; do | |
279 | # Find and end after the first match | |
280 | if first_address_in_network "${network}" "${addresses[@]}"; then | |
281 | return 0 | |
282 | fi | |
283 | done | |
284 | ||
285 | # Nothing found | |
286 | return 1 | |
287 | } | |
288 | ||
71ea0d68 SS |
289 | dhcpcd_get_pid() { |
290 | # This function returns the pid of a dhcpcd by a given | |
291 | # network device, if a pidfile exists. | |
292 | ||
293 | local device="$1" | |
18136c5c | 294 | local pidfile="/var/run/dhcpcd/${device}.pid" |
71ea0d68 SS |
295 | |
296 | # Check if a pid file exists. | |
297 | if [ -f "${pidfile}" ] ; then | |
298 | ||
299 | # Get the pid from the file. | |
300 | local pid="$(<"${pidfile}")" | |
301 | ||
302 | echo "${pid}" | |
303 | fi | |
304 | } | |
305 | ||
306 | dhcpcd_is_running() { | |
307 | # This functions checks if a dhcpcd is running by a given pid. | |
308 | ||
309 | local pid="$1" | |
310 | ||
311 | # Check if a dhcpcd is running. | |
312 | if [ -n "${pid}" -a -d "/proc/${pid}" ]; then | |
313 | # Return "0" (True) if a dhcpcd is running. | |
314 | return 0 | |
315 | fi | |
316 | ||
317 | # Return 1 (False) no dhcpcd is running. | |
318 | return 1 | |
319 | } | |
320 | ||
321 | dhcpcd_start() { | |
322 | # This function will start a dhcpcd on a speciefied device. | |
71ea0d68 | 323 | local device="$1" |
c6551e73 MT |
324 | shift |
325 | ||
5d0d1144 | 326 | local dhcp_start=() |
71ea0d68 SS |
327 | |
328 | boot_mesg -n "Starting dhcpcd on the ${device} interface..." | |
329 | ||
330 | # Check if a dhcpcd is already running. | |
331 | local pid="$(dhcpcd_get_pid "${device}")" | |
332 | ||
333 | if dhcpcd_is_running "${pid}"; then | |
334 | boot_mesg "dhcpcd already running!" ${WARNING} | |
335 | echo_warning | |
336 | exit 2 | |
337 | fi | |
338 | ||
339 | # Check if a DHCP hostname has been set. | |
340 | if [ -n "${RED_DHCP_HOSTNAME}" ]; then | |
5d0d1144 MT |
341 | dhcp_start+=( "-h" "${RED_DHCP_HOSTNAME}" ) |
342 | fi | |
343 | ||
344 | # Tell dhcpcd to use the configured MTU | |
345 | if [ -n "${RED_DHCP_FORCE_MTU}" ]; then | |
346 | dhcp_start+=( "--static" "mtu=${RED_DHCP_FORCE_MTU}" ) | |
71ea0d68 SS |
347 | fi |
348 | ||
c6551e73 MT |
349 | # Append any further command line options |
350 | dhcp_start+=( $@ ) | |
351 | ||
71ea0d68 | 352 | # Start dhcpcd. |
5d0d1144 | 353 | /sbin/dhcpcd "${dhcp_start[@]}" ${device} >/dev/null 2>&1 |
71ea0d68 SS |
354 | ret="$?" |
355 | ||
356 | if [ "${ret}" -eq 0 ]; then | |
357 | . /var/ipfire/dhcpc/dhcpcd-"${device}".info | |
71ea0d68 | 358 | |
f938083f AF |
359 | if [ $ip_address ]; then |
360 | echo "" | |
361 | echo_ok | |
362 | boot_mesg " DHCP Assigned Settings for ${device}:" | |
71ea0d68 | 363 | boot_mesg_flush |
f938083f AF |
364 | boot_mesg " IP Address: $ip_address" |
365 | boot_mesg_flush | |
366 | ||
367 | if [ -n "${RED_DHCP_HOSTNAME}" ]; then | |
368 | boot_mesg " Hostname: $RED_DHCP_HOSTNAME" | |
369 | boot_mesg_flush | |
370 | fi | |
71ea0d68 | 371 | |
f938083f AF |
372 | boot_mesg " Subnet Mask: $subnet_mask" |
373 | boot_mesg_flush | |
374 | boot_mesg " Default Gateway: $routers" | |
375 | boot_mesg_flush | |
376 | boot_mesg " DNS Server: $domain_name_servers" | |
377 | boot_mesg_flush | |
378 | else | |
379 | echo "" | |
380 | echo_ok | |
381 | boot_mesg "DHCP for ${device} still running..." | |
382 | boot_mesg_flush | |
383 | fi | |
71ea0d68 SS |
384 | else |
385 | echo "" | |
386 | $(exit "${ret}") | |
387 | evaluate_retval | |
388 | fi | |
389 | } | |
390 | ||
391 | dhcpcd_stop() { | |
392 | # This function stops a previously started dhcpcd on a given device. | |
393 | ||
394 | local device="$1" | |
395 | local dhcp_stop="-k" | |
396 | local leaseinfo="/var/ipfire/dhcpc/dhcpcd-${device}.info" | |
397 | ||
398 | boot_mesg -n "Stopping dhcpcd on the ${device} interface..." | |
399 | ||
400 | # Check if a dhcpcd is running. | |
401 | local pid="$(dhcpcd_get_pid "${device}")" | |
402 | ||
403 | if ! dhcpcd_is_running "${pid}"; then | |
02d67e75 | 404 | boot_mesg " Not running." ${WARNING} |
71ea0d68 SS |
405 | echo_warning |
406 | exit 1 | |
407 | fi | |
408 | ||
d43bb759 | 409 | # Stop dhcpcd. |
2e28ecea | 410 | /sbin/dhcpcd ${dhcp_stop} ${device} &> /dev/null |
d43bb759 AF |
411 | ret="$?" |
412 | ||
413 | # Wait until dhcpd has stopped. | |
414 | while [ -d "/proc/${pid}" ]; do | |
415 | sleep 1 | |
66acb7f1 AF |
416 | # repeat stop if dhcp was still running |
417 | /sbin/dhcpcd ${dhcp_stop} ${device} &> /dev/null | |
d43bb759 AF |
418 | done |
419 | ||
420 | # Display console message, depended on the exit code | |
421 | # of the stopped dhcpcd. | |
422 | if [ "${ret}" -eq 0 ]; then | |
423 | boot_mesg | |
424 | echo_ok | |
425 | elif [ "${ret}" -eq 1 ]; then | |
426 | boot_mesg "failed to stop dhcpcd!" ${WARNING} | |
427 | echo_warning | |
428 | else | |
429 | boot_mesg | |
430 | echo_failure | |
71ea0d68 SS |
431 | fi |
432 | } | |
957863f7 MT |
433 | |
434 | # QMI stuff | |
435 | ||
436 | qmi_find_device() { | |
437 | local intf="${1}" | |
438 | local _intf | |
439 | ||
440 | local path | |
441 | for path in /dev/cdc-*; do | |
442 | if [ -c "${path}" ]; then | |
580c249a | 443 | _intf="$(qmi_find_interface "${path}")" |
957863f7 MT |
444 | |
445 | # Check if the interface matches | |
446 | if [ "${intf}" = "${_intf}" ]; then | |
447 | echo "${path}" | |
448 | return 0 | |
449 | fi | |
450 | fi | |
451 | done | |
452 | ||
453 | # Nothing found | |
454 | return 1 | |
455 | } | |
456 | ||
580c249a MT |
457 | qmi_find_interface() { |
458 | local device="${1}" | |
459 | ||
460 | qmicli --device="${device}" --device-open-proxy --get-wwan-iface | |
461 | } | |
462 | ||
957863f7 MT |
463 | qmi_enable_rawip_mode() { |
464 | local intf="${1}" | |
465 | ||
466 | # Shut down the device first | |
467 | ip link set "${intf}" down &>/dev/null | |
468 | ||
469 | echo "Y" > "/sys/class/net/${intf}/qmi/raw_ip" | |
470 | } | |
471 | ||
472 | qmi_configure_apn() { | |
473 | local device="${1}" | |
474 | ||
475 | # APN settings | |
476 | local apn="${2}" | |
477 | local auth="${3}" | |
478 | local username="${4}" | |
479 | local password="${5}" | |
480 | ||
481 | local args=( | |
482 | # We only support IPv4 right now | |
483 | "ip-type=4" | |
484 | ) | |
485 | ||
486 | # Set APN | |
487 | if [ -n "${apn}" ]; then | |
488 | args+=( "apn=${apn}" ) | |
489 | fi | |
490 | ||
491 | # Set auth | |
492 | case "${auth}" in | |
493 | PAP|CHAP) | |
494 | args+=( "auth=${auth}" ) | |
495 | ;; | |
496 | esac | |
497 | ||
498 | # Set username | |
499 | if [ -n "${username}" ]; then | |
500 | args+=( "username=${username}" ) | |
501 | fi | |
502 | ||
503 | # Set password | |
504 | if [ -n "${password}" ]; then | |
505 | args+=( "password=${password}" ) | |
506 | fi | |
507 | ||
508 | local _args | |
509 | ||
510 | local arg | |
511 | for arg in ${args[@]}; do | |
512 | if [ -n "${_args}" ]; then | |
513 | _args="${_args}," | |
514 | fi | |
515 | _args="${_args}${arg}" | |
516 | done | |
517 | ||
518 | qmicli --device="${device}" --device-open-proxy \ | |
519 | --wds-start-network="${_args}" \ | |
b1ff8adb | 520 | --client-no-release-cid &>/dev/null |
957863f7 MT |
521 | } |
522 | ||
523 | qmi_reset() { | |
524 | local device="${1}" | |
525 | ||
526 | qmicli --device="${device}" --device-open-proxy \ | |
b1ff8adb | 527 | --wds-reset &>/dev/null |
957863f7 | 528 | } |
580c249a MT |
529 | |
530 | # Assigns a "static" MAC address | |
531 | qmi_assign_address() { | |
532 | local intf="${1}" | |
533 | ||
534 | # Find the device | |
535 | local device="$(qmi_find_device "${intf}")" | |
536 | ||
caef75c5 SS |
537 | # Switch off the raw_ip mode to be able to proper |
538 | # assign the generated MAC address. | |
539 | echo "N" > "/sys/class/net/${intf}/qmi/raw_ip" | |
540 | ||
580c249a MT |
541 | local address |
542 | ||
543 | # Generate a "random" MAC address using the device number | |
544 | printf -v address "02:ff:ff:ff:ff:%02x" "${device:12}" | |
545 | ||
546 | # Change the MAC address | |
547 | ip link set "${intf}" address "${address}" | |
548 | } |