]>
| 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 | } |