From c15127b6ab24bb16ab61957a69b623c80ee372f0 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Thu, 16 Oct 2025 10:27:53 +0200 Subject: [PATCH] Add --apply-egress-mtu option and corresponding unittests to allow automatic MTU adjustment on egress interface before setting WireGuard MTU See: https://chatgpt.com/share/68efc179-1a10-800f-9656-1e8731b40546 (German discussion) --- __pycache__/main.cpython-313.pyc | Bin 17752 -> 18313 bytes __pycache__/test.cpython-313.pyc | Bin 10096 -> 14914 bytes main.py | 11 ++++ test.py | 100 +++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc index a142012f92f594175fa6e9b0e7957444379e78c6..cfb2c30246bc6bdcdbd350910aa35b8a3b9e584c 100644 GIT binary patch delta 1186 zcmYjRT})eL7(VZ5kFB(&&>sFFoQ9RQlpYGDV-#?9u)5(!3x~6H?K)_?L)*BY&X%EQ zvUsO6WG?T8#>5!!=7j;$7_&Q#7hmRhSDS3Q&ubKBoTk_=`s(*jWmTGl2;nU zM?D?pp&HCbu>TI+hGD#I{}=qY>21a}gC6hpTFL6K-X1uJHyqtCg6j@D9Ku;S9H;#Wh;`ocR3)9XV946dt@H(y1jf}DaBLiM>@%W`( zk8YP)6RfPYg!%}|u8(07AG>*^G6nQrK6+RbvTo&8lG;N}b%4R}!2A_$|)T$V+i*4=`zE`WPL~?46 zrTR?0Lq;YM1WyyDL@W9StXy10s8MGr4N2T~! zvL~AGsl6Bbyfd(%idDdJAmdQ;;}THQF^Z5(!dX&uDN}=GnSX^G64pKxYW)(qMT2j)*+*L)0B#T+$ z2~I`Kh=NkgdR=1abN>s?wXyh0hSDU2<1?XfK#<NA)7Z_}T|@UnV`G^Qmm~A{BeCsBZ0r4U{A}5h_|16k35^VIBsRj|k8NGu z%9bss?-`>Hjn+>>w}#ipzaGD5JX8uEIR(w{0b`qk0{xL}x3?}@>$VT_i&p$*@>{rr Y>8S&-gC9<9>Vqs?gWY3V3?6Oy9}3ty-v9sr delta 711 zcmY*XOHUI~6uxI3DQ)_YK&dUkGO49gTH6`M;-dtrl%j~DoeVx&D`lY=2#YpaqYGmU ziH{g!j{m`x!8&n)JL8&|i3?u=mqr$Xx^&~6p|yIG`})rJedpZA{bl&@0NlS^E(f9Q z>E_m4NUFQn1ZL8suM3-uyWlhfW>XVt64yiB9_b%UrkD_3g#r8={tXI_^!f06Ux2Rc zkr3?1dL#%bG$LUb#A+mEJD@Rcq8`MRh|s_fVO{pZVRVTFNaL31hatQx&f}ce(@@8v zGK^p{+Qm_625ZrWa0J=@J8)EA>hA%5RL$l`@kg=)U&V4Th7k8b&T<+@C0^r?{f$50 zV>dmHAQe;wdi94qxWrh&VH3jNPytVHUoU*u67)mJq(<#^?^^!uN zK_?pIizp|(P{Q$K49=K|ZF$W@T~#bg0nQ?nqu$trVs9Bxbf#(1nrCm&!L2= zitOtsS&wr`<7w?PnuCs6Ga4*gd`BzM6;fq-X4Eyeq;4s3SB>^|a qUV?#7a(m%DuIB2&>j1Z5yTTIAdGF>s*8h=fTgq+IZJ@G?O8)?h7qEK( diff --git a/__pycache__/test.cpython-313.pyc b/__pycache__/test.cpython-313.pyc index 953acee2e51d7556262e3c18fcdb33e57bdf26db..cc2751871faf62e4b0500e79d762207773aeed8e 100644 GIT binary patch delta 3328 zcmcInTTC126`t{RJhr(712#4c;gWU0#$22W2_V2^SIrVN*fiB9+Ua1A%_v}7|BRub z)za-nC0c3I>Q}2gqN*zqX{EBF4_h@4n+*>ut+a{-E3#HrUF}1qtyGCLkyb^0=s9B> z$b}ZE>L9*3|Ly$epZUIX#ygij)+(Mjoje0q|NA>LUx$8O@i&9X{K4*|(R0mooQWF3 zEDkb^-f~6jqUN&(`j)Ye^-;lelK#rT8Hkbn%fyD)-#->G*v28S0y|B{>DR7w#{jha z4$=fS(u^>O(1LIrA&4-vK3|t%*|GJ%)>j*j_hZ*70KbJe&~_r|ZcWotq6a*?J-=fI z*YA3k&Fn7yLTK~$g+inXrhQXuW|)}YbYNkO{z7=W=DXV;)upC{f^|3ZO;;uKE zrfjsw(h@LF*}~ujFM+vQTeKKvvaW3H-zVL)#eFPbiCUvv825+kC@U`7qWu1fZbO=% zvP?D>*B`_weB+L@27#GkCVdA-iZ-lj!U&ws{fJXWns+y{f1>v+ElVE{8k?CU>#tb+ zEguL-+3f6%fSe+-ss`q?oS@3uq9znO24!s~BuKfWASaV@TvO&{VInpqywcMj?)3|~ zbV5i-X(>J{%16*>#4rHcK;4~YS8s`AOn>2w5aRpXC*!HxoKF% zUy*^v#n&MW4kE|81T`}|3;b4v=yjrGHPAwNNaR2T!C?QLL!g9Jxkf5crGbN=L zg>;6@Nwc~z$JYSD!uhTS0y7~;!AnRpRPjjde7 z{$ojUM4d+{Nfj@Yq)&ATZIvWcnfp1sG=98D)dhtl^x~tZ@szArrUT;8$LADH2n1j# zu#nR0*DH%bVKfLSJrwenbQPZ=iaZU%;&W+fdglJ`(!$Y z3IOKz(dUvo! z_&sF|eFXVF^3?Kw%lFn&!Usv!w?~3{qW9^EK4{$V@sUp3#tAF*Zv^?sdFvgPY};jvjp-qd5YwKRFOQ0umKT@AVLX5=z$2^ z%_ skip apply auf egress ---------- + + @patch("main.wg_default_is_active", return_value=True) + @patch("main.wg_is_active", return_value=True) + @patch("main.set_mtu") + @patch("main.probe_pmtu", return_value=1500) + @patch("main.read_mtu", return_value=1500) + @patch("main.exists_iface", return_value=True) + @patch("main.get_default_ifaces", return_value=["wg0"]) # wg0 wird als egress gewählt + @patch("main.require_root", return_value=None) + def test_apply_egress_mtu_skips_when_egress_is_wg( + self, _req_root, _get_def, _exists, _read_mtu, _probe, mock_set_mtu, _wg_active, _wg_def_active + ): + """ + Wenn egress == wg0, soll das Skript den egress-Apply überspringen, aber wg0 ganz normal setzen. + """ + argv = ["main.py", "--dry-run", "--apply-egress-mtu", "--prefer-wg-egress", "--wg-if", "wg0"] + with patch.object(sys, "argv", argv): + out = io.StringIO() + with redirect_stdout(out): + automtu.main() + s = out.getvalue() + + self.assertIn("Detected egress interface: wg0", s) + self.assertIn("Skipping egress MTU apply because egress == wg0", s) + # wg0 wird trotzdem gesetzt (1500-80=1420) + mock_set_mtu.assert_any_call("wg0", 1420, True) + # Es darf nur ein set_mtu-Aufruf erfolgen (kein separater egress-Apply) + self.assertEqual(mock_set_mtu.call_count, 1) + + # ---------- --apply-egress-mtu plus --set-wg-mtu override ---------- + + @patch("main.set_mtu") + @patch("main.probe_pmtu", return_value=1452) + @patch("main.read_mtu", return_value=1500) + @patch("main.exists_iface", return_value=True) + @patch("main.get_default_ifaces", return_value=["eth0"]) + @patch("main.require_root", return_value=None) + def test_apply_egress_mtu_with_forced_wg_override( + self, _req_root, _get_def, _exists, _read_mtu, _probe_pmtu, mock_set_mtu + ): + """ + Egress wird auf 1452 gesetzt, aber wg0 wird mit --set-wg-mtu (z. B. 1300) überschrieben, + unabhängig vom berechneten Wert (1372). + """ + argv = [ + "main.py", "--dry-run", + "--apply-egress-mtu", + "--pmtu-target", "1.1.1.1", + "--set-wg-mtu", "1300", + ] + with patch.object(sys, "argv", argv): + buf = io.StringIO() + with redirect_stdout(buf): + automtu.main() + + out = buf.getvalue() + self.assertIn("Applying effective MTU 1452 to egress eth0", out) + self.assertIn("Computed wg0 MTU: 1372", out) # erst berechnet + self.assertIn("Forcing WireGuard MTU (override): 1300", out) # dann überschrieben + + calls = [ + unittest.mock.call("eth0", 1452, True), + unittest.mock.call("wg0", 1300, True), + ] + mock_set_mtu.assert_has_calls(calls, any_order=False) + self.assertEqual(mock_set_mtu.call_count, 2) if __name__ == "__main__": unittest.main(verbosity=2)