From 4b516916dc229124598552913233a2aa738a51fd Mon Sep 17 00:00:00 2001 From: Clayton Craft Date: Wed, 25 Jan 2023 00:14:08 -0800 Subject: [PATCH] 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 --- .ci/shellcheck.sh | 1 + main/postmarketos-base-ui/APKBUILD | 12 +- ...etc-NetworkManager-conf.d-use-dnsmasq.conf | 2 + ...tworkManager-dispatcher.d-99-dns-filter.sh | 145 ++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 main/postmarketos-base-ui/rootfs-etc-NetworkManager-conf.d-use-dnsmasq.conf create mode 100644 main/postmarketos-base-ui/rootfs-etc-NetworkManager-dispatcher.d-99-dns-filter.sh diff --git a/.ci/shellcheck.sh b/.ci/shellcheck.sh index bd870c4af..d8c46bbb6 100755 --- a/.ci/shellcheck.sh +++ b/.ci/shellcheck.sh @@ -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 diff --git a/main/postmarketos-base-ui/APKBUILD b/main/postmarketos-base-ui/APKBUILD index 2715398c3..d5df724f4 100644 --- a/main/postmarketos-base-ui/APKBUILD +++ b/main/postmarketos-base-ui/APKBUILD @@ -1,6 +1,6 @@ # Maintainer: Clayton Craft 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 " diff --git a/main/postmarketos-base-ui/rootfs-etc-NetworkManager-conf.d-use-dnsmasq.conf b/main/postmarketos-base-ui/rootfs-etc-NetworkManager-conf.d-use-dnsmasq.conf new file mode 100644 index 000000000..53a8b1725 --- /dev/null +++ b/main/postmarketos-base-ui/rootfs-etc-NetworkManager-conf.d-use-dnsmasq.conf @@ -0,0 +1,2 @@ +[main] +dns=dnsmasq diff --git a/main/postmarketos-base-ui/rootfs-etc-NetworkManager-dispatcher.d-99-dns-filter.sh b/main/postmarketos-base-ui/rootfs-etc-NetworkManager-dispatcher.d-99-dns-filter.sh new file mode 100644 index 000000000..cbc57fc9b --- /dev/null +++ b/main/postmarketos-base-ui/rootfs-etc-NetworkManager-dispatcher.d-99-dns-filter.sh @@ -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"