pmos-base-ui-networkmanager: set up dnsmasq for filtering lookups (MR 3823)

This uses a dispatcher script to configure filtering A and AAAA records
based on which IP versions are routable on the NM primary connection.

gojq is preferred over the 'standard' jq because it's considerably
faster... the dispatcher script took 0.89s on my L5 with jq, and 0.07s
with gojq. the difference is probably greater on slower phones... so it
seemed worth installing it.

fixes #1430

Co-authored-by: Arnavion <me@arnavion.dev>
This commit is contained in:
Clayton Craft 2023-01-25 00:14:08 -08:00
parent 08b32ff4ba
commit 4b516916dc
No known key found for this signature in database
GPG key ID: 4A4CED6D7EDF950A
4 changed files with 159 additions and 1 deletions

View file

@ -17,6 +17,7 @@ sh_files="
./main/mdss-fb-init-hack/mdss-fb-init-hack.sh
./main/osk-sdl/unlock.sh
./main/postmarketos-base/rootfs-usr-lib-firmwareload.sh
./main/postmarketos-base-ui/rootfs-etc-NetworkManager-dispatcher.d-99-dns-filter.sh
./main/postmarketos-installkernel/installkernel-pmos
./main/postmarketos-initramfs/init.sh
./main/postmarketos-initramfs/init_functions.sh

View file

