Files
bpfire/src/initscripts/networking/functions.network
2024-09-24 08:45:31 +00:00

483 lines
10 KiB
Bash

#!/bin/bash
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
# 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 <http://www.gnu.org/licenses/>. #
# #
###############################################################################
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_intfs() {
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}"
}