From 09372994bb522536ba9d0f81c047570dcb095c42 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 22 Jun 2022 18:56:35 -0300 Subject: [PATCH] macOS system extension support Adds support for building Lokinet as a system extension, and fixes various problems in the macos implementation found during development of the system extension support. --- CMakeLists.txt | 4 +- cmake/StaticBuild.cmake | 9 ++ cmake/check_for_std_filesystem.cmake | 1 + cmake/installer.cmake | 2 + contrib/mac.sh | 9 +- contrib/macos/Info.plist.in | 24 --- contrib/macos/LokinetExtension.Info.plist.in | 40 ----- contrib/macos/README.txt | 38 ----- contrib/macos/lokinet-extension.Info.plist.in | 64 ++++++++ ...=> lokinet-extension.dev.provisionprofile} | Bin 25425 -> 25537 bytes ...kinet-extension.plugin.entitlements.plist} | 8 +- ...lokinet-extension.release.provisionprofile | Bin 0 -> 12849 bytes ...kinet-extension.sysext.entitlements.plist} | 17 +- contrib/macos/lokinet.Info.plist.in | 39 +++++ ...onprofile => lokinet.dev.provisionprofile} | Bin 25457 -> 25424 bytes .../macos/lokinet.plugin.entitlements.plist | 28 ++++ .../macos/lokinet.release.provisionprofile | Bin 0 -> 12888 bytes .../macos/lokinet.sysext.entitlements.plist | 36 +++++ contrib/macos/notarize.py.in | 47 +++++- contrib/macos/sign.sh.in | 29 +++- daemon/CMakeLists.txt | 149 +++++++++++++++--- daemon/lokinet.swift | 66 ++++++-- docs/macos-signing.txt | 146 +++++++++++------ external/CMakeLists.txt | 3 +- llarp/CMakeLists.txt | 2 +- llarp/apple/CMakeLists.txt | 39 +++-- llarp/apple/DNSTrampoline.h | 20 +-- llarp/apple/DNSTrampoline.m | 6 +- llarp/apple/PacketTunnelProvider.m | 45 +++++- llarp/apple/context_wrapper.cpp | 38 +++-- llarp/apple/context_wrapper.h | 27 +++- llarp/config/config.cpp | 6 +- llarp/constants/apple.hpp | 15 ++ llarp/dns/unbound_resolver.cpp | 60 ++++--- llarp/handlers/tun.cpp | 9 +- 35 files changed, 718 insertions(+), 308 deletions(-) delete mode 100644 contrib/macos/Info.plist.in delete mode 100644 contrib/macos/LokinetExtension.Info.plist.in delete mode 100644 contrib/macos/README.txt create mode 100644 contrib/macos/lokinet-extension.Info.plist.in rename contrib/macos/{lokinet-extension.provisionprofile => lokinet-extension.dev.provisionprofile} (79%) rename contrib/macos/{lokinet-extension.entitlements.plist => lokinet-extension.plugin.entitlements.plist} (75%) create mode 100644 contrib/macos/lokinet-extension.release.provisionprofile rename contrib/macos/{lokinet.entitlements.plist => lokinet-extension.sysext.entitlements.plist} (60%) create mode 100644 contrib/macos/lokinet.Info.plist.in rename contrib/macos/{lokinet.provisionprofile => lokinet.dev.provisionprofile} (80%) create mode 100644 contrib/macos/lokinet.plugin.entitlements.plist create mode 100644 contrib/macos/lokinet.release.provisionprofile create mode 100644 contrib/macos/lokinet.sysext.entitlements.plist mode change 100644 => 100755 contrib/macos/notarize.py.in create mode 100644 llarp/constants/apple.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 028c5a333..eca295599 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10) # bionic's cmake version set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Has to be set before `project()`, and ignored on non-macos: -set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)") +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "macOS deployment target (Apple clang only)") option(BUILD_DAEMON "build lokinet daemon and associated utils" ON) @@ -311,6 +311,6 @@ if(NOT TARGET uninstall) endif() -if(BUILD_PACKAGE AND NOT APPLE) +if(BUILD_PACKAGE) include(cmake/installer.cmake) endif() diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 3ddbe9757..db39eff78 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -351,6 +351,15 @@ set_target_properties(libzmq PROPERTIES INTERFACE_LINK_LIBRARIES "${libzmq_link_libs}" INTERFACE_COMPILE_DEFINITIONS "ZMQ_STATIC") + +# +# +# +# Everything that follows is *only* for lokinet-bootstrap (i.e. if adding new deps put them *above* +# this). +# +# +# if(NOT WITH_BOOTSTRAP) return() endif() diff --git a/cmake/check_for_std_filesystem.cmake b/cmake/check_for_std_filesystem.cmake index aef0448ec..84248d07e 100644 --- a/cmake/check_for_std_filesystem.cmake +++ b/cmake/check_for_std_filesystem.cmake @@ -44,6 +44,7 @@ if(filesystem_is_good EQUAL 1) else() # Probably broken AF macos message(STATUS "std::filesystem is not available, apparently this compiler isn't C++17 compliant; falling back to ghc::filesystem") + set(GHC_FILESYSTEM_WITH_INSTALL OFF CACHE INTERNAL "") add_subdirectory(external/ghc-filesystem) target_link_libraries(filesystem INTERFACE ghc_filesystem) target_compile_definitions(filesystem INTERFACE USE_GHC_FILESYSTEM) diff --git a/cmake/installer.cmake b/cmake/installer.cmake index bdd4958fc..60e39f69b 100644 --- a/cmake/installer.cmake +++ b/cmake/installer.cmake @@ -5,6 +5,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") if(WIN32) include(cmake/win32_installer_deps.cmake) +elseif(APPLE) + set(CPACK_GENERATOR DragNDrop;ZIP) endif() diff --git a/contrib/mac.sh b/contrib/mac.sh index 0ddcbe3ff..855f6bcc5 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -18,16 +18,9 @@ cd build-mac cmake \ -G Ninja \ -DBUILD_STATIC_DEPS=ON \ - -DBUILD_PACKAGE=ON \ - -DBUILD_SHARED_LIBS=OFF \ - -DBUILD_TESTING=OFF \ -DBUILD_LIBLOKINET=OFF \ -DWITH_TESTS=OFF \ -DNATIVE_BUILD=OFF \ - -DSTATIC_LINK=ON \ - -DWITH_SYSTEMD=OFF \ - -DFORCE_OXENMQ_SUBMODULE=ON \ - -DSUBMODULE_CHECK=OFF \ -DWITH_LTO=ON \ -DCMAKE_BUILD_TYPE=Release \ "$@" \ @@ -35,5 +28,5 @@ cmake \ ninja sign echo -e "Build complete, your app is here:\n" -ls -lad $(pwd)/daemon/lokinet.app +ls -lad $(pwd)/Lokinet.app echo "" diff --git a/contrib/macos/Info.plist.in b/contrib/macos/Info.plist.in deleted file mode 100644 index 9311f2404..000000000 --- a/contrib/macos/Info.plist.in +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - Lokinet - CFBundleExecutable - MacOS/lokinet - CFBundleIdentifier - com.loki-project.lokinet - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - lokinet - CFBundlePackageType - XPC! - CFBundleShortVersionString - @lokinet_VERSION@ - CFBundleVersion - @lokinet_VERSION@.@LOKINET_APPLE_BUILD@ - - diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in deleted file mode 100644 index 80afb1b94..000000000 --- a/contrib/macos/LokinetExtension.Info.plist.in +++ /dev/null @@ -1,40 +0,0 @@ - - - - - CFBundleDisplayName - Lokinet - - CFBundleExecutable - lokinet-extension - - CFBundleIdentifier - com.loki-project.lokinet.network-extension - - CFBundleInfoDictionaryVersion - 6.0 - - CFBundlePackageType - XPC! - - CFBundleName - lokinet - - CFBundleVersion - @lokinet_VERSION@ - - ITSAppUsesNonExemptEncryption - - - LSMinimumSystemVersion - 11.0 - - NSExtension - - NSExtensionPointIdentifier - com.apple.networkextension.packet-tunnel - NSExtensionPrincipalClass - LLARPPacketTunnel - - - diff --git a/contrib/macos/README.txt b/contrib/macos/README.txt deleted file mode 100644 index 9880ecc3c..000000000 --- a/contrib/macos/README.txt +++ /dev/null @@ -1,38 +0,0 @@ -This directory contains the magical incantations and random voodoo symbols needed to coax an Apple -build. There's no reason builds have to be this stupid, except that Apple wants to funnel everyone -into the no-CI, no-help, undocumented, non-toy-apps-need-not-apply modern Apple culture. - -This is disgusting. - -But it gets worse. - -The following two files, in particular, are the very worst manifestations of this already toxic -Apple cancer: they are required for proper permissions to run on macOS, are undocumented, and can -only be regenerated through the entirely closed source Apple Developer backend, for which you have -to pay money first to get a team account (a personal account will not work), and they lock the -resulting binaries to only run on individually selected Apple computers selected at the time the -profile is provisioned (with no ability to allow it to run anywhere). - - lokinet.provisionprofile - lokinet-extension.provisionprofile - -This is actively hostile to open source development, but that is nothing new for Apple. - -In order to make things work, you'll have to replace these provisioning profiles with your own -(after paying Apple for the privilege of developing on their platform, of course) and change all the -team/application/bundle IDs to reference your own team, matching the provisioning profiles. The -provisioning profiles must be a "macOS Development" provisioning profile, and must include the -signing keys and the authorized devices on which you want to run it. (The profiles bundled in this -repository contains the lokinet team's "Apple Development" keys associated with the Oxen project, -and mac dev boxes. This is *useless* for anyone else). - -Also take note that you *must not* put a development build `lokinet.app` inside /Applications -because if you do, it won't work because *on top* of the ridiculous signing and entitlement bullshit -that Apple makes you jump through, the rules *also* differ for binaries placed in /Applications -versus binaries placed elsewhere, but like everything else here, it is entirely undocumented. - -If you are reading this to try to build Lokinet for yourself for an Apple operating system and -simultaneously care about open source, privacy, or freedom then you, my friend, are a walking -contradiction: you are trying to get Lokinet to work on a platform that actively despises open -source, privacy, and freedom. Even Windows is a better choice in all of these categories than -Apple. diff --git a/contrib/macos/lokinet-extension.Info.plist.in b/contrib/macos/lokinet-extension.Info.plist.in new file mode 100644 index 000000000..7647393ee --- /dev/null +++ b/contrib/macos/lokinet-extension.Info.plist.in @@ -0,0 +1,64 @@ + + + + + CFBundleDevelopmentRegion + en + + CFBundleDisplayName + Lokinet Network Extension + + CFBundleExecutable + org.lokinet.network-extension + + CFBundleIdentifier + org.lokinet.network-extension + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundlePackageType + SYSX + + CFBundleName + org.lokinet.network-extension + + CFBundleVersion + @lokinet_VERSION@.@LOKINET_APPLE_BUILD@ + + CFBundleShortVersionString + @lokinet_VERSION@ + + CFBundleSupportedPlatforms + + MacOSX + + + ITSAppUsesNonExemptEncryption + + + LSMinimumSystemVersion + 10.15 + + NSHumanReadableCopyright + Copyright © 2022 The Oxen Project, licensed under GPLv3-or-later + + NSSystemExtensionUsageDescription + Provides Lokinet Network connectivity. + + NetworkExtension + + NEMachServiceName + SUQ8J2PCT7.org.lokinet.network-extension + + NEProviderClasses + + com.apple.networkextension.packet-tunnel + LLARPPacketTunnel + + com.apple.networkextension.dns-proxy + LLARPDNSProxy + + + + diff --git a/contrib/macos/lokinet-extension.provisionprofile b/contrib/macos/lokinet-extension.dev.provisionprofile similarity index 79% rename from contrib/macos/lokinet-extension.provisionprofile rename to contrib/macos/lokinet-extension.dev.provisionprofile index 33605eba6be8a7f8be5a1949b2cbf88e31aea9b8..c7a1b32698aee7964ceaeae06b215d6b40992bd5 100644 GIT binary patch delta 3664 zcmbVPd(7lkb?>*yChSHDNGy+1iIkE;laDXs$Gp5vHr#7_Y|r?5#xs75U65jX=JWV9 z@0mNcnvU31M2P}bGEkKO1qp>9XiJ-|8j1p;q6$(aHcFA&q*S7UR;tu0Ak?&~3bc22 zlih4n@kd7*UHi`UIdjhWo!{^H`DYLQ;#&vjsPn_AJYuE!Qvn*}+4#UuprT*_yb@XdP%k5BQ0qbR>i4g^juU4ep)qY9op7 z&7_{0%ffI&u`T5O$Ao_uZ7ESSe6}sCHxbD`)ZPSjov$AnUS z;r?GwPMna`-H+~m+szdaig2MQFo+@AojF(9PE6YBw#7+qikhkAm35E>D_`Q~o?S@? zeC3LN)waq5$yxw~YgZ`McBejhFoosJ19E;Kr7M?37;SaD_&HG&!@frT z0JU`cqx~N#JeymoS-J|??#P!g1jluZbR7R28|1mhQnk}$ABaZ+ar+A5Q_V7sQEQ7* zC|E*(TL9Z6l8VEOMxI?>I<^+OeXUUK0m+Pog95Zk1cqgaby{cDXcm%B9VrU0 z7d#JwECg7AAXF4J=+`4nZS*Q8=0iu>1GR`L5nzPfLi7<#BtVx8H*Etj_I|HOuHB1wr}>AskU4s$>ObgV8_N-4jRyRg_WJb-jsFa<*^aR#%i+>m;Dkg*PPr**=E)0`bGgeqBQ{} zYvc&6J}u-M4N`$IXb)!nv@%#Dt5~)wbWIV~&dM^}{xnP4sn|lE#v>A^tUH3$rP>fW zVnbbFcGhrEIr65;%w^|Qu39a5dET4v{$65|yqjb_246+K! zhCm6EfG}!Ia1e_b;`KcmNY?N`C;jM4W@xf$K^lIki0O)~;~;Ag_;M>n)Sx2hJC+Z& z&_xhk1BF);1~6efiogN5^J&9fAG`H26_lBHs`%D|HnptV%H8fHJDxWcxfXF&*kRkv zS#^`jYF=Bnt2$f)(dfz>uQ_AFF`uN-s-MA(>l`;`ad;fyaC@v{0bi<|ak+9PCXQjL z0LL)YEV+k7NdR^Td$omD9oa%#$!5J)HmDx1hpRQSSR}IoN-zxPFcce54@mL#DiT7h z?VAQW5bCCkfF!lD5jBuORn57z!)kcXd%K5@&TRMmYwRKyz`GIJLFk<3@oD7jD0~_StUi*g>IYTJ8&AaLJZl78{{% z4wGTEtxT+@7)IR%a~N+X+hkbiLMuz~|A}GJseE)4OTp_-Yl7+p{DGj1y4AH86|1jy;CsN@SyE}!BXN0xd zVk7Iol4k8m;>}DX#XMHSD(poq--7ijWATwR4Ob)Gp@4MAR2_NLWn!38GkP{zR7`)+ zkQy9AGtma5vXWzOQdXd`PnEgYeef;srn}W{ZBmX#X42!EQsGxSQq-+!0L?rD!vBSH z8VP7OJmM6muT33>j1)uwLf6?-!9W2$7!#e33i7=&=?r2Qm=MVeJk+oD2N4|X>zlc? zE4}Bf+i8$P%Fkis_8?8vHc=$2>@XX0oieVysVI`W4kDNh>`F|OcuiC}B-x_~`d5yP z!+}%}udoowuq#{fKt`csR}z)saz(s6awzgX+gcj1KraP3TD-@FmDA2lrP07?70H#g!U9U6hH@t$!wHF631wX0EvjazEgNW5fu7TIuKdq_Gj1bfK`lxVK!7!i7c+qP1uGok7%O8g*R>n|?nWQj^0h!X6t|Tc*aU z<0fACOtW6{Csmmrjv2o*Ub|=$hO$k%0FsV@z<`IlZ}6Yok}7jUzL6UqM+yokiMM&F z2O25BI^lm4OcZ&FVEEdpvk3}Oy%H9tAjBe;uat8?xF!vx*NHL^l@Oe()2KDUt?;!2 z?u`kBx)hdn9(QKj5?cgJBw2C0qZ7G|!TPmccwOHpp&k|sv&QO`C5Ow@R6nkF>}Jv| z>J?6xL!XEBW{>uzy4NeF6gIE%mUNJ5V!Z&b_#s8X6k!F>-uvBNsuI~C$m4+mu&_tt ztFt&JdnUjTJB=1DlQY5VfA59Y(g;?>ZVW{-!)%61CRGnro~~&5-a;%fjheq`w=`Q@S7=>{wPM24a~E26;H*J)iP3TS?z>6@ zZ|R*oed^S%gVgsf^2KtP9St|j;dl{E#&<^J#nMaDyGqG0-=Df`IbRJ+7d9w7xNb5J zFZ@t@)4?^bA*Vanow&`b*6E>FrjBYgu6k7V1Nw+NX8j}9<2af=t}^8Tdx7rW`^GyN zhGAK@%(>LNue|e|x}JXP^=Fh1J$&kki;pBPyev)plsANcoAeCPRF-}rI8`O(j4{FBeT@PU7P>c@XWt-t@mvp@OX z(=XllZ>DGebJ~CCeHWiTqn_rz`{)g=+y3p=yC3+2;!_t^KYYh0 oo&hHP^~K-4G<)(pU-{S5w|t8Fmi(N3@$+~6#Q5725C7r+06!P$+5i9m delta 3521 zcmaJ^d#vPEedgX>Hd=N!EFz>pXw^VcP;PF<_IMs%$R_9b?U`d=dpr+2g4B;0&v-mz z&v<4$9*Iu1k-{UiJVrniq-sl2Ap%4VTOQ#ZArT2ERRb!m)SwbxEkX!YqO^hlXYNgQ zvxW8#%l5H-ey{KMeLp|`#Lho{W#>F`!9yob-g2*W?=Q~mT(f)eg122dx4W}Lo+3`3 zc;Vi)$97-&!WR%14CTseI~Ok)uRnglsJ#39lPA^gEQ_bZKjt?R?WLPrch;xKl1Wz2 zmCEPn;-ydSyuES*$SkE6+j4*5sX+JGSe7-0V_9wiHg_?9bYqR!xgQY zZ+?BwB=uYq`OFseC29~wL@E8csb@%R&a`$bv>W6|741k9m62-tL(L2>-Shh4?yeAR zes=pGoH0Sb!&H``$w7N_-TA_rY?3WQ-3FQ1TPMT_JJHHHkeIC&Pd7qE*GavI*Z>KmS=4Q-vDJ>|^|laNRBMF| zk8wsxPeK_NWN4dt;!5i22?mgSfB^)CC<_8fi2-7PF0(9K6bf?KST^Ua&8_T%HxY=_ zx31F29A;`1cQ_N3{@2>3c;{cN{SfFd@Fx9Xs2%7sgh6u}=sJ)CbpSxaDmSW(F4cw= z8x6deHzk$Oqn;$hL}^)sdYjTKQ4%yKK4nxo1Wgl_)HCX>0%Pn^Xr%agcf_}eYGy74 z2ON-A8{`qAS5s5>CBE2MJ5j0IaaV#@Y0Uj@4k}bVYErGTop6c4hGM9P5Fkj1fNc6) zptm7xR8qCvZ*!VFnlx%7zr45T&KFdg4ks&c00Xrp83=-2m4_zafG!mfppU-Kcv#4E z9%MMs5Y%9>4xWu%=Rl^$fP)bTc@XT4;S$a=HP%b)(sy%Gj5#f^z+QKd4gy@@`UuG~>pD1!fM-DvthjE4UJ%Q;e(3%4oL_Bz zeCIoE0bL;@mg)-RD3rIy3WbV;*YFvynHWrUZ1J*Fr!e&JtNR6@lIq;0nP0AlXk&JyrnTa32L%6awLQBxOjm%DR8#t8GC zH_9?eKlEFJ(BcItk>=r`CNvCL9=hrxt~zT)N(qoB$^QX4+-osL+(2X~bqE95fIt>- zc`+29SIkTuVaII4HWo45z=UM^##xhE7FV zhdoZ>mEvR^#$#qu^jIYFEBSy=3Wbq`CUlaEI^&OLMxx4Wz3A*&Y|W_p&9d+31f5!w zXi*Vae_1n`=CFFOs-+>Oo6N&#tj#Xd4Pd&gked#p0t8}Q2rOcVW+2!_>>;wgc;^W> z==#ea_iA|L-8GD->Z@FzP3^P8nq^-`bLITqv2FuYk?tPEb1HjYTUIiHh z5R6GUQN&5a!8l7%FOYN&1SRq+# zAF@;f@PUPO(Ms_VTpk51N*90$D@Yn%fp{k4N)pH+jo9g+0INlQq%LaT7n{L$%@?bI zHEISvRx6u@QCCz`e4Y5CR=Vys;K(h?fjw@`ts<5(s<2UVIWXk;Z9s>2%e3_M7%DiK#)+NyKDWKF3^ zTotW>-|z9P%(h8dn$-@HI2C8KHi$SsFXdicWCpzhs;u?1#yDX{t5StB@q7iz6^6FI zRZu?bg)m1AD^s3BA|#)S*X(vwJbw^Dqg}#hKesyD{Lz6<@PW#0daS#~+|w7(_vT7(iP`SWS2V)L2+Hfdzx%QTt~EWOcM;FX!WMLWBrrmvMkcLIs-q0j6(E z<$yw020sU}xa+Qrj%x*XnvYZQLn{`AGSktMQP zD$_-qc+KUXjFZR7>yKae_dn7U#I_ha_8wM zne(TgKKqdPGv(ql4?lLp-y!{tAN!H~xr@Jee^{>m8PEnFT)%hsspS6uPO~=^?>Kel z_^badFWmRdi}&2|s<%ehJbfM_vrji4{^DouzWaZOr com.apple.application-identifier - SUQ8J2PCT7.com.loki-project.lokinet.network-extension + SUQ8J2PCT7.org.lokinet.network-extension com.apple.developer.networking.networkextension - packet-tunnel-provider-systemextension + packet-tunnel-provider + dns-proxy com.apple.developer.team-identifier @@ -16,9 +17,6 @@ com.apple.security.app-sandbox - com.apple.security.get-task-allow - - com.apple.security.network.client diff --git a/contrib/macos/lokinet-extension.release.provisionprofile b/contrib/macos/lokinet-extension.release.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..1eaefd12ef77108fbdb608b8a8240cc2160177ae GIT binary patch literal 12849 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 com.apple.application-identifier - SUQ8J2PCT7.com.loki-project.lokinet + SUQ8J2PCT7.org.lokinet.network-extension com.apple.developer.networking.networkextension packet-tunnel-provider-systemextension - dns-proxy-systemextension - dns-settings + dns-proxy-systemextension com.apple.developer.team-identifier @@ -18,13 +17,15 @@ com.apple.security.app-sandbox - com.apple.security.get-task-allow - + com.apple.security.application-groups + + SUQ8J2PCT7.org.lokinet + - com.apple.security.network.client + com.apple.security.network.client - - com.apple.security.network.server + + com.apple.security.network.server diff --git a/contrib/macos/lokinet.Info.plist.in b/contrib/macos/lokinet.Info.plist.in new file mode 100644 index 000000000..c03953cde --- /dev/null +++ b/contrib/macos/lokinet.Info.plist.in @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + + CFBundleDisplayName + Lokinet + + CFBundleExecutable + Lokinet + + CFBundleIdentifier + org.lokinet + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundleName + Lokinet + + CFBundlePackageType + APPL + + CFBundleShortVersionString + @lokinet_VERSION@ + + CFBundleVersion + @lokinet_VERSION@.@LOKINET_APPLE_BUILD@ + + LSMinimumSystemVersion + 10.15 + + NSHumanReadableCopyright + Copyright © 2022 The Oxen Project, licensed under GPLv3-or-later + + + diff --git a/contrib/macos/lokinet.provisionprofile b/contrib/macos/lokinet.dev.provisionprofile similarity index 80% rename from contrib/macos/lokinet.provisionprofile rename to contrib/macos/lokinet.dev.provisionprofile index 9fbcd4f7cb49fe6d7e31f7d4505e100ca99c224d..e15cccff4efcd2fccfa605bcb7c4693e62593f63 100644 GIT binary patch delta 3556 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 JZ##6c_AivuxY_^! diff --git a/contrib/macos/lokinet.plugin.entitlements.plist b/contrib/macos/lokinet.plugin.entitlements.plist new file mode 100644 index 000000000..7c172b9e0 --- /dev/null +++ b/contrib/macos/lokinet.plugin.entitlements.plist @@ -0,0 +1,28 @@ + + + + + com.apple.application-identifier + SUQ8J2PCT7.org.lokinet + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + dns-proxy + dns-settings + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + com.apple.security.app-sandbox + + + com.apple.security.network.client + + + com.apple.security.network.server + + + + diff --git a/contrib/macos/lokinet.release.provisionprofile b/contrib/macos/lokinet.release.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..6aaeead39f68543487b2cc9893436586b347b764 GIT binary patch literal 12888 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 + + + + com.apple.application-identifier + SUQ8J2PCT7.org.lokinet + + com.apple.developer.networking.networkextension + + packet-tunnel-provider-systemextension + dns-proxy-systemextension + dns-settings + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + com.apple.developer.system-extension.install + + + com.apple.security.app-sandbox + + + com.apple.security.application-groups + + SUQ8J2PCT7.org.lokinet + + + com.apple.security.network.client + + + com.apple.security.network.server + + + + diff --git a/contrib/macos/notarize.py.in b/contrib/macos/notarize.py.in old mode 100644 new mode 100755 index e042bface..5752e8b55 --- a/contrib/macos/notarize.py.in +++ b/contrib/macos/notarize.py.in @@ -4,21 +4,47 @@ import sys import plistlib import subprocess import time +import os +import os.path + +def bold_red(x): + return "\x1b[31;1m" + x + "\x1b[0m" + +if not @notarize_py_is_sysext@: + print(bold_red("\nUnable to notarize: this lokinet is not built as a system extension\n"), file=sys.stderr) + sys.exit(1) + +if not all(("@MACOS_NOTARIZE_USER@", "@MACOS_NOTARIZE_PASS@", "@MACOS_NOTARIZE_ASC@")): + print(bold_red("\nUnable to notarize: one or more required notarization variable not set; see contrib/macos/README.txt\n") + + " Called with -DMACOS_NOTARIZE_USER=@MACOS_NOTARIZE_USER@\n" + " -DMACOS_NOTARIZE_PASS=@MACOS_NOTARIZE_PASS@\n" + " -DMACOS_NOTARIZE_ASC=@MACOS_NOTARIZE_ASC@\n", + file=sys.stderr) + sys.exit(1) + +os.chdir("@PROJECT_BINARY_DIR@") +app = "Lokinet.app" +zipfile = "Lokinet.app.notarize.zip" +print(f"Creating lokinet.app.notarize.zip from lokinet.app") +if os.path.exists(zipfile): + os.remove(zipfile) +subprocess.run(['zip', '-r', zipfile, app]) -pkg = "lokinet-@PROJECT_VERSION@-Darwin.pkg" userpass = ('--username', "@MACOS_NOTARIZE_USER@", '--password', "@MACOS_NOTARIZE_PASS@") -print("Submitting {} for notarization; this may take a minute...".format(pkg)) +print("Submitting {} for notarization; this may take a minute...".format(zipfile)) started = time.time() -result = subprocess.run([ +command = [ 'xcrun', 'altool', '--notarize-app', - '--primary-bundle-id', 'org.lokinet.lokinet.pkg.@PROJECT_VERSION@', + '--primary-bundle-id', 'org.lokinet.@PROJECT_VERSION@', *userpass, '--asc-provider', "@MACOS_NOTARIZE_ASC@", - '--file', pkg, + '--file', zipfile, '--output-format', 'xml' - ], stdout=subprocess.PIPE) + ] +print(command) +result = subprocess.run(command, stdout=subprocess.PIPE) data = plistlib.loads(result.stdout) if 'success-message' not in data or 'notarization-upload' not in data or 'RequestUUID' not in data['notarization-upload']: @@ -70,7 +96,12 @@ print("\n") if not success: sys.exit(42) -print("Stapling {}".format(pkg)) -result = subprocess.run(['xcrun', 'stapler', 'staple', pkg]) +if os.path.exists(zipfile): + os.remove(zipfile) + +print("Stapling {}...".format(app), end='') +result = subprocess.run(['xcrun', 'stapler', 'staple', app]) result.check_returncode() + +print(" success.\n") diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index 6ebf0859a..a949f1ec5 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,10 +1,25 @@ #!/usr/bin/env bash + set -e -codesign --verbose=4 --force -s "@CODESIGN_APPEX@" \ - --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.entitlements.plist" \ - --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/PlugIns/lokinet-extension.appex" -for file in "@SIGN_TARGET@/Contents/MacOS/lokinet" "@SIGN_TARGET@" ; do - codesign --verbose=4 --force -s "@CODESIGN_APP@" \ - --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.entitlements.plist" \ - --deep --strict --timestamp --options=runtime "$file" + +if [ -z "@CODESIGN" ]; then + echo "Cannot codesign: this build was not configured with codesigning" >&2 + exit 1 +fi + +for ext in systemextension appex; do + netext="@lokinet_ext_dir@/org.lokinet.network-extension.$ext" + if [ -e "@SIGN_TARGET@/$netext" ]; then + echo -e "\n\e[33;1mSigning $netext...\e[0m\n" >&2 + codesign --verbose=4 --force -s "@CODESIGN_ID@" \ + --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist" \ + --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/$netext" + fi +done + +for sub in "/Contents/MacOS/Lokinet" "" ; do + echo -e "\n\e[33;1mSigning $(basename @SIGN_TARGET@)$sub...\e[0m\n" >&2 + codesign --verbose=4 --force -s "@CODESIGN_ID@" \ + --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist" \ + --deep --strict --timestamp --options=runtime "@SIGN_TARGET@$sub" done diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 50999b080..93e93162a 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,14 +1,18 @@ -add_executable(lokinet-vpn lokinet-vpn.cpp) +set(exetargets lokinet) + if(APPLE) add_executable(lokinet lokinet.swift) - enable_lto(lokinet) else() add_executable(lokinet lokinet.cpp) - enable_lto(lokinet lokinet-vpn) endif() +add_executable(lokinet-vpn lokinet-vpn.cpp) +enable_lto(lokinet lokinet-vpn) +list(APPEND exetargets lokinet-vpn) + if(WITH_BOOTSTRAP) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) + list(APPEND exetargets lokinet-bootstrap) enable_lto(lokinet-bootstrap) endif() @@ -42,11 +46,6 @@ if(WITH_BOOTSTRAP) endif() endif() -set(exetargets lokinet lokinet-vpn) -if(WITH_BOOTSTRAP) - list(APPEND exetargets lokinet-bootstrap) -endif() - foreach(exe ${exetargets}) if(WIN32 AND NOT MSVC_VERSION) target_sources(${exe} PRIVATE ${CMAKE_BINARY_DIR}/${exe}.rc) @@ -57,10 +56,13 @@ foreach(exe ${exetargets}) endif() target_link_libraries(${exe} PUBLIC liblokinet) target_include_directories(${exe} PUBLIC "${PROJECT_SOURCE_DIR}") - target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL}) + add_log_tag(${exe}) if(should_install) if(APPLE) - install(TARGETS ${exe} BUNDLE DESTINATION "${PROJECT_BINARY_DIR}" COMPONENT lokinet) + install(TARGETS ${exe} + BUNDLE DESTINATION "${PROJECT_BINARY_DIR}" + RUNTIME DESTINATION "." + COMPONENT lokinet) else() install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet) endif() @@ -68,10 +70,77 @@ foreach(exe ${exetargets}) endforeach() if(APPLE) - - set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity") - set(CODESIGN_EXT "${CODESIGN_APP}" CACHE STRING "codesign the internal extension using this key identity; defaults to CODESIGN_APP if empty") + option(MACOS_SYSTEM_EXTENSION + "Build the network extension as a system extension rather than a plugin. This must be ON for non-app store release builds, and must be OFF for dev builds and Mac App Store distribution builds" + OFF) option(CODESIGN "codesign the resulting app and extension" ON) + set(CODESIGN_ID "" CACHE STRING "codesign the macos app using this key identity; if empty we'll try to guess") + set(default_profile_type "dev") + if(MACOS_SYSTEM_EXTENSION) + set(default_profile_type "release") + endif() + set(CODESIGN_PROFILE "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.${default_profile_type}.provisionprofile" CACHE FILEPATH + "Path to a .provisionprofile to use for the main app") + set(CODESIGN_EXT_PROFILE "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.${default_profile_type}.provisionprofile" CACHE FILEPATH + "Path to a .provisionprofile to use for the extension") + + if(CODESIGN AND NOT CODESIGN_ID) + if(MACOS_SYSTEM_EXTENSION) + set(codesign_cert_pattern "Developer ID Application") + else() + set(codesign_cert_pattern "Apple Development") + endif() + execute_process( + COMMAND security find-identity -v -p codesigning + COMMAND sed -n "s/^ *[0-9][0-9]*) *\\([A-F0-9]\\{40\\}\\) *\"\\(${codesign_cert_pattern}.*\\)\"\$/\\1 \\2/p" + RESULT_VARIABLE find_id_exit_code + OUTPUT_VARIABLE find_id_output) + if(NOT find_id_exit_code EQUAL 0) + message(FATAL_ERROR "Finding signing identities with security find-identity failed; try specifying an id using -DCODESIGN_ID=...") + endif() + + string(REGEX MATCHALL "(^|\n)[0-9A-F]+" find_id_sign_id "${find_id_output}") + if(NOT find_id_sign_id) + message(FATAL_ERROR "Did not find any \"${codesign_cert_pattern}\" identity; try specifying an id using -DCODESIGN_ID=...") + endif() + if (find_id_sign_id MATCHES ";") + message(FATAL_ERROR "Found multiple \"${codesign_cert_pattern}\" identities:\n${find_id_output}\nSpecify an identify using -DCODESIGN_ID=...") + endif() + set(CODESIGN_ID "${find_id_sign_id}" CACHE STRING "" FORCE) + endif() + + if(CODESIGN) + message(STATUS "Codesigning using ${CODESIGN_ID}") + else() + message(WARNING "Codesigning disabled; the resulting build will not run on most macOS systems") + endif() + + if(MACOS_SYSTEM_EXTENSION) + set(lokinet_ext_dir Contents/Library/SystemExtensions) + target_compile_definitions(lokinet PRIVATE MACOS_SYSTEM_EXTENSION) + if (NOT MACOS_NOTARIZE_USER AND NOT MACOS_NOTARIZE_PASS AND NOT MACOS_NOTARIZE_ASC AND EXISTS "$ENV{HOME}/.notarization.cmake") + message(STATUS "Loading notarization info from ~/.notarization.cmake") + include("$ENV{HOME}/.notarization.cmake") + endif() + if (MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC) + message(STATUS "Enabling notarization with account ${MACOS_NOTARIZE_ASC}/${MACOS_NOTARIZE_USER}") + else() + message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization will fail; see contrib/macos/README.txt") + endif() + else() + set(lokinet_ext_dir Contents/PlugIns) + endif() + + foreach(var CODESIGN_PROFILE CODESIGN_EXT_PROFILE) + if(NOT ${var}) + message(WARNING "Missing a ${var} provisioning profile, and not building a system extension: Apple will most likely log an uninformative error message to the system log and then kill harmless kittens if you try to run the result") + endif() + if(NOT EXISTS "${${var}}") + message(FATAL_ERROR "Provisioning profile ${${var}} does not exist; fix your -D${var} path") + endif() + endforeach() + message(STATUS "Using ${CODESIGN_PROFILE} provisioning profile") + message(STATUS "Using ${CODESIGN_EXT_PROFILE} extension provisioning profile") set(mac_icon ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns) add_custom_command(OUTPUT ${mac_icon} @@ -79,37 +148,50 @@ if(APPLE) DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) add_custom_target(icons DEPENDS ${mac_icon}) add_dependencies(lokinet icons lokinet-extension) + set(post_build_pp) + if(CODESIGN AND CODESIGN_PROFILE) + set(post_build_pp COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CODESIGN_PROFILE} + $/Contents/embedded.provisionprofile) + endif() + add_custom_command(TARGET lokinet POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed $/Contents/Resources/bootstrap.signed - COMMAND mkdir -p $/Contents/PlugIns - COMMAND cp -a $ $/Contents/PlugIns/ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile - $/Contents/embedded.provisionprofile - ) + COMMAND mkdir -p $/${lokinet_ext_dir} + COMMAND cp -a $ $/${lokinet_ext_dir} + ${post_build_pp} + ) set_target_properties(lokinet PROPERTIES + OUTPUT_NAME Lokinet MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router" MACOSX_BUNDLE_BUNDLE_NAME "Lokinet" MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION}" MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}" - MACOSX_BUNDLE_GUI_IDENTIFIER "com.loki-project.lokinet" - MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" + MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet" + MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${mac_icon}" - MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") + MACOSX_BUNDLE_COPYRIGHT "© 2022, The Oxen Project" + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}" + ) + if(NOT CODESIGN) message(STATUS "codesigning disabled") add_custom_target( sign DEPENDS lokinet lokinet-extension COMMAND "true") - elseif (CODESIGN_APP AND CODESIGN_EXT) - message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_EXT} (appex)") - set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app") + elseif(CODESIGN) + set(SIGN_TARGET "${PROJECT_BINARY_DIR}/lokinet.app") + if(MACOS_SYSTEM_EXTENSION) + set(LOKINET_ENTITLEMENTS_TYPE sysext) + else() + set(LOKINET_ENTITLEMENTS_TYPE plugin) + endif() configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" "${PROJECT_BINARY_DIR}/sign.sh" @@ -119,6 +201,25 @@ if(APPLE) DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) + + if(NOT (MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC)) + message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization disabled") + endif() + if (MACOS_SYSTEM_EXTENSION) + set(notarize_py_is_sysext True) + else() + set(notarize_py_is_sysext False) + endif() + configure_file( + "${PROJECT_SOURCE_DIR}/contrib/macos/notarize.py.in" + "${PROJECT_BINARY_DIR}/notarize.py" + @ONLY) + add_custom_target( + notarize + DEPENDS "${PROJECT_BINARY_DIR}/notarize.py" sign + COMMAND "${PROJECT_BINARY_DIR}/notarize.py" + ) + else() message(FATAL_ERROR "CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_EXT (=${CODESIGN_EXT}) are not set. To disable code signing use -DCODESIGN=OFF") endif() diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 86277cb88..1d8e0a106 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -1,6 +1,7 @@ import AppKit import Foundation import NetworkExtension +import SystemExtensions let app = NSApplication.shared @@ -11,14 +12,13 @@ let HELP_STRING = "usage: lokinet [--start|--stop]" class LokinetMain: NSObject, NSApplicationDelegate { var vpnManager = NETunnelProviderManager() - let lokinetComponent = "com.loki-project.lokinet.network-extension" - var mode = "" + var mode = START + let netextBundleId = "org.lokinet.network-extension" func applicationDidFinishLaunching(_: Notification) { if self.mode == START { - setupVPNTunnel() - } - else if self.mode == STOP { + startNetworkExtension() + } else if self.mode == STOP { tearDownVPNTunnel() } else { self.result(msg: HELP_STRING) @@ -46,7 +46,7 @@ class LokinetMain: NSObject, NSApplicationDelegate { if let savedManagers = savedManagers { for manager in savedManagers { - if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { + if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.netextBundleId { manager.isEnabled = false self.result(msg: "Lokinet Down") return @@ -57,8 +57,21 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } + func startNetworkExtension() { +#if MACOS_SYSTEM_EXTENSION + NSLog("Loading Lokinet network extension") + // Start by activating the system extension + let activationRequest = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: netextBundleId, queue: .main) + activationRequest.delegate = self + OSSystemExtensionManager.shared.submitRequest(activationRequest) +#else + setupVPNTunnel() +#endif + } + func setupVPNTunnel() { - NSLog("Starting up Lokinet") + + NSLog("Starting up Lokinet tunnel") NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in if let error = error { self.result(msg: error.localizedDescription) @@ -67,7 +80,7 @@ class LokinetMain: NSObject, NSApplicationDelegate { if let savedManagers = savedManagers { for manager in savedManagers { - if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { + if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.netextBundleId { NSLog("Found saved VPN Manager") self.vpnManager = manager } @@ -76,7 +89,7 @@ class LokinetMain: NSObject, NSApplicationDelegate { let providerProtocol = NETunnelProviderProtocol() providerProtocol.serverAddress = "loki.loki" // Needs to be set to some non-null dummy value providerProtocol.username = "anonymous" - providerProtocol.providerBundleIdentifier = self.lokinetComponent + providerProtocol.providerBundleIdentifier = self.netextBundleId providerProtocol.enforceRoutes = true // macos seems to have trouble when this is true, and reports are that this breaks and // doesn't do what it says on the tin in the first place. Needs more testing. @@ -130,11 +143,42 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } +#if MACOS_SYSTEM_EXTENSION + +extension LokinetMain: OSSystemExtensionRequestDelegate { + + func request(_ request: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) { + guard result == .completed else { + NSLog("Unexpected result %d for system extension request", result.rawValue) + return + } + NSLog("Lokinet system extension loaded") + setupVPNTunnel() + } + + func request(_ request: OSSystemExtensionRequest, didFailWithError error: Error) { + NSLog("System extension request failed: %@", error.localizedDescription) + } + + func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) { + NSLog("Extension %@ requires user approval", request.identifier) + } + + func request(_ request: OSSystemExtensionRequest, + actionForReplacingExtension existing: OSSystemExtensionProperties, + withExtension extension: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction { + NSLog("Replacing extension %@ version %@ with version %@", request.identifier, existing.bundleShortVersion, `extension`.bundleShortVersion) + return .replace + } +} + +#endif + let args = CommandLine.arguments -if args.count > 1 { +if args.count <= 2 { let delegate = LokinetMain() - delegate.mode = args[1] + delegate.mode = args.count > 1 ? args[1] : START app.delegate = delegate app.run() } else { diff --git a/docs/macos-signing.txt b/docs/macos-signing.txt index 9e6f2ba07..9e323da8e 100644 --- a/docs/macos-signing.txt +++ b/docs/macos-signing.txt @@ -1,73 +1,123 @@ -Codesigning and notarization on macOS +If you are reading this to try to build Lokinet for yourself for an Apple operating system and +simultaneously care about open source, privacy, or freedom then you, my friend, are a walking +contradiction: you are trying to get Lokinet to work on a platform that actively despises open +source, privacy, and freedom. Even Windows is a better choice in all of these categories than +Apple. -This is painful. Thankfully most of the pain is now in CMake and a python script. +This directory contains the magical incantations and random voodoo symbols needed to coax an Apple +build. There's no reason builds have to be this stupid, except that Apple wants to funnel everyone +into the no-CI, no-help, undocumented, non-toy-apps-need-not-apply modern Apple culture. -To build, codesign, and notarized and installer package, CMake needs to be invoked with: +This is disgusting. - cd build - rm -rf * # optional but recommended - cmake .. -DBUILD_PACKAGE=ON -DDOWNLOAD_SODIUM=ON -DMACOS_SIGN_APP=ABC123... -DMACOS_SIGN_PKG=DEF456... +But it gets worse. -where the ABC123... key is a "Developer ID Installer" key and PKG key is a "Developer ID -Application" key. You have to go through a bunch of pain, pay Apple money, and then read a bunch of -poorly written documentation that doesn't help very much to create these and get them working. But once you have them -set up in Keychain, you should be able to list your keys with: +The following two files, in particular, are the very worst manifestations of this already toxic +Apple cancer: they are required for proper permissions to run on macOS, are undocumented, and can +only be regenerated through the entirely closed source Apple Developer backend, for which you have +to pay money first to get a team account (a personal account will not work), and they lock the +resulting binaries to only run on individually selected Apple computers selected at the time the +profile is provisioned (with no ability to allow it to run anywhere). - security find-identity -v + lokinet.dev.provisionprofile + lokinet-extension.dev.provisionprofile -and you should see (at least) one "Developer ID Installer: ..." and one "Developer ID Application: -...". You need both for reasons that only Apple knows. The former is used to sign the installer -.pkg, and the latter is used to sign everything *inside* the .pkg, and you can't use the same key -for both because Apple designed code signing by marketing committee rather than ask any actual -competent software developers how code signing should work. +This is actively hostile to open source development, but that is nothing new for Apple. -Either way, these two values can be specified either by hex value or description string that -`security find-identity -v` spits out. +There are also release provisioning profiles -You also need to set up the notarization parameters; these can either be specified directly on the -cmake command line by adding: + lokinet.release.provisionprofile + lokinet-extension.release.provisionprofile - -DMACOS_NOTARIZE_ASC=XYZ123 -DMACOS_NOTARIZE_USER=me@example.com -DMACOS_NOTARIZE_PASS=@keychain:codesigning-password +These ones allow distribution of the app, but only if notarized, and again require notarization plus +signing by a (paid) Apple developer account. -or, more simply, by putting them inside a `~/.notarization.cmake` file that will be included if it -exists (and the MACOS_SIGN_* variables are set) -- see below. +In order to make things work, you'll have to replace these provisioning profiles with your own +(after paying Apple for the privilege of developing on their platform, of course) and change all the +team/application/bundle IDs to reference your own team, matching the provisioning profiles. The dev +provisioning profiles must be a "macOS Development" provisioning profile, and must include the +signing keys and the authorized devices on which you want to run it. (The profiles bundled in this +repository contains the lokinet team's "Apple Development" keys associated with the Oxen project, +and mac dev boxes. This is *useless* for anyone else). -These three values here are: +For release builds, you still need a provisioning profile, but it must be a "Distribution: Developer +ID" provisioning profile, and are tied to a (paid) Developer ID. The ones in the repository are +attached to the Oxen Project Developer ID and are useless to anyone else. -MACOS_NOTARIZE_ASC: +Once you have that in place, you need to build and sign the package using a certificate matching +your provisioning profile before your Apple system will allow it to run. (That's right, your $2000 +box won't let you run programs you build from source on it unless you also subscribe to a $100/year +Apple developer account). -Organization-specific unique value; this is printed inside (brackets) when you run: `security -find-identity -v`: +Okay, so now that you have paid Apple more money for the privilege of using your own computer, +here's how you make a signed lokinet app: - 1) 1C75DDBF884DEF3D5927C3F29BB7FC5ADAE2E1B3 "Apple Development: me@example.com (ABC123XYZ9)" +1) Decide which type of build you are doing: a lokinet system extension, or an app extension. The + former must be signed and notarized and will only work when placed in the /Applications folder, + but will not work as a dev build and cannot be distributed outside the Mac App Store. The latter + is usable as a dev build, but still requires a signature and Apple-provided provisioningprofile + listing the limited number of devices on which it is allowed to run. -MACOS_NOTARIZE_USER: + For system extension builds you want to add the -DMACOS_SYSTEM_EXTENSION=ON flag to cmake. -Your Apple Developer login. +2) Figure out the certificate to use for signing and make sure you have it installed. For a + distributable system extension build you need a "Developer ID Application" key and certificate, + issued by your paid developer.apple.com account. For dev builds you need a "Apple Development" + certificate. -MACOS_NOTARIZE_PASS: + In most cases you don't need to specify these; the default cmake script will figure them out. + (If it can't, e.g. because you have multiple of the right type installed, it will error with the + keys it found). -This should be an app-specific password created for signing on the Apple Developer website. You -*can* specify it directly, but it is much better to use the magic `@keychain:blah` value, where -'blah' is a password name recorded in Keychain. To get that in place you run: + To be explicit, use `security find-identity -v` to list your keys, then list the key identity + with -DCODESIGN_ID=..... - export HISTFILE='' # for bash: you don't want to store this in your history - xcrun altool --store-password-in-keychain-item "NOTARIZE_PASSWORD" -u "user" -p "password" +3) If you are doing a system extension build you will need to provide notarization login information by adding: -where NOTARIZE_PASSWORD is just some name for the password (I called it 'blah' or -'codesigning-password' above), and the "user" and "password" are replaced with your actual Apple -Developer account device-specific login credentials. + -DMACOS_NOTARIZE_ASC=XYZ123 -DMACOS_NOTARIZE_USER=me@example.com -DMACOS_NOTARIZE_PASS=@keychain:codesigning-password -Optionally, put these last three inside a `~/.notarization.cmake` file: + a) The first value (XYZ123) needs to be the organization-specific unique value, and is printed in + brackets in the certificate description. For example: - set(MACOS_NOTARIZE_USER "jagerman@jagerman.com") - set(MACOS_NOTARIZE_PASS "@keychain:codesigning-password") - set(MACOS_NOTARIZE_ASC "SUQ8J2PCT7") + 15095CD1E6AF441ABC69BDC52EE186A18200A49F "Developer ID Application: Some Developer (ABC123XYZ9)" -Then, finally, you can build the package from the build directory with: + would require ABC123XYZ9 for this field. - make package -j4 # or whatever -j makes you happy - make notarize + b) The USER field is your Apple Developer login e-mail address. -The former builds and signs the package, the latter submits it for notarization. This can take a -few minutes; the script polls Apple's server until it is finished passing or failing notarization. + c) The PASS field is a keychain reference holding your "Application-Specific Password". To set + up such a password for your account, consult Apple documentation. Once you have it, load it + into your keychain via: + + export HISTFILE='' # Don't want to store this in the shell history + xcrun altool --store-password-in-keychain-item "codesigning-password" -u "user" -p "password" + + You can change "codesigning-password" to whatever you want (just make sure it agrees with the + -DMACOS_NOTARIZE_PASS option you build with). "user" and "password" should be your developer + account device-specific login credentials provided by Apple. + + To make your life easier, stash these settings into a `~/.notarization.cmake` file inside your + home directory; if you have not specified them in the build, and this file exists, lokinet's + cmake will load it: + + set(MACOS_NOTARIZE_USER "me@example.com") + set(MACOS_NOTARIZE_PASS "@keychain:codesigning-password") + set(MACOS_NOTARIZE_ASC "ABC123XYZ9") + +4) Build and sign the package; there is a script `contrib/mac.sh` that can help (extra cmake options + you need can be appended to the end), or you can build yourself in a build directory. See the + script for the other cmake options that are typically needed. Note that `-G Ninja` (as well as a + working ninja builder) are required. + + If you get an error `errSecInternalComponent` this is Apple's highly descriptive way of telling + you that you need to unlock your keychain, which you can do by running `security unlock`. + + If doing it yourself, `ninja sign` will build and then sign the app. + + If you need to also notarize (e.g. for a system extension build) run `./notarize.py` from the + build directory (or alternatively `ninja notarize`, but the former gives you status output while + it runs). + +5) Packaging the app: you want to use `-DBUILD_PACKAGE=ON` when configuring with cmake and then, + once all signing and notarization is complete, run `cpack` which will give you a .dmg and a .zip + containing the release. diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 0ea284a78..6514f72a1 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -41,7 +41,7 @@ endif() macro(system_or_submodule BIGNAME smallname pkgconf subdir) option(FORCE_${BIGNAME}_SUBMODULE "force using ${smallname} submodule" OFF) - if(NOT STATIC AND NOT FORCE_${BIGNAME}_SUBMODULE) + if(NOT BUILD_STATIC_DEPS AND NOT FORCE_${BIGNAME}_SUBMODULE AND NOT FORCE_ALL_SUBMODULES) pkg_check_modules(${BIGNAME} ${pkgconf} IMPORTED_TARGET) endif() if(${BIGNAME}_FOUND) @@ -64,6 +64,7 @@ endmacro() system_or_submodule(OXENC oxenc liboxenc>=1.0.3 oxen-encoding) system_or_submodule(OXENMQ oxenmq liboxenmq>=1.2.12 oxen-mq) set(JSON_BuildTests OFF CACHE INTERNAL "") +set(JSON_Install OFF CACHE INTERNAL "") system_or_submodule(NLOHMANN nlohmann_json nlohmann_json>=3.7.0 nlohmann) if (STATIC OR FORCE_SPDLOG_SUBMODULE OR FORCE_FMT_SUBMODULE) diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 0782add06..c6dd5e6f6 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -252,7 +252,7 @@ if(BUILD_LIBLOKINET) if(WIN32) target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector) install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet) - else() + elseif(NOT APPLE) install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet) endif() endif() diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index ad18d9920..30b984653 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -25,26 +25,37 @@ target_link_libraries(lokinet-extension PRIVATE ${COREFOUNDATION} ${NETEXT}) -# Not sure what -fapplication-extension does, but XCode puts it in so... # -fobjc-arc enables automatic reference counting for objective-C code # -e _NSExtensionMain because the appex has that instead of a `main` function entry point, of course. -target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) -target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) +target_compile_options(lokinet-extension PRIVATE -fobjc-arc) +if(MACOS_SYSTEM_EXTENSION) + target_compile_definitions(lokinet-extension PRIVATE MACOS_SYSTEM_EXTENSION) + target_compile_definitions(lokinet-util PUBLIC MACOS_SYSTEM_EXTENSION) +else() + target_link_options(lokinet-extension PRIVATE -e _NSExtensionMain) +endif() -target_link_libraries(lokinet-extension PUBLIC - liblokinet - ${COREFOUNDATION} - ${NETEXT}) +if(MACOS_SYSTEM_EXTENSION) + set(bundle_ext systemextension) + set(product_type com.apple.product-type.system-extension) +else() + set(bundle_ext appex) + set(product_type com.apple.product-type.app-extension) +endif() set_target_properties(lokinet-extension PROPERTIES BUNDLE TRUE - BUNDLE_EXTENSION appex - MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + BUNDLE_EXTENSION ${bundle_ext} + OUTPUT_NAME org.lokinet.network-extension + MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.Info.plist.in + XCODE_PRODUCT_TYPE ${product_type} ) -add_custom_command(TARGET lokinet-extension - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile - $/Contents/embedded.provisionprofile +if(CODESIGN AND CODESIGN_EXT_PROFILE) + add_custom_command(TARGET lokinet-extension + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CODESIGN_EXT_PROFILE} + $/Contents/embedded.provisionprofile ) +endif() diff --git a/llarp/apple/DNSTrampoline.h b/llarp/apple/DNSTrampoline.h index 4935d43c8..117d567b2 100644 --- a/llarp/apple/DNSTrampoline.h +++ b/llarp/apple/DNSTrampoline.h @@ -5,18 +5,19 @@ extern NSString* error_domain; /** - * "Trampoline" class that listens for UDP DNS packets on port 1053 coming from lokinet's embedded - * libunbound (when exit mode is enabled), wraps them via NetworkExtension's crappy UDP API, then - * sends responses back to libunbound to be parsed/etc. This class knows nothing about DNS, it is - * basically just a UDP packet forwarder. + * "Trampoline" class that listens for UDP DNS packets when we have exit mode enabled. These arrive + * on localhost:1053 coming from lokinet's embedded libunbound (when exit mode is enabled), wraps + * them via NetworkExtension's crappy UDP API, then sends responses back to libunbound to be + * parsed/etc. This class knows nothing about DNS, it is basically just a UDP packet forwarder, but + * using Apple magic reinvented wheel wrappers that are oh so wonderful like everything Apple. * * So for a lokinet configuration of "upstream=1.1.1.1", when exit mode is OFF: - * - DNS requests go to TUNNELIP:53, get sent to libunbound, which forwards them (directly) to the - * upstream DNS server(s). + * - DNS requests go unbound either to 127.0.0.1:53 directly (system extension) or bounced through + * TUNNELIP:53 (app extension), which forwards them (directly) to the upstream DNS server(s). * With exit mode ON: - * - DNS requests go to TUNNELIP:53, get send to libunbound, which forwards them to 127.0.0.1:1053, - * which encapsulates them in Apple's god awful crap, then (on a response) sends them back to - * libunbound. + * - DNS requests go to unbound, as above, and unbound forwards them to 127.0.0.1:1053, which + * encapsulates them in Apple's god awful crap, then (on a response) sends them back to + * libunbound to be delivered back to the requestor. * (This assumes a non-lokinet DNS; .loki and .snode get handled before either of these). */ @interface LLARPDNSTrampoline : NSObject @@ -40,6 +41,7 @@ extern NSString* error_domain; uv_async_t write_trigger; } - (void)startWithUpstreamDns:(NWUDPSession*)dns + listenIp:(NSString*)listenIp listenPort:(uint16_t)listenPort uvLoop:(uv_loop_t*)loop completionHandler:(void (^)(NSError* error))completionHandler; diff --git a/llarp/apple/DNSTrampoline.m b/llarp/apple/DNSTrampoline.m index 0a78a13e2..cbbe211a3 100644 --- a/llarp/apple/DNSTrampoline.m +++ b/llarp/apple/DNSTrampoline.m @@ -1,7 +1,7 @@ #include "DNSTrampoline.h" #include -NSString* error_domain = @"com.loki-project.lokinet"; +NSString* error_domain = @"org.lokinet"; // Receiving an incoming packet, presumably from libunbound. NB: this is called from the libuv @@ -68,10 +68,12 @@ static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* b @implementation LLARPDNSTrampoline - (void)startWithUpstreamDns:(NWUDPSession*) dns + listenIp:(NSString*) listenIp listenPort:(uint16_t) listenPort uvLoop:(uv_loop_t*) loop completionHandler:(void (^)(NSError* error))completionHandler { + NSLog(@"Setting up trampoline"); pending_writes = [[NSMutableArray alloc] init]; write_trigger.data = (__bridge void*) self; uv_async_init(loop, &write_trigger, write_flusher); @@ -79,7 +81,7 @@ static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* b request_socket.data = (__bridge void*) self; uv_udp_init(loop, &request_socket); struct sockaddr_in recv_addr; - uv_ip4_addr("127.0.0.1", listenPort, &recv_addr); + uv_ip4_addr(listenIp.UTF8String, listenPort, &recv_addr); int ret = uv_udp_bind(&request_socket, (const struct sockaddr*) &recv_addr, UV_UDP_REUSEADDR); if (ret < 0) { NSString* errstr = [NSString stringWithFormat:@"Failed to start DNS trampoline: %s", uv_strerror(ret)]; diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index b340e56cb..0dac9953f 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -3,9 +3,12 @@ #include "context_wrapper.h" #include "DNSTrampoline.h" +#define LLARP_APPLE_PACKET_BUF_SIZE 64 + @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; + llarp_incoming_packet packet_buf[LLARP_APPLE_PACKET_BUF_SIZE]; @public NEPacketTunnelNetworkSettings* settings; @public NEIPv4Route* tun_route4; @public NEIPv6Route* tun_route6; @@ -35,8 +38,8 @@ static void packet_writer(int af, const void* data, size_t size, void* ctx) { NSData* buf = [NSData dataWithBytesNoCopy:(void*)data length:size freeWhenDone:NO]; LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; - NEPacket* packet = [[NEPacket alloc] initWithData:buf protocolFamily: af]; - [t.packetFlow writePacketObjects:@[packet]]; + [t.packetFlow writePackets:@[buf] + withProtocols:@[[NSNumber numberWithInt:af]]]; } static void start_packet_reader(void* ctx) { @@ -48,6 +51,7 @@ static void start_packet_reader(void* ctx) { } static void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { + NSLog(@"Adding IPv4 route %s:%s to packet tunnel", addr, netmask); NEIPv4Route* route = [[NEIPv4Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] subnetMask: [NSString stringWithUTF8String:netmask]]; @@ -65,6 +69,7 @@ static void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { } static void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { + NSLog(@"Removing IPv4 route %s:%s to packet tunnel", addr, netmask); NEIPv4Route* route = [[NEIPv4Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] subnetMask: [NSString stringWithUTF8String:netmask]]; @@ -124,6 +129,7 @@ static void del_ipv6_route(const char* addr, int prefix, void* ctx) { } static void add_default_route(void* ctx) { + NSLog(@"Making the tunnel the default route"); LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute]; @@ -133,6 +139,7 @@ static void add_default_route(void* ctx) { } static void del_default_route(void* ctx) { + NSLog(@"Removing default route from tunnel"); LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; t->settings.IPv4Settings.includedRoutes = @[t->tun_route4]; @@ -148,9 +155,21 @@ static void del_default_route(void* ctx) { [self.packetFlow readPacketObjectsWithCompletionHandler: ^(NSArray* packets) { if (lokinet == nil) return; + + size_t size = 0; for (NEPacket* p in packets) { - llarp_apple_incoming(lokinet, p.data.bytes, p.data.length); + packet_buf[size].bytes = p.data.bytes; + packet_buf[size].size = p.data.length; + size++; + if (size >= LLARP_APPLE_PACKET_BUF_SIZE) + { + llarp_apple_incoming(lokinet, packet_buf, size); + size = 0; + } } + if (size > 0) + llarp_apple_incoming(lokinet, packet_buf, size); + [self readPackets]; }]; } @@ -190,7 +209,10 @@ static void del_default_route(void* ctx) { // We don't have a fixed address so just stick some bogus value here: settings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.3.2.1"]; - NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[ip]]; + NSString* dns_ip = [NSString stringWithUTF8String:conf.dns_bind_ip]; + + NSLog(@"setting dns to %@", dns_ip); + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dns_ip]]; dns.domainName = @"localhost.loki"; dns.matchDomains = @[@""]; // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems @@ -246,11 +268,13 @@ static void del_default_route(void* ctx) { return completionHandler(start_failure); } - NSLog(@"Starting DNS exit mode trampoline to %@ on 127.0.0.1:%d", upstreamdns_ep, dns_trampoline_port); + NSString* dns_tramp_ip = @"127.0.0.1"; + NSLog(@"Starting DNS exit mode trampoline to %@ on %@:%d", upstreamdns_ep, dns_tramp_ip, dns_trampoline_port); NWUDPSession* upstreamdns = [strongSelf createUDPSessionThroughTunnelToEndpoint:upstreamdns_ep fromEndpoint:nil]; strongSelf->dns_tramp = [LLARPDNSTrampoline alloc]; [strongSelf->dns_tramp startWithUpstreamDns:upstreamdns + listenIp:dns_tramp_ip listenPort:dns_trampoline_port uvLoop:llarp_apple_get_uv_loop(strongSelf->lokinet) completionHandler:^(NSError* error) { @@ -258,7 +282,7 @@ static void del_default_route(void* ctx) { NSLog(@"Error starting dns trampoline: %@", error); return completionHandler(error); }]; - }]; + }]; } - (void)stopTunnelWithReason:(NEProviderStopReason)reason @@ -308,3 +332,12 @@ static void del_default_route(void* ctx) { } @end + +#ifdef MACOS_SYSTEM_EXTENSION + +int main() { + [NEProvider startSystemExtensionMode]; + dispatch_main(); +} + +#endif diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index f2a904251..4fc85c804 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -14,10 +15,6 @@ namespace { - // The default 127.0.0.1:53 won't work (because we run unprivileged) so remap it to this (unless - // specifically overridden to something else in the config): - const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"}; - struct instance_data { llarp::apple::Context context; @@ -30,7 +27,8 @@ namespace } // namespace -const uint16_t dns_trampoline_port = 1053; +// Expose this with C linkage so that objective-c can use it +extern "C" const uint16_t dns_trampoline_port = llarp::apple::dns_trampoline_port; void* llarp_apple_init(llarp_apple_config* appleconf) @@ -89,10 +87,12 @@ llarp_apple_init(llarp_apple_config* appleconf) } } - // The default DNS bind setting just isn't something we can use as a non-root network extension - // so remap the default value to a high port unless explicitly set to something else. - if (config->dns.m_bind == llarp::SockAddr{"127.0.0.1:53"}) - config->dns.m_bind = DefaultDNSBind; +#ifdef MACOS_SYSTEM_EXTENSION + std::strncpy( + appleconf->dns_bind_ip, + config->dns.m_bind.hostString().c_str(), + sizeof(appleconf->dns_bind_ip)); +#endif // If no explicit bootstrap then set the system default one included with the app bundle if (config->bootstrap.files.empty()) @@ -170,20 +170,26 @@ llarp_apple_get_uv_loop(void* lokinet) } int -llarp_apple_incoming(void* lokinet, const void* bytes, size_t size) +llarp_apple_incoming(void* lokinet, const llarp_incoming_packet* packets, size_t size) { auto& inst = *static_cast(lokinet); auto iface = inst.iface.lock(); if (!iface) - return -2; + return -1; - llarp_buffer_t buf{static_cast(bytes), size}; - if (iface->OfferReadPacket(buf)) - return 0; + int count = 0; + for (size_t i = 0; i < size; i++) + { + llarp_buffer_t buf{static_cast(packets[i].bytes), packets[i].size}; + if (iface->OfferReadPacket(buf)) + count++; + else + llarp::LogError("invalid IP packet: ", llarp::buffer_printer(buf)); + } - llarp::LogError("invalid IP packet: ", llarp::buffer_printer(buf)); - return -1; + iface->MaybeWakeUpperLayers(); + return count; } void diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 37c8a5c7b..1f09a46d3 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -82,6 +82,12 @@ extern "C" char upstream_dns[INET_ADDRSTRLEN]; uint16_t upstream_dns_port; +#ifdef MACOS_SYSTEM_EXTENSION + /// DNS bind IP; llarp_apple_init writes the lokinet config value here so that we know (in Apple + /// API code) what to set DNS to when lokinet gets turned on. Null terminated. + char dns_bind_ip[INET_ADDRSTRLEN]; +#endif + /// \defgroup callbacks Callbacks /// Callbacks we invoke for various operations that require glue into the Apple network /// extension APIs. All of these except for ns_logger are passed the pointer provided to @@ -135,12 +141,23 @@ extern "C" uv_loop_t* llarp_apple_get_uv_loop(void* lokinet); - /// Called to deliver an incoming packet from the apple layer into lokinet; returns 0 on success, - /// -1 if the packet could not be parsed, -2 if there is no current active VPNInterface associated - /// with the lokinet (which generally means llarp_apple_start wasn't called or failed, or lokinet - /// is in the process of shutting down). + /// Struct of packet data; a C array of tests gets passed to llarp_apple_incoming + typedef struct llarp_incoming_packet + { + const void* bytes; + size_t size; + } llarp_incoming_packet; + + /// Called to deliver one or more incoming packets from the apple layer into lokinet. Takes a C + /// array of `llarp_incoming_packets` with pointers/sizes set to the individual new packets that + /// have arrived. + /// + /// Returns the number of valid packets on success (which can be less than the number of provided + /// packets, if some failed to parse), or -1 if there is no current active VPNInterface associated + /// with the lokinet instance (which generally means llarp_apple_start wasn't called or failed, or + /// lokinet is in the process of shutting down). int - llarp_apple_incoming(void* lokinet, const void* bytes, size_t size); + llarp_apple_incoming(void* lokinet, const llarp_incoming_packet* packets, size_t size); /// Stops a lokinet instance created with `llarp_apple_initialize`. This waits for lokinet to /// shut down and rejoins the thread. After this call the given pointer is no longer valid. diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 90be0b1ee..7fc78746d 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -775,11 +775,7 @@ namespace llarp // Most non-linux platforms have loopback as 127.0.0.1/32, but linux uses 127.0.0.1/8 so that we // can bind to other 127.* IPs to avoid conflicting with something else that may be listening on // 127.0.0.1:53. -#ifdef __linux__ - constexpr Default DefaultDNSBind{"127.3.2.1:53"}; -#else - constexpr Default DefaultDNSBind{"127.0.0.1:53"}; -#endif + constexpr Default DefaultDNSBind{platform::is_linux ? "127.3.2.1:53" : "127.0.0.1:53"}; // Default, but if we get any upstream (including upstream=, i.e. empty string) we clear it constexpr Default DefaultUpstreamDNS{"9.9.9.10"}; diff --git a/llarp/constants/apple.hpp b/llarp/constants/apple.hpp new file mode 100644 index 000000000..46a94f9bc --- /dev/null +++ b/llarp/constants/apple.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace llarp::apple +{ + /// Localhost port on macOS where we proxy DNS requests *through* the tunnel, because without + /// calling into special snowflake Apple network APIs an extension's network connections all go + /// around the tunnel, even when the tunnel is (supposedly) the default route. + inline constexpr std::uint16_t dns_trampoline_port = 1053; + + /// We query the above trampoline from unbound with this fixed source port (so that the trampoline + /// is simplified by not having to track different ports for different requests). + inline constexpr std::uint16_t dns_trampoline_source_port = 1054; +} // namespace llarp::apple diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index a65728285..cc1fd3d87 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -1,6 +1,8 @@ #include "unbound_resolver.hpp" #include "server.hpp" +#include +#include #include #include #include @@ -144,37 +146,51 @@ namespace llarp::dns bool UnboundResolver::AddUpstreamResolver(const SockAddr& upstreamResolver) { - std::stringstream ss; - auto hoststr = upstreamResolver.hostString(); - ss << hoststr; + const auto hoststr = upstreamResolver.hostString(); + std::string upstream = hoststr; - if (const auto port = upstreamResolver.getPort(); port != 53) - ss << "@" << port; + const auto port = upstreamResolver.getPort(); + if (port != 53) + { + upstream += '@'; + upstream += std::to_string(port); + } - const auto str = ss.str(); - if (ub_ctx_set_fwd(unboundContext, str.c_str()) != 0) + LogError("Adding upstream resolver ", upstream); + if (ub_ctx_set_fwd(unboundContext, upstream.c_str()) != 0) { Reset(); return false; } -#ifdef __APPLE__ - // On Apple, we configure a localhost resolver to trampoline requests through the tunnel to the - // actual upstream (because the network extension itself cannot route through the tunnel using - // normal sockets but instead we "get" to use Apple's interfaces, hurray). - if (hoststr == "127.0.0.1") + if constexpr (platform::is_apple) { - // Not at all clear why this is needed but without it we get "send failed: Can't assign - // requested address" when unbound tries to connect to the localhost address using a source - // address of 0.0.0.0. Yay apple. - ub_ctx_set_option(unboundContext, "outgoing-interface:", hoststr.c_str()); - - // The trampoline expects just a single source port (and sends everything back to it) - ub_ctx_set_option(unboundContext, "outgoing-range:", "1"); - ub_ctx_set_option(unboundContext, "outgoing-port-avoid:", "0-65535"); - ub_ctx_set_option(unboundContext, "outgoing-port-permit:", "1253"); + // On Apple, when we turn on exit mode, we can't directly connect to upstream from here + // because, from within the network extension, macOS ignores setting the tunnel as the default + // route and would leak all DNS; instead we have to bounce things through the objective C + // trampoline code so that it can call into Apple's special snowflake API to set up a socket + // that has the magic Apple snowflake sauce added on top so that it actually routes through + // the tunnel instead of around it. + // + // This behaviour is all carefully and explicitly documented by Apple with plenty of examples + // and other exposition, of course, just like all of their wonderful new APIs to reinvent + // standard unix interfaces. + if (hoststr == "127.0.0.1" && port == apple::dns_trampoline_port) + { + // Not at all clear why this is needed but without it we get "send failed: Can't assign + // requested address" when unbound tries to connect to the localhost address using a source + // address of 0.0.0.0. Yay apple. + ub_ctx_set_option(unboundContext, "outgoing-interface:", "127.0.0.1"); + + // The trampoline expects just a single source port (and sends everything back to it) + ub_ctx_set_option(unboundContext, "outgoing-range:", "1"); + ub_ctx_set_option(unboundContext, "outgoing-port-avoid:", "0-65535"); + ub_ctx_set_option( + unboundContext, + "outgoing-port-permit:", + std::to_string(apple::dns_trampoline_source_port).c_str()); + } } -#endif return true; } diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index e14e37c06..776b2edb1 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -72,9 +72,10 @@ namespace llarp #ifdef __APPLE__ // DNS on Apple is a bit weird because in order for the NetworkExtension itself to send data // through the tunnel we have to proxy DNS requests through Apple APIs (and so our actual - // upstream DNS won't be set in our resolvers, which is why the vanilla IsUpstreamResolver - // won't work for us. However when active the mac also only queries the main tunnel IP for - // DNS, so we consider anything else to be upstream-bound DNS to let it through the tunnel. + // upstream DNS won't be set in our resolvers, which is why the vanilla IsUpstreamResolver, + // above, won't work for us). However when active the mac also only queries the main tunnel + // IP for DNS, so we consider anything else to be upstream-bound DNS to let it through the + // tunnel. bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override { @@ -88,7 +89,7 @@ namespace llarp { m_PacketRouter = std::make_unique( [this](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); }); -#if defined(ANDROID) || defined(__APPLE__) +#if defined(ANDROID) || (defined(__APPLE__) && !defined(MACOS_SYSTEM_EXTENSION)) m_Resolver = std::make_shared(r, this); m_PacketRouter->AddUDPHandler(huint16_t{53}, [&](net::IPPacket pkt) { const size_t ip_header_size = (pkt.Header()->ihl * 4);