@ -1,6 +1,6 @@
# Maintainer: Clayton Craft <clayton@craftyguy.net>
pkgname=postmarketos-base-ui
pkgver=7
pkgver=8
pkgrel=0
pkgdesc="Meta package for minimal postmarketOS UI base"
url="https://postmarketos.org"
@ -39,6 +39,7 @@ replaces_priority=100 # leave plenty for alpine
_source644="
etc/NetworkManager/conf.d/hostname-mode.conf
etc/NetworkManager/conf.d/use-dnsmasq.conf
etc/chrony/chrony.conf
etc/conf.d/openrc-settingsd
etc/conf.d/tinydm
@ -50,6 +51,7 @@ _source644="
etc/X11/Xwrapper.config
"
_source755="
etc/NetworkManager/dispatcher.d/99-dns-filter.sh
etc/tinydm.d/env-wayland.d/50-firefox-wayland.sh
etc/tinydm.d/env-wayland.d/50-sdl-wayland.sh
"
@ -129,13 +131,19 @@ _obexd() {
networkmanager() {
depends="
busctl
dnsmasq-dnssec-dbus>=2.89-r2
gojq
networkmanager
networkmanager-cli
networkmanager-openrc
networkmanager-tui
networkmanager-wifi
networkmanager-wwan"
amove etc/NetworkManager/conf.d/hostname-mode.conf
amove etc/NetworkManager/conf.d/use-dnsmasq.conf
amove etc/NetworkManager/dispatcher.d/99-dns-filter.sh
}
_default_camera() {
@ -147,6 +155,7 @@ _default_camera() {
sha512sums="
3c9ae7415f4891bee8595166ed6a42cb577a837f741c6b5409d193558626348b41516888a01d0c4895282c5f4e9a1ff838c19712888750b2ef68429bb4b42ee3 rootfs-etc-NetworkManager-conf.d-hostname-mode.conf
900554534191fa0797064d35350934cdd8af59f30f0ae7d8ec63c2e11c44a16c643d3024b6543940488cd590fec1d392548bcaacc3be88cddff90f69b17ece07 rootfs-etc-NetworkManager-conf.d-use-dnsmasq.conf
e5d049db1d82c510bab9246208b51b8ec2711d008d67792fc10d4c0b65ed4dece7b5ae3c3dd28a8539d177b6849c1f921cb9fef3d2c7bee0355451f7b4757ec6 rootfs-etc-chrony-chrony.conf
49fb494b659fe0149a93eafe109609acce6a470bb8acea160638d07e0e4b11af2544f34549d5ef2deb2914a7ef13d0d470b04ad62981f14f96999af02a5f24cf rootfs-etc-conf.d-openrc-settingsd
44e4283c6f77de83915977dd3bc2d8e2d96b3ed6cc68d3cc156304359ae649b5a8b0bac843e517ec6faa2066dd43ba85e313899b1eda04862f864fb9eb508aa0 rootfs-etc-conf.d-tinydm
@ -156,6 +165,7 @@ fe0651904c1f40ffa67d83daca190af199f63247e53642a59a1e1147cd06776fcf20b7b2fcc53737
90b30cbea660ef6cd4c0461b6935de0cd63a84a1a40edb24348a83044c97935b974bd8bafda9cd558e92d3eb69e22c5ccf55483b80f839e24f0eb57ae2df6fe3 rootfs-etc-skel-.profile
6b9c7bb73213187eb9ca8a94109b2b816f50c1158c90fec2e92b373864280d67741589e5bfbab8810945f031d2f4b535aad78a72e46e52ea50be5b85324da381 rootfs-etc-sleep-inhibitor.conf
cac604e25c46e695dd30bd5a10cfd2d69595fcc3bc290096ac94b76b10834d591ea6576afb79c46b5da492a1dbf8660cf87b6110cd39937e15237bc74fa7a5c6 rootfs-etc-X11-Xwrapper.config
52d58729cbf3cd0318de633e8a8da74c7af246025a8c5746d5e7c854bdabbf27fa07d8558ffec92a30491cdb687fe4414de5adcddd7da5be3510f918fba463a2 rootfs-etc-NetworkManager-dispatcher.d-99-dns-filter.sh
d1ddd43489e6016e3ffd716027ed2bae4a2ab5f213118bdbcb96750e267ab7c0367cd0e0e386300aa5550352653144f5caeddd790621fe0879f83ca1995bb65c rootfs-etc-tinydm.d-env-wayland.d-50-firefox-wayland.sh
ecaa57d033a119a53a6574c27636b7c89d659d75ea48a973a6a4ff6f90e5d07202529fd489bfc9dfc7430f5b60f40612f6d5c06f7fab47e681b0a3112a874058 rootfs-etc-tinydm.d-env-wayland.d-50-sdl-wayland.sh
"

View file

@ -0,0 +1,2 @@
[main]
dns=dnsmasq

View file

@ -0,0 +1,145 @@
#!/bin/sh
# This dispatcher script exists to configure a dnsmasq instance managed by
# NetworkManager to restrict DNS responses based on the IP configuration
# supported by NetworkManager's "Primary Connection". The script requires that
# NetworkManager is configured to use/manage dnsmasq.
# For more information about *why* this is necessary, see:
# - https://gitlab.com/postmarketOS/pmaports/-/issues/1430
# - https://gitlab.com/postmarketOS/pmaports/-/merge_requests/3823
# Related:
# - https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1279
set -eu
log_tag="nm-dns-filter"
dbus="busctl --json=short"
# gojq is like... 10x faster than jq on a modest phone... (0.07s vs 0.89s)
jq=gojq
action="${2:-}"
# Get the gateway for the given connection and IP protocol version
# $1: D-Bus path to connection
# $2: IP version, e.g. '4' or '6'
get_gateway() {
_conn="$1"
_ver="$2"
_ipcfg="$($dbus get-property \
org.freedesktop.NetworkManager \
"$_conn" \
org.freedesktop.NetworkManager.Connection.Active \
"Ip${_ver}Config" | $jq -r '.data')"
if [ -z "$_ipcfg" ]; then
logger -i -t "$log_tag" "error: unable to determine IP config for primary connection!"
exit 1
fi
logger -i -t "$log_tag" "pri conn ip$_ver config path: $_ipcfg"
_attempt=0
# NetworkManager dispatches to the script as soon as the interface comes
# up, which for an IPv6 network may be before the device has received an
# Router Advertisement (RA). This means that there may be no IPv6 gateway
# defined right now, but if we wait a few seconds an RA might arrive and a
# gateway might become defined. NM does not dispatch to scripts when an RA
# arrives and triggers a change in IP address / gateway / routes, so the
# current invocation is our only chance. So we wait up to 5 seconds for the
# gateway to be defined before deciding that the network doesn't have IPv6
# connectivity. NetworkManager-dispatcher man page says that the dispatcher
# will kill scripts that run for "too long", that's currently (in NM 1.42)
# set to 10 minutes, but let's keep our timeout much shorter.
while [ "$_attempt" -lt 5 ]; do
_gateway="$($dbus get-property \
org.freedesktop.NetworkManager \
"$_ipcfg" \
"org.freedesktop.NetworkManager.IP${_ver}Config" \
Gateway | $jq -r '.data')"
if [ -n "$_gateway" ]; then
break
fi
sleep 1
_attempt="$(( _attempt + 1 ))"
done
logger -i -t "$log_tag" "ip$_ver gateway: $_gateway"
echo "$_gateway"
}
# $1: filter record type, e.g. 'A' or 'AAAA'
# $2: bool value, e.g. 'true' or 'false'
set_filter() {
_type="$1"
_val="$2"
logger -i -t "$log_tag" "setting $_type filter to '$_val'"
$dbus call org.freedesktop.NetworkManager.dnsmasq \
/uk/org/thekelleys/dnsmasq \
org.freedesktop.NetworkManager.dnsmasq \
"SetFilter$_type" b "$_val"
}
# The up/down actions are probably(?) sufficient to act on. The goal is to only
# update filtering in dnsmasq when there's some possibility that the _primary
# connection_ has changed.
case "$action" in
"up" | "down" | "reapply")
;;
*)
# unsupported action
exit 0
esac
primaryConn="$($dbus get-property \
org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager \
PrimaryConnection | $jq -r '.data')"
if [ -z "$primaryConn" ]; then
logger -i -t "$log_tag" "unable to determine primary connection!"
exit 1
fi
# This looks at the primary connection's 'gateway' property for the IP6Config
# and IP4Config interfaces, and assumes that if the gateway is unset then the
# connection does not "support" the protocol.
ip4gateway="$(get_gateway "$primaryConn" 4)"
ip6gateway="$(get_gateway "$primaryConn" 6)"
# if no gateways, disable all filtering (default dnsmasq behavior)
if [ -z "$ip4gateway" ] && [ -z "$ip6gateway" ]; then
logger -i -t "$log_tag" "no gateways for primary connection"
logger -i -t "$log_tag" "disabling IPv4 filter"
set_filter A false
logger -i -t "$log_tag" "disabling IPv6 filter"
set_filter AAAA false
else # toggle filters individually depending on gateway status
if [ -z "$ip4gateway" ]; then
logger -i -t "$log_tag" "enabling IPv4 filter"
set_filter A true
else
logger -i -t "$log_tag" "disabling IPv4 filter"
set_filter A false
fi
if [ -z "$ip6gateway" ]; then
logger -i -t "$log_tag" "enabling IPv6 filter"
set_filter AAAA true
else
logger -i -t "$log_tag" "disabling IPv6 filter"
set_filter AAAA false
fi
fi
# dnsmasq will continue to use possibly unfiltered results from its cache, so
# clear the cache
# also see: https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/msg16695.html
$dbus call \
org.freedesktop.NetworkManager.dnsmasq \
/uk/org/thekelleys/dnsmasq org.freedesktop.NetworkManager.dnsmasq \
ClearCache
logger -i -t "$log_tag" "dns filter config applied successfully"