Files
bpfire/src/initscripts/networking/functions.network
Vincent Li d854559daf initscripts: sync networking functions from IPFire
following commit made changes to networking functions

commit 76ea485d9edb781328e307c68b1f878d933408e5
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Fri Sep 27 17:39:22 2024 +0200

    wireguard: Select the correct source IP address for N2N peers

    This is so that the firewall chooses the correct IP address when trying
    to establish connections to the remote networks.

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

commit d99826dc71
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Tue Sep 24 10:33:22 2024 +0200

    suricata: Enable scanning IPsec packets

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

commit db151ad716
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Sun Sep 22 17:08:03 2024 +0200

    suricata: Add support for zones having multiple interfaces

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

commit 1b7d1abdf0
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Tue Sep 10 10:50:15 2024 +0200

    suricata: Add option to scan WireGuard

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

commit 79cce701a9
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Tue Sep 10 10:40:28 2024 +0200

    suricata: Restore the interface selection

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

commit 3f863ee70d
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Sat Mar 23 14:32:30 2024 +0100

    initscripts: Add some basic functions for IP address maths

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

commit e340d393d3
Author: Michael Tremer <michael.tremer@ipfire.org>
Date:   Fri Mar 22 17:40:15 2024 +0100

    network: Don't include initscript headers twice

    Everywhere we import the functions, we have already imported the
    standard includes.

    Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>

Signed-off-by: Vincent Li <vincent.mc.li@gmail.com>
2025-07-02 16:55:13 +00:00

549 lines
11 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
;;
IPSEC)
local VARS=(
id status x1 x2 type x3 x4 x5 x6 x7 x8 x9 x10
x11 x12 x13 x14 x15 x16 x17 x18 x19 x20
x21 x22 x23 x24 x25 x26 x27 x28 x29 x30
x31 x32 x33 x34 interface_mode rest
)
while IFS="," read -r "${VARS[@]}"; do
# Check if the connection is enabled
[ "${status}" = "on" ] || continue
# Check if this a net-to-net connection
[ "${type}" = "net" ] || continue
# Determine the interface name
case "${interface_mode}" in
gre|vti)
echo "${interface_mode}${id}"
;;
esac
done < /var/ipfire/vpn/config
return 0
;;
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}" ]
}
# Takes a network and list of IP addresses and will return the first IP address
# that is in the given network.
first_address_in_network() {
local network="${1}"
shift
local addr
for addr in $@; do
if network_address_in_network "${addr}" "${network}"; then
echo "${addr}"
return 0
fi
done
return 1
}
# Returns the first of IPFire's own IP addresses that is in any of the given networks
ipfire_address_in_networks() {
local addresses=()
local var
for var in GREEN_ADDRESS BLUE_ADDRESS ORANGE_ADDRESS; do
if [ -n "${!var}" ]; then
addresses+=( "${!var}" )
fi
done
local network
for network in $@; do
# Find and end after the first match
if first_address_in_network "${network}" "${addresses[@]}"; then
return 0
fi
done
# Nothing found
return 1
}
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}"
}