pmaports/main/postmarketos-base-ui/rootfs-usr-lib-NetworkManager-dispatcher.d-50-tethering.sh
Arnav Singh de08bca311
main/postmarketos-{base-ui,config-nftables}: reorganize NM configs and scripts (MR 4254)
1. Move all configs from /etc/NetworkManager/conf.d to
   /usr/lib/NetworkManager/conf.d since the latter is more appropriate for
   distribution-provided config files. In particular this means apk will
   update them when the package file is changed rather than creating
   `.apk-new` files. If a user wants to override such a file, they can create
   a file with the same name under /etc/NetworkManager/conf.d

2. Move all dispatcher scripts from /etc/NetworkManager/dispatcher.d to
   /usr/lib/NetworkManager/dispatcher.d for the same reason.

3. Rename all configs to have a "50-" prefix so that users can add their own
   "99-" overrides with a guarantee that they'll be processed after
   distribution-provided configs.

4. Rename dispatcher scripts to have a "50-" prefix instead of "85-" and "99-"
   since they're distribution-provided files.

5. Move 50-tethering.conf from the base-ui package to
   the base-ui-networkmanager package.

There are also some device packages that put config files without a numeric
prefix in /etc/NetworkManager/conf.d . This MR doesn't change those.

[ci:skip-build] already built successfully in CI
2023-07-17 10:06:52 -07:00

119 lines
4 KiB
Bash

#!/bin/sh -e
# Handle USB tethering with unudhcpd and NetworkManager while also
# keeping SSH login over USB working when tethering is disabled.
#
# Copyright (c) 2023 Dylan Van Assche
# SPDX-License-Identifier: GPL-3.0-or-later
# Must match with the supplied connection profile,
# using UUID allows the user to change the connection name if they want to.
con_uuid="83bd1823-feca-4c2b-9205-4b83dc792e1f"
interface="usb0"
host_ip="172.16.42.1"
client_ip="172.16.42.2"
# Skip if iface does not match
if [ "$DEVICE_IFACE" != "$interface" ]; then
exit 0
fi
# Trigger a disconnect/connect event on the client side to request a new DHCP lease.
reactivate_gadget() {
# Mount configFS
mkdir -p /config
mount -t configfs none /config || true
logger -t nm-tethering "configFS mounted"
# Reactivate gadget
udc=$(cat /config/usb_gadget/g1/UDC)
echo "" > /config/usb_gadget/g1/UDC
sleep 1
echo "$udc" > /config/usb_gadget/g1/UDC
logger -t nm-tethering "gadget reactivated"
# Unmount configFS
umount /config
rm -rf /config
logger -t nm-tethering "configFS unmounted"
}
# Default static IP for SSH acccess
# 1. Configure NetworkManager connection to use IP 172.16.42.1, same as initfs.
# 2. Disable IPv6 as unudhcpd only supplies IPv4 addresses.
# 3. Start unudhcpd to handle DHCP requests.
# 4. Reactivate the USB Ethernet gadget to force the clients to reactivate the interface.
disable_tethering() {
# Configure static IP and bring up connection automatically
nmcli connection modify "$con_uuid" ipv4.address "$host_ip/16"
nmcli connection modify "$con_uuid" ipv4.method "manual"
nmcli connection modify "$con_uuid" ipv6.method "link-local"
nmcli connection modify "$con_uuid" connection.autoconnect "true"
# If unudhpcd is not running, start it and configure it similar to initfs
if [ ! "$(pidof unudhcpd)" ]; then
(unudhcpd -i "$interface" -s "$host_ip" -c "$client_ip") &
logger -t nm-tethering "unudhcpd started"
reactivate_gadget
logger -t nm-tethering "USB tethering disabled"
fi
}
# USB tethering
# 1. Enforce 172.16.42.1 as host IP even in tethering mode.
# 2. Stop unudhcpd as NetworkManager will spawn dnsmasq to handle DNS and DHCP requests.
# 3. Reactivate the USB Ethernet gadget to force the clients to reactivate the interface.
enable_tethering() {
# Enforce the same IP range as when tethering is disabled, this will retrigger
# the script as we have to reapply again, also bring up connection automatically.
ip=$(nmcli connection show "$con_uuid" --active | grep ipv4.addresses | tr -s " " | cut -d " " -f2)
if [ "$ip" != "$host_ip/16" ]; then
logger -t nm-tethering "Enforcing $host_ip/16 as DHCP range"
nmcli connection modify "$con_uuid" ipv4.address "$host_ip/16"
nmcli connection modify "$con_uuid" connection.autoconnect "true"
nmcli device reapply "$interface"
return
fi
# Kill unudhcpd if needed
if [ "$(pidof unudhcpd)" ]; then
killall unudhcpd
logger -t nm-tethering "unudhcpd stopped"
reactivate_gadget
logger -t nm-tethering "USB tethering enabled"
fi
}
# Handle dispatcher events for tethering
method=$(nmcli connection show "$con_uuid" --active | grep ipv4.method | tr -s " " | cut -d " " -f2)
case $NM_DISPATCHER_ACTION in
# Always disable tethering on insert or removal for security
"up"|"down")
disable_tethering
# The connection may have been configured before to tethering which
# is not desired when iface comes up or is shut down as tethering must be
# disabled. Enforce this by triggering a reapply after modifying the connection
# which will cause NetworkManager to trigger the script again.
# If the iface is already down since dispatcher scripts are executed async,
# the command will fail which is fine to ignore
if [ "$method" = "shared" ]; then
logger -t nm-tethering "Enforcing tethering disabled on iface up/down"
nmcli device reapply "$interface" || true
fi
;;
# Enable tethering if the user explicitly enabled it
"reapply")
if [ "$method" = "shared" ]; then
enable_tethering
elif [ "$method" = "manual" ]; then
disable_tethering
fi
;;
esac