#!/bin/bash ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2007-2022 IPFire Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings) eval $(/usr/local/bin/readhash /var/ipfire/dns/settings) ip2bin() { local address="${1}" local IFS='.' local octet local n=0 for octet in ${address}; do # Shift n (( n <<= 8 )) # Apply the octet (( n |= octet )) done echo "${n}" } bin2ip() { local n="${1}" local IFS='.' local address=() for i in {3..0}; do address+=( $(( n >> (8 * i) & 0xff )) ) done echo "${address[*]}" } network_get_intf() { local zone="${1}" case "${zone}" in RED) # For PPPoE, the RED interface is called ppp0 (unless we use QMI) if [ "${RED_TYPE}" = "PPPOE" ] && [ "${RED_DRIVER}" != "qmi_wwan" ]; then echo "ppp0" return 0 # Otherwise we return RED_DEV elif [ -n "${RED_DEV}" ]; then echo "${RED_DEV}" return 0 fi ;; GREEN) if [ -n "${GREEN_DEV}" ]; then echo "${GREEN_DEV}" return 0 fi ;; ORANGE) if [ -n "${ORANGE_DEV}" ]; then echo "${ORANGE_DEV}" return 0 fi ;; BLUE) if [ -n "${BLUE_DEV}" ]; then echo "${BLUE_DEV}" return 0 fi ;; WIREGUARD|WG) echo "wg+" return 0 ;; OPENVPN|OVPN) # OpenVPN is using all tun devices echo "tun+" return 0 ;; esac # Not found return 1 } network_get_address() { local network="${1}" # Return everything before the slash echo "${network%%/*}" } network_get_prefix() { local network="${1}" # Consider everything after the / the prefix local prefix="${network##*/}" # If the prefix is valid, return it if network_prefix_is_valid "${prefix}"; then echo "${prefix}" # Otherwise it might be a subnet mask else network_netmask_to_prefix "${prefix}" fi } network_get_netmask() { local network="${1}" # Consider everything after the / the netmask local netmask="${network##*/}" # If we have a prefix, we need to convert if network_prefix_is_valid "${netmask}"; then network_prefix_to_netmask "${netmask}" # Otherwise return what we got else echo "${netmask}" fi } network_prefix_is_valid() { local prefix="${1}" # The prefix must be numbers only if ! [[ "${prefix}" =~ ^[0-9]+$ ]]; then return 1 fi # Must be a number between 0 and 32 (inclusive) [ "${prefix}" -ge 0 -a "${prefix}" -le 32 ] } network_prefix_to_netmask() { local prefix="${1}" # Set n with all bits set local n=0xffffffff # Shift (( n <<= (32 - prefix) )) # Convert back bin2ip "${n}" } network_netmask_to_prefix() { local netmask="${1}" local prefix=0 # Convert to binary local n="$(ip2bin "${netmask}")" while [ "${n}" -gt 0 ]; do # If the highest bit is not set, we are done [ "$(( n & (1 << 31) ))" -eq 0 ] && break # Increment prefix & shift n (( prefix++ )) (( n <<= 1 )) done echo "${prefix}" } network_address_in_network() { local address="${1}" local network="${2}" # Split the network into its address & mask local netaddr="$(network_get_address "${network}")" local netmask="$(network_get_netmask "${network}")" # Abort if we could not parse the network if [ -z "${netaddr}" -o -z "${netmask}" ]; then return 1 fi # Convert everything to binary address="$(ip2bin "${address}")" netaddr="$(ip2bin "${netaddr}")" netmask="$(ip2bin "${netmask}")" # Ensure the network address is the first address (( netaddr &= netmask )) # Compute broadcast local broadcast=$(( netaddr | (~netmask & 0xffffffff) )) # Return true if address is in the network [ "${address}" -ge "${netaddr}" -a "${address}" -le "${broadcast}" ] } dhcpcd_get_pid() { # This function returns the pid of a dhcpcd by a given # network device, if a pidfile exists. local device="$1" local pidfile="/var/run/dhcpcd/${device}.pid" # Check if a pid file exists. if [ -f "${pidfile}" ] ; then # Get the pid from the file. local pid="$(<"${pidfile}")" echo "${pid}" fi } dhcpcd_is_running() { # This functions checks if a dhcpcd is running by a given pid. local pid="$1" # Check if a dhcpcd is running. if [ -n "${pid}" -a -d "/proc/${pid}" ]; then # Return "0" (True) if a dhcpcd is running. return 0 fi # Return 1 (False) no dhcpcd is running. return 1 } dhcpcd_start() { # This function will start a dhcpcd on a speciefied device. local device="$1" shift local dhcp_start=() boot_mesg -n "Starting dhcpcd on the ${device} interface..." # Check if a dhcpcd is already running. local pid="$(dhcpcd_get_pid "${device}")" if dhcpcd_is_running "${pid}"; then boot_mesg "dhcpcd already running!" ${WARNING} echo_warning exit 2 fi # Check if a DHCP hostname has been set. if [ -n "${RED_DHCP_HOSTNAME}" ]; then dhcp_start+=( "-h" "${RED_DHCP_HOSTNAME}" ) fi # Tell dhcpcd to use the configured MTU if [ -n "${RED_DHCP_FORCE_MTU}" ]; then dhcp_start+=( "--static" "mtu=${RED_DHCP_FORCE_MTU}" ) fi # Append any further command line options dhcp_start+=( $@ ) # Start dhcpcd. /sbin/dhcpcd "${dhcp_start[@]}" ${device} >/dev/null 2>&1 ret="$?" if [ "${ret}" -eq 0 ]; then . /var/ipfire/dhcpc/dhcpcd-"${device}".info if [ $ip_address ]; then echo "" echo_ok boot_mesg " DHCP Assigned Settings for ${device}:" boot_mesg_flush boot_mesg " IP Address: $ip_address" boot_mesg_flush if [ -n "${RED_DHCP_HOSTNAME}" ]; then boot_mesg " Hostname: $RED_DHCP_HOSTNAME" boot_mesg_flush fi boot_mesg " Subnet Mask: $subnet_mask" boot_mesg_flush boot_mesg " Default Gateway: $routers" boot_mesg_flush boot_mesg " DNS Server: $domain_name_servers" boot_mesg_flush else echo "" echo_ok boot_mesg "DHCP for ${device} still running..." boot_mesg_flush fi else echo "" $(exit "${ret}") evaluate_retval fi } dhcpcd_stop() { # This function stops a previously started dhcpcd on a given device. local device="$1" local dhcp_stop="-k" local leaseinfo="/var/ipfire/dhcpc/dhcpcd-${device}.info" boot_mesg -n "Stopping dhcpcd on the ${device} interface..." # Check if a dhcpcd is running. local pid="$(dhcpcd_get_pid "${device}")" if ! dhcpcd_is_running "${pid}"; then boot_mesg " Not running." ${WARNING} echo_warning exit 1 fi # Stop dhcpcd. /sbin/dhcpcd ${dhcp_stop} ${device} &> /dev/null ret="$?" # Wait until dhcpd has stopped. while [ -d "/proc/${pid}" ]; do sleep 1 # repeat stop if dhcp was still running /sbin/dhcpcd ${dhcp_stop} ${device} &> /dev/null done # Display console message, depended on the exit code # of the stopped dhcpcd. if [ "${ret}" -eq 0 ]; then boot_mesg echo_ok elif [ "${ret}" -eq 1 ]; then boot_mesg "failed to stop dhcpcd!" ${WARNING} echo_warning else boot_mesg echo_failure fi } # QMI stuff qmi_find_device() { local intf="${1}" local _intf local path for path in /dev/cdc-*; do if [ -c "${path}" ]; then _intf="$(qmi_find_interface "${path}")" # Check if the interface matches if [ "${intf}" = "${_intf}" ]; then echo "${path}" return 0 fi fi done # Nothing found return 1 } qmi_find_interface() { local device="${1}" qmicli --device="${device}" --device-open-proxy --get-wwan-iface } qmi_enable_rawip_mode() { local intf="${1}" # Shut down the device first ip link set "${intf}" down &>/dev/null echo "Y" > "/sys/class/net/${intf}/qmi/raw_ip" } qmi_configure_apn() { local device="${1}" # APN settings local apn="${2}" local auth="${3}" local username="${4}" local password="${5}" local args=( # We only support IPv4 right now "ip-type=4" ) # Set APN if [ -n "${apn}" ]; then args+=( "apn=${apn}" ) fi # Set auth case "${auth}" in PAP|CHAP) args+=( "auth=${auth}" ) ;; esac # Set username if [ -n "${username}" ]; then args+=( "username=${username}" ) fi # Set password if [ -n "${password}" ]; then args+=( "password=${password}" ) fi local _args local arg for arg in ${args[@]}; do if [ -n "${_args}" ]; then _args="${_args}," fi _args="${_args}${arg}" done qmicli --device="${device}" --device-open-proxy \ --wds-start-network="${_args}" \ --client-no-release-cid &>/dev/null } qmi_reset() { local device="${1}" qmicli --device="${device}" --device-open-proxy \ --wds-reset &>/dev/null } # Assigns a "static" MAC address qmi_assign_address() { local intf="${1}" # Find the device local device="$(qmi_find_device "${intf}")" # Switch off the raw_ip mode to be able to proper # assign the generated MAC address. echo "N" > "/sys/class/net/${intf}/qmi/raw_ip" local address # Generate a "random" MAC address using the device number printf -v address "02:ff:ff:ff:ff:%02x" "${device:12}" # Change the MAC address ip link set "${intf}" address "${address}" }