mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-09 18:45:54 +02:00
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> commitd99826dc71Author: 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> commitdb151ad716Author: 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> commit1b7d1abdf0Author: 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> commit79cce701a9Author: 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> commit3f863ee70dAuthor: 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> commite340d393d3Author: 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>
549 lines
11 KiB
Bash
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}"
|
|
}
|