From 7ba15f91f3eb12e58add1bb512a67fe4f31d4475 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 18 May 2021 16:38:09 -0400 Subject: [PATCH 01/81] add --help and -h flags to lokinet-bootstrap to show help message --- daemon/lokinet-bootstrap.cpp | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/daemon/lokinet-bootstrap.cpp b/daemon/lokinet-bootstrap.cpp index 7e8a4305a..12feac244 100644 --- a/daemon/lokinet-bootstrap.cpp +++ b/daemon/lokinet-bootstrap.cpp @@ -9,6 +9,7 @@ #include #include +#include #ifndef _WIN32 #include @@ -28,6 +29,24 @@ namespace std::cout << msg << std::endl; return 1; } + + int + print_help(std::string exe) + { + std::cout << R"(Lokinet bootstrap.signed fetchy program thing + +Downloads the initial bootstrap.signed for lokinet into a local file from a default or user defined server via the reachable network. + +Usage: )" << exe + << R"( [bootstrap_url [output_file]] + +bootstrap_url can be a named value in which we will use a predefined url that +holds a bootstrap file + +)"; + return 0; + } + } // namespace int @@ -42,6 +61,15 @@ main(int argc, char* argv[]) std::string bootstrap_url = bootstrap_urls.at("lokinet"); fs::path outputfile{llarp::GetDefaultBootstrap()}; + const std::unordered_set help_args = {"-h", "--help"}; + + for (int idx = 1; idx < argc; idx++) + { + const std::string arg{argv[idx]}; + if (help_args.count(arg)) + return print_help(argv[0]); + } + if (argc > 1) { if (auto itr = bootstrap_urls.find(argv[1]); itr != bootstrap_urls.end()) @@ -57,7 +85,7 @@ main(int argc, char* argv[]) { outputfile = fs::path{argv[2]}; } - + std::cout << "fetching " << bootstrap_url << std::endl; cpr::Response resp = #ifdef _WIN32 cpr::Get( @@ -79,6 +107,7 @@ main(int argc, char* argv[]) { try { + std::cout << "writing bootstrap file to: " << outputfile << std::endl; fs::ofstream ofs{outputfile, std::ios::binary}; ofs.exceptions(fs::ofstream::failbit); ofs << data; From 4f1bd14d3c64bfec63f8574cc88790b390956d14 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 6 Jul 2021 08:53:52 -0400 Subject: [PATCH 02/81] fix issue with excessively pedantic stl on archlinux --- llarp/util/str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/util/str.cpp b/llarp/util/str.cpp index a87cfd9ed..60090c3ad 100644 --- a/llarp/util/str.cpp +++ b/llarp/util/str.cpp @@ -84,7 +84,7 @@ namespace llarp last = next; // advance to next non-delimiter - while (str[last] == delimiter and last < str_size) + while (last < str_size and str[last] == delimiter) last++; } else From dace0224ecb5239e06fe43b89a2f5fefe3d4337a Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 9 Jul 2021 09:51:51 -0400 Subject: [PATCH 03/81] fix dns on android --- llarp/handlers/tun.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 4a34df612..116bfedee 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -87,8 +87,8 @@ namespace llarp OwnedBuffer buf{pkt.sz - (8 + ip_header_size)}; std::copy_n(ptr + 8, buf.sz, buf.buf.get()); - if (m_Resolver->ShouldHandlePacket(laddr, raddr, buf)) - m_Resolver->HandlePacket(laddr, raddr, buf); + if (m_Resolver->ShouldHandlePacket(raddr, laddr, buf)) + m_Resolver->HandlePacket(raddr, laddr, buf); else HandleGotUserPacket(std::move(pkt)); }); From e96ec156ead606ba93e1c7597388edff3bc52b56 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 25 Jun 2021 09:36:50 -0400 Subject: [PATCH 04/81] add / remove route blackhole so we dont leak if we crash --- llarp/net/route.cpp | 67 ++++++++++++++++++++++++++++++++---- llarp/net/route.hpp | 8 +++++ llarp/router/route_poker.cpp | 5 +++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/llarp/net/route.cpp b/llarp/net/route.cpp index 051d86fae..109823fb3 100644 --- a/llarp/net/route.cpp +++ b/llarp/net/route.cpp @@ -112,6 +112,40 @@ namespace llarp::net return 0; } + struct nl_req + { + struct nlmsghdr n; + struct rtmsg r; + char buf[4096]; + }; + + /// add/remove a route blackhole + int + do_blackhole(int sock, int cmd, int flags, int af) + { + nl_req nl_request{}; + /* Initialize request structure */ + nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; + nl_request.n.nlmsg_type = cmd; + nl_request.n.nlmsg_pid = getpid(); + nl_request.r.rtm_family = af; + nl_request.r.rtm_table = RT_TABLE_LOCAL; + nl_request.r.rtm_type = RTN_BLACKHOLE; + nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE; + if (af == AF_INET) + { + uint32_t addr{}; + rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &addr, sizeof(addr)); + } + else + { + uint128_t addr{}; + rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &addr, sizeof(addr)); + } + return send(sock, &nl_request, sizeof(nl_request), 0); + } + int do_route( int sock, @@ -122,12 +156,7 @@ namespace llarp::net GatewayMode mode, int if_idx) { - struct - { - struct nlmsghdr n; - struct rtmsg r; - char buf[4096]; - } nl_request{}; + nl_req nl_request{}; /* Initialize request structure */ nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); @@ -360,6 +389,32 @@ namespace llarp::net #endif } + void + AddBlackhole() + { + LogInfo("adding route blackhole to drop all traffic"); +#if __linux__ +#ifndef ANDROID + NLSocket sock; + do_blackhole(sock.fd, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, AF_INET); + do_blackhole(sock.fd, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, AF_INET6); +#endif +#endif + } + + void + DelBlackhole() + { + LogInfo("remove route blackhole"); +#if __linux__ +#ifndef ANDROID + NLSocket sock; + do_blackhole(sock.fd, RTM_DELROUTE, 0, AF_INET); + do_blackhole(sock.fd, RTM_DELROUTE, 0, AF_INET6); +#endif +#endif + } + void AddDefaultRouteViaInterface(std::string ifname) { diff --git a/llarp/net/route.hpp b/llarp/net/route.hpp index 6dccbbf23..23e75f8d6 100644 --- a/llarp/net/route.hpp +++ b/llarp/net/route.hpp @@ -25,4 +25,12 @@ namespace llarp::net void DelDefaultRouteViaInterface(std::string ifname); + /// add route blackhole for all traffic + void + AddBlackhole(); + + /// delete route blackhole for all traffic + void + DelBlackhole(); + } // namespace llarp::net diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index 29818e840..2d9b1e3ee 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -91,6 +91,7 @@ namespace llarp if (gateway.h) net::DelRoute(ip.ToString(), gateway.ToString()); } + net::DelBlackhole(); } std::optional @@ -185,6 +186,8 @@ namespace llarp void RoutePoker::Up() { + // black hole all routes by default + net::AddBlackhole(); // explicit route pokes for first hops m_Router->ForEachPeer( [&](auto session, auto) mutable { AddRoute(session->GetRemoteEndpoint().asIPv4()); }, @@ -204,6 +207,8 @@ namespace llarp // remove default route const auto ep = m_Router->hiddenServiceContext().GetDefault(); net::DelDefaultRouteViaInterface(ep->GetIfName()); + // delete route blackhole + net::DelBlackhole(); } } // namespace llarp From 048fdad056f26ae8f100b4aafc30c53352e18ea9 Mon Sep 17 00:00:00 2001 From: Sean Date: Thu, 29 Jul 2021 15:51:19 +1000 Subject: [PATCH 05/81] Update readme.md --- readme.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 69ddd90c4..b0b08e446 100644 --- a/readme.md +++ b/readme.md @@ -153,12 +153,17 @@ to configure as relay: ## Running on Linux -**DO NOT RUN AS ROOT**, run as normal user. This requires the binary to have the proper setcaps set by `make install` on the binary. +**DO NOT RUN AS ROOT**, run as normal user. to run, after you create default config: $ lokinet +This requires the binary to have the proper capabilities which is usually set by `make install` on the binary. If you have errors regarding permissions to open a new interface this can be resolved using: + + $ sudo setcap cap_net_admin,cap_net_bind_service=+eip /usr/local/bin/lokinet + + ## Running on macOS/UNIX/BSD **YOU HAVE TO RUN AS ROOT**, run using sudo. Elevated privileges are needed to create the virtual tunnel interface. From 29418f7a7baf4842bf2f9ffc606585efa8f61d4f Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 6 Aug 2021 14:25:32 -0300 Subject: [PATCH 06/81] bencode-dump.py: support reading from stdin So that you can pipe bt-encoded output into it, e.g. from the in-progress oxend bt-rpc interface. --- contrib/bencode-dump.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contrib/bencode-dump.py b/contrib/bencode-dump.py index 1c1f55499..8b5b8e642 100755 --- a/contrib/bencode-dump.py +++ b/contrib/bencode-dump.py @@ -3,11 +3,13 @@ import sys import pprint -if len(sys.argv) != 2 or sys.argv[1].startswith('-'): +if len(sys.argv) == 1 or (len(sys.argv) == 2 and sys.argv[1] == '-'): + f = sys.stdin.buffer +elif len(sys.argv) != 2 or sys.argv[1].startswith('-'): print("Usage: {} FILE -- dumps a bencoded file".format(sys.argv[0]), file=sys.stderr) sys.exit(1) - -f = open(sys.argv[1], 'rb') +else: + f = open(sys.argv[1], 'rb') class HexPrinter(): def __init__(self, data): From ae1243e9d9c36eeaf3fe128fcc1d0c8e6ff167a7 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 10 Aug 2021 17:13:27 -0300 Subject: [PATCH 07/81] Remove unused defaults.hpp The definitions in here aren't actually used anywhere anymore, so just drop it. --- llarp/config/config.cpp | 1 - llarp/constants/defaults.hpp | 18 ------------------ 2 files changed, 19 deletions(-) delete mode 100644 llarp/constants/defaults.hpp diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index bef3e521f..ef4667780 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -3,7 +3,6 @@ #include "config/definition.hpp" #include "ini.hpp" -#include #include #include #include diff --git a/llarp/constants/defaults.hpp b/llarp/constants/defaults.hpp deleted file mode 100644 index 884fdf1bf..000000000 --- a/llarp/constants/defaults.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#ifndef DEFAULT_RESOLVER_US -#define DEFAULT_RESOLVER_US "1.1.1.1" -#endif -#ifndef DEFAULT_RESOLVER_EU -#define DEFAULT_RESOLVER_EU "1.1.1.1" -#endif -#ifndef DEFAULT_RESOLVER_AU -#define DEFAULT_RESOLVER_AU "1.1.1.1" -#endif - -#ifndef DEFAULT_LOKINET_USER -#define DEFAULT_LOKINET_USER "lokinet" -#endif -#ifndef DEFAULT_LOKINET_GROUP -#define DEFAULT_LOKINET_GROUP "lokinet" -#endif From f40052df85498065d9fad5066d3b3968782ae0b5 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 10 Aug 2021 17:27:23 -0300 Subject: [PATCH 08/81] Remove old unused lokinet-bootstrap script We compile one now for various, but the script apparently never got removed. --- lokinet-bootstrap | 65 ----------------------------------------------- 1 file changed, 65 deletions(-) delete mode 100755 lokinet-bootstrap diff --git a/lokinet-bootstrap b/lokinet-bootstrap deleted file mode 100755 index 683173b69..000000000 --- a/lokinet-bootstrap +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash -# this shell script will be replaced by a proper program in the future (probably) -# -# from https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux -RED='\033[0;31m' -GREEN='\033[0;32m' -NC='\033[0m' # No Color - -set -e - -helpme= -default_mainnet=https://seed.lokinet.org/lokinet.signed -default_testnet=https://seed.lokinet.org/testnet.signed -default_dest="$HOME/.lokinet/bootstrap.signed" - -if [ "$#" -gt 2 ]; then - helpme=y -fi - -if [ -z "$1" ] || [ "$1" == "mainnet" ] || [ "$1" == "lokinet" ]; then - url="${default_mainnet}" -elif [ "$1" == "testnet" ]; then - url="${default_testnet}" -elif [[ "$1" = -* ]]; then - helpme=y -else - url="$1" -fi - -if [[ "$2" = -* ]]; then - helpme=y -elif [ -n "$2" ]; then - dest="$2" -else - dest="$default_dest" -fi - -if [ -n "$helpme" ]; then - echo "Usage: $0 [URL [DEST]] -- download bootstrap file from URL (default: lokinet) and save to DEST (default: $default_dest)." - echo "URL can be a full URL, or else 'lokinet' or 'testnet' to use the default lokinet/testnet seed URL. 'mainnet' can be used" - echo "as an alias for 'lokinet'." - exit 1 -fi - -destdir="$(dirname $dest)" -if [ ! -d "$destdir" ]; then - mkdir "$destdir" -fi - -echo "downloading $url" - -# use temp file to not overrwrite existing bootstrap file on fail -#tmp=mktemp -tmp=/tmp/bootstrap.tmp - -# MacOS does not have wget without homebrew but does have curl -# Rick also had indicated most BSDs have curl too -if curl -fsSL "$url" >"$tmp"; then - mv "$tmp" "$dest" - echo -e "${GREEN}lokinet successfully bootstrapped${NC}" -else - echo -e "${RED}failed to download bootstrap from $url${NC}" - rm -f "$tmp" - exit 1 -fi From 9950adf472349e849966e8d467118b92ed90aceb Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 11 Aug 2021 00:12:26 -0300 Subject: [PATCH 09/81] Remove unneeded split(str, char) method This function had a bug in stable (fixed in dev) when `last` returns npos, but the function also appears to basically be duplicating what the next split version can do, so this just removes it and uses the single more generic split(strview, strview) method. --- llarp/config/config.cpp | 2 +- llarp/net/route.cpp | 2 +- llarp/net/sock_addr.cpp | 4 +-- llarp/util/str.cpp | 29 ---------------------- llarp/util/str.hpp | 8 ------ test/net/test_sock_addr.cpp | 4 +-- test/util/test_llarp_util_str.cpp | 41 +++++++++++++++++++++++-------- 7 files changed, 37 insertions(+), 53 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index bef3e521f..78d152602 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -798,7 +798,7 @@ namespace llarp { info.interface = std::string{name}; - std::vector splits = split(value, ','); + std::vector splits = split(value, ","); for (std::string_view str : splits) { int asNum = std::atoi(str.data()); diff --git a/llarp/net/route.cpp b/llarp/net/route.cpp index 109823fb3..604208465 100644 --- a/llarp/net/route.cpp +++ b/llarp/net/route.cpp @@ -558,7 +558,7 @@ namespace llarp::net std::ifstream inf("/proc/net/route"); for (std::string line; std::getline(inf, line);) { - const auto parts = split(line, '\t'); + const auto parts = split(line, "\t"); if (parts[1].find_first_not_of('0') == std::string::npos and parts[0] != ifname) { const auto& ip = parts[2]; diff --git a/llarp/net/sock_addr.cpp b/llarp/net/sock_addr.cpp index 2fd6ddf5a..ee6817414 100644 --- a/llarp/net/sock_addr.cpp +++ b/llarp/net/sock_addr.cpp @@ -244,7 +244,7 @@ namespace llarp // NOTE: this potentially involves multiple memory allocations, // reimplement without split() if it is performance bottleneck - auto splits = split(str, ':'); + auto splits = split(str, ":"); // TODO: having ":port" at the end makes this ambiguous with IPv6 // come up with a strategy for implementing @@ -260,7 +260,7 @@ namespace llarp assert(splits.size() > 0); // splits[0] should be dot-separated IPv4 - auto ipSplits = split(splits[0], '.'); + auto ipSplits = split(splits[0], "."); if (ipSplits.size() != 4) throw std::invalid_argument(stringify(str, " is not a valid IPv4 address")); diff --git a/llarp/util/str.cpp b/llarp/util/str.cpp index 60090c3ad..512d5c55b 100644 --- a/llarp/util/str.cpp +++ b/llarp/util/str.cpp @@ -67,35 +67,6 @@ namespace llarp return str; } - std::vector - split(const std::string_view str, char delimiter) - { - std::vector splits; - const auto str_size = str.size(); - size_t last = 0; - size_t next = 0; - while (last < str_size and next < std::string_view::npos) - { - next = str.find_first_of(delimiter, last); - if (next > last) - { - splits.push_back(str.substr(last, next - last)); - - last = next; - - // advance to next non-delimiter - while (last < str_size and str[last] == delimiter) - last++; - } - else - { - break; - } - } - - return splits; - } - using namespace std::literals; std::vector diff --git a/llarp/util/str.hpp b/llarp/util/str.hpp index ab6e4588d..2fdebe838 100644 --- a/llarp/util/str.hpp +++ b/llarp/util/str.hpp @@ -35,14 +35,6 @@ namespace llarp return o.str(); } - /// Split a string on a given delimiter - // - /// @param str is the string to split - /// @param delimiter is the character to split on - /// @return a vector of std::string_views with the split words, excluding the delimeter - std::vector - split(const std::string_view str, char delimiter); - using namespace std::literals; /// Returns true if the first string is equal to the second string, compared case-insensitively. diff --git a/test/net/test_sock_addr.cpp b/test/net/test_sock_addr.cpp index 9102a96ed..c0b666745 100644 --- a/test/net/test_sock_addr.cpp +++ b/test/net/test_sock_addr.cpp @@ -43,9 +43,9 @@ TEST_CASE("SockAddr fromString", "[SockAddr]") CHECK_THROWS_WITH(llarp::SockAddr("1.2.3"), "1.2.3 is not a valid IPv4 address"); - CHECK_THROWS_WITH(llarp::SockAddr("1.2.3."), "1.2.3. is not a valid IPv4 address"); + CHECK_THROWS_WITH(llarp::SockAddr("1.2.3."), "1.2.3. contains invalid numeric value"); - CHECK_THROWS_WITH(llarp::SockAddr(".1.2.3"), ".1.2.3 is not a valid IPv4 address"); + CHECK_THROWS_WITH(llarp::SockAddr(".1.2.3"), ".1.2.3 contains invalid numeric value"); CHECK_THROWS_WITH(llarp::SockAddr("1.2.3.4.5"), "1.2.3.4.5 is not a valid IPv4 address"); diff --git a/test/util/test_llarp_util_str.cpp b/test/util/test_llarp_util_str.cpp index b7cd15fba..b53173660 100644 --- a/test/util/test_llarp_util_str.cpp +++ b/test/util/test_llarp_util_str.cpp @@ -91,7 +91,7 @@ TEST_CASE("neither true nor false string values", "[str][nottruefalse]") { } TEST_CASE("split strings with multiple matches", "[str]") { - auto splits = llarp::split("this is a test", ' '); + auto splits = llarp::split("this is a test", " "); REQUIRE(splits.size() == 4); REQUIRE(splits[0] == "this"); REQUIRE(splits[1] == "is"); @@ -100,13 +100,13 @@ TEST_CASE("split strings with multiple matches", "[str]") { } TEST_CASE("split strings with single match", "[str]") { - auto splits = llarp::split("uno", ';'); + auto splits = llarp::split("uno", ";"); REQUIRE(splits.size() == 1); REQUIRE(splits[0] == "uno"); } -TEST_CASE("split strings with consecutive delimiters", "[str]") { - auto splits = llarp::split("a o e u", ' '); +TEST_CASE("split_any strings with consecutive delimiters", "[str]") { + auto splits = llarp::split_any("a o e u", " "); REQUIRE(splits.size() == 4); REQUIRE(splits[0] == "a"); REQUIRE(splits[1] == "o"); @@ -115,14 +115,35 @@ TEST_CASE("split strings with consecutive delimiters", "[str]") { } TEST_CASE("split delimiter-only string", "[str]") { - auto splits = llarp::split(" ", ' '); - REQUIRE(splits.size() == 0); + { + auto splits = llarp::split(" ", " "); + REQUIRE(splits.size() == 5); + } + + { + auto splits = llarp::split_any(" ", " "); + REQUIRE(splits.size() == 2); + } + + { + auto splits = llarp::split(" ", " ", true); + REQUIRE(splits.size() == 0); + } - splits = llarp::split(" ", ' '); - REQUIRE(splits.size() == 0); + { + auto splits = llarp::split_any(" ", " ", true); + REQUIRE(splits.size() == 0); + } } TEST_CASE("split empty string", "[str]") { - auto splits = llarp::split("", ' '); - REQUIRE(splits.size() == 0); + { + auto splits = llarp::split("", " "); + REQUIRE(splits.size() == 1); + } + + { + auto splits = llarp::split("", " ", true); + REQUIRE(splits.size() == 0); + } } From 73f0432b2873d3af91a0c8cf2dd107463318b9d9 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 11 Aug 2021 18:24:11 -0300 Subject: [PATCH 10/81] Fix default upstream DNS not working The default upstream DNS was being set to 1.1.1.1:0, which doesn't work. This fixes it to also set the port so that default upstream resolution (i.e. with an empty config) works again. --- llarp/config/config.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index bef3e521f..721a479df 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -711,6 +711,8 @@ namespace llarp // Default, but if we get any upstream (including upstream=, i.e. empty string) we clear it constexpr Default DefaultUpstreamDNS{"1.1.1.1"}; m_upstreamDNS.emplace_back(DefaultUpstreamDNS.val); + if (!m_upstreamDNS.back().getPort()) + m_upstreamDNS.back().setPort(53); conf.defineOption( "dns", From 37dde7da057f55b3e6a587e17c0c61f02008317f Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 16 Aug 2021 08:37:58 -0400 Subject: [PATCH 11/81] format --- llarp/config/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 16678d214..4e1b4c80e 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -711,7 +711,7 @@ namespace llarp constexpr Default DefaultUpstreamDNS{"1.1.1.1"}; m_upstreamDNS.emplace_back(DefaultUpstreamDNS.val); if (!m_upstreamDNS.back().getPort()) - m_upstreamDNS.back().setPort(53); + m_upstreamDNS.back().setPort(53); conf.defineOption( "dns", From 08718624522a28a08531553ac2b4ad0a67c2f8df Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 10:42:04 -0400 Subject: [PATCH 12/81] initial routing table refactor * move routing table manipulation to vpn platform * add initial linux implementation of vpn platform route manipulation --- llarp/ev/vpn.hpp | 38 +++++ llarp/router/route_poker.cpp | 34 ++-- llarp/vpn/linux.hpp | 292 ++++++++++++++++++++++++++++++++++- 3 files changed, 351 insertions(+), 13 deletions(-) diff --git a/llarp/ev/vpn.hpp b/llarp/ev/vpn.hpp index 6f5c3c540..f911a310b 100644 --- a/llarp/ev/vpn.hpp +++ b/llarp/ev/vpn.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace llarp { struct Context; @@ -59,6 +61,38 @@ namespace llarp::vpn WritePacket(net::IPPacket pkt) = 0; }; + class IRouteManager + { + public: + using IPVariant_t = std::variant; + + IRouteManager() = default; + IRouteManager(const IRouteManager&) = delete; + IRouteManager(IRouteManager&&) = delete; + virtual ~IRouteManager() = default; + + virtual void + AddRoute(IPVariant_t ip, IPVariant_t gateway) = 0; + + virtual void + DelRoute(IPVariant_t ip, IPVariant_t gateway) = 0; + + virtual void + AddDefaultRouteViaInterface(std::string ifname) = 0; + + virtual void + DelDefaultRouteViaInterface(std::string ifname) = 0; + + virtual std::vector + GetGatewaysNotOnInterface(std::string ifname) = 0; + + virtual void + AddBlackhole() = 0; + + virtual void + DelBlackhole() = 0; + }; + /// a vpn platform /// responsible for obtaining vpn interfaces class Platform @@ -73,6 +107,10 @@ namespace llarp::vpn /// blocks until ready, throws on error virtual std::shared_ptr ObtainInterface(InterfaceInfo info) = 0; + + /// get owned ip route manager for managing routing table + virtual IRouteManager& + RouteManager() = 0; }; /// create native vpn platform diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index 2d9b1e3ee..5e44c82e2 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -30,13 +30,15 @@ namespace llarp void RoutePoker::DisableRoute(huint32_t ip, huint32_t gateway) { - net::DelRoute(ip.ToString(), gateway.ToString()); + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); + route.DelRoute(ip, gateway); } void RoutePoker::EnableRoute(huint32_t ip, huint32_t gateway) { - net::AddRoute(ip.ToString(), gateway.ToString()); + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); + route.AddRoute(ip, gateway); } void @@ -86,12 +88,13 @@ namespace llarp RoutePoker::~RoutePoker() { + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); for (const auto& [ip, gateway] : m_PokedRoutes) { if (gateway.h) - net::DelRoute(ip.ToString(), gateway.ToString()); + route.DelRoute(ip, gateway); } - net::DelBlackhole(); + route.DelBlackhole(); } std::optional @@ -101,14 +104,17 @@ namespace llarp throw std::runtime_error("Attempting to use RoutePoker before calling Init"); const auto ep = m_Router->hiddenServiceContext().GetDefault(); - const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName()); + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); + const auto gateways = route.GetGatewaysNotOnInterface(ep->GetIfName()); if (gateways.empty()) { return std::nullopt; } - huint32_t addr{}; - addr.FromString(gateways[0]); - return addr; + if (auto* ptr = std::get_if(&gateways[0])) + { + return huint32_t{*ptr}; + } + return std::nullopt; } void @@ -186,15 +192,17 @@ namespace llarp void RoutePoker::Up() { + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); + // black hole all routes by default - net::AddBlackhole(); + route.AddBlackhole(); // explicit route pokes for first hops m_Router->ForEachPeer( [&](auto session, auto) mutable { AddRoute(session->GetRemoteEndpoint().asIPv4()); }, false); // add default route const auto ep = m_Router->hiddenServiceContext().GetDefault(); - net::AddDefaultRouteViaInterface(ep->GetIfName()); + route.AddDefaultRouteViaInterface(ep->GetIfName()); } void @@ -206,9 +214,11 @@ namespace llarp false); // remove default route const auto ep = m_Router->hiddenServiceContext().GetDefault(); - net::DelDefaultRouteViaInterface(ep->GetIfName()); + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); + + route.DelDefaultRouteViaInterface(ep->GetIfName()); // delete route blackhole - net::DelBlackhole(); + route.DelBlackhole(); } } // namespace llarp diff --git a/llarp/vpn/linux.hpp b/llarp/vpn/linux.hpp index 8d67a6256..a50f14f04 100644 --- a/llarp/vpn/linux.hpp +++ b/llarp/vpn/linux.hpp @@ -6,9 +6,19 @@ #include #include #include "common.hpp" -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + namespace llarp::vpn { struct in6_ifreq @@ -121,14 +131,294 @@ namespace llarp::vpn } }; + class LinuxRouteManager : public IRouteManager + { + const int fd; + + enum class GatewayMode + { + eFirstHop, + eLowerDefault, + eUpperDefault + }; + + struct NLRequest + { + nlmsghdr n; + rtmsg r; + char buf[4096]; + + void + AddData(int type, const void* data, int alen) + { +#define NLMSG_TAIL(nmsg) ((struct rtattr*)(((intptr_t)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + + int len = RTA_LENGTH(alen); + rtattr* rta; + if (NLMSG_ALIGN(n.nlmsg_len) + RTA_ALIGN(len) > sizeof(*this)) + { + throw std::length_error{"nlrequest add data overflow"}; + } + rta = NLMSG_TAIL(&n); + rta->rta_type = type; + rta->rta_len = len; + if (alen) + { + memcpy(RTA_DATA(rta), data, alen); + } + n.nlmsg_len = NLMSG_ALIGN(n.nlmsg_len) + RTA_ALIGN(len); +#undef NLMSG_TAIL + } + }; + + /* Helper structure for ip address data and attributes */ + struct _inet_addr + { + unsigned char family; + unsigned char bitlen; + unsigned char data[sizeof(struct in6_addr)]; + + _inet_addr(huint32_t addr, int bits = 32) + { + family = AF_INET; + bitlen = bits; + htobe32buf(data, addr.h); + } + + _inet_addr(huint128_t addr, int bits = 128) + { + family = AF_INET6; + bitlen = bits; + const nuint128_t net = ToNet(addr); + std::memcpy(data, &net, 16); + } + }; + + void + Blackhole(int cmd, int flags, int af) + { + NLRequest nl_request{}; + /* Initialize request structure */ + nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; + nl_request.n.nlmsg_type = cmd; + nl_request.n.nlmsg_pid = getpid(); + nl_request.r.rtm_family = af; + nl_request.r.rtm_table = RT_TABLE_LOCAL; + nl_request.r.rtm_type = RTN_BLACKHOLE; + nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE; + if (af == AF_INET) + { + uint32_t addr{}; + nl_request.AddData(RTA_DST, &addr, sizeof(addr)); + } + else + { + uint128_t addr{}; + nl_request.AddData(RTA_DST, &addr, sizeof(addr)); + } + send(fd, &nl_request, sizeof(nl_request), 0); + } + + void + Route( + int cmd, + int flags, + const _inet_addr& dst, + const _inet_addr& gw, + GatewayMode mode, + int if_idx) + { + NLRequest nl_request{}; + + /* Initialize request structure */ + nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; + nl_request.n.nlmsg_type = cmd; + nl_request.n.nlmsg_pid = getpid(); + nl_request.r.rtm_family = dst.family; + nl_request.r.rtm_table = RT_TABLE_MAIN; + if (if_idx) + { + nl_request.r.rtm_scope = RT_SCOPE_LINK; + } + else + { + nl_request.r.rtm_scope = RT_SCOPE_NOWHERE; + } + /* Set additional flags if NOT deleting route */ + if (cmd != RTM_DELROUTE) + { + nl_request.r.rtm_protocol = RTPROT_BOOT; + nl_request.r.rtm_type = RTN_UNICAST; + } + + nl_request.r.rtm_family = dst.family; + nl_request.r.rtm_dst_len = dst.bitlen; + nl_request.r.rtm_scope = 0; + + /* Set gateway */ + if (gw.bitlen != 0 and dst.family == AF_INET) + { + nl_request.AddData(RTA_GATEWAY, &gw.data, gw.bitlen / 8); + } + nl_request.r.rtm_family = gw.family; + if (mode == GatewayMode::eFirstHop) + { + nl_request.AddData(RTA_DST, &dst.data, dst.bitlen / 8); + /* Set interface */ + nl_request.AddData(RTA_OIF, &if_idx, sizeof(int)); + } + if (mode == GatewayMode::eUpperDefault) + { + if (dst.family == AF_INET) + { + nl_request.AddData(RTA_DST, &dst.data, sizeof(uint32_t)); + } + else + { + nl_request.AddData(RTA_OIF, &if_idx, sizeof(int)); + nl_request.AddData(RTA_DST, &dst.data, sizeof(in6_addr)); + } + } + /* Send message to the netlink */ + send(fd, &nl_request, sizeof(nl_request), 0); + } + + void + DefaultRouteViaInterface(std::string ifname, int cmd, int flags) + { + int if_idx = if_nametoindex(ifname.c_str()); + const auto maybe = GetInterfaceAddr(ifname); + if (not maybe) + throw std::runtime_error{"we dont have our own network interface?"}; + + const _inet_addr gateway{maybe->asIPv4()}; + const _inet_addr lower{ipaddr_ipv4_bits(0, 0, 0, 0), 1}; + const _inet_addr upper{ipaddr_ipv4_bits(128, 0, 0, 0), 1}; + + Route(cmd, flags, lower, gateway, GatewayMode::eLowerDefault, if_idx); + Route(cmd, flags, upper, gateway, GatewayMode::eUpperDefault, if_idx); + + if (const auto maybe6 = GetInterfaceIPv6Address(ifname)) + { + const _inet_addr gateway6{*maybe6, 128}; + for (const std::string str : {"::", "4000::", "8000::", "c000::"}) + { + huint128_t _hole{}; + _hole.FromString(str); + const _inet_addr hole6{_hole, 2}; + Route(cmd, flags, hole6, gateway6, GatewayMode::eUpperDefault, if_idx); + } + } + } + + void + Route(int cmd, int flags, IPVariant_t ip, IPVariant_t gateway) + { + // do bullshit double std::visit because lol variants + std::visit( + [gateway, cmd, flags, this](auto&& ip) { + const _inet_addr toAddr{ip}; + std::visit( + [toAddr, cmd, flags, this](auto&& gateway) { + const _inet_addr gwAddr{gateway}; + Route(cmd, flags, toAddr, gwAddr, GatewayMode::eFirstHop, 0); + }, + gateway); + }, + ip); + } + + public: + LinuxRouteManager() : fd{socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)} + { + if (fd == -1) + throw std::runtime_error{"failed to make netlink socket"}; + } + + ~LinuxRouteManager() + { + close(fd); + } + + void + AddRoute(IPVariant_t ip, IPVariant_t gateway) override + { + Route(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, ip, gateway); + } + + void + DelRoute(IPVariant_t ip, IPVariant_t gateway) override + { + Route(RTM_DELROUTE, 0, ip, gateway); + } + + void + AddDefaultRouteViaInterface(std::string ifname) override + { + DefaultRouteViaInterface(ifname, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL); + } + + void + DelDefaultRouteViaInterface(std::string ifname) override + { + DefaultRouteViaInterface(ifname, RTM_DELROUTE, 0); + } + + std::vector + GetGatewaysNotOnInterface(std::string ifname) override + { + std::vector gateways{}; + std::ifstream inf{"/proc/net/route"}; + for (std::string line; std::getline(inf, line);) + { + const auto parts = split(line, "\t"); + if (parts[1].find_first_not_of('0') == std::string::npos and parts[0] != ifname) + { + const auto& ip = parts[2]; + if ((ip.size() == sizeof(uint32_t) * 2) and oxenmq::is_hex(ip)) + { + huint32_t x{}; + oxenmq::from_hex(ip.begin(), ip.end(), reinterpret_cast(&x.h)); + gateways.emplace_back(x); + } + } + } + return gateways; + } + + void + AddBlackhole() override + { + Blackhole(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, AF_INET); + Blackhole(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, AF_INET6); + } + + void + DelBlackhole() override + { + Blackhole(RTM_DELROUTE, 0, AF_INET); + Blackhole(RTM_DELROUTE, 0, AF_INET6); + } + }; + class LinuxPlatform : public Platform { + LinuxRouteManager _routeManager{}; + public: std::shared_ptr ObtainInterface(InterfaceInfo info) override { return std::make_shared(std::move(info)); }; + + IRouteManager& + RouteManager() override + { + return _routeManager; + } }; } // namespace llarp::vpn From 9791fd62a070b0eeb1f10dc0e8e39424dc944032 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 11:02:21 -0400 Subject: [PATCH 13/81] initial win32 port of route manager --- llarp/vpn/win32.hpp | 156 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/llarp/vpn/win32.hpp b/llarp/vpn/win32.hpp index 405cfabe1..d56cf4b8b 100644 --- a/llarp/vpn/win32.hpp +++ b/llarp/vpn/win32.hpp @@ -159,6 +159,16 @@ namespace llarp::vpn } public: + static std::string + RouteCommand() + { + std::wstring wcmd = get_win_sys_path() + L"\\route.exe"; + + using convert_type = std::codecvt_utf8; + std::wstring_convert converter; + return converter.to_bytes(wcmd); + } + Win32Interface(InterfaceInfo info) : m_ReadQueue{1024}, m_Info{std::move(info)} { DWORD len; @@ -433,8 +443,149 @@ namespace llarp::vpn } }; + template + void + ForEachWIN32Interface(Visit visit) + { +#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) + MIB_IPFORWARDTABLE* pIpForwardTable; + DWORD dwSize = 0; + DWORD dwRetVal = 0; + + pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(sizeof(MIB_IPFORWARDTABLE)); + if (pIpForwardTable == nullptr) + return; + + if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) + { + FREE(pIpForwardTable); + pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(dwSize); + if (pIpForwardTable == nullptr) + { + return; + } + } + + if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) + { + for (int i = 0; i < (int)pIpForwardTable->dwNumEntries; i++) + { + visit(&pIpForwardTable->table[i]); + } + } + FREE(pIpForwardTable); +#undef MALLOC +#undef FREE + } + + class Win32RouteManager : public IRouteManager + { + void + Execute(std::string cmd) const + { + LogInfo(cmd); + ::system(cmd.c_str()); + } + + static std::string + RouteCommand() + { + return Win32Interface::RouteCommand(); + } + + void + Route(IPVariant_t ip, IPVariant_t gateway, std::string cmd) + { + std::stringstream ss; + std::string ip_str; + std::string gateway_str; + + std::visit([&ip_str](auto&& ip) { ip_str = ip.ToString(); }, ip); + std::visit([&gateway_str](auto&& gateway) { gateway_str = gateway.ToString(); }, gateway); + + ss << RouteCommand() << " " << cmd << " " << ip_str << " MASK 255.255.255.255 " << gateway_str + << " METRIC 2"; + Execute(ss.str()); + } + + void + DefaultRouteViaInterface(std::string ifname, std::string cmd) + { + // poke hole for loopback bacause god is dead on windows + Execute(RouteCommand() + " " + cmd + " 127.0.0.0 MASK 255.0.0.0 0.0.0.0"); + + huint32_t ip{}; + ip.FromString(ifname); + const auto ipv6 = net::ExpandV4Lan(ip); + + Execute(RouteCommand() + " " + cmd + " ::/2 " + ipv6.ToString()); + Execute(RouteCommand() + " " + cmd + " 4000::/2 " + ipv6.ToString()); + Execute(RouteCommand() + " " + cmd + " 8000::/2 " + ipv6.ToString()); + Execute(RouteCommand() + " " + cmd + " c000::/2 " + ipv6.ToString()); + + ifname.back()++; + Execute(RouteCommand() + " " + cmd + " 0.0.0.0 MASK 128.0.0.0 " + ifname); + Execute(RouteCommand() + " " + cmd + " 128.0.0.0 MASK 128.0.0.0 " + ifname); + } + + public: + void + AddRoute(IPVariant_t ip, IPVariant_t gateway) override + { + Route(ip, gateway, "ADD"); + } + + void + DelRoute(IPVariant_t ip, IPVariant_t gateway) override + { + Route(ip, gateway, "DELETE"); + } + + void + AddBlackhole() override{}; + + void + DelBlackhole() override{}; + + std::vector + GetGatewaysNotOnInterface(std::string ifname) override + { + std::vector gateways; + ForEachWIN32Interface([&](auto w32interface) { + struct in_addr gateway, interface_addr; + gateway.S_un.S_addr = (u_long)w32interface->dwForwardDest; + interface_addr.S_un.S_addr = (u_long)w32interface->dwForwardNextHop; + std::string interface_name{inet_ntoa(interface_addr)}; + if ((!gateway.S_un.S_addr) and interface_name != ifname) + { + llarp::LogTrace( + "Win32 find gateway: Adding gateway (", interface_name, ") to list of gateways."); + huint32_t x{}; + if (x.FromString(interface_name)) + gateways.push_back(x); + } + }); + return gateways; + } + + void + AddDefaultRouteViaInterface(std::string ifname) override + { + DefaultRouteViaInterface(ifname, "ADD"); + } + + void + DelDefaultRouteViaInterface(std::string ifname) override + { + DefaultRouteViaInterface(ifname, "DELETE"); + } + }; + class Win32Platform : public Platform { + Win32RouteManager _routeManager{}; + public: std::shared_ptr ObtainInterface(InterfaceInfo info) override @@ -443,6 +594,11 @@ namespace llarp::vpn netif->Start(); return netif; }; + IRouteManager& + RouteManager() override + { + return _routeManager; + } }; } // namespace llarp::vpn From 64cd2990bcfe39b6ba3577cb8233f86fd5e36e82 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 11:07:54 -0400 Subject: [PATCH 14/81] remove old routing table maniuplation code --- llarp/CMakeLists.txt | 1 - llarp/net/route.cpp | 616 ----------------------------------- llarp/net/route.hpp | 36 -- llarp/router/route_poker.cpp | 1 - llarp/router/router.cpp | 1 - llarp/rpc/rpc_server.cpp | 1 - llarp/vpn/win32.hpp | 89 ++--- 7 files changed, 52 insertions(+), 693 deletions(-) delete mode 100644 llarp/net/route.cpp delete mode 100644 llarp/net/route.hpp diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index d1aed3353..3ae31ae4e 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -52,7 +52,6 @@ add_library(lokinet-platform net/ip_range.cpp net/net.cpp net/net_int.cpp - net/route.cpp net/sock_addr.cpp vpn/packet_router.cpp vpn/platform.cpp diff --git a/llarp/net/route.cpp b/llarp/net/route.cpp deleted file mode 100644 index 604208465..000000000 --- a/llarp/net/route.cpp +++ /dev/null @@ -1,616 +0,0 @@ -#include "route.hpp" - -#ifdef __linux__ -#include -#include -#include -#include -#include -#ifndef ANDROID -#include -#include -#endif -#include "net.hpp" -#include -#include -#endif -#ifdef __APPLE__ -#include "net.hpp" -#include -#endif -#ifdef _WIN32 -#include -#include -#include -#include -#include -#include -#include -#include -#include "net_int.hpp" -#include "ip.hpp" -#endif - -#include -#include -#include - -namespace llarp::net -{ -#ifndef __linux__ - void - Execute(std::string cmd) - { - LogInfo(cmd); - system(cmd.c_str()); - } -#endif - -#ifdef __linux__ -#ifndef ANDROID - - enum class GatewayMode - { - eFirstHop, - eLowerDefault, - eUpperDefault - }; - - struct NLSocket - { - NLSocket() : fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) - { - if (fd == -1) - throw std::runtime_error("failed to make netlink socket"); - } - - ~NLSocket() - { - if (fd != -1) - close(fd); - } - - const int fd; - }; - - /* Helper structure for ip address data and attributes */ - typedef struct - { - unsigned char family; - unsigned char bitlen; - unsigned char data[sizeof(struct in6_addr)]; - } _inet_addr; - - /* */ - -#define NLMSG_TAIL(nmsg) ((struct rtattr*)(((intptr_t)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) - - /* Add new data to rtattr */ - int - rtattr_add(struct nlmsghdr* n, unsigned int maxlen, int type, const void* data, int alen) - { - int len = RTA_LENGTH(alen); - struct rtattr* rta; - - if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) - { - fprintf(stderr, "rtattr_add error: message exceeded bound of %d\n", maxlen); - return -1; - } - - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - - if (alen) - { - memcpy(RTA_DATA(rta), data, alen); - } - - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - - return 0; - } - - struct nl_req - { - struct nlmsghdr n; - struct rtmsg r; - char buf[4096]; - }; - - /// add/remove a route blackhole - int - do_blackhole(int sock, int cmd, int flags, int af) - { - nl_req nl_request{}; - /* Initialize request structure */ - nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; - nl_request.n.nlmsg_type = cmd; - nl_request.n.nlmsg_pid = getpid(); - nl_request.r.rtm_family = af; - nl_request.r.rtm_table = RT_TABLE_LOCAL; - nl_request.r.rtm_type = RTN_BLACKHOLE; - nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE; - if (af == AF_INET) - { - uint32_t addr{}; - rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &addr, sizeof(addr)); - } - else - { - uint128_t addr{}; - rtattr_add(&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &addr, sizeof(addr)); - } - return send(sock, &nl_request, sizeof(nl_request), 0); - } - - int - do_route( - int sock, - int cmd, - int flags, - const _inet_addr* dst, - const _inet_addr* gw, - GatewayMode mode, - int if_idx) - { - nl_req nl_request{}; - - /* Initialize request structure */ - nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags; - nl_request.n.nlmsg_type = cmd; - nl_request.n.nlmsg_pid = getpid(); - nl_request.r.rtm_family = dst->family; - nl_request.r.rtm_table = RT_TABLE_MAIN; - if (if_idx) - { - nl_request.r.rtm_scope = RT_SCOPE_LINK; - } - else - { - nl_request.r.rtm_scope = RT_SCOPE_NOWHERE; - } - /* Set additional flags if NOT deleting route */ - if (cmd != RTM_DELROUTE) - { - nl_request.r.rtm_protocol = RTPROT_BOOT; - nl_request.r.rtm_type = RTN_UNICAST; - } - - nl_request.r.rtm_family = dst->family; - nl_request.r.rtm_dst_len = dst->bitlen; - nl_request.r.rtm_scope = 0; - - /* Set gateway */ - if (gw->bitlen != 0 and dst->family == AF_INET) - { - rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &gw->data, gw->bitlen / 8); - } - nl_request.r.rtm_family = gw->family; - if (mode == GatewayMode::eFirstHop) - { - rtattr_add( - &nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &dst->data, dst->bitlen / 8); - /* Set interface */ - rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int)); - } - if (mode == GatewayMode::eUpperDefault) - { - if (dst->family == AF_INET) - { - rtattr_add( - &nl_request.n, - sizeof(nl_request), - /*RTA_NEWDST*/ RTA_DST, - &dst->data, - sizeof(uint32_t)); - } - else - { - rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int)); - rtattr_add( - &nl_request.n, - sizeof(nl_request), - /*RTA_NEWDST*/ RTA_DST, - &dst->data, - sizeof(in6_addr)); - } - } - /* Send message to the netlink */ - return send(sock, &nl_request, sizeof(nl_request), 0); - } - - int - read_addr(const char* addr, _inet_addr* res, int bitlen = 32) - { - if (strchr(addr, ':')) - { - res->family = AF_INET6; - res->bitlen = bitlen; - } - else - { - res->family = AF_INET; - res->bitlen = bitlen; - } - return inet_pton(res->family, addr, res->data); - } - -#endif -#endif - -#ifdef _WIN32 - - std::wstring - get_win_sys_path() - { - wchar_t win_sys_path[MAX_PATH] = {0}; - const wchar_t* default_sys_path = L"C:\\Windows\\system32"; - - if (!GetSystemDirectoryW(win_sys_path, _countof(win_sys_path))) - { - wcsncpy(win_sys_path, default_sys_path, _countof(win_sys_path)); - win_sys_path[_countof(win_sys_path) - 1] = L'\0'; - } - return win_sys_path; - } - - std::string - RouteCommand() - { - std::wstring wcmd = get_win_sys_path() + L"\\route.exe"; - - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - return converter.to_bytes(wcmd); - } - - std::string - NetshCommand() - { - std::wstring wcmd = get_win_sys_path() + L"\\netsh.exe"; - - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - return converter.to_bytes(wcmd); - } - - template - void - ForEachWIN32Interface(Visit visit) - { -#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) -#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) - MIB_IPFORWARDTABLE* pIpForwardTable; - DWORD dwSize = 0; - DWORD dwRetVal = 0; - - pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(sizeof(MIB_IPFORWARDTABLE)); - if (pIpForwardTable == nullptr) - return; - - if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) - { - FREE(pIpForwardTable); - pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(dwSize); - if (pIpForwardTable == nullptr) - { - return; - } - } - - if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) - { - for (int i = 0; i < (int)pIpForwardTable->dwNumEntries; i++) - { - visit(&pIpForwardTable->table[i]); - } - } - FREE(pIpForwardTable); -#undef MALLOC -#undef FREE - } - - std::optional - GetInterfaceIndex(huint32_t ip) - { - std::optional ret = std::nullopt; - ForEachWIN32Interface([&ret, n = ToNet(ip)](auto* iface) { - if (ret.has_value()) - return; - if (iface->dwForwardNextHop == n.n) - { - ret = iface->dwForwardIfIndex; - } - }); - return ret; - } - -#endif - - void - AddRoute(std::string ip, std::string gateway) - { - LogInfo("Add route: ", ip, " via ", gateway); -#ifdef __linux__ -#ifndef ANDROID - NLSocket sock; - int if_idx = 0; - _inet_addr to_addr{}; - _inet_addr gw_addr{}; - int nl_cmd = RTM_NEWROUTE; - int nl_flags = NLM_F_CREATE | NLM_F_EXCL; - read_addr(gateway.c_str(), &gw_addr); - read_addr(ip.c_str(), &to_addr); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eFirstHop, if_idx); -#endif -#else - std::stringstream ss; -#if _WIN32 - ss << RouteCommand() << " ADD " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2"; -#elif __APPLE__ - ss << "/sbin/route -n add -host " << ip << " " << gateway; -#else -#error unsupported platform -#endif - Execute(ss.str()); -#endif - } - - void - DelRoute(std::string ip, std::string gateway) - { - LogInfo("Delete route: ", ip, " via ", gateway); -#ifdef __linux__ -#ifndef ANDROID - NLSocket sock; - int if_idx = 0; - _inet_addr to_addr{}; - _inet_addr gw_addr{}; - int nl_cmd = RTM_DELROUTE; - int nl_flags = 0; - read_addr(gateway.c_str(), &gw_addr); - read_addr(ip.c_str(), &to_addr); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eFirstHop, if_idx); -#endif -#else - std::stringstream ss; -#if _WIN32 - ss << RouteCommand() << " DELETE " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2"; -#elif __APPLE__ - ss << "/sbin/route -n delete -host " << ip << " " << gateway; -#else -#error unsupported platform -#endif - Execute(ss.str()); -#endif - } - - void - AddBlackhole() - { - LogInfo("adding route blackhole to drop all traffic"); -#if __linux__ -#ifndef ANDROID - NLSocket sock; - do_blackhole(sock.fd, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, AF_INET); - do_blackhole(sock.fd, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, AF_INET6); -#endif -#endif - } - - void - DelBlackhole() - { - LogInfo("remove route blackhole"); -#if __linux__ -#ifndef ANDROID - NLSocket sock; - do_blackhole(sock.fd, RTM_DELROUTE, 0, AF_INET); - do_blackhole(sock.fd, RTM_DELROUTE, 0, AF_INET6); -#endif -#endif - } - - void - AddDefaultRouteViaInterface(std::string ifname) - { - LogInfo("Add default route via ", ifname); -#ifdef __linux__ -#ifndef ANDROID - NLSocket sock; - int if_idx = if_nametoindex(ifname.c_str()); - _inet_addr to_addr{}; - _inet_addr gw_addr{}; - const auto maybe = GetInterfaceAddr(ifname); - if (not maybe.has_value()) - throw std::runtime_error("we dont have our own net interface?"); - int nl_cmd = RTM_NEWROUTE; - int nl_flags = NLM_F_CREATE | NLM_F_EXCL; - const auto host = maybe->asIPv4().ToString(); - read_addr(host.c_str(), &gw_addr); - read_addr("0.0.0.0", &to_addr, 1); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eLowerDefault, if_idx); - read_addr("128.0.0.0", &to_addr, 1); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - const auto maybeInt = GetInterfaceIPv6Address(ifname); - if (maybeInt.has_value()) - { - const auto host = maybeInt->ToString(); - LogInfo("add v6 route via ", host); - read_addr(host.c_str(), &gw_addr, 128); - read_addr("::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - read_addr("4000::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - read_addr("8000::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - read_addr("c000::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - } -#endif -#elif _WIN32 - // poke hole for loopback bacause god is dead on windows - Execute(RouteCommand() + " ADD 127.0.0.0 MASK 255.0.0.0 0.0.0.0"); - - huint32_t ip{}; - ip.FromString(ifname); - const auto ipv6 = net::ExpandV4Lan(ip); - - Execute(RouteCommand() + " ADD ::/2 " + ipv6.ToString()); - Execute(RouteCommand() + " ADD 4000::/2 " + ipv6.ToString()); - Execute(RouteCommand() + " ADD 8000::/2 " + ipv6.ToString()); - Execute(RouteCommand() + " ADD c000::/2 " + ipv6.ToString()); - ifname.back()++; - Execute(RouteCommand() + " ADD 0.0.0.0 MASK 128.0.0.0 " + ifname); - Execute(RouteCommand() + " ADD 128.0.0.0 MASK 128.0.0.0 " + ifname); - -#elif __APPLE__ - Execute("/sbin/route -n add -cloning -net 0.0.0.0 -netmask 128.0.0.0 -interface " + ifname); - Execute("/sbin/route -n add -cloning -net 128.0.0.0 -netmask 128.0.0.0 -interface " + ifname); - - Execute("/sbin/route -n add -inet6 -net ::/2 -interface " + ifname); - Execute("/sbin/route -n add -inet6 -net 4000::/2 -interface " + ifname); - Execute("/sbin/route -n add -inet6 -net 8000::/2 -interface " + ifname); - Execute("/sbin/route -n add -inet6 -net c000::/2 -interface " + ifname); -#else -#error unsupported platform -#endif - } - - void - DelDefaultRouteViaInterface(std::string ifname) - { - LogInfo("Remove default route via ", ifname); -#ifdef __linux__ -#ifndef ANDROID - NLSocket sock; - int if_idx = if_nametoindex(ifname.c_str()); - _inet_addr to_addr{}; - _inet_addr gw_addr{}; - const auto maybe = GetInterfaceAddr(ifname); - - if (not maybe.has_value()) - throw std::runtime_error("we dont have our own net interface?"); - int nl_cmd = RTM_DELROUTE; - int nl_flags = 0; - const auto host = maybe->asIPv4().ToString(); - read_addr(host.c_str(), &gw_addr); - read_addr("0.0.0.0", &to_addr, 1); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eLowerDefault, if_idx); - read_addr("128.0.0.0", &to_addr, 1); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - - const auto maybeInt = GetInterfaceIPv6Address(ifname); - if (maybeInt.has_value()) - { - const auto host = maybeInt->ToString(); - LogInfo("del v6 route via ", host); - read_addr(host.c_str(), &gw_addr, 128); - read_addr("::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - read_addr("4000::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - read_addr("8000::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - read_addr("c000::", &to_addr, 2); - do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, GatewayMode::eUpperDefault, if_idx); - } -#endif -#elif _WIN32 - huint32_t ip{}; - ip.FromString(ifname); - const auto ipv6 = net::ExpandV4Lan(ip); - - Execute(RouteCommand() + " DELETE ::/2 " + ipv6.ToString()); - Execute(RouteCommand() + " DELETE 4000::/2 " + ipv6.ToString()); - Execute(RouteCommand() + " DELETE 8000::/2 " + ipv6.ToString()); - Execute(RouteCommand() + " DELETE c000::/2 " + ipv6.ToString()); - ifname.back()++; - Execute(RouteCommand() + " DELETE 0.0.0.0 MASK 128.0.0.0 " + ifname); - Execute(RouteCommand() + " DELETE 128.0.0.0 MASK 128.0.0.0 " + ifname); - Execute(RouteCommand() + " DELETE 127.0.0.0 MASK 255.0.0.0 0.0.0.0"); -#elif __APPLE__ - Execute("/sbin/route -n delete -cloning -net 0.0.0.0 -netmask 128.0.0.0 -interface " + ifname); - Execute( - "/sbin/route -n delete -cloning -net 128.0.0.0 -netmask 128.0.0.0 -interface " + ifname); - - Execute("/sbin/route -n delete -inet6 -net ::/2 -interface " + ifname); - Execute("/sbin/route -n delete -inet6 -net 4000::/2 -interface " + ifname); - Execute("/sbin/route -n delete -inet6 -net 8000::/2 -interface " + ifname); - Execute("/sbin/route -n delete -inet6 -net c000::/2 -interface " + ifname); - -#else -#error unsupported platform -#endif - } - - std::vector - GetGatewaysNotOnInterface(std::string ifname) - { - std::vector gateways; -#ifdef __linux__ -#ifdef ANDROID -#else - std::ifstream inf("/proc/net/route"); - for (std::string line; std::getline(inf, line);) - { - const auto parts = split(line, "\t"); - if (parts[1].find_first_not_of('0') == std::string::npos and parts[0] != ifname) - { - const auto& ip = parts[2]; - if ((ip.size() == sizeof(uint32_t) * 2) and oxenmq::is_hex(ip)) - { - huint32_t x{}; - oxenmq::from_hex(ip.begin(), ip.end(), reinterpret_cast(&x.h)); - gateways.emplace_back(x.ToString()); - } - } - } -#endif - return gateways; -#elif _WIN32 - ForEachWIN32Interface([&](auto w32interface) { - struct in_addr gateway, interface_addr; - gateway.S_un.S_addr = (u_long)w32interface->dwForwardDest; - interface_addr.S_un.S_addr = (u_long)w32interface->dwForwardNextHop; - std::string interface_name{inet_ntoa(interface_addr)}; - if ((!gateway.S_un.S_addr) and interface_name != ifname) - { - llarp::LogTrace( - "Win32 find gateway: Adding gateway (", interface_name, ") to list of gateways."); - gateways.push_back(std::move(interface_name)); - } - }); - return gateways; -#elif __APPLE__ - LogDebug("get gateways not on ", ifname); - // mac os is so godawful man - FILE* p = popen("/usr/sbin/netstat -rn -f inet", "r"); - if (p == nullptr) - { - return gateways; - } - char* line = nullptr; - size_t len = 0; - ssize_t read = 0; - while ((read = getline(&line, &len, p)) != -1) - { - const std::string line_str(line, len); - const auto parts = llarp::split_any(line_str, " "sv, true); - if (parts[0] == "default" and parts[3] != ifname) - { - gateways.emplace_back(parts[1]); - } - } - pclose(p); - return gateways; -#else -#error unsupported platform -#endif - } - -} // namespace llarp::net diff --git a/llarp/net/route.hpp b/llarp/net/route.hpp deleted file mode 100644 index 23e75f8d6..000000000 --- a/llarp/net/route.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include - -namespace llarp::net -{ - /// get every ip address that is a gateway that isn't owned by interface with name ifname - std::vector - GetGatewaysNotOnInterface(std::string ifname); - - /// add route to ipaddr via gateway ip - void - AddRoute(std::string ipaddr, std::string gateway); - - /// delete route to ipaddr via gateway ip - void - DelRoute(std::string ipaddr, std::string gateway); - - /// add default route via interface with name ifname - void - AddDefaultRouteViaInterface(std::string ifname); - - /// delete default route via interface with name ifname - void - DelDefaultRouteViaInterface(std::string ifname); - - /// add route blackhole for all traffic - void - AddBlackhole(); - - /// delete route blackhole for all traffic - void - DelBlackhole(); - -} // namespace llarp::net diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index 5e44c82e2..9017125bc 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -1,7 +1,6 @@ #include "route_poker.hpp" #include "abstractrouter.hpp" #include "net/sock_addr.hpp" -#include #include #include diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index d5333ba9f..4fa608afc 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/llarp/rpc/rpc_server.cpp b/llarp/rpc/rpc_server.cpp index ac4dac512..38045d6c4 100644 --- a/llarp/rpc/rpc_server.cpp +++ b/llarp/rpc/rpc_server.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/llarp/vpn/win32.hpp b/llarp/vpn/win32.hpp index d56cf4b8b..f0ad23207 100644 --- a/llarp/vpn/win32.hpp +++ b/llarp/vpn/win32.hpp @@ -117,6 +117,57 @@ namespace llarp::vpn return deviceid; } + template + void + ForEachWIN32Interface(Visit visit) + { +#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) + MIB_IPFORWARDTABLE* pIpForwardTable; + DWORD dwSize = 0; + DWORD dwRetVal = 0; + + pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(sizeof(MIB_IPFORWARDTABLE)); + if (pIpForwardTable == nullptr) + return; + + if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) + { + FREE(pIpForwardTable); + pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(dwSize); + if (pIpForwardTable == nullptr) + { + return; + } + } + + if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) + { + for (int i = 0; i < (int)pIpForwardTable->dwNumEntries; i++) + { + visit(&pIpForwardTable->table[i]); + } + } + FREE(pIpForwardTable); +#undef MALLOC +#undef FREE + } + + std::optional + GetInterfaceIndex(huint32_t ip) + { + std::optional ret = std::nullopt; + ForEachWIN32Interface([&ret, n = ToNet(ip)](auto* iface) { + if (ret.has_value()) + return; + if (iface->dwForwardNextHop == n.n) + { + ret = iface->dwForwardIfIndex; + } + }); + return ret; + } + class Win32Interface final : public NetworkInterface { std::atomic m_Run; @@ -316,7 +367,7 @@ namespace llarp::vpn { if (ifaddr.fam == AF_INET6) { - const auto maybe = net::GetInterfaceIndex(ip); + const auto maybe = GetInterfaceIndex(ip); if (maybe.has_value()) { NetSH( @@ -443,42 +494,6 @@ namespace llarp::vpn } }; - template - void - ForEachWIN32Interface(Visit visit) - { -#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) -#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) - MIB_IPFORWARDTABLE* pIpForwardTable; - DWORD dwSize = 0; - DWORD dwRetVal = 0; - - pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(sizeof(MIB_IPFORWARDTABLE)); - if (pIpForwardTable == nullptr) - return; - - if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) - { - FREE(pIpForwardTable); - pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(dwSize); - if (pIpForwardTable == nullptr) - { - return; - } - } - - if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) - { - for (int i = 0; i < (int)pIpForwardTable->dwNumEntries; i++) - { - visit(&pIpForwardTable->table[i]); - } - } - FREE(pIpForwardTable); -#undef MALLOC -#undef FREE - } - class Win32RouteManager : public IRouteManager { void From e25ae7192f0e735ab6b39a23bf48746402b64698 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 11:40:40 -0400 Subject: [PATCH 15/81] introduce add/del route via interface to route manager --- llarp/ev/vpn.hpp | 6 ++++++ llarp/vpn/linux.hpp | 44 ++++++++++++++++++++++++++++++++++++++++++-- llarp/vpn/win32.hpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/llarp/ev/vpn.hpp b/llarp/ev/vpn.hpp index f911a310b..65f96c594 100644 --- a/llarp/ev/vpn.hpp +++ b/llarp/ev/vpn.hpp @@ -83,6 +83,12 @@ namespace llarp::vpn virtual void DelDefaultRouteViaInterface(std::string ifname) = 0; + virtual void + AddRouteViaInterface(std::string ifname, IPRange range) = 0; + + virtual void + DelRouteViaInterface(std::string ifname, IPRange range) = 0; + virtual std::vector GetGatewaysNotOnInterface(std::string ifname) = 0; diff --git a/llarp/vpn/linux.hpp b/llarp/vpn/linux.hpp index a50f14f04..c3f81e1e1 100644 --- a/llarp/vpn/linux.hpp +++ b/llarp/vpn/linux.hpp @@ -178,14 +178,14 @@ namespace llarp::vpn unsigned char bitlen; unsigned char data[sizeof(struct in6_addr)]; - _inet_addr(huint32_t addr, int bits = 32) + _inet_addr(huint32_t addr, size_t bits = 32) { family = AF_INET; bitlen = bits; htobe32buf(data, addr.h); } - _inet_addr(huint128_t addr, int bits = 128) + _inet_addr(huint128_t addr, size_t bits = 128) { family = AF_INET6; bitlen = bits; @@ -313,6 +313,34 @@ namespace llarp::vpn } } + void + RouteViaInterface(int cmd, int flags, std::string ifname, IPRange range) + { + int if_idx = if_nametoindex(ifname.c_str()); + if (range.IsV4()) + { + const auto maybe = GetInterfaceAddr(ifname); + if (not maybe) + throw std::runtime_error{"we dont have our own network interface?"}; + + const _inet_addr gateway{maybe->asIPv4()}; + + const _inet_addr addr{ + net::TruncateV6(range.addr), bits::count_bits(net::TruncateV6(range.netmask_bits))}; + + Route(cmd, flags, addr, gateway, GatewayMode::eUpperDefault, if_idx); + } + else + { + const auto maybe = GetInterfaceIPv6Address(ifname); + if (not maybe) + throw std::runtime_error{"we dont have our own network interface?"}; + const _inet_addr gateway{*maybe, 128}; + const _inet_addr addr{range.addr, bits::count_bits(range.netmask_bits)}; + Route(cmd, flags, addr, gateway, GatewayMode::eUpperDefault, if_idx); + } + } + void Route(int cmd, int flags, IPVariant_t ip, IPVariant_t gateway) { @@ -366,6 +394,18 @@ namespace llarp::vpn DefaultRouteViaInterface(ifname, RTM_DELROUTE, 0); } + void + AddRouteViaInterface(std::string ifname, IPRange range) override + { + RouteViaInterface(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, ifname, range); + } + + void + DelRouteViaInterface(std::string ifname, IPRange range) override + { + RouteViaInterface(RTM_DELROUTE, 0, ifname, range); + } + std::vector GetGatewaysNotOnInterface(std::string ifname) override { diff --git a/llarp/vpn/win32.hpp b/llarp/vpn/win32.hpp index f0ad23207..64f1d1fed 100644 --- a/llarp/vpn/win32.hpp +++ b/llarp/vpn/win32.hpp @@ -544,6 +544,25 @@ namespace llarp::vpn Execute(RouteCommand() + " " + cmd + " 128.0.0.0 MASK 128.0.0.0 " + ifname); } + void + RouteViaInterface(std::string ifname, IPRange range, std::string cmd) + { + if (range.IsV4()) + { + const huint32_t addr4 = net::TruncateV6(range.addr); + const huint32_t mask4 = net::TruncateV6(range.netmask_bits); + Execute( + RouteCommand() + " " + cmd + " " + addr4.ToString() + " MASK " + mask4.ToString() + " " + + ifname); + } + else + { + Execute( + RouteCommand() + " " + cmd + range.addr.ToString() + " MASK " + + range.netmask_bits.ToString() + " " + ifname); + } + } + public: void AddRoute(IPVariant_t ip, IPVariant_t gateway) override @@ -557,6 +576,18 @@ namespace llarp::vpn Route(ip, gateway, "DELETE"); } + void + AddRouteViaInterface(std::string ifname, IPRange range) override + { + RouteViaInterface(ifname, range, "ADD"); + } + + void + DelRouteViaInterface(std::string ifname, IPRange range) override + { + RouteViaInterface(ifname, range, "DELETE"); + } + void AddBlackhole() override{}; From c9b9ed91c2b0d553544342c899b1d8e7298a7abe Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 11:42:24 -0400 Subject: [PATCH 16/81] make add/del blackhole default to empty implementation --- llarp/ev/vpn.hpp | 4 ++-- llarp/vpn/win32.hpp | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/llarp/ev/vpn.hpp b/llarp/ev/vpn.hpp index 65f96c594..c43ac35bd 100644 --- a/llarp/ev/vpn.hpp +++ b/llarp/ev/vpn.hpp @@ -93,10 +93,10 @@ namespace llarp::vpn GetGatewaysNotOnInterface(std::string ifname) = 0; virtual void - AddBlackhole() = 0; + AddBlackhole(){}; virtual void - DelBlackhole() = 0; + DelBlackhole(){}; }; /// a vpn platform diff --git a/llarp/vpn/win32.hpp b/llarp/vpn/win32.hpp index 64f1d1fed..cda174802 100644 --- a/llarp/vpn/win32.hpp +++ b/llarp/vpn/win32.hpp @@ -588,12 +588,6 @@ namespace llarp::vpn RouteViaInterface(ifname, range, "DELETE"); } - void - AddBlackhole() override{}; - - void - DelBlackhole() override{}; - std::vector GetGatewaysNotOnInterface(std::string ifname) override { From 07a58ffa6c2b370775f7c13b74818d7c59af938f Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 11:55:57 -0400 Subject: [PATCH 17/81] use vpn::NetworkInterface for add/del route via interface instead of string --- llarp/ev/vpn.hpp | 4 ++-- llarp/vpn/linux.hpp | 8 ++++---- llarp/vpn/win32.hpp | 13 +++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/llarp/ev/vpn.hpp b/llarp/ev/vpn.hpp index c43ac35bd..c3346fcdd 100644 --- a/llarp/ev/vpn.hpp +++ b/llarp/ev/vpn.hpp @@ -84,10 +84,10 @@ namespace llarp::vpn DelDefaultRouteViaInterface(std::string ifname) = 0; virtual void - AddRouteViaInterface(std::string ifname, IPRange range) = 0; + AddRouteViaInterface(NetworkInterface& vpn, IPRange range) = 0; virtual void - DelRouteViaInterface(std::string ifname, IPRange range) = 0; + DelRouteViaInterface(NetworkInterface& vpn, IPRange range) = 0; virtual std::vector GetGatewaysNotOnInterface(std::string ifname) = 0; diff --git a/llarp/vpn/linux.hpp b/llarp/vpn/linux.hpp index c3f81e1e1..5401ef10a 100644 --- a/llarp/vpn/linux.hpp +++ b/llarp/vpn/linux.hpp @@ -395,15 +395,15 @@ namespace llarp::vpn } void - AddRouteViaInterface(std::string ifname, IPRange range) override + AddRouteViaInterface(NetworkInterface& vpn, IPRange range) override { - RouteViaInterface(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, ifname, range); + RouteViaInterface(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, vpn.IfName(), range); } void - DelRouteViaInterface(std::string ifname, IPRange range) override + DelRouteViaInterface(NetworkInterface& vpn, IPRange range) override { - RouteViaInterface(RTM_DELROUTE, 0, ifname, range); + RouteViaInterface(RTM_DELROUTE, 0, vpn.IfName(), range); } std::vector diff --git a/llarp/vpn/win32.hpp b/llarp/vpn/win32.hpp index cda174802..06e2c8297 100644 --- a/llarp/vpn/win32.hpp +++ b/llarp/vpn/win32.hpp @@ -175,7 +175,7 @@ namespace llarp::vpn std::vector m_Threads; thread::Queue m_ReadQueue; - const InterfaceInfo m_Info; + InterfaceInfo m_Info; static std::wstring get_win_sys_path() @@ -274,6 +274,7 @@ namespace llarp::vpn IPADDR sock[3]{}; const nuint32_t addr = xhtonl(net::TruncateV6(ifaddr.range.addr)); ip = net::TruncateV6(ifaddr.range.addr); + m_Info.ifname = ip.ToString(); const nuint32_t mask = xhtonl(net::TruncateV6(ifaddr.range.netmask_bits)); LogInfo("address ", addr, " netmask ", mask); sock[0] = addr.n; @@ -409,7 +410,7 @@ namespace llarp::vpn std::string IfName() const override { - return ""; + return m_Info.ifname; } void @@ -577,15 +578,15 @@ namespace llarp::vpn } void - AddRouteViaInterface(std::string ifname, IPRange range) override + AddRouteViaInterface(NetworkInterface& vpn, IPRange range) override { - RouteViaInterface(ifname, range, "ADD"); + RouteViaInterface(vpn.IfName(), range, "ADD"); } void - DelRouteViaInterface(std::string ifname, IPRange range) override + DelRouteViaInterface(NetworkInterface& vpn, IPRange range) override { - RouteViaInterface(ifname, range, "DELETE"); + RouteViaInterface(vpn.IfName(), range, "DELETE"); } std::vector From 6251c13d46b539c0ee6d6747b89e10d9dd9590ea Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 27 Aug 2021 19:49:01 -0400 Subject: [PATCH 18/81] add NOP implementation of VPN route manager for android --- llarp/vpn/android.hpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/llarp/vpn/android.hpp b/llarp/vpn/android.hpp index b2c3ef5b3..c9792a009 100644 --- a/llarp/vpn/android.hpp +++ b/llarp/vpn/android.hpp @@ -60,9 +60,32 @@ namespace llarp::vpn } }; + class AndroidRouteManager : public IRouteManager + { + void AddRoute(IPVariant_t, IPVariant_t) override{}; + + void DelRoute(IPVariant_t, IPVariant_t) override{}; + + void AddDefaultRouteViaInterface(std::string) override{}; + + void DelDefaultRouteViaInterface(std::string) override{}; + + void + AddRouteViaInterface(NetworkInterface&, IPRange) override{}; + + void + DelRouteViaInterface(NetworkInterface&, IPRange) override{}; + + std::vector GetGatewaysNotOnInterface(std::string) override + { + return std::vector{}; + }; + }; + class AndroidPlatform : public Platform { const int fd; + AndroidRouteManager _routeManager{}; public: AndroidPlatform(llarp::Context* ctx) : fd(ctx->androidFD) @@ -73,6 +96,11 @@ namespace llarp::vpn { return std::make_shared(std::move(info), fd); } + IRouteManager& + RouteManager() override + { + return _routeManager; + } }; } // namespace llarp::vpn From 3deb55193fc6207e4660a8087a23a1017f687914 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 16:52:43 -0300 Subject: [PATCH 19/81] SockAddr string optimization - Reduce buffer size to INET6_ADDRSTRLEN, and use a single buf rather than two identical ones in each branch. - Don't pre-reserve because doing so is usually going to over-allocate, but also because it prevents SSO, especially for the IPv4 case which should fit in SSO for all IPv4 addresses. --- llarp/net/sock_addr.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/llarp/net/sock_addr.cpp b/llarp/net/sock_addr.cpp index ee6817414..a09a88527 100644 --- a/llarp/net/sock_addr.cpp +++ b/llarp/net/sock_addr.cpp @@ -299,24 +299,17 @@ namespace llarp SockAddr::hostString() const { std::string str; - + char buf[INET6_ADDRSTRLEN] = {0x0}; if (isIPv4()) { // handle IPv4 mapped addrs - constexpr auto MaxIPv4PlusPortStringSize = 22; - str.reserve(MaxIPv4PlusPortStringSize); - char buf[128] = {0x0}; inet_ntop(AF_INET, &m_addr4.sin_addr.s_addr, buf, sizeof(buf)); - str.append(buf); + str = buf; } else { - constexpr auto MaxIPv6PlusPortStringSize = 128; - str.reserve(MaxIPv6PlusPortStringSize); - - char buf[128] = {0x0}; inet_ntop(AF_INET6, &m_addr.sin6_addr.s6_addr, buf, sizeof(buf)); - + str.reserve(std::strlen(buf) + 2); str.append("["); str.append(buf); str.append("]"); From 439183bf19cc08711ff6884c5405d0896c97960f Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 31 Aug 2021 12:05:01 -0400 Subject: [PATCH 20/81] bump openssl static deps version for upstream security update --- cmake/StaticBuild.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 783ae11d1..adf00bc0f 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -5,10 +5,10 @@ set(LOCAL_MIRROR "" CACHE STRING "local mirror path/URL for lib downloads") -set(OPENSSL_VERSION 1.1.1k CACHE STRING "openssl version") +set(OPENSSL_VERSION 1.1.1l CACHE STRING "openssl version") set(OPENSSL_MIRROR ${LOCAL_MIRROR} https://www.openssl.org/source CACHE STRING "openssl download mirror(s)") set(OPENSSL_SOURCE openssl-${OPENSSL_VERSION}.tar.gz) -set(OPENSSL_HASH SHA256=892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5 +set(OPENSSL_HASH SHA256=0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1 CACHE STRING "openssl source hash") set(EXPAT_VERSION 2.3.0 CACHE STRING "expat version") From a70035b7ec98dd4a9a7bdee0f5143adf7d18f196 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 21:30:13 -0300 Subject: [PATCH 21/81] Revert "fix dns on android" This reverts commit dace0224ecb5239e06fe43b89a2f5fefe3d4337a. This reportedly didn't fix things on Android, and most definitely breaks macOS (with this we get a bunch of errors about expecting inbound when we have outbound). --- llarp/handlers/tun.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 116bfedee..4a34df612 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -87,8 +87,8 @@ namespace llarp OwnedBuffer buf{pkt.sz - (8 + ip_header_size)}; std::copy_n(ptr + 8, buf.sz, buf.buf.get()); - if (m_Resolver->ShouldHandlePacket(raddr, laddr, buf)) - m_Resolver->HandlePacket(raddr, laddr, buf); + if (m_Resolver->ShouldHandlePacket(laddr, raddr, buf)) + m_Resolver->HandlePacket(laddr, raddr, buf); else HandleGotUserPacket(std::move(pkt)); }); From 3ce329d2bf7b4b157f0aa3fb50a4a1606e332415 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 12:03:39 -0300 Subject: [PATCH 22/81] Reapply "fix dns on android" + fix argument order The reason the dns fix on android didn't work is that the DnsInterceptor had a reversed to/from argument order for its `SendServerMessageBufferTo` overload, and so android/mac needed the to/from to be reversed so that the second reverse cancelled out the first one. Upon review, the DnsInterceptor order (to, from) is more intuitive than the base order (from, to), so this reapplies the dns fix and swaps everything *except* DnsInterceptor to match the (to, from) argument order. --- llarp/dns/server.cpp | 11 ++++++----- llarp/dns/server.hpp | 4 ++-- llarp/handlers/tun.cpp | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index 22155ec4c..deeea0dbe 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -60,7 +60,7 @@ namespace llarp::dns auto failFunc = [self = weak_from_this()]( const SockAddr& from, const SockAddr& to, Message msg) { if (auto this_ptr = self.lock()) - this_ptr->SendServerMessageBufferTo(from, to, msg.ToBuffer()); + this_ptr->SendServerMessageBufferTo(to, from, msg.ToBuffer()); }; auto replyFunc = [self = weak_from_this()](auto&&... args) { @@ -95,7 +95,8 @@ namespace llarp::dns } void - Proxy::SendServerMessageBufferTo(const SockAddr&, const SockAddr& to, llarp_buffer_t buf) + Proxy::SendServerMessageBufferTo( + const SockAddr& to, [[maybe_unused]] const SockAddr& from, llarp_buffer_t buf) { if (!m_Server->send(to, buf)) llarp::LogError("dns reply failed"); @@ -157,7 +158,7 @@ namespace llarp::dns // yea it is, let's turn off DoH because god is dead. msg.AddNXReply(); // press F to pay respects - SendServerMessageBufferTo(resolver, from, msg.ToBuffer()); + SendServerMessageBufferTo(from, resolver, msg.ToBuffer()); return; } } @@ -165,7 +166,7 @@ namespace llarp::dns if (m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg)) { auto reply = [self = shared_from_this(), to = from, resolver](dns::Message msg) { - self->SendServerMessageBufferTo(resolver, to, msg.ToBuffer()); + self->SendServerMessageBufferTo(to, resolver, msg.ToBuffer()); }; if (!m_QueryHandler->HandleHookedDNSMessage(std::move(msg), reply)) { @@ -177,7 +178,7 @@ namespace llarp::dns // no upstream resolvers // let's serv fail it msg.AddServFail(); - SendServerMessageBufferTo(resolver, from, msg.ToBuffer()); + SendServerMessageBufferTo(from, resolver, msg.ToBuffer()); } else { diff --git a/llarp/dns/server.hpp b/llarp/dns/server.hpp index e778b2e22..21f45ed54 100644 --- a/llarp/dns/server.hpp +++ b/llarp/dns/server.hpp @@ -54,7 +54,7 @@ namespace llarp protected: virtual void - SendServerMessageBufferTo(const SockAddr& from, const SockAddr& to, llarp_buffer_t buf) = 0; + SendServerMessageBufferTo(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) = 0; private: void @@ -84,7 +84,7 @@ namespace llarp protected: void SendServerMessageBufferTo( - const SockAddr& from, const SockAddr& to, llarp_buffer_t buf) override; + const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) override; private: std::shared_ptr m_Server; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 4a34df612..116bfedee 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -87,8 +87,8 @@ namespace llarp OwnedBuffer buf{pkt.sz - (8 + ip_header_size)}; std::copy_n(ptr + 8, buf.sz, buf.buf.get()); - if (m_Resolver->ShouldHandlePacket(laddr, raddr, buf)) - m_Resolver->HandlePacket(laddr, raddr, buf); + if (m_Resolver->ShouldHandlePacket(raddr, laddr, buf)) + m_Resolver->HandlePacket(raddr, laddr, buf); else HandleGotUserPacket(std::move(pkt)); }); From a4a9062f128010b1b1647b9969f8c52e71a59407 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 1 Sep 2021 12:07:10 -0400 Subject: [PATCH 23/81] dont save addrmap on android as it hangs --- llarp/handlers/tun.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 116bfedee..81a02fad3 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -974,6 +974,7 @@ namespace llarp TunEndpoint::Stop() { // save address map if applicable +#ifndef ANDROID if (m_PersistAddrMapFile) { const auto& file = *m_PersistAddrMapFile; @@ -994,6 +995,7 @@ namespace llarp maybe->write(data.data(), data.size()); } } +#endif if (m_Resolver) m_Resolver->Stop(); return llarp::service::Endpoint::Stop(); From 0c1a3e19bda555c2b5d1a83f9c42298c631c7bfc Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 1 Sep 2021 13:05:58 -0400 Subject: [PATCH 24/81] redo dns to use event loop on non windows and threading bullshit on windows --- llarp/dns/unbound_resolver.cpp | 52 +++++++++++++++++++++++++++------- llarp/dns/unbound_resolver.hpp | 11 +++++-- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index 90ebbbcd3..c68379b40 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -25,11 +25,18 @@ namespace llarp::dns UnboundResolver::Reset() { started = false; - if (runner) +#ifdef _WIN32 + if (runner.joinable()) { - runner->join(); - runner.reset(); + runner.join(); } +#else + if (udp) + { + udp->close(); + } + udp.reset(); +#endif if (unboundContext) { ub_ctx_delete(unboundContext); @@ -37,12 +44,16 @@ namespace llarp::dns unboundContext = nullptr; } - UnboundResolver::UnboundResolver(EventLoop_ptr loop, ReplyFunction reply, FailFunction fail) - : unboundContext(nullptr) - , started(false) - , replyFunc(loop->make_caller(std::move(reply))) - , failFunc(loop->make_caller(std::move(fail))) - {} + UnboundResolver::UnboundResolver(EventLoop_ptr _loop, ReplyFunction reply, FailFunction fail) + : unboundContext{nullptr} + , started{false} + , replyFunc{_loop->make_caller(std::move(reply))} + , failFunc{_loop->make_caller(std::move(fail))} + { +#ifndef _WIN32 + loop = _loop->MaybeGetUVWLoop(); +#endif + } // static callback void @@ -94,14 +105,33 @@ namespace llarp::dns } ub_ctx_async(unboundContext, 1); - runner = std::make_unique([&]() { +#ifdef _WIN32 + runner = std::thread{[&]() { while (started) { if (unboundContext) ub_wait(unboundContext); std::this_thread::sleep_for(25ms); } - }); + if (unboundContext) + ub_process(unboundContext); + }}; +#else + if (auto loop_ptr = loop.lock()) + { + udp = loop_ptr->resource(ub_fd(unboundContext)); + udp->on([ptr = weak_from_this()](auto&, auto&) { + if (auto self = ptr.lock()) + { + if (self->unboundContext) + { + ub_process(self->unboundContext); + } + } + }); + udp->start(uvw::PollHandle::Event::READABLE); + } +#endif started = true; return true; } diff --git a/llarp/dns/unbound_resolver.hpp b/llarp/dns/unbound_resolver.hpp index e1861ab88..e44f3e7e0 100644 --- a/llarp/dns/unbound_resolver.hpp +++ b/llarp/dns/unbound_resolver.hpp @@ -13,6 +13,8 @@ #ifdef _WIN32 #include +#else +#include #endif namespace llarp::dns @@ -28,11 +30,16 @@ namespace llarp::dns ub_ctx* unboundContext; std::atomic started; - std::unique_ptr runner; + +#ifdef _WIN32 + std::thread runner; +#else + std::weak_ptr loop; + std::shared_ptr udp; +#endif ReplyFunction replyFunc; FailFunction failFunc; - void Reset(); From 14c93e2b93e26785fa7056e5bbb3f97f2e6cb3b9 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 14:36:38 -0300 Subject: [PATCH 25/81] Unbound callbacks also need arguments reversed PR #1725 reversed argument orders but UnboundResolver was still using (from,to) ordering in its callbacks, which leaked through to make a wrong order in our reply function (which simply forwards arguments). This fixes that bug by making UnboundResolver callback argument order consistent (i.e. using to, from) with the PacketHandler argument order. --- llarp/dns/server.cpp | 2 +- llarp/dns/unbound_resolver.cpp | 8 ++++---- llarp/dns/unbound_resolver.hpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index deeea0dbe..5c8d6b4ca 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -58,7 +58,7 @@ namespace llarp::dns return true; auto failFunc = [self = weak_from_this()]( - const SockAddr& from, const SockAddr& to, Message msg) { + const SockAddr& to, const SockAddr& from, Message msg) { if (auto this_ptr = self.lock()) this_ptr->SendServerMessageBufferTo(to, from, msg.ToBuffer()); }; diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index 90ebbbcd3..422a5c6fd 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -58,7 +58,7 @@ namespace llarp::dns { Message& msg = lookup->msg; msg.AddServFail(); - this_ptr->failFunc(lookup->resolverAddr, lookup->askerAddr, msg); + this_ptr->failFunc(lookup->askerAddr, lookup->resolverAddr, msg); ub_resolve_free(result); return; } @@ -73,7 +73,7 @@ namespace llarp::dns buf.cur = buf.base; hdr.Encode(&buf); - this_ptr->replyFunc(lookup->resolverAddr, lookup->askerAddr, std::move(pkt)); + this_ptr->replyFunc(lookup->askerAddr, lookup->resolverAddr, std::move(pkt)); ub_resolve_free(result); } @@ -145,7 +145,7 @@ namespace llarp::dns if (not unboundContext) { msg.AddServFail(); - failFunc(to, from, std::move(msg)); + failFunc(from, to, std::move(msg)); return; } @@ -163,7 +163,7 @@ namespace llarp::dns if (err != 0) { msg.AddServFail(); - failFunc(to, from, std::move(msg)); + failFunc(from, to, std::move(msg)); return; } } diff --git a/llarp/dns/unbound_resolver.hpp b/llarp/dns/unbound_resolver.hpp index e1861ab88..8d6605304 100644 --- a/llarp/dns/unbound_resolver.hpp +++ b/llarp/dns/unbound_resolver.hpp @@ -18,9 +18,9 @@ namespace llarp::dns { using ReplyFunction = - std::function; + std::function; using FailFunction = - std::function; + std::function; class UnboundResolver : public std::enable_shared_from_this { From a8a7ef54619b8552306b4ddf5db9f52890f86978 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:40:25 -0300 Subject: [PATCH 26/81] Stop using deprecated OMQ connect_remote overload --- llarp/rpc/endpoint_rpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/rpc/endpoint_rpc.cpp b/llarp/rpc/endpoint_rpc.cpp index 8f59576c6..302f14d65 100644 --- a/llarp/rpc/endpoint_rpc.cpp +++ b/llarp/rpc/endpoint_rpc.cpp @@ -22,7 +22,7 @@ namespace llarp::rpc if (m_AuthURL.empty() or m_AuthMethod.empty()) return; m_LMQ->connect_remote( - m_AuthURL, + oxenmq::address{m_AuthURL}, [self = shared_from_this()](oxenmq::ConnectionID c) { self->m_Conn = std::move(c); LogInfo("connected to endpoint auth server via ", *self->m_Conn); From f65ec8e79f6dd8149282f59071baf372018dc4ed Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 2 Sep 2021 12:01:36 -0400 Subject: [PATCH 27/81] make ci try building the flutter apk in the android apk pipeline --- .drone.jsonnet | 8 +++++++- contrib/ci/drone-static-upload.sh | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 436a039ee..330d90fe6 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -76,7 +76,13 @@ local apk_builder(name, image, extra_cmds=[], allow_fail=false, jobs=6) = { [if allow_fail then "failure"]: "ignore", environment: { SSH_KEY: { from_secret: "SSH_KEY" }, ANDROID: "android" }, commands: [ - 'VERBOSE=1 JOBS='+jobs+' NDK=/usr/lib/android-ndk ./contrib/android.sh' + 'VERBOSE=1 JOBS='+jobs+' NDK=/usr/lib/android-ndk ./contrib/android.sh', + 'git clone https://github.com/oxen-io/lokinet-mobile', + 'cp -av lokinet-jni-*/* lokinet-mobile/lokinet_lib/android/src/main/jniLibs/', + 'cd lokinet-mobile', + 'flutter build apk --debug', + 'cd ..', + 'cp lokinet-mobile/build/app/outputs/apk/debug/app-debug.apk lokinet.apk' ] + extra_cmds } ] diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh index bdbd57561..9c5879f09 100755 --- a/contrib/ci/drone-static-upload.sh +++ b/contrib/ci/drone-static-upload.sh @@ -42,6 +42,7 @@ if [ -e build-windows ]; then elif [ -e build-android ] ; then # android af ngl cp -av lokinet-jni-* "$base" + cp -av *.apk "$base" archive="$base.tar.xz" tar cJvf "$archive" "$base" else From c39225b3b927bdae6b710f271ddc3e73d7a43206 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 2 Sep 2021 12:03:04 -0400 Subject: [PATCH 28/81] correct lokinet flutter url --- .drone.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 330d90fe6..89cfddacb 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -77,7 +77,7 @@ local apk_builder(name, image, extra_cmds=[], allow_fail=false, jobs=6) = { environment: { SSH_KEY: { from_secret: "SSH_KEY" }, ANDROID: "android" }, commands: [ 'VERBOSE=1 JOBS='+jobs+' NDK=/usr/lib/android-ndk ./contrib/android.sh', - 'git clone https://github.com/oxen-io/lokinet-mobile', + 'git clone https://github.com/majestrate/lokinet-mobile', 'cp -av lokinet-jni-*/* lokinet-mobile/lokinet_lib/android/src/main/jniLibs/', 'cd lokinet-mobile', 'flutter build apk --debug', From 92cfa8a5589b74632ded41397937e439c8f3cdfc Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 2 Sep 2021 13:05:16 -0400 Subject: [PATCH 29/81] dont bundle raw jni libs --- contrib/ci/drone-static-upload.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh index 9c5879f09..f81a40c8a 100755 --- a/contrib/ci/drone-static-upload.sh +++ b/contrib/ci/drone-static-upload.sh @@ -41,7 +41,6 @@ if [ -e build-windows ]; then zip -r "$archive" "$base" elif [ -e build-android ] ; then # android af ngl - cp -av lokinet-jni-* "$base" cp -av *.apk "$base" archive="$base.tar.xz" tar cJvf "$archive" "$base" From 63ed5c16edca42b494f8a90964b5142f7404ee71 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 2 Sep 2021 13:11:29 -0400 Subject: [PATCH 30/81] upload bare apk as ci artifact --- contrib/ci/drone-static-upload.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh index f81a40c8a..c5d35bfaa 100755 --- a/contrib/ci/drone-static-upload.sh +++ b/contrib/ci/drone-static-upload.sh @@ -39,11 +39,10 @@ if [ -e build-windows ]; then # zipit up yo archive="$base.zip" zip -r "$archive" "$base" -elif [ -e build-android ] ; then +elif [ -e lokinet.apk ] ; then # android af ngl - cp -av *.apk "$base" - archive="$base.tar.xz" - tar cJvf "$archive" "$base" + archive="$base.apk" + cp -av lokinet.apk "$archive" else cp -av daemon/lokinet daemon/lokinet-vpn daemon/lokinet-bootstrap "$base" # tar dat shiz up yo From 0708a0d8976cbbd163d2e2990136decea0b5112e Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 14 May 2021 13:07:44 -0400 Subject: [PATCH 31/81] initial network extension code for macos probably does not work --- CMakeLists.txt | 69 +++---- cmake/installer.cmake | 1 + cmake/macos_installer_deps.cmake | 91 ++-------- contrib/format.sh | 18 +- contrib/lokinet.svg | 22 +++ contrib/mac.sh | 28 +++ contrib/macos/Info.plist | 24 +++ contrib/macos/LokinetExtension.Info.plist | 31 ++++ contrib/macos/lokinet.entitlements.plist | 10 + contrib/macos/{uninstaller => }/mk-icns.sh | 0 contrib/macos/sign.sh.in | 8 + contrib/windows.sh | 5 + daemon/CMakeLists.txt | 68 ++++++- daemon/Lokinet.modulemap.in | 4 + daemon/lokinet.mm | 9 + daemon/lokinet.swift | 77 ++++++++ daemon/swift/Lokinet/module.modulemap | 4 + daemon/swift/LokinetMain.swift | 43 +++++ external/CMakeLists.txt | 18 +- include/llarp.hpp | 1 - include/lokinet-extension.hpp | 18 ++ llarp/CMakeLists.txt | 27 +++ llarp/config/config.cpp | 14 ++ llarp/config/config.hpp | 5 + llarp/framework.mm | 202 +++++++++++++++++++++ llarp/vpn/apple.hpp | 173 ------------------ llarp/vpn/platform.cpp | 10 +- readme.md | 9 +- 28 files changed, 678 insertions(+), 311 deletions(-) create mode 100644 contrib/lokinet.svg create mode 100755 contrib/mac.sh create mode 100644 contrib/macos/Info.plist create mode 100644 contrib/macos/LokinetExtension.Info.plist create mode 100644 contrib/macos/lokinet.entitlements.plist rename contrib/macos/{uninstaller => }/mk-icns.sh (100%) create mode 100755 contrib/macos/sign.sh.in create mode 100644 daemon/Lokinet.modulemap.in create mode 100644 daemon/lokinet.mm create mode 100644 daemon/lokinet.swift create mode 100644 daemon/swift/Lokinet/module.modulemap create mode 100644 daemon/swift/LokinetMain.swift create mode 100644 include/lokinet-extension.hpp create mode 100644 llarp/framework.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f982142c..9f9b1a4a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,14 @@ 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(LANGS ASM C CXX) +if(APPLE) + set(LANGS ${LANGS} OBJC Swift) +endif() + find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) - foreach(lang C CXX) + foreach(lang ${LANGS}) if(NOT DEFINED CMAKE_${lang}_COMPILER_LAUNCHER AND NOT CMAKE_${lang}_COMPILER MATCHES ".*/ccache") message(STATUS "Enabling ccache for ${lang}") set(CMAKE_${lang}_COMPILER_LAUNCHER ${CCACHE_PROGRAM} CACHE STRING "") @@ -15,10 +20,11 @@ if(CCACHE_PROGRAM) endforeach() endif() + project(lokinet VERSION 0.9.5 DESCRIPTION "lokinet - IP packet onion router" - LANGUAGES C CXX) + LANGUAGES ${LANGS}) set(RELEASE_MOTTO "A Series of Tubes" CACHE STRING "Release motto") @@ -32,7 +38,6 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - # Core options option(USE_AVX2 "enable avx2 code" OFF) option(USE_NETNS "enable networking namespace support. Linux only" OFF) @@ -94,14 +99,6 @@ endif() add_definitions(-D${CMAKE_SYSTEM_NAME}) -if(MSVC_VERSION) - enable_language(ASM_MASM) - list(APPEND CMAKE_ASM_MASM_SOURCE_FILE_EXTENSIONS s) - add_definitions(-D_WIN32_WINNT=0x0600 -DNOMINMAX -DSODIUM_STATIC) -else() - enable_language(ASM) -endif() - include(cmake/solaris.cmake) include(cmake/win32.cmake) @@ -184,8 +181,12 @@ else() endif() -# this is messing with release builds -add_compile_options(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0) +if(NOT APPLE) + add_compile_options(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations -Werror=vla) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wno-unknown-warning-option) + endif() +endif() if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux" AND SHADOW) message( FATAL_ERROR "shadow-framework is Linux only" ) @@ -213,17 +214,6 @@ if(TRACY_ROOT) endif() -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wno-unknown-warning-option) -endif() - -if (NOT MSVC_VERSION) - add_compile_options(-Wall -Wextra -Wno-unknown-pragmas) - # vla are evil - add_compile_options(-Werror=vla) - add_compile_options(-Wno-unused-function -Wno-deprecated-declarations) -endif() - include(cmake/coverage.cmake) # these vars are set by the cmake toolchain spec @@ -231,18 +221,20 @@ if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE) include(cmake/cross_compile.cmake) endif() -if(NATIVE_BUILD) - if(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le) - add_compile_options(-mcpu=native -mtune=native) - else() - add_compile_options(-march=native -mtune=native) - endif() -elseif(NOT NON_PC_TARGET) - if (USE_AVX2) - add_compile_options(-march=haswell -mtune=haswell -mfpmath=sse) - else() - # Public binary releases - add_compile_options(-march=nocona -mtune=haswell -mfpmath=sse) +if(NOT APPLE) + if(NATIVE_BUILD) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le) + add_compile_options(-mcpu=native -mtune=native) + else() + add_compile_options(-march=native -mtune=native) + endif() + elseif(NOT NON_PC_TARGET) + if (USE_AVX2) + add_compile_options(-march=haswell -mtune=haswell -mfpmath=sse) + else() + # Public binary releases + add_compile_options(-march=nocona -mtune=haswell -mfpmath=sse) + endif() endif() endif() @@ -332,12 +324,11 @@ endif() add_subdirectory(crypto) add_subdirectory(llarp) add_subdirectory(daemon) + + if(WITH_HIVE) add_subdirectory(pybind) endif() - - - if (NOT SHADOW) if(WITH_TESTS OR WITH_HIVE) add_subdirectory(test) diff --git a/cmake/installer.cmake b/cmake/installer.cmake index 789a88ee4..b08a9d7b4 100644 --- a/cmake/installer.cmake +++ b/cmake/installer.cmake @@ -14,3 +14,4 @@ endif() # This must always be last! include(CPack) + diff --git a/cmake/macos_installer_deps.cmake b/cmake/macos_installer_deps.cmake index a56995a73..b315b389b 100644 --- a/cmake/macos_installer_deps.cmake +++ b/cmake/macos_installer_deps.cmake @@ -1,8 +1,9 @@ # macos specific cpack stuff goes here +return() + # Here we build lokinet-network-control-panel into 'lokinet-gui.app' in "extra/" where a postinstall # script will then move it to /Applications/. - set(LOKINET_GUI_REPO "https://github.com/oxen-io/loki-network-control-panel.git" CACHE STRING "Can be set to override the default lokinet-gui git repository") set(LOKINET_GUI_CHECKOUT "origin/master" @@ -18,83 +19,25 @@ set(MACOS_NOTARIZE_PASS "" set(MACOS_NOTARIZE_ASC "" CACHE STRING "set macos notarization asc provider; can also set it in ~/.notarization.cmake") -include(ExternalProject) - -message(STATUS "Building UninstallLokinet.app") - -ExternalProject_Add(lokinet-uninstaller - SOURCE_DIR ${CMAKE_SOURCE_DIR}/contrib/macos/uninstaller - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR} -DMACOS_SIGN=${MACOS_SIGN_APP} - -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -) - -message(STATUS "Building LokinetGUI.app from ${LOKINET_GUI_REPO} @ ${LOKINET_GUI_CHECKOUT}") - if(NOT BUILD_STATIC_DEPS) message(FATAL_ERROR "Building an installer on macos requires -DBUILD_STATIC_DEPS=ON") endif() - - -ExternalProject_Add(lokinet-gui - DEPENDS oxenmq::oxenmq - GIT_REPOSITORY "${LOKINET_GUI_REPO}" - GIT_TAG "${LOKINET_GUI_CHECKOUT}" - CMAKE_ARGS -DMACOS_APP=ON -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR} -DMACOS_SIGN=${MACOS_SIGN_APP} - -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DBUILD_SHARED_LIBS=OFF - "-DOXENMQ_LIBRARIES=$$$$$" - "-DOXENMQ_INCLUDE_DIRS=$" - ) - -install(PROGRAMS ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet_uninstall.sh - DESTINATION "bin/" - COMPONENT lokinet) - -install(DIRECTORY ${PROJECT_BINARY_DIR}/LokinetGUI.app - DESTINATION "../../Applications/Lokinet" - USE_SOURCE_PERMISSIONS - COMPONENT gui - PATTERN "*" - ) - -install(DIRECTORY ${PROJECT_BINARY_DIR}/UninstallLokinet.app - DESTINATION "../../Applications/Lokinet" - USE_SOURCE_PERMISSIONS - COMPONENT gui - PATTERN "*" - ) - -# copy files that will be later moved by the postinstall script to proper locations -install(FILES ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet_macos_daemon_script.sh - ${CMAKE_SOURCE_DIR}/contrib/macos/network.loki.lokinet.daemon.plist - ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet-newsyslog.conf - DESTINATION "extra/" - COMPONENT lokinet) - -set(CPACK_COMPONENTS_ALL lokinet gui) - -set(CPACK_COMPONENT_LOKINET_DISPLAY_NAME "Lokinet Service") -set(CPACK_COMPONENT_LOKINET_DESCRIPTION "Main Lokinet runtime service, managed by Launchd") - -set(CPACK_COMPONENT_GUI_DISPLAY_NAME "Lokinet GUI") -set(CPACK_COMPONENT_GUI_DESCRIPTION "Small GUI which provides stats and limited runtime control of the Lokinet service. Resides in the system tray.") - -set(CPACK_GENERATOR "productbuild") -set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/lokinet") -set(CPACK_PREINSTALL_LOKINET_SCRIPT ${CMAKE_SOURCE_DIR}/contrib/macos/preinstall) -set(CPACK_POSTFLIGHT_LOKINET_SCRIPT ${CMAKE_SOURCE_DIR}/contrib/macos/postinstall) - -set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE.txt") - -set(CPACK_PRODUCTBUILD_IDENTITY_NAME "${MACOS_SIGN_PKG}") - -if(MACOS_SIGN_APP) - add_custom_target(sign ALL - echo "Signing lokinet and lokinet-vpn binaries" - COMMAND codesign -s "${MACOS_SIGN_APP}" --strict --options runtime --force -vvv $ $ - DEPENDS lokinet lokinet-vpn - ) -endif() +#set(CPACK_GENERATOR "Bundle") + +#set(MACOSX_BUNDLE_BUNDLE_NAME Lokinet) +#set(CPACK_BUNDLE_NAME Lokinet) +#set(CPACK_BUNDLE_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist) +#set(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns") +#set(CPACK_BUNDLE_STARTUP_COMMAND ${CMAKE_BINARY_DIR}/daemon/lokinet) +#set(MACOSX_BUNDLE_GUI_IDENTIFIER org.lokinet.lokinet) +#set(MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router") +#set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}) +#set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) +#set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) +#set(MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") +#set(CPACK_BUNDLE_APPLE_ENTITLEMENTS ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements) +#set(CPACK_BUNDLE_APPLE_CERT_APP "${MACOS_SIGN_APP}") if(MACOS_SIGN_APP AND MACOS_SIGN_PKG) if(NOT MACOS_NOTARIZE_USER) diff --git a/contrib/format.sh b/contrib/format.sh index f83c27436..26ed77d3c 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -18,7 +18,23 @@ fi cd "$(dirname $0)/../" if [ "$1" = "verify" ] ; then - exit $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '' | wc -l) + if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then + exit 1 + fi else $binary -i $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') &> /dev/null fi + +swift_format=$(which swiftformat 2>/dev/null) +if [ $? -eq 0 ]; then + if [ "$1" = "verify" ] ; then + for f in $(find daemon | grep -E '\.swift$' | grep -v '\#') ; do + if [ $($swift_format --quiet --dryrun < "$f" | diff "$f" - | wc -l) -ne 0 ] ; then + exit 1 + fi + done + else + $swift_format --quiet $(find daemon | grep -E '\.swift$' | grep -v '\#') + fi + +fi diff --git a/contrib/lokinet.svg b/contrib/lokinet.svg new file mode 100644 index 000000000..f8e760248 --- /dev/null +++ b/contrib/lokinet.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/contrib/mac.sh b/contrib/mac.sh new file mode 100755 index 000000000..62e14802e --- /dev/null +++ b/contrib/mac.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# +# build the shit on mac +# t. jeff +# + +set -e +set +x +mkdir -p build-mac +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=OFF \ + -DCMAKE_INSTALL_PREFIX=$(pwd) \ + -DCMAKE_BUILD_TYPE=Release \ + $@ .. +ninja install && ninja sign diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist new file mode 100644 index 000000000..de014151e --- /dev/null +++ b/contrib/macos/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Lokinet + CFBundleExecutable + MacOS/lokinet + CFBundleIdentifier + org.lokinet.Daemon + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + lokinet + CFBundlePackageType + XPC! + CFBundleShortVersionString + 0.1 + CFBundleVersion + 0.1 + + diff --git a/contrib/macos/LokinetExtension.Info.plist b/contrib/macos/LokinetExtension.Info.plist new file mode 100644 index 000000000..bc6b357af --- /dev/null +++ b/contrib/macos/LokinetExtension.Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Lokinet + CFBundleExecutable + lokinet-extension + CFBundleIdentifier + org.lokinet.NetworkExtension + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Lokinet + CFBundlePackageType + XPC! + CFBundleShortVersionString + 0.1 + CFBundleVersion + 0.1 + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + Lokinet.LLARPPacketTunnel + + + diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist new file mode 100644 index 000000000..589ce8b28 --- /dev/null +++ b/contrib/macos/lokinet.entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + diff --git a/contrib/macos/uninstaller/mk-icns.sh b/contrib/macos/mk-icns.sh similarity index 100% rename from contrib/macos/uninstaller/mk-icns.sh rename to contrib/macos/mk-icns.sh diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in new file mode 100755 index 000000000..fc1136d9b --- /dev/null +++ b/contrib/macos/sign.sh.in @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -x +set -e +for file in "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do + codesign -vvvv --force -s "${CODESIGN_KEY}" --entitlements "${SIGN_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file" +done + +codesign --verify "${SIGN_TARGET}" diff --git a/contrib/windows.sh b/contrib/windows.sh index c1224afe1..5d6bf399c 100755 --- a/contrib/windows.sh +++ b/contrib/windows.sh @@ -1,4 +1,9 @@ #!/bin/bash +# +# helper script for me for when i cross compile for windows +# t. jeff +# + set -e set +x mkdir -p build-windows diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 7c6e8a45b..257daebed 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,4 +1,16 @@ -add_executable(lokinet lokinet.cpp) +if(APPLE) + option(WITH_SWIFT "use swift" ON) + if(WITH_SWIFT) + add_executable(lokinet lokinet.swift) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) + target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) + else() + add_executable(lokinet lokinet.mm) + endif() + target_link_libraries(lokinet PUBLIC lokinet-extension) +else() + add_executable(lokinet lokinet.cpp) +endif() add_executable(lokinet-vpn lokinet-vpn.cpp) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) enable_lto(lokinet lokinet-vpn lokinet-bootstrap) @@ -30,7 +42,12 @@ if(NOT WIN32) target_link_libraries(lokinet-bootstrap PUBLIC OpenSSL::SSL OpenSSL::Crypto) endif() -foreach(exe lokinet lokinet-vpn lokinet-bootstrap) +set(exetargets lokinet-vpn lokinet-bootstrap) +if(NOT APPLE) + set(exetargets lokinet ${exes}) +endif() + +foreach(exe ${exetargets}) if(WIN32 AND NOT MSVC_VERSION) target_sources(${exe} PRIVATE ../llarp/win32/version.rc) target_link_libraries(${exe} PRIVATE -static-libstdc++ -static-libgcc --static -Wl,--pic-executable,-e,mainCRTStartup,--subsystem,console:5.00) @@ -46,10 +63,55 @@ foreach(exe lokinet lokinet-vpn lokinet-bootstrap) target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL}) add_log_tag(${exe}) if(should_install) - install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet) + if(APPLE) + install(TARGETS ${exe} BUNDLE DESTINATION "${CMAKE_BINARY_DIR}" COMPONENT lokinet) + else() + install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet) + endif() endif() endforeach() +if(APPLE) +# add_custom_command(TARGET lokinet +# POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E echo "setting rpath" +# COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ +# ) + add_custom_target(icons ALL + COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns + DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) + add_dependencies(lokinet icons lokinet-extension) + install(TARGETS lokinet-extension FRAMEWORK DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app/Contents/Frameworks" COMPONENT lokinet) + set_target_properties(lokinet + PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router" + MACOSX_BUNDLE_BUNDLE_NAME "Lokinet" + MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}.$lokinet_VERSION_MINOR}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}" + MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet.lokinet" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist" + MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" + MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") + option(CODESIGN_KEY "codesign all the shit with this key" OFF) + if (CODESIGN_KEY) + message(STATUS "codesigning with ${CODESIGN_KEY}") + set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") + set(SIGN_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist") + configure_file( + "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" + "${CMAKE_BINARY_DIR}/sign.sh") + add_custom_target( + sign + DEPENDS "${CMAKE_BINARY_DIR}/sign.sh" lokinet lokinet-extension + COMMAND "${CMAKE_BINARY_DIR}/sign.sh" + ) + else() + message(STATUS "will not codesign") + endif() +endif() + if(SETCAP) install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)") endif() diff --git a/daemon/Lokinet.modulemap.in b/daemon/Lokinet.modulemap.in new file mode 100644 index 000000000..607823e38 --- /dev/null +++ b/daemon/Lokinet.modulemap.in @@ -0,0 +1,4 @@ + +module LokinetExtension { + header "@CMAKE_SOURCE_DIR@/include/lokinet-extension.hpp" +} \ No newline at end of file diff --git a/daemon/lokinet.mm b/daemon/lokinet.mm new file mode 100644 index 000000000..1baa58379 --- /dev/null +++ b/daemon/lokinet.mm @@ -0,0 +1,9 @@ +#import +#include + + +int main (int argc, const char * argv[]) +{ + + return 0; +} diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift new file mode 100644 index 000000000..28eefe06c --- /dev/null +++ b/daemon/lokinet.swift @@ -0,0 +1,77 @@ +// AppDelegateExtension.swift + +import Foundation +import LokinetExtension +import NetworkExtension + +class LokinetMain: NSObject { + var vpnManager = NETunnelProviderManager() + + let lokinetComponent = "org.lokinet.NetworkExtension" + var lokinetAdminTimer: DispatchSourceTimer? + + func runMain() { + print("Starting up lokinet") + NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in + if let error = error { + print(error) + } + + if let savedManagers = savedManagers { + for manager in savedManagers { + if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { + print("Found saved VPN Manager") + self.vpnManager = manager + } + } + } + let providerProtocol = NETunnelProviderProtocol() + providerProtocol.serverAddress = "lokinet" + providerProtocol.providerBundleIdentifier = self.lokinetComponent + self.vpnManager.protocolConfiguration = providerProtocol + self.vpnManager.isEnabled = true + self.vpnManager.saveToPreferences(completionHandler: { error -> Void in + if error != nil { + print("Error saving to preferences") + } else { + print("saved...") + self.vpnManager.loadFromPreferences(completionHandler: { error in + if error != nil { + print("Error loading from preferences") + } else { + do { + print("Trying to start") + self.initializeConnectionObserver() + try self.vpnManager.connection.startVPNTunnel() + } catch let error as NSError { + print(error) + } catch { + print("There was a fatal error") + } + } + }) + } + }) + } + } + + func initializeConnectionObserver() { + NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in + + if self.vpnManager.connection.status == .invalid { + print("VPN configuration is invalid") + } else if self.vpnManager.connection.status == .disconnected { + print("VPN is disconnected.") + } else if self.vpnManager.connection.status == .connecting { + print("VPN is connecting...") + } else if self.vpnManager.connection.status == .reasserting { + print("VPN is reasserting...") + } else if self.vpnManager.connection.status == .disconnecting { + print("VPN is disconnecting...") + } + } + } +} + +let lokinet = LokinetMain() +lokinet.runMain() diff --git a/daemon/swift/Lokinet/module.modulemap b/daemon/swift/Lokinet/module.modulemap new file mode 100644 index 000000000..fda10e4b7 --- /dev/null +++ b/daemon/swift/Lokinet/module.modulemap @@ -0,0 +1,4 @@ + +module Lokinet { + header "lokinet-extension.hpp" +} \ No newline at end of file diff --git a/daemon/swift/LokinetMain.swift b/daemon/swift/LokinetMain.swift new file mode 100644 index 000000000..561df3e7f --- /dev/null +++ b/daemon/swift/LokinetMain.swift @@ -0,0 +1,43 @@ +// AppDelegateExtension.swift +// lifed from yggdrasil network ios port +// + +import Foundation +import Lokinet +import NetworkExtension + +class LokinetMain: PlatformAppDelegate { + var vpnManager = NETunnelProviderManager() + var app = NSApplication.shared() + let lokinetComponent = "org.lokinet.NetworkExtension" + var lokinetAdminTimer: DispatchSourceTimer? + + func runMain() { + print("Starting up lokinet") + NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in + if let error = error { + print(error) + } + + if let savedManagers = savedManagers { + for manager in savedManagers { + if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { + print("Found saved VPN Manager") + self.vpnManager = manager + } + } + } + + self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in + if let error = error { + print(error) + } + self.vpnManager.localizedDescription = "Lokinet" + self.vpnManager.isEnabled = true + }) + } + app.finishLaunching() + app.run() + print("end") + } +} diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 9634f0036..f574f4193 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -50,6 +50,16 @@ add_library(uvw INTERFACE) target_include_directories(uvw INTERFACE uvw/src) target_link_libraries(uvw INTERFACE libuv) + + +# We don't need any of these as we don't use the ssl crypto helper code at all: +set(ENABLE_GNUTLS OFF CACHE BOOL "Disable gnutls for ngtcp2") +set(ENABLE_OPENSSL OFF CACHE BOOL "Disable openssl for ngtcp2") +set(ENABLE_BORINGSSL OFF CACHE BOOL "Disable boringssl for ngtcp2") + +add_definitions(-D_GNU_SOURCE) +add_subdirectory(ngtcp2 EXCLUDE_FROM_ALL) + # cpr configuration. Ideally we'd just do this via add_subdirectory, but cpr's cmake requires # 3.15+, and we target lower than that (and this is fairly simple to build). @@ -75,11 +85,3 @@ target_link_libraries(cpr PUBLIC CURL::libcurl) target_include_directories(cpr PUBLIC cpr/include) target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) add_library(cpr::cpr ALIAS cpr) - -# We don't need any of these as we don't use the ssl crypto helper code at all: -set(ENABLE_GNUTLS OFF CACHE BOOL "Disable gnutls for ngtcp2") -set(ENABLE_OPENSSL OFF CACHE BOOL "Disable openssl for ngtcp2") -set(ENABLE_BORINGSSL OFF CACHE BOOL "Disable boringssl for ngtcp2") - -add_definitions(-D_GNU_SOURCE) -add_subdirectory(ngtcp2 EXCLUDE_FROM_ALL) diff --git a/include/llarp.hpp b/include/llarp.hpp index e333e2495..5838d3569 100644 --- a/include/llarp.hpp +++ b/include/llarp.hpp @@ -120,7 +120,6 @@ namespace llarp std::unique_ptr> closeWaiter; }; - } // namespace llarp #endif diff --git a/include/lokinet-extension.hpp b/include/lokinet-extension.hpp new file mode 100644 index 000000000..5bbae9946 --- /dev/null +++ b/include/lokinet-extension.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +struct ContextWrapper; + +@interface LLARPPacketTunnel : NEPacketTunnelProvider +{ + @private + struct ContextWrapper* m_Context; +} +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler; + +@end diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 3ae31ae4e..aaf388457 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -262,6 +262,33 @@ if(BUILD_LIBLOKINET) add_log_tag(lokinet-shared) endif() +if(APPLE) + find_library(NETEXT NetworkExtension REQUIRED) + find_library(COREFOUNDATION CoreFoundation REQUIRED) + + add_library(lokinet-extension SHARED + framework.mm + ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + target_include_directories(lokinet-extension PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(lokinet-extension PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) + + set_target_properties(lokinet-extension PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION CXX + MACOSX_FRAMEWORK_IDENTIFIER org.lokinet.NetworkExtension + MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist + # "current version" in semantic format in Mach-O binary file + VERSION 16.4.0 + # "compatibility version" in semantic format in Mach-O binary file + SOVERSION 1.0.0 + PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + +endif() + foreach(lokinet_lib liblokinet lokinet-platform lokinet-util lokinet-cryptography) add_log_tag(${lokinet_lib}) endforeach() diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 4e1b4c80e..3542e9326 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1446,4 +1446,18 @@ namespace llarp return config; } +#ifdef __APPLE__ + std::shared_ptr + Config::NetworkExtensionConfig() + { + auto config = std::make_shared(fs::path{}); + config->Load(); + config->logging.m_logLevel = eLogInfo; + config->api.m_enableRPCServer = false; + config->network.m_saveProfiles = false; + config->bootstrap.files.clear(); + return config; + } +#endif + } // namespace llarp diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 03f7a000c..35360aeb8 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -260,6 +260,11 @@ namespace llarp static std::shared_ptr EmbeddedConfig(); +#ifdef __APPLE__ + static std::shared_ptr + NetworkExtensionConfig(); +#endif + private: /// Load (initialize) a default config. /// diff --git a/llarp/framework.mm b/llarp/framework.mm new file mode 100644 index 000000000..a5bd7d93f --- /dev/null +++ b/llarp/framework.mm @@ -0,0 +1,202 @@ +#include +#include + +#include +#include +#include + +#include + +namespace llarp::apple +{ + struct FrameworkContext : public llarp::Context + { + + explicit FrameworkContext(NEPacketTunnelProvider * tunnel); + + ~FrameworkContext() {} + + std::shared_ptr + makeVPNPlatform() override; + + void + Start(); + + private: + NEPacketTunnelProvider * m_Tunnel; + std::unique_ptr m_Runner; + }; + + class VPNInterface final : public vpn::NetworkInterface + { + NEPacketTunnelProvider * m_Tunnel; + + static inline constexpr auto PacketQueueSize = 1024; + + thread::Queue m_ReadQueue; + + void + OfferReadPacket(NSData * data) + { + llarp::net::IPPacket pkt; + const llarp_buffer_t buf{static_cast(data.bytes), data.length}; + if(pkt.Load(buf)) + m_ReadQueue.tryPushBack(std::move(pkt)); + } + + public: + explicit VPNInterface(NEPacketTunnelProvider * tunnel) + : m_Tunnel{tunnel}, + m_ReadQueue{PacketQueueSize} + { + auto handler = + [this](NSArray * packets, NSArray *) + { + NSUInteger num = [packets count]; + for(NSUInteger idx = 0; idx < num ; ++idx) + { + NSData * pkt = [packets objectAtIndex:idx]; + OfferReadPacket(pkt); + } + }; + [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; + } + + int + PollFD() const override + { + return -1; + } + + std::string + IfName() const override + { + return ""; + } + + net::IPPacket + ReadNextPacket() override + { + net::IPPacket pkt{}; + if(not m_ReadQueue.empty()) + pkt = m_ReadQueue.popFront(); + return pkt; + } + + bool + WritePacket(net::IPPacket pkt) override + { + const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET; + const uint8_t * pktbuf = pkt.buf; + const size_t pktsz = pkt.sz; + NSData * datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; + NEPacket * npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; + NSArray * pkts = @[npkt]; + return [m_Tunnel.packetFlow writePacketObjects:pkts]; + } + + }; + + class VPNPlatform final : public vpn::Platform + { + NEPacketTunnelProvider * m_Tunnel; + public: + explicit VPNPlatform(NEPacketTunnelProvider * tunnel) + : m_Tunnel{tunnel} + { + } + + std::shared_ptr + ObtainInterface(vpn::InterfaceInfo) override + { + return std::make_shared(m_Tunnel); + } + }; + + + FrameworkContext::FrameworkContext(NEPacketTunnelProvider * tunnel) : + llarp::Context{}, + m_Tunnel{tunnel} + { + } + + void + FrameworkContext::Start() + { + std::promise result; + + m_Runner = std::make_unique( + [&result, this]() + { + const RuntimeOptions opts{}; + try + { + Setup(opts); + Configure(llarp::Config::NetworkExtensionConfig()); + } + catch(std::exception & ) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + Run(opts); + }); + + auto ftr = result.get_future(); + ftr.get(); + } + + std::shared_ptr + FrameworkContext::makeVPNPlatform() + { + return std::make_shared(m_Tunnel); + } +} + + +struct ContextWrapper +{ + std::shared_ptr m_Context; +public: + explicit ContextWrapper(NEPacketTunnelProvider * tunnel) : + m_Context{std::make_shared(tunnel)} + {} + + void + Start() + { + m_Context->Start(); + } + + void + Stop() + { + m_Context->CloseAsync(); + m_Context->Wait(); + } +}; + + + +@implementation LLARPPacketTunnel + +- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completionHandler { + m_Context = new ContextWrapper{self}; + m_Context->Start(); + completionHandler(nullptr); +} + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason +completionHandler:(void (^)(void))completionHandler { + if(m_Context) + { + m_Context->Stop(); + delete m_Context; + m_Context = nullptr; + } + completionHandler(); +} + + +@end diff --git a/llarp/vpn/apple.hpp b/llarp/vpn/apple.hpp index f20c50ce3..e69de29bb 100644 --- a/llarp/vpn/apple.hpp +++ b/llarp/vpn/apple.hpp @@ -1,173 +0,0 @@ -#pragma once - -#include -#include "common.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace llarp::vpn -{ - class AppleInterface : public NetworkInterface - { - const int m_FD; - const InterfaceInfo m_Info; - std::string m_IfName; - - static void - Exec(std::string cmd) - { - LogDebug(cmd); - system(cmd.c_str()); - } - - public: - AppleInterface(InterfaceInfo info) - : m_FD{::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL)}, m_Info{std::move(info)} - { - if (m_FD == -1) - throw std::invalid_argument{"cannot open control socket: " + std::string{strerror(errno)}}; - - ctl_info cinfo{}; - const std::string apple_utun = "com.apple.net.utun_control"; - std::copy_n(apple_utun.c_str(), apple_utun.size(), cinfo.ctl_name); - if (::ioctl(m_FD, CTLIOCGINFO, &cinfo) < 0) - { - ::close(m_FD); - throw std::runtime_error{"ioctl CTLIOCGINFO call failed: " + std::string{strerror(errno)}}; - } - sockaddr_ctl addr{}; - addr.sc_id = cinfo.ctl_id; - - addr.sc_len = sizeof(addr); - addr.sc_family = AF_SYSTEM; - addr.ss_sysaddr = AF_SYS_CONTROL; - addr.sc_unit = 0; - - if (connect(m_FD, (sockaddr*)&addr, sizeof(addr)) < 0) - { - ::close(m_FD); - throw std::runtime_error{ - "cannot connect to control socket address: " + std::string{strerror(errno)}}; - } - uint32_t namesz = IFNAMSIZ; - char name[IFNAMSIZ + 1]{}; - if (getsockopt(m_FD, SYSPROTO_CONTROL, 2, name, &namesz) < 0) - { - ::close(m_FD); - throw std::runtime_error{ - "cannot query for interface name: " + std::string{strerror(errno)}}; - } - m_IfName = name; - for (const auto& ifaddr : m_Info.addrs) - { - if (ifaddr.fam == AF_INET) - { - const huint32_t addr = net::TruncateV6(ifaddr.range.addr); - const huint32_t netmask = net::TruncateV6(ifaddr.range.netmask_bits); - const huint32_t daddr = addr & netmask; - Exec( - "/sbin/ifconfig " + m_IfName + " " + addr.ToString() + " " + daddr.ToString() - + " mtu 1500 netmask 255.255.255.255 up"); - Exec( - "/sbin/route add " + daddr.ToString() + " -netmask " + netmask.ToString() - + " -interface " + m_IfName); - Exec("/sbin/route add " + addr.ToString() + " -interface lo0"); - } - else if (ifaddr.fam == AF_INET6) - { - Exec("/sbin/ifconfig " + m_IfName + " inet6 " + ifaddr.range.ToString()); - } - } - } - - ~AppleInterface() - { - ::close(m_FD); - } - - std::string - IfName() const override - { - return m_IfName; - } - - int - PollFD() const override - { - return m_FD; - } - - net::IPPacket - ReadNextPacket() override - { - constexpr int uintsize = sizeof(unsigned int); - net::IPPacket pkt{}; - unsigned int pktinfo = 0; - const struct iovec vecs[2] = { - {.iov_base = &pktinfo, .iov_len = uintsize}, - {.iov_base = pkt.buf, .iov_len = sizeof(pkt.buf)}}; - int sz = readv(m_FD, vecs, 2); - if (sz >= uintsize) - pkt.sz = sz - uintsize; - else if (sz >= 0 || errno == EAGAIN || errno == EWOULDBLOCK) - pkt.sz = 0; - else - throw std::error_code{errno, std::system_category()}; - return pkt; - } - - bool - WritePacket(net::IPPacket pkt) override - { - static unsigned int af4 = htonl(AF_INET); - static unsigned int af6 = htonl(AF_INET6); - - const struct iovec vecs[2] = { - {.iov_base = pkt.IsV6() ? &af6 : &af4, .iov_len = sizeof(unsigned int)}, - {.iov_base = pkt.buf, .iov_len = pkt.sz}}; - - ssize_t n = writev(m_FD, vecs, 2); - if (n >= (int)sizeof(unsigned int)) - { - n -= sizeof(unsigned int); - return static_cast(n) == pkt.sz; - } - return false; - } - }; - - class ApplePlatform : public Platform - { - public: - std::shared_ptr - ObtainInterface(InterfaceInfo info) override - { - return std::make_shared(std::move(info)); - } - }; -} // namespace llarp::vpn diff --git a/llarp/vpn/platform.cpp b/llarp/vpn/platform.cpp index 0784ba110..341e28fcb 100644 --- a/llarp/vpn/platform.cpp +++ b/llarp/vpn/platform.cpp @@ -1,3 +1,6 @@ + +#include + #ifdef _WIN32 #include "win32.hpp" #endif @@ -8,9 +11,8 @@ #include "linux.hpp" #endif #endif -#ifdef __APPLE__ -#include "apple.hpp" -#endif + +#include namespace llarp::vpn { @@ -30,7 +32,7 @@ namespace llarp::vpn #endif #endif #ifdef __APPLE__ - plat = std::make_shared(); + throw std::runtime_error{"not supported"}; #endif return plat; } diff --git a/readme.md b/readme.md index b0b08e446..9122baf13 100644 --- a/readme.md +++ b/readme.md @@ -62,14 +62,7 @@ alternatively you can build from source, make sure you have cmake, libuv and xco $ git clone --recursive https://github.com/oxen-io/lokinet $ cd lokinet - $ mkdir build - $ cd build - $ cmake .. -DBUILD_STATIC_DEPS=ON -DBUILD_SHARED_LIBS=OFF -DSTATIC_LINK=ON - $ make -j$(sysctl -n hw.ncpu) - -install: - - $ sudo make install + $ ./contrib/mac.sh -DCODESIGN_KEY='insert your key identity here' ### Windows From 5edd045c9b1cfb1c8b605b4c91805b2d5825e6bf Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 30 Jun 2021 07:21:17 -0400 Subject: [PATCH 32/81] add swift version bullshit file and additional bullshittery --- .swift-version | 1 + CMakeLists.txt | 1 + contrib/format.sh | 4 +- contrib/macos/Info.plist | 2 +- contrib/macos/LokinetExtension.Info.plist | 31 ---- contrib/macos/LokinetExtension.Info.plist.in | 40 +++++ .../lokinet-extension.entitlements.plist.in | 25 +++ contrib/macos/lokinet.entitlements.plist | 10 -- contrib/macos/lokinet.entitlements.plist.in | 24 +++ contrib/macos/sign.sh.in | 8 +- daemon/CMakeLists.txt | 58 ++++--- daemon/lokinet.cpp | 8 + daemon/lokinet.mm | 9 - daemon/lokinet.swift | 68 +++++--- daemon/swift/Lokinet/module.modulemap | 4 - daemon/swift/LokinetMain.swift | 43 ----- include/lokinet-extension.hpp | 5 +- llarp/CMakeLists.txt | 20 ++- llarp/framework.mm | 163 ++++++++++-------- llarp/util/logging/apple_logger.hpp | 32 ++++ llarp/util/logging/apple_logger.mm | 38 ++++ readme.md | 2 +- 22 files changed, 358 insertions(+), 238 deletions(-) create mode 100644 .swift-version delete mode 100644 contrib/macos/LokinetExtension.Info.plist create mode 100644 contrib/macos/LokinetExtension.Info.plist.in create mode 100644 contrib/macos/lokinet-extension.entitlements.plist.in delete mode 100644 contrib/macos/lokinet.entitlements.plist create mode 100644 contrib/macos/lokinet.entitlements.plist.in delete mode 100644 daemon/lokinet.mm delete mode 100644 daemon/swift/Lokinet/module.modulemap delete mode 100644 daemon/swift/LokinetMain.swift create mode 100644 llarp/util/logging/apple_logger.hpp create mode 100644 llarp/util/logging/apple_logger.mm diff --git a/.swift-version b/.swift-version new file mode 100644 index 000000000..8ae03c119 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +5.4.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f9b1a4a0..aa6fc1290 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ if(RELEASE_MOTTO AND CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]") add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}") endif() +set(LOKINET_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") diff --git a/contrib/format.sh b/contrib/format.sh index 26ed77d3c..5b5f5a495 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -18,11 +18,11 @@ fi cd "$(dirname $0)/../" if [ "$1" = "verify" ] ; then - if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then + if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm)$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then exit 1 fi else - $binary -i $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') &> /dev/null + $binary -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm)$' | grep -v '\#') &> /dev/null fi swift_format=$(which swiftformat 2>/dev/null) diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist index de014151e..d39aed3a8 100644 --- a/contrib/macos/Info.plist +++ b/contrib/macos/Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable MacOS/lokinet CFBundleIdentifier - org.lokinet.Daemon + com.loki-project.lokinet CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/contrib/macos/LokinetExtension.Info.plist b/contrib/macos/LokinetExtension.Info.plist deleted file mode 100644 index bc6b357af..000000000 --- a/contrib/macos/LokinetExtension.Info.plist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - Lokinet - CFBundleExecutable - lokinet-extension - CFBundleIdentifier - org.lokinet.NetworkExtension - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Lokinet - CFBundlePackageType - XPC! - CFBundleShortVersionString - 0.1 - CFBundleVersion - 0.1 - NSExtension - - NSExtensionPointIdentifier - com.apple.networkextension.packet-tunnel - NSExtensionPrincipalClass - Lokinet.LLARPPacketTunnel - - - diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in new file mode 100644 index 000000000..7f6ecadbb --- /dev/null +++ b/contrib/macos/LokinetExtension.Info.plist.in @@ -0,0 +1,40 @@ + + + + + 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/lokinet-extension.entitlements.plist.in b/contrib/macos/lokinet-extension.entitlements.plist.in new file mode 100644 index 000000000..6f8dfb41b --- /dev/null +++ b/contrib/macos/lokinet-extension.entitlements.plist.in @@ -0,0 +1,25 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + com.apple.security.network.client + + + diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist deleted file mode 100644 index 589ce8b28..000000000 --- a/contrib/macos/lokinet.entitlements.plist +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - - diff --git a/contrib/macos/lokinet.entitlements.plist.in b/contrib/macos/lokinet.entitlements.plist.in new file mode 100644 index 000000000..66bbbb80c --- /dev/null +++ b/contrib/macos/lokinet.entitlements.plist.in @@ -0,0 +1,24 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + com.apple.security.network.client + + + diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index fc1136d9b..c255a94e8 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,8 +1,6 @@ #!/usr/bin/env bash -set -x set -e -for file in "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do - codesign -vvvv --force -s "${CODESIGN_KEY}" --entitlements "${SIGN_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file" +codesign --verbose=4 --force -s "${CODESIGN_KEY}" --entitlements "${NETEXT_ENTITLEMENTS}" --deep --timestamp --options=runtime "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" +for file in "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do + codesign --verbose=4 --force -s "${CODESIGN_KEY}" --entitlements "${LOKINET_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file" done - -codesign --verify "${SIGN_TARGET}" diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 257daebed..a03ebef2a 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,19 +1,17 @@ if(APPLE) - option(WITH_SWIFT "use swift" ON) - if(WITH_SWIFT) - add_executable(lokinet lokinet.swift) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) - target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) - else() - add_executable(lokinet lokinet.mm) - endif() + set(LOKINET_SWIFT_SOURCES lokinet.swift) + add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) + target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) target_link_libraries(lokinet PUBLIC lokinet-extension) + add_executable(lokinet-old lokinet.cpp) + enable_lto(lokinet-old) else() add_executable(lokinet lokinet.cpp) + add_executable(lokinet-vpn lokinet-vpn.cpp) + add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) + enable_lto(lokinet lokinet-vpn lokinet-bootstrap) endif() -add_executable(lokinet-vpn lokinet-vpn.cpp) -add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) -enable_lto(lokinet lokinet-vpn lokinet-bootstrap) if(TRACY_ROOT) target_sources(lokinet PRIVATE ${TRACY_ROOT}/TracyClient.cpp) @@ -35,16 +33,19 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") endif() endif() -target_link_libraries(lokinet-bootstrap PUBLIC cpr::cpr) -if(NOT WIN32) - find_package(OpenSSL REQUIRED) - # because debian sid's curl doesn't link against openssl for some godawful cursed reason - target_link_libraries(lokinet-bootstrap PUBLIC OpenSSL::SSL OpenSSL::Crypto) +if(NOT APPLE) + target_link_libraries(lokinet-bootstrap PUBLIC cpr::cpr) + if(NOT WIN32) + find_package(OpenSSL REQUIRED) + # because debian sid's curl doesn't link against openssl for some godawful cursed reason + target_link_libraries(lokinet-bootstrap PUBLIC OpenSSL::SSL OpenSSL::Crypto) + endif() endif() -set(exetargets lokinet-vpn lokinet-bootstrap) -if(NOT APPLE) - set(exetargets lokinet ${exes}) +if(APPLE) + set(exetargets lokinet-old lokinet) +else() + set(exetargets lokinet lokinet-vpn lokinet-bootstrap) endif() foreach(exe ${exetargets}) @@ -55,11 +56,11 @@ foreach(exe ${exetargets}) elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") target_link_directories(${exe} PRIVATE /usr/local/lib) endif() - target_link_libraries(${exe} PRIVATE liblokinet) + target_link_libraries(${exe} PUBLIC liblokinet) if(WITH_JEMALLOC) target_link_libraries(${exe} PUBLIC jemalloc) endif() - target_include_directories(${exe} PRIVATE ${CMAKE_SOURCE_DIR}) + target_include_directories(${exe} PUBLIC "${PROJECT_SOURCE_DIR}") target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL}) add_log_tag(${exe}) if(should_install) @@ -87,18 +88,23 @@ if(APPLE) MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router" MACOSX_BUNDLE_BUNDLE_NAME "Lokinet" - MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}" + MACOSX_BUNDLE_BUNDLE_VERSION "${LOKINET_VERSION}" MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}.$lokinet_VERSION_MINOR}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}" - MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet.lokinet" + MACOSX_BUNDLE_GUI_IDENTIFIER "com.loki-project.lokinet" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") option(CODESIGN_KEY "codesign all the shit with this key" OFF) - if (CODESIGN_KEY) + if (CODESIGN_KEY AND CODESIGN_TEAM_ID) message(STATUS "codesigning with ${CODESIGN_KEY}") - set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") - set(SIGN_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist") + set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") + configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist.in" + "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") + configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet-extension.entitlements.plist.in" + "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") + set(LOKINET_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") + set(NETEXT_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" "${CMAKE_BINARY_DIR}/sign.sh") diff --git a/daemon/lokinet.cpp b/daemon/lokinet.cpp index 316d1b856..52664e897 100644 --- a/daemon/lokinet.cpp +++ b/daemon/lokinet.cpp @@ -11,6 +11,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include #include @@ -396,6 +400,10 @@ lokinet_main(int argc, char* argv[]) { return result; } +#ifdef __APPLE__ + llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); +#endif + llarp::RuntimeOptions opts; #ifdef _WIN32 diff --git a/daemon/lokinet.mm b/daemon/lokinet.mm deleted file mode 100644 index 1baa58379..000000000 --- a/daemon/lokinet.mm +++ /dev/null @@ -1,9 +0,0 @@ -#import -#include - - -int main (int argc, const char * argv[]) -{ - - return 0; -} diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 28eefe06c..b80c01227 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -1,52 +1,70 @@ -// AppDelegateExtension.swift - +import AppKit import Foundation import LokinetExtension import NetworkExtension -class LokinetMain: NSObject { - var vpnManager = NETunnelProviderManager() +let app = NSApplication.shared - let lokinetComponent = "org.lokinet.NetworkExtension" +class LokinetMain: NSObject, NSApplicationDelegate { + var vpnManager = NETunnelProviderManager() + let lokinetComponent = "com.loki-project.lokinet.network-extension" var lokinetAdminTimer: DispatchSourceTimer? - func runMain() { - print("Starting up lokinet") - NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in + func applicationDidFinishLaunching(_: Notification) { + setupVPNJizz() + } + + func bail() { + app.terminate(self) + } + + func setupVPNJizz() { + NSLog("Starting up lokinet") + NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in if let error = error { - print(error) + NSLog(error.localizedDescription) + bail() } if let savedManagers = savedManagers { for manager in savedManagers { if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { - print("Found saved VPN Manager") + NSLog("%@", manager) + NSLog("Found saved VPN Manager") self.vpnManager = manager } } } let providerProtocol = NETunnelProviderProtocol() - providerProtocol.serverAddress = "lokinet" + providerProtocol.serverAddress = "" + providerProtocol.username = "anonymous" providerProtocol.providerBundleIdentifier = self.lokinetComponent + providerProtocol.includeAllNetworks = true self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true + self.vpnManager.isOnDemandEnabled = true self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { - print("Error saving to preferences") + NSLog("Error saving to preferences") + NSLog(error!.localizedDescription) + bail() } else { - print("saved...") self.vpnManager.loadFromPreferences(completionHandler: { error in if error != nil { - print("Error loading from preferences") + NSLog("Error loading from preferences") + NSLog(error!.localizedDescription) + bail() } else { do { - print("Trying to start") + NSLog("Trying to start") self.initializeConnectionObserver() try self.vpnManager.connection.startVPNTunnel() } catch let error as NSError { - print(error) + NSLog(error.localizedDescription) + bail() } catch { - print("There was a fatal error") + NSLog("There was a fatal error") + bail() } } }) @@ -57,21 +75,21 @@ class LokinetMain: NSObject { func initializeConnectionObserver() { NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in - if self.vpnManager.connection.status == .invalid { - print("VPN configuration is invalid") + NSLog("VPN configuration is invalid") } else if self.vpnManager.connection.status == .disconnected { - print("VPN is disconnected.") + NSLog("VPN is disconnected.") } else if self.vpnManager.connection.status == .connecting { - print("VPN is connecting...") + NSLog("VPN is connecting...") } else if self.vpnManager.connection.status == .reasserting { - print("VPN is reasserting...") + NSLog("VPN is reasserting...") } else if self.vpnManager.connection.status == .disconnecting { - print("VPN is disconnecting...") + NSLog("VPN is disconnecting...") } } } } -let lokinet = LokinetMain() -lokinet.runMain() +let delegate = LokinetMain() +app.delegate = delegate +app.run() diff --git a/daemon/swift/Lokinet/module.modulemap b/daemon/swift/Lokinet/module.modulemap deleted file mode 100644 index fda10e4b7..000000000 --- a/daemon/swift/Lokinet/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ - -module Lokinet { - header "lokinet-extension.hpp" -} \ No newline at end of file diff --git a/daemon/swift/LokinetMain.swift b/daemon/swift/LokinetMain.swift deleted file mode 100644 index 561df3e7f..000000000 --- a/daemon/swift/LokinetMain.swift +++ /dev/null @@ -1,43 +0,0 @@ -// AppDelegateExtension.swift -// lifed from yggdrasil network ios port -// - -import Foundation -import Lokinet -import NetworkExtension - -class LokinetMain: PlatformAppDelegate { - var vpnManager = NETunnelProviderManager() - var app = NSApplication.shared() - let lokinetComponent = "org.lokinet.NetworkExtension" - var lokinetAdminTimer: DispatchSourceTimer? - - func runMain() { - print("Starting up lokinet") - NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in - if let error = error { - print(error) - } - - if let savedManagers = savedManagers { - for manager in savedManagers { - if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { - print("Found saved VPN Manager") - self.vpnManager = manager - } - } - } - - self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in - if let error = error { - print(error) - } - self.vpnManager.localizedDescription = "Lokinet" - self.vpnManager.isEnabled = true - }) - } - app.finishLaunching() - app.run() - print("end") - } -} diff --git a/include/lokinet-extension.hpp b/include/lokinet-extension.hpp index 5bbae9946..df436ab4e 100644 --- a/include/lokinet-extension.hpp +++ b/include/lokinet-extension.hpp @@ -6,13 +6,16 @@ struct ContextWrapper; @interface LLARPPacketTunnel : NEPacketTunnelProvider { - @private struct ContextWrapper* m_Context; } + - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError* error))completionHandler; - (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler; +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler; + @end diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index aaf388457..6730dd0a5 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(lokinet-util util/fs.cpp util/json.cpp util/logging/android_logger.cpp + util/logging/apple_logger.mm util/logging/buffer.cpp util/logging/file_logger.cpp util/logging/json_logger.cpp @@ -37,6 +38,11 @@ target_link_libraries(lokinet-util PUBLIC oxenmq::oxenmq ) +if(APPLE) + find_library(FOUNDATION Foundation REQUIRED) + target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) +endif() + if(ANDROID) target_link_libraries(lokinet-util PUBLIC log) endif() @@ -263,6 +269,7 @@ if(BUILD_LIBLOKINET) endif() if(APPLE) + # god made apple so that man may suffer find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) @@ -276,15 +283,18 @@ if(APPLE) ${COREFOUNDATION} ${NETEXT}) + configure_file(${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in + ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist) + set_target_properties(lokinet-extension PROPERTIES FRAMEWORK TRUE - FRAMEWORK_VERSION CXX - MACOSX_FRAMEWORK_IDENTIFIER org.lokinet.NetworkExtension - MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist + FRAMEWORK_VERSION ${lokinet_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER com.loki-project.lokinet.network-extension + MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist # "current version" in semantic format in Mach-O binary file - VERSION 16.4.0 + VERSION ${lokinet_VERSION} # "compatibility version" in semantic format in Mach-O binary file - SOVERSION 1.0.0 + SOVERSION ${lokinet_VERSION} PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) endif() diff --git a/llarp/framework.mm b/llarp/framework.mm index a5bd7d93f..032c2424a 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -11,54 +12,51 @@ namespace llarp::apple { struct FrameworkContext : public llarp::Context { - - explicit FrameworkContext(NEPacketTunnelProvider * tunnel); + explicit FrameworkContext(NEPacketTunnelProvider* tunnel); + + ~FrameworkContext() + {} - ~FrameworkContext() {} - std::shared_ptr makeVPNPlatform() override; void Start(); - - private: - NEPacketTunnelProvider * m_Tunnel; + + private: + NEPacketTunnelProvider* const m_Tunnel; std::unique_ptr m_Runner; - }; + }; class VPNInterface final : public vpn::NetworkInterface { - NEPacketTunnelProvider * m_Tunnel; + NEPacketTunnelProvider* const m_Tunnel; static inline constexpr auto PacketQueueSize = 1024; - + thread::Queue m_ReadQueue; void - OfferReadPacket(NSData * data) + OfferReadPacket(NSData* data) { llarp::net::IPPacket pkt; - const llarp_buffer_t buf{static_cast(data.bytes), data.length}; - if(pkt.Load(buf)) + const llarp_buffer_t buf{static_cast(data.bytes), data.length}; + if (pkt.Load(buf)) m_ReadQueue.tryPushBack(std::move(pkt)); } - public: - explicit VPNInterface(NEPacketTunnelProvider * tunnel) - : m_Tunnel{tunnel}, - m_ReadQueue{PacketQueueSize} + public: + explicit VPNInterface(NEPacketTunnelProvider* tunnel) + : m_Tunnel{tunnel}, m_ReadQueue{PacketQueueSize} { - auto handler = - [this](NSArray * packets, NSArray *) + auto handler = [this](NSArray* packets, NSArray*) { + NSUInteger num = [packets count]; + for (NSUInteger idx = 0; idx < num; ++idx) { - NSUInteger num = [packets count]; - for(NSUInteger idx = 0; idx < num ; ++idx) - { - NSData * pkt = [packets objectAtIndex:idx]; - OfferReadPacket(pkt); - } - }; + NSData* pkt = [packets objectAtIndex:idx]; + OfferReadPacket(pkt); + } + }; [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; } @@ -73,12 +71,12 @@ namespace llarp::apple { return ""; } - + net::IPPacket ReadNextPacket() override { net::IPPacket pkt{}; - if(not m_ReadQueue.empty()) + if (not m_ReadQueue.empty()) pkt = m_ReadQueue.popFront(); return pkt; } @@ -87,61 +85,53 @@ namespace llarp::apple WritePacket(net::IPPacket pkt) override { const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET; - const uint8_t * pktbuf = pkt.buf; + const uint8_t* pktbuf = pkt.buf; const size_t pktsz = pkt.sz; - NSData * datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; - NEPacket * npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; - NSArray * pkts = @[npkt]; + NSData* datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; + NEPacket* npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; + NSArray* pkts = @[npkt]; return [m_Tunnel.packetFlow writePacketObjects:pkts]; } - }; class VPNPlatform final : public vpn::Platform { - NEPacketTunnelProvider * m_Tunnel; - public: - explicit VPNPlatform(NEPacketTunnelProvider * tunnel) - : m_Tunnel{tunnel} - { - } - - std::shared_ptr - ObtainInterface(vpn::InterfaceInfo) override + NEPacketTunnelProvider* const m_Tunnel; + + public: + explicit VPNPlatform(NEPacketTunnelProvider* tunnel) : m_Tunnel{tunnel} + {} + + std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override { return std::make_shared(m_Tunnel); } }; - - FrameworkContext::FrameworkContext(NEPacketTunnelProvider * tunnel) : - llarp::Context{}, - m_Tunnel{tunnel} - { - } + FrameworkContext::FrameworkContext(NEPacketTunnelProvider* tunnel) + : llarp::Context{}, m_Tunnel{tunnel} + {} void FrameworkContext::Start() { std::promise result; - m_Runner = std::make_unique( - [&result, this]() + m_Runner = std::make_unique([&result, this]() { + const RuntimeOptions opts{}; + try { - const RuntimeOptions opts{}; - try - { - Setup(opts); - Configure(llarp::Config::NetworkExtensionConfig()); - } - catch(std::exception & ) - { - result.set_exception(std::current_exception()); - return; - } - result.set_value(); - Run(opts); - }); + Setup(opts); + Configure(llarp::Config::NetworkExtensionConfig()); + } + catch (std::exception&) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + Run(opts); + }); auto ftr = result.get_future(); ftr.get(); @@ -154,13 +144,13 @@ namespace llarp::apple } } - struct ContextWrapper { - std::shared_ptr m_Context; -public: - explicit ContextWrapper(NEPacketTunnelProvider * tunnel) : - m_Context{std::make_shared(tunnel)} + std::unique_ptr m_Context; + + public: + explicit ContextWrapper(NEPacketTunnelProvider* tunnel) + : m_Context{std::make_unique(tunnel)} {} void @@ -176,20 +166,35 @@ public: m_Context->Wait(); } }; - +static std::string_view +DataAsStringView(NSData* data) +{ + return std::string_view{reinterpret_cast(data.bytes), data.length}; +} + +static NSData* +StringViewToData(std::string_view data) +{ + const char* ptr = data.data(); + const size_t sz = data.size(); + return [NSData dataWithBytes:ptr length:sz]; +} @implementation LLARPPacketTunnel -- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completionHandler { +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError*))completionHandler +{ m_Context = new ContextWrapper{self}; m_Context->Start(); - completionHandler(nullptr); + [self setTunnelNetworkSettings:nullptr completionHandler:completionHandler]; } -- (void)stopTunnelWithReason:(NEProviderStopReason)reason -completionHandler:(void (^)(void))completionHandler { - if(m_Context) +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler +{ + if (m_Context) { m_Context->Stop(); delete m_Context; @@ -198,5 +203,13 @@ completionHandler:(void (^)(void))completionHandler { completionHandler(); } +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler +{ + const auto data = DataAsStringView(messageData); + LogInfo("app message: ", data); + + completionHandler(StringViewToData("ok")); +} @end diff --git a/llarp/util/logging/apple_logger.hpp b/llarp/util/logging/apple_logger.hpp new file mode 100644 index 000000000..00450b391 --- /dev/null +++ b/llarp/util/logging/apple_logger.hpp @@ -0,0 +1,32 @@ +#pragma once +#ifdef __APPLE__ +#include "logstream.hpp" + +namespace llarp +{ + struct NSLogStream : public ILogStream + { + void + PreLog( + std::stringstream& s, + LogLevel lvl, + const char* fname, + int lineno, + const std::string& nodename) const override; + + void + Print(LogLevel lvl, const char* tag, const std::string& msg) override; + + void + PostLog(std::stringstream& ss) const override; + + virtual void + ImmediateFlush() override + {} + + void Tick(llarp_time_t) override + {} + }; +} // namespace llarp + +#endif diff --git a/llarp/util/logging/apple_logger.mm b/llarp/util/logging/apple_logger.mm new file mode 100644 index 000000000..e5ca746c1 --- /dev/null +++ b/llarp/util/logging/apple_logger.mm @@ -0,0 +1,38 @@ +#ifdef __APPLE__ +#include "apple_logger.hpp" +#include "logger_internal.hpp" + +#include + +namespace llarp +{ + void + NSLogStream::PreLog( + std::stringstream& ss, + LogLevel lvl, + const char* fname, + int lineno, + const std::string& nodename) const + { + ss << "[" << LogLevelToString(lvl) << "] "; + ss << "[" << nodename << "]" + << "(" << thread_id_string() << ") " << log_timestamp() << " " << fname << ":" << lineno + << "\t"; + } + + void + NSLogStream::Print(LogLevel, const char*, const std::string& msg) + { + const char* msg_ptr = msg.c_str(); + const char* msg_fmt = "%s"; + NSString* fmt = [[NSString alloc] initWithUTF8String:msg_ptr]; + NSString* str = [[NSString alloc] initWithUTF8String:msg_fmt]; + NSLog(fmt, str); + } + + void + NSLogStream::PostLog(std::stringstream&) const + {} + +} // namespace llarp +#endif diff --git a/readme.md b/readme.md index 9122baf13..42b339e53 100644 --- a/readme.md +++ b/readme.md @@ -62,7 +62,7 @@ alternatively you can build from source, make sure you have cmake, libuv and xco $ git clone --recursive https://github.com/oxen-io/lokinet $ cd lokinet - $ ./contrib/mac.sh -DCODESIGN_KEY='insert your key identity here' + $ ./contrib/mac.sh -DCODESIGN_KEY='insert your key identity here' -DCODESIGN_TEAM_ID='team id here' ### Windows From 0bb00baacfc54c67f17f372f933c8d261d95d5c5 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 27 Jul 2021 15:43:48 -0300 Subject: [PATCH 33/81] Various cmake build cleanups/refactors - Added contrib/macos/README.txt with description of the cancer happening here. - Add provisioningprofiles that Apple wants to make things work properly - Made the entitlements files match the provisioningprofiles - Remove configured entitlements files; we *can't* change any of the things here because they are closedly tied to the provisioningprofiles -- which means if someone wants to build their own Lokinet, they have to replace a bunch of crap and change application IDs throughout. This is the hostile-to-open-source Apple way. - Remove unused old lokinet binary, as we're no longer using it on macos - Use a POST_BUILD rather than install to copy things around into the right places - Convert all the configure_file's to consistently use @ONLY - Misc cleanups --- contrib/mac.sh | 4 +- contrib/macos/LokinetExtension.Info.plist.in | 2 +- contrib/macos/README.txt | 23 +++++++ .../lokinet-extension.entitlements.plist | 32 ++++++++++ .../lokinet-extension.entitlements.plist.in | 25 -------- .../macos/lokinet-extension.provisionprofile | Bin 0 -> 13123 bytes contrib/macos/lokinet.entitlements.plist | 32 ++++++++++ contrib/macos/lokinet.entitlements.plist.in | 24 -------- contrib/macos/lokinet.provisionprofile | Bin 0 -> 13010 bytes contrib/macos/sign.sh.in | 10 ++- daemon/CMakeLists.txt | 57 +++++++++--------- llarp/CMakeLists.txt | 18 +++--- 12 files changed, 136 insertions(+), 91 deletions(-) create mode 100644 contrib/macos/README.txt create mode 100644 contrib/macos/lokinet-extension.entitlements.plist delete mode 100644 contrib/macos/lokinet-extension.entitlements.plist.in create mode 100644 contrib/macos/lokinet-extension.provisionprofile create mode 100644 contrib/macos/lokinet.entitlements.plist delete mode 100644 contrib/macos/lokinet.entitlements.plist.in create mode 100644 contrib/macos/lokinet.provisionprofile diff --git a/contrib/mac.sh b/contrib/mac.sh index 62e14802e..bfbaf712b 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -22,7 +22,7 @@ cmake \ -DFORCE_OXENMQ_SUBMODULE=ON \ -DSUBMODULE_CHECK=OFF \ -DWITH_LTO=OFF \ - -DCMAKE_INSTALL_PREFIX=$(pwd) \ -DCMAKE_BUILD_TYPE=Release \ - $@ .. + "$@" \ + .. ninja install && ninja sign diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in index 7f6ecadbb..30dc5f8ea 100644 --- a/contrib/macos/LokinetExtension.Info.plist.in +++ b/contrib/macos/LokinetExtension.Info.plist.in @@ -21,7 +21,7 @@ lokinet CFBundleVersion - ${LOKINET_VERSION} + @LOKINET_VERSION@ ITSAppUsesNonExemptEncryption diff --git a/contrib/macos/README.txt b/contrib/macos/README.txt new file mode 100644 index 000000000..f79fd33d0 --- /dev/null +++ b/contrib/macos/README.txt @@ -0,0 +1,23 @@ +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. + + + + +These two files, in particular, are the very worst manifestations of this 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: + + lokinet.provisionprofile + lokinet-extension.provisionprofile + +This is actively hostile to open source development, but that is nothing new for Apple. + +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.entitlements.plist b/contrib/macos/lokinet-extension.entitlements.plist new file mode 100644 index 000000000..e5dd7cbfc --- /dev/null +++ b/contrib/macos/lokinet-extension.entitlements.plist @@ -0,0 +1,32 @@ + + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider-systemextension + app-proxy-provider-systemextension + content-filter-provider-systemextension + dns-proxy-systemextension + dns-settings + + + com.apple.developer.networking.vpn.api + + allow-vpn + + + com.apple.application-identifier + SUQ8J2PCT7.com.loki-project.lokinet.network-extension + + keychain-access-groups + + SUQ8J2PCT7.* + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + + diff --git a/contrib/macos/lokinet-extension.entitlements.plist.in b/contrib/macos/lokinet-extension.entitlements.plist.in deleted file mode 100644 index 6f8dfb41b..000000000 --- a/contrib/macos/lokinet-extension.entitlements.plist.in +++ /dev/null @@ -1,25 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - - com.apple.security.network.client - - - diff --git a/contrib/macos/lokinet-extension.provisionprofile b/contrib/macos/lokinet-extension.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..331f788e2cc8ab11a662c0a0ca6b780442097d15 GIT binary patch literal 13123 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 Co`9AB literal 0 HcmV?d00001 diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist new file mode 100644 index 000000000..83675e789 --- /dev/null +++ b/contrib/macos/lokinet.entitlements.plist @@ -0,0 +1,32 @@ + + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider-systemextension + app-proxy-provider-systemextension + content-filter-provider-systemextension + dns-proxy-systemextension + dns-settings + + + com.apple.developer.networking.vpn.api + + allow-vpn + + + com.apple.application-identifier + SUQ8J2PCT7.com.loki-project.lokinet + + keychain-access-groups + + SUQ8J2PCT7.* + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + + diff --git a/contrib/macos/lokinet.entitlements.plist.in b/contrib/macos/lokinet.entitlements.plist.in deleted file mode 100644 index 66bbbb80c..000000000 --- a/contrib/macos/lokinet.entitlements.plist.in +++ /dev/null @@ -1,24 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - - com.apple.security.network.client - - - diff --git a/contrib/macos/lokinet.provisionprofile b/contrib/macos/lokinet.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..b6528e4535cfca157c7c48f09aa34b5be7996d78 GIT binary patch literal 13010 zcmdUWd6?VO)ptBe$esa0LPANIEI`R*Vp+DwHY5RUwq;wg<=ut?vSiD$Wy|ADwxN(r zUPv246DXvmECoVB+4m(OZz(TOwht&!^`;P2c1GMnR*Qeh+&ph_M zy1Mt=bIk8c!|o_e}mk=5d=#ikX=;+}L-P(`^Yty&xjJNxX5k6%4~ z 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 -# ) + + set(CODESIGN_KEY "" CACHE STRING "codesign the macos app using this key identity") + add_custom_target(icons ALL COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) add_dependencies(lokinet icons lokinet-extension) - install(TARGETS lokinet-extension FRAMEWORK DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app/Contents/Frameworks" COMPONENT lokinet) + add_custom_command(TARGET lokinet + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "setting rpath" + COMMAND ${CMAKE_COMMAND} -E echo ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ + COMMAND mkdir -p $/Contents/Frameworks + COMMAND cp -au $ $/Contents/Frameworks/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile + $/Contents/embedded.provisionprofile + ) + set_target_properties(lokinet PROPERTIES 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}.$lokinet_VERSION_MINOR}" + 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 "${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist" + MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" - MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") - option(CODESIGN_KEY "codesign all the shit with this key" OFF) - if (CODESIGN_KEY AND CODESIGN_TEAM_ID) + MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") + if (CODESIGN_KEY) message(STATUS "codesigning with ${CODESIGN_KEY}") - set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") - configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist.in" - "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") - configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet-extension.entitlements.plist.in" - "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") - set(LOKINET_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") - set(NETEXT_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") + set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" - "${CMAKE_BINARY_DIR}/sign.sh") + "${PROJECT_BINARY_DIR}/sign.sh" + @ONLY) add_custom_target( sign - DEPENDS "${CMAKE_BINARY_DIR}/sign.sh" lokinet lokinet-extension - COMMAND "${CMAKE_BINARY_DIR}/sign.sh" + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension + COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() - message(STATUS "will not codesign") + message(WARNING "Not codesigning: CODESIGN_KEY is not set") endif() endif() diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 6730dd0a5..a561cec07 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -272,19 +272,16 @@ if(APPLE) # god made apple so that man may suffer find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) - + add_library(lokinet-extension SHARED - framework.mm - ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) - target_include_directories(lokinet-extension PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}) + framework.mm) target_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) - configure_file(${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist) + configure_file(${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in + ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist @ONLY) set_target_properties(lokinet-extension PROPERTIES FRAMEWORK TRUE @@ -296,6 +293,13 @@ if(APPLE) # "compatibility version" in semantic format in Mach-O binary file SOVERSION ${lokinet_VERSION} PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + + add_custom_command(TARGET lokinet-extension + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile + $/Versions/Current/embedded.provisionprofile + ) + endif() From faf8a699a67614ef5a291d2150af28acd930b566 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 28 Jul 2021 11:30:42 -0300 Subject: [PATCH 34/81] Set version into Info.plist, don't manually configure cmake already treats the info plist as a file to be configured (not merely copied) so we don't need to configure_file ourselves to a temp file. --- CMakeLists.txt | 6 ++++++ contrib/macos/{Info.plist => Info.plist.in} | 4 ++-- daemon/CMakeLists.txt | 2 +- llarp/CMakeLists.txt | 5 +---- 4 files changed, 10 insertions(+), 7 deletions(-) rename contrib/macos/{Info.plist => Info.plist.in} (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa6fc1290..3a72a1b8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,12 @@ project(lokinet DESCRIPTION "lokinet - IP packet onion router" LANGUAGES ${LANGS}) +if(APPLE) + # Apple build number: must be incremented to submit a new build for the same lokinet version, + # should be reset to 0 when the lokinet version increments. + set(LOKINET_APPLE_BUILD 0) +endif() + set(RELEASE_MOTTO "A Series of Tubes" CACHE STRING "Release motto") add_definitions(-DLLARP_VERSION_MAJOR=${lokinet_VERSION_MAJOR}) diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist.in similarity index 87% rename from contrib/macos/Info.plist rename to contrib/macos/Info.plist.in index d39aed3a8..5e09e839b 100644 --- a/contrib/macos/Info.plist +++ b/contrib/macos/Info.plist.in @@ -17,8 +17,8 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 0.1 + @LOKINET_VERSION@ CFBundleVersion - 0.1 + @LOKINET_VERSION@.@LOKINET_APPLE_BUILD@ diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 39f1b1acd..724c14513 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -97,7 +97,7 @@ if(APPLE) 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" + MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") if (CODESIGN_KEY) diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index a561cec07..ba47b0e68 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -280,14 +280,11 @@ if(APPLE) ${COREFOUNDATION} ${NETEXT}) - configure_file(${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist @ONLY) - set_target_properties(lokinet-extension PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION ${lokinet_VERSION} MACOSX_FRAMEWORK_IDENTIFIER com.loki-project.lokinet.network-extension - MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist + MACOSX_FRAMEWORK_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in # "current version" in semantic format in Mach-O binary file VERSION ${lokinet_VERSION} # "compatibility version" in semantic format in Mach-O binary file From 3ab117a03b54bf7ecfa6603fc11fd8473a9f9690 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 29 Jul 2021 14:09:18 -0300 Subject: [PATCH 35/81] Switch extension from a framework to an appex --- contrib/macos/README.txt | 25 +++++++++++--- .../lokinet-extension.entitlements.plist | 31 ++++++++---------- .../macos/lokinet-extension.provisionprofile | Bin 13123 -> 17274 bytes contrib/macos/lokinet.entitlements.plist | 24 ++++---------- contrib/macos/lokinet.provisionprofile | Bin 13010 -> 17016 bytes contrib/macos/sign.sh.in | 6 ++-- daemon/CMakeLists.txt | 18 ++++------ daemon/lokinet.swift | 7 ++-- llarp/CMakeLists.txt | 24 +++++++------- llarp/framework.mm | 2 ++ 10 files changed, 70 insertions(+), 67 deletions(-) diff --git a/contrib/macos/README.txt b/contrib/macos/README.txt index f79fd33d0..9880ecc3c 100644 --- a/contrib/macos/README.txt +++ b/contrib/macos/README.txt @@ -4,18 +4,33 @@ into the no-CI, no-help, undocumented, non-toy-apps-need-not-apply modern Apple This is disgusting. +But it gets worse. - - -These two files, in particular, are the very worst manifestations of this 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: +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 diff --git a/contrib/macos/lokinet-extension.entitlements.plist b/contrib/macos/lokinet-extension.entitlements.plist index e5dd7cbfc..8233a7926 100644 --- a/contrib/macos/lokinet-extension.entitlements.plist +++ b/contrib/macos/lokinet-extension.entitlements.plist @@ -2,31 +2,28 @@ - - com.apple.developer.networking.networkextension - - packet-tunnel-provider-systemextension - app-proxy-provider-systemextension - content-filter-provider-systemextension - dns-proxy-systemextension - dns-settings - - - com.apple.developer.networking.vpn.api - - allow-vpn - - com.apple.application-identifier SUQ8J2PCT7.com.loki-project.lokinet.network-extension - keychain-access-groups + com.apple.developer.networking.networkextension - SUQ8J2PCT7.* + packet-tunnel-provider com.apple.developer.team-identifier SUQ8J2PCT7 + com.apple.security.app-sandbox + + + com.apple.security.get-task-allow + + + com.apple.security.network.client + + + com.apple.security.network.server + + diff --git a/contrib/macos/lokinet-extension.provisionprofile b/contrib/macos/lokinet-extension.provisionprofile index 331f788e2cc8ab11a662c0a0ca6b780442097d15..71f066bda46e4ac64927e6331401cc3b0b627844 100644 GIT binary patch delta 9710 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 delta 5898 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 diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist index 83675e789..155d265ba 100644 --- a/contrib/macos/lokinet.entitlements.plist +++ b/contrib/macos/lokinet.entitlements.plist @@ -2,31 +2,21 @@ - - com.apple.developer.networking.networkextension - - packet-tunnel-provider-systemextension - app-proxy-provider-systemextension - content-filter-provider-systemextension - dns-proxy-systemextension - dns-settings - - - com.apple.developer.networking.vpn.api - - allow-vpn - - com.apple.application-identifier SUQ8J2PCT7.com.loki-project.lokinet - keychain-access-groups + com.apple.developer.networking.networkextension - SUQ8J2PCT7.* + packet-tunnel-provider com.apple.developer.team-identifier SUQ8J2PCT7 + com.apple.security.app-sandbox + + + com.apple.security.get-task-allow + diff --git a/contrib/macos/lokinet.provisionprofile b/contrib/macos/lokinet.provisionprofile index b6528e4535cfca157c7c48f09aa34b5be7996d78..f740cd98a782e2dc35dc4fac71a9da6e29a5809a 100644 GIT binary patch literal 17016 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 OPxj7>e(Tj$_xvBCZ)^(y delta 6101 zcma)Ad+aP%UH6uj_SOK!*wPje`U2Wtf9&k+?5kc1XWp~BXLe_H9y=pK=dn9G@7QeYzH@R8eYIXwF2`91)JNDBp|!A?|Qsm~n|25L37JwFyuWU^x{NO~OQ#p7NY zD;<9uqIW?m5;aws_hCfR8trVQfCQu`Y9xSgsLGKWYnk03BgZFuGDVUOPiB@b&Rs6r z*g@(YzIXGD_XyNn(KLn_2R%uuOO3w5D3D}Mf~Sh2uhunr$fTvph^n|_Y)FQu_q@Xk zH@|T&Wd$V}v?fU$Q}jqpp(rpGE=>!G(n5P4GXf};KuRfeO@d*+@a32$(=ZfgO}2qc zvmOwK6KY|HYi(-G8dB0oSsUP4_Mr<+^F6k6VJ(O%Q4;Yemh9TnR-346L~iX08V<|iuA5ySW87pZBqimY8k4PgF;ZCBj^j^{=ouzh0?NFHgpGQ=XmPi3IuM;6_;he^Ek=`mZ@losjvc#7J$ zW%MSyNMGsNlz=XuV@^|Awx*NSd?w?*Ag{{RQPbbZ>WWJWA~T}dI-6l)f8K(cR$tk6 zvalT6Dd^FW3cFo%unc!c_9hl_yq8Z>FWHR!+GMj{k!!0C`u(MDJD4uQRv?IWIl$;q zx5X&)qSiEurptIDfQQfB^e&URh*BIX6@(!OD2kpD2s@cAy#pfYMczF0NK=9g@EG<4 zS3BwXo}nd%2NuHGc82=`h;q zoVYPLO+@W9H*u|^8URTNQYu?Gh`yAV%}uG`6|TFo^k(GJz@$l8a^fy-O~i$bH+Pc0 z%_`bM)f_n$=m(NLbi|Jts~Wn8b4vNUxO8^qg< zg-2_1A{Cx1zyU69?D2WZ2+^V<^h{w+gtZ-On2UGIllf&6JtH^lMsHUWfq1mq8n1~@>=y^HkhEDY?upF)8$|yHk}446*s zj8?v)M<@@naUM-|F*WpPJN>XF-lSU!{#Mpho5@$NB3?3B+_%1^Dr2W zBmrp@b>&GC5IoTbU~II;ovy_9!?p>1CuI~~#H47(vnkfxHb_awrFOLN)TN8d?FmK@ zSUYp%fmZ9vM>vdoZaIw^9qSazmbJjBZs?$lx>6@oB$sCz6WofL(}}%fo%VR`PD{|n z2a$?vEptIHWGdi-N^3(BJ5g1%C+Xy2fBT#EV00p8WJrQphanX}1BtIeK%CAyRbR*x zpalh>k0|`b1xko)#T1|d0Rh7EqlDa&<`k(2j1!Z*U6V7~Be`)qm}Q|MZ>3tdnJi&y znX6qU(DmM~9(GJ@z2{c5r4Ka_khz(rQkhF)ovDd|3XgJO5iAsOP2dfSZMz}gnJc|b zEEtK@q_(bI*141(dImU}`kC*ceH_F{jZwCR7U3}z@Vp&8Z4(=8nvx7m;s$dodXiP!%b0RND>tNpX@Zq7i-S%FIvs$ulH}F}n z%MZo0HRkHJsL^IP&SKT-C9QHy9uXVOpu0QYT4$zQcGm6PIs~>vGML=aeJf9U#iD1d zqNZnVl*SgB0KNeQ9y|Q}EjR8jRlDmpJxw)l=l7POzeuK=Rb#d4t_Hn+R>FXrv)}1;KO}pP5*EyQ= z8@89D&FDx`hv=;WtIY>9nrC|Z#xe=gq`Pc56y%tlFk%+9TFk>Gu_!sI>n6Fp5Cv+` zu#OC>FLzwE<+>$?WY;pbSu?wB$ET7t_S20j?GRX;R#0Z>AB);Qr#Q>4OiVG8ORy==r=Gu4c*|3t%d?mAY0fyiZ)zs-V z!UTtwJirjcqc)T=z{<;D+2fWGvcg415kpT+{kSg8hIu5V^QAFJRZaxtCSS)Sp}J{d zy8YZ*4u%@nkmdQz&D}JUdU6RfZi!r<+Cj$1V+Y@l?VE3RY6~9`xH>2_a%*>U9J)Km$7{;;%RY?RNf8>oPOT+8ARb38Tz0Tj*BcG*@k@h z^2-VVl@122x|~`Qh>X^ShDr6RF_-IjMyz`7WG_a@nMG4h%v_{NtD_L)v|_sg4|doVghp_?#u~X zUql0>lE9*yx2|uxGh&M$#iP~C1?GBDw914&h}Yb(r;C@4j4Jn4D3@(GPZUtYvA}0Q zhv?RZ^>)d2!anK9NMKVUmbPue7|TEf!+9}I7TtK)Y~u9_3CBj!d#UWn`b!H|rbq&tI_8b_ zCi-??l+c7HVaT}9hsSQU_lO}z6L0Q>_(nm5_DYY^r^uFq?4}o<0#1RElmxfb`FvDI zXbuU~~*uLKv@za7GcsTqhhj&S8dL-a5qldA=2QI$>beaj&@_IH9vx^aK2ir zAnDznWg!ELmtJ&oAc#GExHDXIyvsmdv;3~-ya{{q%ilhH=iR@!|AWtb;QCu9 zcmK&ZpZ@q$U-+5ZpL^(v=!vg<{wZ+hXVcGx>f zW6#mgwjX#m|JCn2^sm;J9v{8)bmbwj_cFW>j{Uq1I+Mh?G4KJh;Mvw!y3w?2Bs-+bbK0itp&-2eap diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index 9e906dba1..b05a06e2a 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -e -codesign --verbose=4 --force -s "@CODESIGN_KEY@" \ +codesign --verbose=4 --force -s "@CODESIGN_DEV@" \ --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.entitlements.plist" \ - --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/Frameworks/lokinet-extension.framework" + --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_KEY@" \ + codesign --verbose=4 --force -s "@CODESIGN_APP@" \ --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.entitlements.plist" \ --deep --strict --timestamp --options=runtime "$file" done diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 724c14513..cd9e9c200 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,9 +1,7 @@ if(APPLE) set(LOKINET_SWIFT_SOURCES lokinet.swift) add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) - target_link_libraries(lokinet PUBLIC lokinet-extension) else() add_executable(lokinet lokinet.cpp) add_executable(lokinet-vpn lokinet-vpn.cpp) @@ -71,7 +69,8 @@ endforeach() if(APPLE) - set(CODESIGN_KEY "" CACHE STRING "codesign the macos app using this key identity") + set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity") + set(CODESIGN_DEV "" CACHE STRING "codesign the internal extension using this key identity") add_custom_target(icons ALL COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns @@ -79,11 +78,8 @@ if(APPLE) add_dependencies(lokinet icons lokinet-extension) add_custom_command(TARGET lokinet POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo "setting rpath" - COMMAND ${CMAKE_COMMAND} -E echo ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ - COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ - COMMAND mkdir -p $/Contents/Frameworks - COMMAND cp -au $ $/Contents/Frameworks/ + COMMAND mkdir -p $/Contents/PlugIns + COMMAND cp -au $ $/Contents/PlugIns/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile $/Contents/embedded.provisionprofile ) @@ -100,8 +96,8 @@ if(APPLE) MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") - if (CODESIGN_KEY) - message(STATUS "codesigning with ${CODESIGN_KEY}") + if (CODESIGN_APP AND CODESIGN_DEV) + message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_DEV} (appex)") set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" @@ -113,7 +109,7 @@ if(APPLE) COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() - message(WARNING "Not codesigning: CODESIGN_KEY is not set") + message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_DEV (=${CODESIGN_DEV}) are not set") endif() endif() diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index b80c01227..564cbf62a 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -36,13 +36,16 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } let providerProtocol = NETunnelProviderProtocol() - providerProtocol.serverAddress = "" + providerProtocol.serverAddress = "loki.loki" // Needs to be set to some non-null dummy value providerProtocol.username = "anonymous" providerProtocol.providerBundleIdentifier = self.lokinetComponent - providerProtocol.includeAllNetworks = 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. + providerProtocol.includeAllNetworks = false self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true self.vpnManager.isOnDemandEnabled = true + self.vpnManager.localizedDescription = "lokinet" self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { NSLog("Error saving to preferences") diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index ba47b0e68..a07c8b70d 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -273,28 +273,28 @@ if(APPLE) find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) - add_library(lokinet-extension SHARED - framework.mm) + add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) target_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) set_target_properties(lokinet-extension PROPERTIES - FRAMEWORK TRUE - FRAMEWORK_VERSION ${lokinet_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER com.loki-project.lokinet.network-extension - MACOSX_FRAMEWORK_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - # "current version" in semantic format in Mach-O binary file - VERSION ${lokinet_VERSION} - # "compatibility version" in semantic format in Mach-O binary file - SOVERSION ${lokinet_VERSION} - PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + 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 + ) + + # Not sure what -fapplication-extension does, but XCode puts it in so... + # -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. + target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) + target_compile_options(lokinet-extension PRIVATE -fapplication-extension) add_custom_command(TARGET lokinet-extension POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile - $/Versions/Current/embedded.provisionprofile + $/Contents/embedded.provisionprofile ) diff --git a/llarp/framework.mm b/llarp/framework.mm index 032c2424a..32cde8978 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -186,6 +186,7 @@ StringViewToData(std::string_view data) - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { + NSLog(@"OMG startTunnelWithOptions"); m_Context = new ContextWrapper{self}; m_Context->Start(); [self setTunnelNetworkSettings:nullptr completionHandler:completionHandler]; @@ -194,6 +195,7 @@ StringViewToData(std::string_view data) - (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler { + NSLog(@"STOP TUNNEL"); if (m_Context) { m_Context->Stop(); From 81d27c35c16893368109693fc0029fc8586a4570 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 29 Jul 2021 14:26:12 -0300 Subject: [PATCH 36/81] Default CODESIGN_APPEX to CODESIGN_APP Sometimes (e.g. dev builds) these can apparently be the same; sometimes it seems they need to be different, because Apple. --- contrib/mac.sh | 17 ++++++++++++++--- contrib/macos/sign.sh.in | 2 +- daemon/CMakeLists.txt | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/contrib/mac.sh b/contrib/mac.sh index bfbaf712b..38070ba96 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -1,11 +1,18 @@ #!/bin/bash # -# build the shit on mac -# t. jeff +# Build the shit on mac +# +# You will generally need to add: -DCODESIGN_APP=... to make this work, and (unless you are a +# lokinet team member) will need to pay Apple money for your own team ID and arse around with +# provisioning profiles. See macos/README.txt. # set -e set +x +if ! [ -f LICENSE.txt ] || ! [ -d llarp ]; then + echo "You need to run this as ./contrib/mac.sh from the top-level lokinet project directory" +fi + mkdir -p build-mac cd build-mac cmake \ @@ -25,4 +32,8 @@ cmake \ -DCMAKE_BUILD_TYPE=Release \ "$@" \ .. -ninja install && ninja sign +ninja sign + +echo -e "Build complete, your app is here:\n" +ls -lad daemon/lokinet.app +echo "" diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index b05a06e2a..6ebf0859a 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -e -codesign --verbose=4 --force -s "@CODESIGN_DEV@" \ +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 diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index cd9e9c200..10f509bbc 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -70,7 +70,7 @@ endforeach() if(APPLE) set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity") - set(CODESIGN_DEV "" CACHE STRING "codesign the internal extension using this key identity") + set(CODESIGN_APPEX "${CODESIGN_APP}" CACHE STRING "codesign the internal extension using this key identity; defaults to CODESIGN_APP if empty") add_custom_target(icons ALL COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns @@ -96,8 +96,8 @@ if(APPLE) MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") - if (CODESIGN_APP AND CODESIGN_DEV) - message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_DEV} (appex)") + if (CODESIGN_APP AND CODESIGN_APPEX) + message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_APPEX} (appex)") set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" @@ -109,7 +109,7 @@ if(APPLE) COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() - message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_DEV (=${CODESIGN_DEV}) are not set") + message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_APPEX (=${CODESIGN_APPEX}) are not set") endif() endif() From 7db24594690b56485f7bed45a03d6c0d72a4906c Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 29 Jul 2021 16:40:25 -0400 Subject: [PATCH 37/81] macos sort of works now --- CMakeLists.txt | 2 +- contrib/macos/LokinetDNSProxy.Info.plist.in | 40 +++++ .../macos/lokinet-dnsproxy.entitlements.plist | 29 ++++ .../macos/lokinet-dnsproxy.provisionprofile | Bin 0 -> 17128 bytes contrib/macos/lokinet.entitlements.plist | 9 + contrib/macos/sign.sh.in | 3 + daemon/CMakeLists.txt | 17 +- daemon/lokinet.swift | 72 +++++++- include/lokinet-dnsproxy.hpp | 19 +++ llarp/CMakeLists.txt | 42 ++++- llarp/apple.hpp | 40 +++++ llarp/config/config.cpp | 1 - llarp/dns/message.cpp | 27 +++ llarp/dns/message.hpp | 9 +- llarp/dns/question.cpp | 14 ++ llarp/dns/question.hpp | 6 + llarp/dns/rr.cpp | 19 +++ llarp/dns/rr.hpp | 5 + llarp/dns/serialize.hpp | 6 +- llarp/dnsproxy.mm | 154 ++++++++++++++++++ llarp/ev/ev_libuv.cpp | 4 +- llarp/framework.mm | 123 +++++++++----- llarp/handlers/tun.cpp | 2 +- llarp/rpc/rpc_server.cpp | 42 +++++ 24 files changed, 619 insertions(+), 66 deletions(-) create mode 100644 contrib/macos/LokinetDNSProxy.Info.plist.in create mode 100644 contrib/macos/lokinet-dnsproxy.entitlements.plist create mode 100644 contrib/macos/lokinet-dnsproxy.provisionprofile create mode 100644 include/lokinet-dnsproxy.hpp create mode 100644 llarp/apple.hpp create mode 100644 llarp/dnsproxy.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a72a1b8c..af550c638 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)") set(LANGS ASM C CXX) if(APPLE) diff --git a/contrib/macos/LokinetDNSProxy.Info.plist.in b/contrib/macos/LokinetDNSProxy.Info.plist.in new file mode 100644 index 000000000..522b476ec --- /dev/null +++ b/contrib/macos/LokinetDNSProxy.Info.plist.in @@ -0,0 +1,40 @@ + + + + + CFBundleDisplayName + Lokinet + + CFBundleExecutable + lokinet-dnsproxy + + CFBundleIdentifier + com.loki-project.lokinet.dns-proxy + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundlePackageType + XPC! + + CFBundleName + lokinet + + CFBundleVersion + @LOKINET_VERSION@ + + ITSAppUsesNonExemptEncryption + + + LSMinimumSystemVersion + 11.0 + + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.dns-proxy + NSExtensionPrincipalClass + DNSProvider + + + diff --git a/contrib/macos/lokinet-dnsproxy.entitlements.plist b/contrib/macos/lokinet-dnsproxy.entitlements.plist new file mode 100644 index 000000000..fa43bbd2b --- /dev/null +++ b/contrib/macos/lokinet-dnsproxy.entitlements.plist @@ -0,0 +1,29 @@ + + + + + com.apple.application-identifier + SUQ8J2PCT7.com.loki-project.lokinet.dns-proxy + + com.apple.developer.networking.networkextension + + dns-proxy + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + com.apple.security.app-sandbox + + + com.apple.security.get-task-allow + + + com.apple.security.network.client + + + com.apple.security.network.server + + + + diff --git a/contrib/macos/lokinet-dnsproxy.provisionprofile b/contrib/macos/lokinet-dnsproxy.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..87cd403bb4919366f2e767f28b38cb0f168a60c0 GIT binary patch literal 17128 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 Z?Z9=CJE$b@rw5OI`eOO=&%e0*zX6(qnR);K literal 0 HcmV?d00001 diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist index 155d265ba..3869f5b04 100644 --- a/contrib/macos/lokinet.entitlements.plist +++ b/contrib/macos/lokinet.entitlements.plist @@ -8,6 +8,8 @@ com.apple.developer.networking.networkextension packet-tunnel-provider + dns-proxy + dns-settings com.apple.developer.team-identifier @@ -18,5 +20,12 @@ com.apple.security.get-task-allow + + com.apple.security.network.client + + + com.apple.security.network.server + + diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index 6ebf0859a..af3d18d55 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -3,6 +3,9 @@ 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" +codesign --verbose=4 --force -s "@CODESIGN_APPEX@" \ + --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-dnsproxy.entitlements.plist" \ + --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/PlugIns/lokinet-dnsproxy.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" \ diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 10f509bbc..ac0598f74 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,14 +1,17 @@ + +add_executable(lokinet-vpn lokinet-vpn.cpp) if(APPLE) set(LOKINET_SWIFT_SOURCES lokinet.swift) add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) else() add_executable(lokinet lokinet.cpp) - add_executable(lokinet-vpn lokinet-vpn.cpp) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) enable_lto(lokinet lokinet-vpn lokinet-bootstrap) endif() + if(TRACY_ROOT) target_sources(lokinet PRIVATE ${TRACY_ROOT}/TracyClient.cpp) endif() @@ -38,9 +41,9 @@ if(NOT APPLE) endif() endif() -set(exetargets lokinet) +set(exetargets lokinet lokinet-vpn) if(NOT APPLE) - list(APPEND exetargets lokinet-vpn lokinet-bootstrap) + list(APPEND exetargets lokinet-bootstrap) endif() foreach(exe ${exetargets}) @@ -76,10 +79,14 @@ if(APPLE) COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) add_dependencies(lokinet icons lokinet-extension) + file(DOWNLOAD "https://seed.lokinet.org/lokinet.signed" ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.signed) add_custom_command(TARGET lokinet POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.signed + $/Contents/Resources/bootstrap.signed COMMAND mkdir -p $/Contents/PlugIns - COMMAND cp -au $ $/Contents/PlugIns/ + COMMAND cp -a $ $/Contents/PlugIns/ + COMMAND cp -a $ $/Contents/PlugIns/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile $/Contents/embedded.provisionprofile ) @@ -105,7 +112,7 @@ if(APPLE) @ONLY) add_custom_target( sign - DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension lokinet-dnsproxy COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 564cbf62a..a12c1da79 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -8,7 +8,7 @@ let app = NSApplication.shared class LokinetMain: NSObject, NSApplicationDelegate { var vpnManager = NETunnelProviderManager() let lokinetComponent = "com.loki-project.lokinet.network-extension" - var lokinetAdminTimer: DispatchSourceTimer? + var dnsComponent = "com.loki-project.lokinet.dns-proxy" func applicationDidFinishLaunching(_: Notification) { setupVPNJizz() @@ -18,12 +18,67 @@ class LokinetMain: NSObject, NSApplicationDelegate { app.terminate(self) } + func setupDNSJizz() { + NSLog("setting up dns settings") + let dns = NEDNSSettingsManager.shared() + let settings = NEDNSSettings(servers: ["172.16.0.1"]) + dns.dnsSettings = settings + dns.loadFromPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + dns.saveToPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + NSLog("dns setting set up probably") + } + } + } + + func setupDNSProxyJizz() { + NSLog("setting up dns proxy") + let dns = NEDNSProxyManager.shared() + let provider = NEDNSProxyProviderProtocol() + provider.providerBundleIdentifier = dnsComponent + provider.username = "Anonymous" + provider.serverAddress = "loki.loki" + provider.includeAllNetworks = true + provider.enforceRoutes = true + dns.providerProtocol = provider + dns.localizedDescription = "lokinet dns" + dns.loadFromPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + provider.includeAllNetworks = true + provider.enforceRoutes = true + dns.isEnabled = true + dns.saveToPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + self.initDNSObserver() + NSLog("dns is up probably") + } + } + } + func setupVPNJizz() { NSLog("Starting up lokinet") NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in if let error = error { NSLog(error.localizedDescription) bail() + return } if let savedManagers = savedManagers { @@ -44,7 +99,10 @@ class LokinetMain: NSObject, NSApplicationDelegate { providerProtocol.includeAllNetworks = false self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true - self.vpnManager.isOnDemandEnabled = true + // self.vpnManager.isOnDemandEnabled = true + let rules = NEAppRule() + rules.matchDomains = ["*.snode", "*.loki"] + self.vpnManager.appRules = [rules] self.vpnManager.localizedDescription = "lokinet" self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { @@ -76,6 +134,13 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } + func initDNSObserver() { + NotificationCenter.default.addObserver(forName: NSNotification.Name.NEDNSProxyConfigurationDidChange, object: NEDNSProxyManager.shared(), queue: OperationQueue.main) { _ -> Void in + let dns = NEDNSProxyManager.shared() + NSLog("%@", dns) + } + } + func initializeConnectionObserver() { NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in if self.vpnManager.connection.status == .invalid { @@ -88,6 +153,9 @@ class LokinetMain: NSObject, NSApplicationDelegate { NSLog("VPN is reasserting...") } else if self.vpnManager.connection.status == .disconnecting { NSLog("VPN is disconnecting...") + } else if self.vpnManager.connection.status == .connected { + NSLog("VPN Connected") + self.setupDNSJizz() } } } diff --git a/include/lokinet-dnsproxy.hpp b/include/lokinet-dnsproxy.hpp new file mode 100644 index 000000000..8f0545090 --- /dev/null +++ b/include/lokinet-dnsproxy.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +struct DNSImpl; + +@interface DNSProvider : NEDNSProxyProvider +{ + struct DNSImpl* m_Impl; +} +- (void)startProxyWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)stopProxyWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler; + +- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow; + +@end diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index a07c8b70d..ca7e25867 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -1,14 +1,12 @@ include(Version) -add_library(lokinet-util - STATIC +set(lokinet_util_src ${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp util/bencode.cpp util/buffer.cpp util/fs.cpp util/json.cpp util/logging/android_logger.cpp - util/logging/apple_logger.mm util/logging/buffer.cpp util/logging/file_logger.cpp util/logging/json_logger.cpp @@ -24,8 +22,18 @@ add_library(lokinet-util util/str.cpp util/thread/queue_manager.cpp util/thread/threading.cpp - util/time.cpp -) + util/time.cpp) + +if(APPLE) + list(APPEND lokinet_util_src + util/logging/apple_logger.mm) +endif() + + +add_library(lokinet-util + STATIC + ${lokinet_util_src}) + add_dependencies(lokinet-util genversion) target_include_directories(lokinet-util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}) @@ -274,11 +282,16 @@ if(APPLE) find_library(COREFOUNDATION CoreFoundation REQUIRED) add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) + add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) target_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) - + target_link_libraries(lokinet-dnsproxy PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) + set_target_properties(lokinet-extension PROPERTIES BUNDLE TRUE BUNDLE_EXTENSION appex @@ -289,7 +302,7 @@ if(APPLE) # Not sure what -fapplication-extension does, but XCode puts it in so... # -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) - target_compile_options(lokinet-extension PRIVATE -fapplication-extension) + target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) add_custom_command(TARGET lokinet-extension POST_BUILD @@ -297,6 +310,21 @@ if(APPLE) $/Contents/embedded.provisionprofile ) + set_target_properties(lokinet-dnsproxy PROPERTIES + BUNDLE TRUE + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + ) + + target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) + target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) + + add_custom_command(TARGET lokinet-dnsproxy + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile + $/Contents/embedded.provisionprofile + ) endif() diff --git a/llarp/apple.hpp b/llarp/apple.hpp new file mode 100644 index 000000000..dc35a9d95 --- /dev/null +++ b/llarp/apple.hpp @@ -0,0 +1,40 @@ +#pragma once +#ifdef __APPLE__ +#include +#include +#include + +static std::string_view +DataAsStringView(NSData* data) +{ + return std::string_view{reinterpret_cast(data.bytes), data.length}; +} + +static NSData* +StringViewToData(std::string_view data) +{ + const char* ptr = data.data(); + const size_t sz = data.size(); + return [NSData dataWithBytes:ptr length:sz]; +} + +static NSString* +StringToNSString(std::string data) +{ + NSData* ptr = StringViewToData(std::string_view{data}); + return [[NSString alloc] initWithData:ptr encoding:NSUTF8StringEncoding]; +} + +static std::string +NSStringToString(NSString* str) +{ + return std::string{[str UTF8String]}; +} + +static std::string +NSObjectToString(NSObject* obj) +{ + return NSStringToString([NSString stringWithFormat:@"%@", obj]); +} + +#endif diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 3542e9326..c10893dc8 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1453,7 +1453,6 @@ namespace llarp auto config = std::make_shared(fs::path{}); config->Load(); config->logging.m_logLevel = eLogInfo; - config->api.m_enableRPCServer = false; config->network.m_saveProfiles = false; config->bootstrap.files.clear(); return config; diff --git a/llarp/dns/message.cpp b/llarp/dns/message.cpp index 99ffed763..f10e9b9c6 100644 --- a/llarp/dns/message.cpp +++ b/llarp/dns/message.cpp @@ -48,6 +48,12 @@ namespace llarp return true; } + util::StatusObject + MessageHeader::ToJSON() const + { + return util::StatusObject{}; + } + Message::Message(Message&& other) : hdr_id(std::move(other.hdr_id)) , hdr_fields(std::move(other.hdr_fields)) @@ -74,6 +80,11 @@ namespace llarp additional.resize(size_t(hdr.ar_count)); } + Message::Message(const Question& question) : hdr_id{0}, hdr_fields{} + { + questions.emplace_back(question); + } + bool Message::Encode(llarp_buffer_t* buf) const { @@ -122,6 +133,22 @@ namespace llarp return true; } + util::StatusObject + Message::ToJSON() const + { + std::vector ques; + std::vector ans; + for (const auto& q : questions) + { + ques.push_back(q.ToJSON()); + } + for (const auto& a : answers) + { + ans.push_back(a.ToJSON()); + } + return util::StatusObject{{"questions", ques}, {"answers", ans}}; + } + OwnedBuffer Message::ToBuffer() const { diff --git a/llarp/dns/message.hpp b/llarp/dns/message.hpp index b7d4571b1..937c37d97 100644 --- a/llarp/dns/message.hpp +++ b/llarp/dns/message.hpp @@ -33,6 +33,9 @@ namespace llarp bool Decode(llarp_buffer_t* buf) override; + util::StatusObject + ToJSON() const override; + bool operator==(const MessageHeader& other) const { @@ -44,11 +47,15 @@ namespace llarp struct Message : public Serialize { - Message(const MessageHeader& hdr); + explicit Message(const MessageHeader& hdr); + explicit Message(const Question& question); Message(Message&& other); Message(const Message& other); + util::StatusObject + ToJSON() const override; + void AddNXReply(RR_TTL_t ttl = 1); diff --git a/llarp/dns/question.cpp b/llarp/dns/question.cpp index 7ec066c30..a8c60c260 100644 --- a/llarp/dns/question.cpp +++ b/llarp/dns/question.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "dns.hpp" namespace llarp { @@ -17,6 +18,13 @@ namespace llarp : qname(other.qname), qtype(other.qtype), qclass(other.qclass) {} + Question::Question(std::string name, QType_t type) + : qname{std::move(name)}, qtype{type}, qclass{qClassIN} + { + if (qname.empty()) + throw std::invalid_argument{"qname cannot be empty"}; + } + bool Question::Encode(llarp_buffer_t* buf) const { @@ -48,6 +56,12 @@ namespace llarp return true; } + util::StatusObject + Question::ToJSON() const + { + return util::StatusObject{{"qname", qname}, {"qtype", qtype}, {"qclass", qclass}}; + } + bool Question::IsName(const std::string& other) const { diff --git a/llarp/dns/question.hpp b/llarp/dns/question.hpp index f2fc00076..5434bbcdd 100644 --- a/llarp/dns/question.hpp +++ b/llarp/dns/question.hpp @@ -14,6 +14,9 @@ namespace llarp struct Question : public Serialize { Question() = default; + + explicit Question(std::string name, QType_t type); + Question(Question&& other); Question(const Question& other); bool @@ -58,6 +61,9 @@ namespace llarp /// determine if we are using this TLD bool HasTLD(const std::string& tld) const; + + util::StatusObject + ToJSON() const override; }; inline std::ostream& diff --git a/llarp/dns/rr.cpp b/llarp/dns/rr.cpp index 3fac87e9b..82ed20470 100644 --- a/llarp/dns/rr.cpp +++ b/llarp/dns/rr.cpp @@ -24,6 +24,14 @@ namespace llarp , rData(std::move(other.rData)) {} + ResourceRecord::ResourceRecord(Name_t name, RRType_t type, RR_RData_t data) + : rr_name{std::move(name)} + , rr_type{type} + , rr_class{qClassIN} + , ttl{1} + , rData{std::move(data)} + {} + bool ResourceRecord::Encode(llarp_buffer_t* buf) const { @@ -77,6 +85,17 @@ namespace llarp return true; } + util::StatusObject + ResourceRecord::ToJSON() const + { + return util::StatusObject{ + {"name", rr_name}, + {"type", rr_type}, + {"class", rr_class}, + {"ttl", ttl}, + {"rdata", std::string{reinterpret_cast(rData.data()), rData.size()}}}; + } + std::ostream& ResourceRecord::print(std::ostream& stream, int level, int spaces) const { diff --git a/llarp/dns/rr.hpp b/llarp/dns/rr.hpp index 0b50235da..e9fa72c27 100644 --- a/llarp/dns/rr.hpp +++ b/llarp/dns/rr.hpp @@ -22,12 +22,17 @@ namespace llarp ResourceRecord(const ResourceRecord& other); ResourceRecord(ResourceRecord&& other); + explicit ResourceRecord(Name_t name, RRType_t type, RR_RData_t rdata); + bool Encode(llarp_buffer_t* buf) const override; bool Decode(llarp_buffer_t* buf) override; + util::StatusObject + ToJSON() const override; + std::ostream& print(std::ostream& stream, int level, int spaces) const; diff --git a/llarp/dns/serialize.hpp b/llarp/dns/serialize.hpp index 8834de04c..94388362a 100644 --- a/llarp/dns/serialize.hpp +++ b/llarp/dns/serialize.hpp @@ -1,7 +1,7 @@ #pragma once #include - +#include #include namespace llarp @@ -20,6 +20,10 @@ namespace llarp /// decode entity from buffer virtual bool Decode(llarp_buffer_t* buf) = 0; + + /// convert this whatever into json + virtual util::StatusObject + ToJSON() const = 0; }; bool diff --git a/llarp/dnsproxy.mm b/llarp/dnsproxy.mm new file mode 100644 index 000000000..56663118c --- /dev/null +++ b/llarp/dnsproxy.mm @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +struct DNSImpl +{ + oxenmq::OxenMQ m_MQ; + std::optional m_Conn; + + explicit DNSImpl(oxenmq::address rpc) + { + m_MQ.start(); + m_MQ.connect_remote( + rpc, [this](auto conn) { m_Conn = conn; }, nullptr); + } + + bool + ShouldHookFlow(NEAppProxyFlow* flow) const + { + LogInfo(NSObjectToString(flow)); + return true; + } + + void + RelayDNSData(NEAppProxyUDPFlow* flow, NWEndpoint* remote, NSData* data) + { + if (not m_Conn) + return; + auto view = DataAsStringView(data); + + llarp_buffer_t buf{view}; + llarp::dns::MessageHeader hdr{}; + if (not hdr.Decode(&buf)) + return; + llarp::dns::Message msg{hdr}; + if (not msg.Decode(&buf)) + return; + llarp::util::StatusObject request{ + {"qname", msg.questions[0].qname}, {"qtype", msg.questions[0].qtype}}; + m_MQ.request( + *m_Conn, + "llarp.dns_query", + [flow, remote, msg = std::make_shared(std::move(msg))]( + bool good, std::vector parts) { + auto closeHandler = [flow](NSError* err) { + [flow closeWriteWithError:err]; + [flow closeReadWithError:err]; + }; + if (good and parts.size() == 1) + { + try + { + const auto obj = nlohmann::json::parse(parts[0]); + const auto result = obj["result"]; + if (const auto itr = result.find("answers"); itr != result.end()) + { + for (const auto& result : (*itr)) + { + llarp::dns::RR_RData_t rdata; + if (const auto data_itr = result.find("rdata"); data_itr != result.end()) + { + const auto data = data_itr->get(); + rdata.resize(data.size()); + std::copy_n(data.begin(), data.size(), rdata.begin()); + } + else + continue; + + msg->answers.emplace_back( + result["name"].get(), + result["type"].get(), + rdata); + } + } + } + catch (std::exception& ex) + { + LogError("dns query failed: ", ex.what()); + return; + } + const auto buf = msg->ToBuffer(); + NSData* data = StringViewToData( + std::string_view{reinterpret_cast(buf.buf.get()), buf.sz}); + [flow writeDatagrams:@[data] sentByEndpoints:@[remote] completionHandler:closeHandler]; + } + else + closeHandler(nullptr); + }, + request.dump()); + } + + void + HandleUDPFlow(NEAppProxyUDPFlow* flow) + { + auto handler = + [this, flow]( + NSArray* datagrams, NSArray* remoteEndpoints, NSError* error) { + if (error) + return; + NSInteger num = [datagrams count]; + for (NSInteger idx = 0; idx < num; ++idx) + { + RelayDNSData(flow, [remoteEndpoints objectAtIndex:idx], [datagrams objectAtIndex:idx]); + } + }; + [flow readDatagramsWithCompletionHandler:handler]; + } +}; + +@implementation DNSProvider + +- (void)startProxyWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler +{ + m_Impl = new DNSImpl{oxenmq::address{"tcp://127.0.0.1:1190"}}; + completionHandler(nil); +} + +- (void)stopProxyWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler +{ + if (m_Impl) + { + delete m_Impl; + m_Impl = nullptr; + } + completionHandler(); +} + +- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow +{ + if (not [flow isKindOfClass:[NEAppProxyUDPFlow class]]) + return NO; + if (m_Impl->ShouldHookFlow(flow)) + { + NEAppProxyUDPFlow* udp = (NEAppProxyUDPFlow*)flow; + auto handler = [impl = m_Impl, udp](NSError* err) { + if (err) + return; + impl->HandleUDPFlow(udp); + }; + [flow openWithLocalEndpoint:nil completionHandler:handler]; + return YES; + } + return NO; +} + +@end diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index f9ce3c4b4..8f38750c1 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -244,7 +244,7 @@ namespace llarp::uv std::shared_ptr netif, std::function handler) { -#ifndef _WIN32 +#ifdef __linux__ using event_t = uvw::PollEvent; auto handle = m_Impl->resource(netif->PollFD()); #else @@ -264,7 +264,7 @@ namespace llarp::uv } }); -#ifndef _WIN32 +#ifdef __linux__ handle->start(uvw::PollHandle::Event::READABLE); #else handle->start(); diff --git a/llarp/framework.mm b/llarp/framework.mm index 32cde8978..f0e2b1521 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -5,8 +5,13 @@ #include #include #include +#include +#include +#include +#include -#include +const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"}; +const llarp::SockAddr DefaultUpstreamDNS{"9.9.9.9:53"}; namespace llarp::apple { @@ -21,7 +26,7 @@ namespace llarp::apple makeVPNPlatform() override; void - Start(); + Start(std::string_view bootstrap); private: NEPacketTunnelProvider* const m_Tunnel; @@ -42,20 +47,39 @@ namespace llarp::apple llarp::net::IPPacket pkt; const llarp_buffer_t buf{static_cast(data.bytes), data.length}; if (pkt.Load(buf)) + { m_ReadQueue.tryPushBack(std::move(pkt)); + } + else + { + LogError("invalid IP packet: ", llarp::buffer_printer(DataAsStringView(data))); + } } public: - explicit VPNInterface(NEPacketTunnelProvider* tunnel) + explicit VPNInterface(NEPacketTunnelProvider* tunnel, llarp::Context* context) : m_Tunnel{tunnel}, m_ReadQueue{PacketQueueSize} { - auto handler = [this](NSArray* packets, NSArray*) { - NSUInteger num = [packets count]; - for (NSUInteger idx = 0; idx < num; ++idx) - { - NSData* pkt = [packets objectAtIndex:idx]; - OfferReadPacket(pkt); - } + context->loop->call_soon([this]() { Read(); }); + } + + void + HandleReadEvent(NSArray* packets, NSArray* protos) + { + NSUInteger num = [packets count]; + for (NSUInteger idx = 0; idx < num; ++idx) + { + NSData* pkt = [packets objectAtIndex:idx]; + OfferReadPacket(pkt); + } + Read(); + } + + void + Read() + { + auto handler = [this](NSArray* packets, NSArray* protos) { + HandleReadEvent(packets, protos); }; [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; } @@ -84,27 +108,27 @@ namespace llarp::apple bool WritePacket(net::IPPacket pkt) override { - const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET; - const uint8_t* pktbuf = pkt.buf; + NSNumber* fam = [NSNumber numberWithInteger:(pkt.IsV6() ? AF_INET6 : AF_INET)]; + void* pktbuf = pkt.buf; const size_t pktsz = pkt.sz; - NSData* datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; - NEPacket* npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; - NSArray* pkts = @[npkt]; - return [m_Tunnel.packetFlow writePacketObjects:pkts]; + NSData* datapkt = [NSData dataWithBytesNoCopy:pktbuf length:pktsz]; + return [m_Tunnel.packetFlow writePackets:@[datapkt] withProtocols:@[fam]]; } }; class VPNPlatform final : public vpn::Platform { NEPacketTunnelProvider* const m_Tunnel; + Context* const m_Context; public: - explicit VPNPlatform(NEPacketTunnelProvider* tunnel) : m_Tunnel{tunnel} + explicit VPNPlatform(NEPacketTunnelProvider* tunnel, Context* context) + : m_Tunnel{tunnel}, m_Context{context} {} std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override { - return std::make_shared(m_Tunnel); + return std::make_shared(m_Tunnel, m_Context); } }; @@ -113,16 +137,20 @@ namespace llarp::apple {} void - FrameworkContext::Start() + FrameworkContext::Start(std::string_view bootstrap) { std::promise result; - m_Runner = std::make_unique([&result, this]() { + m_Runner = std::make_unique([&result, bootstrap = std::string{bootstrap}, this]() { const RuntimeOptions opts{}; try { + auto config = llarp::Config::NetworkExtensionConfig(); + config->bootstrap.files.emplace_back(bootstrap); + config->dns.m_bind = DefaultDNSBind; + config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); + Configure(std::move(config)); Setup(opts); - Configure(llarp::Config::NetworkExtensionConfig()); } catch (std::exception&) { @@ -140,7 +168,7 @@ namespace llarp::apple std::shared_ptr FrameworkContext::makeVPNPlatform() { - return std::make_shared(m_Tunnel); + return std::make_shared(m_Tunnel, this); } } @@ -154,9 +182,10 @@ struct ContextWrapper {} void - Start() + Start(std::string_view bootstrap) { - m_Context->Start(); + llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); + m_Context->Start(std::move(bootstrap)); } void @@ -167,35 +196,42 @@ struct ContextWrapper } }; -static std::string_view -DataAsStringView(NSData* data) -{ - return std::string_view{reinterpret_cast(data.bytes), data.length}; -} - -static NSData* -StringViewToData(std::string_view data) -{ - const char* ptr = data.data(); - const size_t sz = data.size(); - return [NSData dataWithBytes:ptr length:sz]; -} - @implementation LLARPPacketTunnel - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { - NSLog(@"OMG startTunnelWithOptions"); + llarp::huint32_t addr_{}; + llarp::huint32_t mask_{}; + if (auto maybe = llarp::FindFreeRange()) + { + addr_ = llarp::net::TruncateV6(maybe->addr); + mask_ = llarp::net::TruncateV6(maybe->netmask_bits); + } + NSString* addr = StringToNSString(addr_.ToString()); + NSString* mask = StringToNSString(mask_.ToString()); + + NSBundle* main = [NSBundle mainBundle]; + NSString* res = [main pathForResource:@"bootstrap" ofType:@"signed"]; + NSData* path = [res dataUsingEncoding:NSUTF8StringEncoding]; + m_Context = new ContextWrapper{self}; - m_Context->Start(); - [self setTunnelNetworkSettings:nullptr completionHandler:completionHandler]; + m_Context->Start(DataAsStringView(path)); + + NEPacketTunnelNetworkSettings* settings = + [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[addr]]; + NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[addr] + subnetMasks:@[@"255.255.255.255"]]; + ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; + settings.IPv4Settings = ipv4; + settings.DNSSettings = dns; + [self setTunnelNetworkSettings:settings completionHandler:completionHandler]; } - (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler { - NSLog(@"STOP TUNNEL"); if (m_Context) { m_Context->Stop(); @@ -209,9 +245,6 @@ StringViewToData(std::string_view data) completionHandler:(void (^)(NSData* responseData))completionHandler { const auto data = DataAsStringView(messageData); - LogInfo("app message: ", data); - completionHandler(StringViewToData("ok")); } - @end diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 81a02fad3..8da523b22 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -74,7 +74,7 @@ namespace llarp }); m_PacketRouter = std::make_unique( [this](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); }); -#ifdef ANDROID +#if defined(ANDROID) || defined(__APPLE__) 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); diff --git a/llarp/rpc/rpc_server.cpp b/llarp/rpc/rpc_server.cpp index 38045d6c4..8e880a187 100644 --- a/llarp/rpc/rpc_server.cpp +++ b/llarp/rpc/rpc_server.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace llarp::rpc { @@ -561,6 +562,47 @@ namespace llarp::rpc }); }); }) + .add_request_command( + "dns_query", + [&](oxenmq::Message& msg) { + HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) { + std::string endpoint{"default"}; + if (const auto itr = obj.find("endpoint"); itr != obj.end()) + { + endpoint = itr->get(); + } + std::string qname{}; + dns::QType_t qtype = dns::qTypeA; + if (const auto itr = obj.find("qname"); itr != obj.end()) + { + qname = itr->get(); + } + + if (const auto itr = obj.find("qtype"); itr != obj.end()) + { + qtype = itr->get(); + } + + dns::Message msg{dns::Question{qname, qtype}}; + + if (auto ep_ptr = (GetEndpointByName(r, endpoint))) + { + if (auto ep = reinterpret_cast(ep_ptr.get())) + { + if (ep->ShouldHookDNSMessage(msg)) + { + ep->HandleHookedDNSMessage(std::move(msg), [reply](dns::Message msg) { + reply(CreateJSONResponse(msg.ToJSON())); + }); + return; + } + } + reply(CreateJSONError("dns query not accepted by endpoint")); + return; + } + reply(CreateJSONError("no such endpoint for dns query")); + }); + }) .add_request_command("config", [&](oxenmq::Message& msg) { HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) { { From d24221e67a4c90e99cfd2cd3506e016e5987b39c Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Aug 2021 08:58:36 -0400 Subject: [PATCH 38/81] make ci run ./contrib/mac.sh with no codesigning --- .drone.jsonnet | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 89cfddacb..af266144b 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -197,12 +197,7 @@ local mac_builder(name, // basic system headers. WTF apple: 'export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"', 'ulimit -n 1024', // because macos sets ulimit to 256 for some reason yeah idk - 'mkdir build', - 'cd build', - 'cmake .. -DCMAKE_CXX_FLAGS=-fcolor-diagnostics -DCMAKE_BUILD_TYPE='+build_type+' ' + - (if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + cmake_extra, - 'VERBOSE=1 make -j' + jobs, - './test/testAll --use-colour yes', + './contrib/mac.sh' ] + extra_cmds, } ] From 1272a4fbe1d9a77eed354ec8bc36dec4371362a8 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Aug 2021 09:07:31 -0400 Subject: [PATCH 39/81] add dummy sign target for ci when we don't have signing keys remove static macos from ci pipeline --- .drone.jsonnet | 5 ----- contrib/mac.sh | 2 +- daemon/CMakeLists.txt | 4 ++++ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index af266144b..e33d98612 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -275,9 +275,4 @@ local mac_builder(name, // Macos builds: mac_builder('macOS (Release)'), mac_builder('macOS (Debug)', build_type='Debug'), - mac_builder('macOS (Static)', cmake_extra='-DBUILD_STATIC_DEPS=ON -DBUILD_SHARED_LIBS=OFF -DSTATIC_LINK=ON -DDOWNLOAD_SODIUM=FORCE -DDOWNLOAD_CURL=FORCE -DDOWNLOAD_UV=FORCE', - extra_cmds=[ - '../contrib/ci/drone-check-static-libs.sh', - '../contrib/ci/drone-static-upload.sh' - ]), ] diff --git a/contrib/mac.sh b/contrib/mac.sh index 38070ba96..548c9f8b2 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -35,5 +35,5 @@ cmake \ ninja sign echo -e "Build complete, your app is here:\n" -ls -lad daemon/lokinet.app +ls -lad $(pwd)/daemon/lokinet.app echo "" diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index ac0598f74..dae44608f 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -117,6 +117,10 @@ if(APPLE) ) else() message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_APPEX (=${CODESIGN_APPEX}) are not set") + add_custom_target( + sign + DEPENDS lokinet lokinet-extension lokinet-dnsproxy + COMMAND "true") endif() endif() From deb0a982be653d60da31587bb137c1228a3fbfac Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Aug 2021 10:55:53 -0400 Subject: [PATCH 40/81] it works --- daemon/lokinet.swift | 5 +++- llarp/config/config.cpp | 4 +-- llarp/config/config.hpp | 2 +- llarp/context.cpp | 4 +-- llarp/framework.mm | 62 ++++++++++++++++++++++++----------------- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index a12c1da79..9ebf76940 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -22,6 +22,9 @@ class LokinetMain: NSObject, NSApplicationDelegate { NSLog("setting up dns settings") let dns = NEDNSSettingsManager.shared() let settings = NEDNSSettings(servers: ["172.16.0.1"]) + settings.matchDomains = ["*.loki", "*.snode"] + settings.matchDomainsNoSearch = true + settings.domainName = "localhost.loki" dns.dnsSettings = settings dns.loadFromPreferences { [self] (error: Error?) -> Void in if let error = error { @@ -94,6 +97,7 @@ class LokinetMain: NSObject, NSApplicationDelegate { providerProtocol.serverAddress = "loki.loki" // Needs to be set to some non-null dummy value providerProtocol.username = "anonymous" providerProtocol.providerBundleIdentifier = self.lokinetComponent + 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. providerProtocol.includeAllNetworks = false @@ -155,7 +159,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { NSLog("VPN is disconnecting...") } else if self.vpnManager.connection.status == .connected { NSLog("VPN Connected") - self.setupDNSJizz() } } } diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index c10893dc8..caae01abf 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1448,13 +1448,13 @@ namespace llarp #ifdef __APPLE__ std::shared_ptr - Config::NetworkExtensionConfig() + Config::NetworkExtensionConfig(std::string exit) { auto config = std::make_shared(fs::path{}); config->Load(); config->logging.m_logLevel = eLogInfo; - config->network.m_saveProfiles = false; config->bootstrap.files.clear(); + config->network.m_LNSExitMap.Insert(IPRange{}, exit); return config; } #endif diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 35360aeb8..994725e02 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -262,7 +262,7 @@ namespace llarp #ifdef __APPLE__ static std::shared_ptr - NetworkExtensionConfig(); + NetworkExtensionConfig(std::string exit); #endif private: diff --git a/llarp/context.cpp b/llarp/context.cpp index 9bf260ce7..59a54dc28 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -138,8 +138,8 @@ namespace llarp if (IsStopping()) return; - if (CallSafe(std::bind(&Context::HandleSignal, this, SIGTERM))) - closeWaiter = std::make_unique>(); + loop->call([this]() { HandleSignal(SIGTERM); }); + closeWaiter = std::make_unique>(); } bool diff --git a/llarp/framework.mm b/llarp/framework.mm index f0e2b1521..af427a532 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -26,7 +26,7 @@ namespace llarp::apple makeVPNPlatform() override; void - Start(std::string_view bootstrap); + Start(std::string_view bootstrap, std::string exit); private: NEPacketTunnelProvider* const m_Tunnel; @@ -137,29 +137,30 @@ namespace llarp::apple {} void - FrameworkContext::Start(std::string_view bootstrap) + FrameworkContext::Start(std::string_view bootstrap, std::string exit) { std::promise result; - m_Runner = std::make_unique([&result, bootstrap = std::string{bootstrap}, this]() { - const RuntimeOptions opts{}; - try - { - auto config = llarp::Config::NetworkExtensionConfig(); - config->bootstrap.files.emplace_back(bootstrap); - config->dns.m_bind = DefaultDNSBind; - config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); - Configure(std::move(config)); - Setup(opts); - } - catch (std::exception&) - { - result.set_exception(std::current_exception()); - return; - } - result.set_value(); - Run(opts); - }); + m_Runner = + std::make_unique([&result, bootstrap = std::string{bootstrap}, exit, this]() { + const RuntimeOptions opts{}; + try + { + auto config = llarp::Config::NetworkExtensionConfig(exit); + config->bootstrap.files.emplace_back(bootstrap); + config->dns.m_bind = DefaultDNSBind; + config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); + Configure(std::move(config)); + Setup(opts); + } + catch (std::exception&) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + Run(opts); + }); auto ftr = result.get_future(); ftr.get(); @@ -182,10 +183,10 @@ struct ContextWrapper {} void - Start(std::string_view bootstrap) + Start(std::string_view bootstrap, std::string exit) { llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); - m_Context->Start(std::move(bootstrap)); + m_Context->Start(std::move(bootstrap), std::move(exit)); } void @@ -210,20 +211,29 @@ struct ContextWrapper } NSString* addr = StringToNSString(addr_.ToString()); NSString* mask = StringToNSString(mask_.ToString()); + llarp::huint32_t dnsaddr_{addr_ & mask_}; + NSString* dnsaddr = StringToNSString(dnsaddr_.ToString()); + NSLog(@"%@", dnsaddr); NSBundle* main = [NSBundle mainBundle]; NSString* res = [main pathForResource:@"bootstrap" ofType:@"signed"]; NSData* path = [res dataUsingEncoding:NSUTF8StringEncoding]; m_Context = new ContextWrapper{self}; - m_Context->Start(DataAsStringView(path)); + m_Context->Start(DataAsStringView(path), "exit.loki"); NEPacketTunnelNetworkSettings* settings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; - NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[addr]]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]]; + dns.domainName = @"localhost.loki"; + dns.matchDomains = @[@"*.snode", @"*.loki"]; + dns.matchDomainsNoSearch = true; + dns.searchDomains = @[]; + // dns.dnsProtocol = NEDNSProtocolCleartext; NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[addr] subnetMasks:@[@"255.255.255.255"]]; - ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; + ipv4.includedRoutes = @[[NEIPv4Route defaultRoute]]; + // ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; settings.IPv4Settings = ipv4; settings.DNSSettings = dns; [self setTunnelNetworkSettings:settings completionHandler:completionHandler]; From 3f0b34e860b3654ee479f44291836bf45434f0ac Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 23 Aug 2021 12:48:55 -0300 Subject: [PATCH 41/81] Consolidate apple-specific bits into llarp/apple --- llarp/CMakeLists.txt | 66 +------------------ llarp/apple/CMakeLists.txt | 61 +++++++++++++++++ .../{util/logging => apple}/apple_logger.hpp | 6 +- llarp/{util/logging => apple}/apple_logger.mm | 4 +- llarp/{ => apple}/dnsproxy.mm | 0 llarp/{ => apple}/framework.mm | 2 +- 6 files changed, 67 insertions(+), 72 deletions(-) create mode 100644 llarp/apple/CMakeLists.txt rename llarp/{util/logging => apple}/apple_logger.hpp (91%) rename llarp/{util/logging => apple}/apple_logger.mm (93%) rename llarp/{ => apple}/dnsproxy.mm (100%) rename llarp/{ => apple}/framework.mm (99%) diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index ca7e25867..30e90b7be 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -1,6 +1,6 @@ include(Version) -set(lokinet_util_src +add_library(lokinet-util ${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp util/bencode.cpp util/buffer.cpp @@ -24,15 +24,6 @@ set(lokinet_util_src util/thread/threading.cpp util/time.cpp) -if(APPLE) - list(APPEND lokinet_util_src - util/logging/apple_logger.mm) -endif() - - -add_library(lokinet-util - STATIC - ${lokinet_util_src}) add_dependencies(lokinet-util genversion) @@ -46,11 +37,6 @@ target_link_libraries(lokinet-util PUBLIC oxenmq::oxenmq ) -if(APPLE) - find_library(FOUNDATION Foundation REQUIRED) - target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -endif() - if(ANDROID) target_link_libraries(lokinet-util PUBLIC log) endif() @@ -277,55 +263,7 @@ if(BUILD_LIBLOKINET) endif() if(APPLE) - # god made apple so that man may suffer - find_library(NETEXT NetworkExtension REQUIRED) - find_library(COREFOUNDATION CoreFoundation REQUIRED) - - add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) - add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) - target_link_libraries(lokinet-extension PUBLIC - liblokinet - ${COREFOUNDATION} - ${NETEXT}) - target_link_libraries(lokinet-dnsproxy PUBLIC - liblokinet - ${COREFOUNDATION} - ${NETEXT}) - - 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 - ) - - # Not sure what -fapplication-extension does, but XCode puts it in so... - # -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. - target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) - target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) - - 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 - ) - - set_target_properties(lokinet-dnsproxy PROPERTIES - BUNDLE TRUE - BUNDLE_EXTENSION appex - MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in - XCODE_PRODUCT_TYPE com.apple.product-type.app-extension - ) - - target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) - target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) - - add_custom_command(TARGET lokinet-dnsproxy - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile - $/Contents/embedded.provisionprofile - ) - + add_subdirectory(apple) endif() foreach(lokinet_lib liblokinet lokinet-platform lokinet-util lokinet-cryptography) diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt new file mode 100644 index 000000000..0fdea9a41 --- /dev/null +++ b/llarp/apple/CMakeLists.txt @@ -0,0 +1,61 @@ + +# 3.13+ so that we can add link libraries to parent targets +cmake_minimum_required(VERSION 3.13) + +if (BUILD_SHARED_LIBS OR NOT BUILD_STATIC_DEPS OR NOT STATIC_LINK) + message(FATAL_ERROR "macOS builds require a full static build; perhaps use the contrib/macos.sh script to build?") +endif() + +# god made apple so that man may suffer + +find_library(FOUNDATION Foundation REQUIRED) +find_library(NETEXT NetworkExtension REQUIRED) +find_library(COREFOUNDATION CoreFoundation REQUIRED) + +target_sources(lokinet-util PRIVATE apple_logger.mm) +target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) + +add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) +add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) +target_link_libraries(lokinet-extension PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) +target_link_libraries(lokinet-dnsproxy PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) + +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 + ) + +# Not sure what -fapplication-extension does, but XCode puts it in so... +# -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. +target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) +target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) + +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 + ) + +set_target_properties(lokinet-dnsproxy PROPERTIES + BUNDLE TRUE + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + ) + +target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) +target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) + +add_custom_command(TARGET lokinet-dnsproxy + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile + $/Contents/embedded.provisionprofile + ) diff --git a/llarp/util/logging/apple_logger.hpp b/llarp/apple/apple_logger.hpp similarity index 91% rename from llarp/util/logging/apple_logger.hpp rename to llarp/apple/apple_logger.hpp index 00450b391..1546392d1 100644 --- a/llarp/util/logging/apple_logger.hpp +++ b/llarp/apple/apple_logger.hpp @@ -1,6 +1,6 @@ #pragma once -#ifdef __APPLE__ -#include "logstream.hpp" + +#include namespace llarp { @@ -28,5 +28,3 @@ namespace llarp {} }; } // namespace llarp - -#endif diff --git a/llarp/util/logging/apple_logger.mm b/llarp/apple/apple_logger.mm similarity index 93% rename from llarp/util/logging/apple_logger.mm rename to llarp/apple/apple_logger.mm index e5ca746c1..52b544e58 100644 --- a/llarp/util/logging/apple_logger.mm +++ b/llarp/apple/apple_logger.mm @@ -1,6 +1,5 @@ -#ifdef __APPLE__ #include "apple_logger.hpp" -#include "logger_internal.hpp" +#include #include @@ -35,4 +34,3 @@ namespace llarp {} } // namespace llarp -#endif diff --git a/llarp/dnsproxy.mm b/llarp/apple/dnsproxy.mm similarity index 100% rename from llarp/dnsproxy.mm rename to llarp/apple/dnsproxy.mm diff --git a/llarp/framework.mm b/llarp/apple/framework.mm similarity index 99% rename from llarp/framework.mm rename to llarp/apple/framework.mm index af427a532..be7af8022 100644 --- a/llarp/framework.mm +++ b/llarp/apple/framework.mm @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include From 712b5a5608e1e2412519e815c716cd4b5b494a08 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 13:30:30 -0300 Subject: [PATCH 42/81] Tweak icns generation to only run when necessary --- daemon/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index dae44608f..65fd29fe1 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -75,9 +75,11 @@ if(APPLE) set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity") set(CODESIGN_APPEX "${CODESIGN_APP}" CACHE STRING "codesign the internal extension using this key identity; defaults to CODESIGN_APP if empty") - add_custom_target(icons ALL - COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns + set(mac_icon ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns) + add_custom_command(OUTPUT ${mac_icon} + COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${mac_icon} 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) file(DOWNLOAD "https://seed.lokinet.org/lokinet.signed" ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.signed) add_custom_command(TARGET lokinet @@ -101,7 +103,7 @@ if(APPLE) 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_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" + MACOSX_BUNDLE_ICON_FILE "${mac_icon}" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") if (CODESIGN_APP AND CODESIGN_APPEX) message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_APPEX} (appex)") From 329da951b71bf2194c329e852c9cb06ab3f9bcab Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 20:28:58 -0300 Subject: [PATCH 43/81] Apple OS interface cleanup & refactoring - Add a C callback interface (context_wrapper.h) between lokinet and the objective-C code so that: - we can use objective-C (rather than objective-C++), which seems more likely to be supported by Apple into the future; - we minimize the amount of code that needs to be aware of the Apple APIs. - this replaces apple logger objective c++ implementation with a plain c++ implementation that takes a very simple C callback (provided from the obj-c code) to actually make the call to NSLog. - Add various documentation to the code of what is going on. - Send all DNS traffic to the primary IP on the tun interface. The match prefixes simply don't work as advertised, and have weird shit (like even if you get it working for some domains, "instagram.com" still doesn't because of god-knows-what Apple internal politics). - Drop the dns proxy code as we don't need it anymore. - Don't use 9.9.9.9 for default DNS. (We might consider the unfiltered 9.9.9.10 as an alternative default, but if we do it should be a global lokinet change rather than a Mac-specific change). - Parse a lokinet.ini in the data directory, if it exists. (Since we are sandboxed, it is an app-specific "home" directory so is probably buried god knows where, but at least the GUI ought to be able to get it to let users add things to it). - This commit also adds a swift version of the PacketTunnelProvider glue, which ought to work in theory, but the *tooling* for cmake is so underdeveloped that I couldn't find any way to actually get the damn thing working. So I'm committing it here anyway (and will revert it away in the next commit) in case we someday want to switch to it. - --- contrib/format.sh | 2 +- contrib/macos/sign.sh.in | 3 - daemon/CMakeLists.txt | 5 +- llarp/apple/CMakeLists.txt | 41 ++--- llarp/apple/PacketTunnelProvider.m | 134 +++++++++++++++ llarp/apple/PacketTunnelProvider.swift | 129 ++++++++++++++ .../{apple_logger.mm => apple_logger.cpp} | 17 +- llarp/apple/apple_logger.hpp | 18 +- llarp/apple/context.hpp | 23 +++ llarp/apple/context_wrapper.cpp | 162 ++++++++++++++++++ llarp/apple/context_wrapper.h | 94 ++++++++++ llarp/apple/vpn_interface.cpp | 52 ++++++ llarp/apple/vpn_interface.hpp | 51 ++++++ llarp/apple/vpn_platform.hpp | 31 ++++ 14 files changed, 711 insertions(+), 51 deletions(-) create mode 100644 llarp/apple/PacketTunnelProvider.m create mode 100644 llarp/apple/PacketTunnelProvider.swift rename llarp/apple/{apple_logger.mm => apple_logger.cpp} (53%) create mode 100644 llarp/apple/context.hpp create mode 100644 llarp/apple/context_wrapper.cpp create mode 100644 llarp/apple/context_wrapper.h create mode 100644 llarp/apple/vpn_interface.cpp create mode 100644 llarp/apple/vpn_interface.hpp create mode 100644 llarp/apple/vpn_platform.hpp diff --git a/contrib/format.sh b/contrib/format.sh index 5b5f5a495..785d9ba54 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -18,7 +18,7 @@ fi cd "$(dirname $0)/../" if [ "$1" = "verify" ] ; then - if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm)$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then + if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm?)$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then exit 1 fi else diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index af3d18d55..6ebf0859a 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -3,9 +3,6 @@ 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" -codesign --verbose=4 --force -s "@CODESIGN_APPEX@" \ - --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-dnsproxy.entitlements.plist" \ - --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/PlugIns/lokinet-dnsproxy.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" \ diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 65fd29fe1..febc7314a 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -88,7 +88,6 @@ if(APPLE) $/Contents/Resources/bootstrap.signed COMMAND mkdir -p $/Contents/PlugIns COMMAND cp -a $ $/Contents/PlugIns/ - COMMAND cp -a $ $/Contents/PlugIns/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile $/Contents/embedded.provisionprofile ) @@ -114,14 +113,14 @@ if(APPLE) @ONLY) add_custom_target( sign - DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension lokinet-dnsproxy + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_APPEX (=${CODESIGN_APPEX}) are not set") add_custom_target( sign - DEPENDS lokinet lokinet-extension lokinet-dnsproxy + DEPENDS lokinet lokinet-extension COMMAND "true") endif() endif() diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 0fdea9a41..8344e90a1 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -12,16 +12,26 @@ find_library(FOUNDATION Foundation REQUIRED) find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) -target_sources(lokinet-util PRIVATE apple_logger.mm) +target_sources(lokinet-util PRIVATE apple_logger.cpp) target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) -add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) -target_link_libraries(lokinet-extension PUBLIC +target_sources(lokinet-platform PRIVATE vpn_interface.cpp context_wrapper.cpp) + +add_executable(lokinet-extension MACOSX_BUNDLE + PacketTunnelProvider.m + ) +target_link_libraries(lokinet-extension PRIVATE liblokinet ${COREFOUNDATION} ${NETEXT}) -target_link_libraries(lokinet-dnsproxy PUBLIC + +# 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_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) @@ -33,29 +43,8 @@ set_target_properties(lokinet-extension PROPERTIES XCODE_PRODUCT_TYPE com.apple.product-type.app-extension ) -# Not sure what -fapplication-extension does, but XCode puts it in so... -# -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. -target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) -target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) - 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 ) - -set_target_properties(lokinet-dnsproxy PROPERTIES - BUNDLE TRUE - BUNDLE_EXTENSION appex - MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in - XCODE_PRODUCT_TYPE com.apple.product-type.app-extension - ) - -target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) -target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) - -add_custom_command(TARGET lokinet-dnsproxy - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile - $/Contents/embedded.provisionprofile - ) diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m new file mode 100644 index 000000000..b203095f9 --- /dev/null +++ b/llarp/apple/PacketTunnelProvider.m @@ -0,0 +1,134 @@ +#include +#include +#include "context_wrapper.h" + +NSString* error_domain = @"com.loki-project.lokinet"; + +@interface LLARPPacketTunnel : NEPacketTunnelProvider +{ + void* lokinet; +} + +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler; + +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler; + +- (void)readPackets; + +@end + +void nslogger(const char* msg) { NSLog(@"%s", msg); } + +void packet_writer(int af, const void* data, size_t size, void* ctx) { + if (ctx == nil || data == nil) + return; + + 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]]; +} + +void start_packet_reader(void* ctx) { + if (ctx == nil) + return; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + [t readPackets]; +} + +@implementation LLARPPacketTunnel + +- (void)readPackets +{ + [self.packetFlow readPacketObjectsWithCompletionHandler: ^(NSArray* packets) { + if (lokinet == nil) + return; + for (NEPacket* p in packets) { + llarp_apple_incoming(lokinet, p.data.bytes, p.data.length); + } + [self readPackets]; + }]; +} + +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError*))completionHandler +{ + char ip_buf[16]; + char mask_buf[16]; + char dns_buf[16]; + + NSString* default_bootstrap = [[NSBundle mainBundle] pathForResource:@"bootstrap" ofType:@"signed"]; + + lokinet = llarp_apple_init(nslogger, NSHomeDirectory().UTF8String, default_bootstrap.UTF8String, ip_buf, mask_buf, dns_buf); + if (!lokinet) { + NSError *init_failure = [NSError errorWithDomain:error_domain code:500 userInfo:@{@"Error": @"Failed to initialize lokinet"}]; + NSLog(@"%@", [init_failure localizedDescription]); + return completionHandler(init_failure); + } + + NSString* ip = [[NSString alloc] initWithUTF8String:ip_buf]; + NSString* mask = [[NSString alloc] initWithUTF8String:mask_buf]; + NSString* dnsaddr = [[NSString alloc] initWithUTF8String:dns_buf]; + + NEPacketTunnelNetworkSettings* settings = + [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]]; + dns.domainName = @"localhost.loki"; + // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems + // highly unreliable, though: often it just doesn't work at all (perhaps only if we make ourselves + // the default route?), and even when it does work, it seems there are secret reasons that some + // domains (such as instagram.com) still won't work because there's some magic sauce in the OS + // that Apple engineers don't want to disclose ("This is what I expected, actually. Although I + // will not comment on what I believe is happening here", from + // https://developer.apple.com/forums/thread/685410). + // + // So the documentation sucks and the feature doesn't appear to work, so as much as it would be + // nice to capture only .loki and .snode when not in exit mode, we can't, so capture everything + // and use our default upstream. + dns.matchDomains = @[@""]; + dns.matchDomainsNoSearch = true; + dns.searchDomains = @[]; + NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] + subnetMasks:@[mask]]; + settings.IPv4Settings = ipv4; + settings.DNSSettings = dns; + [self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) { + if (err) { + NSLog(@"Failed to configure lokinet tunnel: %@", err); + return completionHandler(err); + } + + int start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, (__bridge void*) self); + if (start_ret != 0) { + NSError *start_failure = [NSError errorWithDomain:error_domain code:start_ret userInfo:@{@"Error": @"Failed to start lokinet"}]; + NSLog(@"%@", start_failure); + lokinet = nil; + return completionHandler(start_failure); + } + completionHandler(nil); + }]; +} + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler +{ + if (lokinet) { + llarp_apple_shutdown(lokinet); + lokinet = nil; + } + completionHandler(); +} + +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler +{ + NSData* response = [NSData dataWithBytesNoCopy:"ok" length:3 freeWhenDone:NO]; + completionHandler(response); +} +@end diff --git a/llarp/apple/PacketTunnelProvider.swift b/llarp/apple/PacketTunnelProvider.swift new file mode 100644 index 000000000..1cee28bed --- /dev/null +++ b/llarp/apple/PacketTunnelProvider.swift @@ -0,0 +1,129 @@ +/// Lokinet network extension swift glue layer + +import NetworkExtension + +enum LokinetError: Error { + case runtimeError(String) +} + +func packet_writer(af: Int32, data: UnsafeRawPointer?, size: Int, ctx: UnsafeMutableRawPointer?) { + if ctx == nil || data == nil { + return + } + let tunnel = ctx!.assumingMemoryBound(to: PacketTunnelProvider.self).pointee + + let packet = NEPacket( + data: Data(bytes: data!, count: 1), + protocolFamily: sa_family_t(af)) + tunnel.packetFlow.writePacketObjects([packet]) +} + + +func start_packet_reader(ctx: UnsafeMutableRawPointer?) { + let tunnel = ctx?.assumingMemoryBound(to: PacketTunnelProvider.self).pointee + tunnel?.readHandler() +} + + +class PacketTunnelProvider: NEPacketTunnelProvider { + + var lokinet: UnsafeMutableRawPointer? + + func readHandler() { + packetFlow.readPacketObjects() { (packets: [NEPacket]) in + if self.lokinet == nil { + return + } + + for p in packets { + p.data.withUnsafeBytes { (buf: UnsafeRawBufferPointer) -> Void in + llarp_apple_incoming(self.lokinet, buf.baseAddress!, buf.count) + } + } + + self.readHandler() + } + } + + override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { + + var ip_buf = Array(repeating: 0, count: 16) + var mask_buf = Array(repeating: 0, count: 16) + var dns_buf = Array(repeating: 0, count: 16) + + lokinet = llarp_apple_init(NSHomeDirectory(), &ip_buf, &mask_buf, &dns_buf) + if lokinet == nil { + NSLog("Lokinet initialization failed!") + completionHandler(LokinetError.runtimeError("Lokinet initialization failed")) + return + } + + let ip = String(cString: ip_buf) + let mask = String(cString: mask_buf) + let dns_addr = String(cString: dns_buf) + + NSLog("Lokinet configured with address %s/%s, dns %s", ip, mask, dns_addr) + + let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") + settings.ipv4Settings = NEIPv4Settings(addresses: [ip], subnetMasks: [mask]) + let dns = NEDNSSettings(servers: [dns_addr]) + dns.domainName = "localhost.loki" + dns.matchDomains = ["snode", "loki"] + dns.matchDomainsNoSearch = true + dns.searchDomains = [] + settings.dnsSettings = dns + + let condition = NSCondition() + condition.lock() + defer { condition.unlock() } + + var system_error: Error? + + setTunnelNetworkSettings(settings) { error in + system_error = error + condition.signal() + } + + condition.wait() + + if let error = system_error { + NSLog("Failed to set up tunnel: %s", error.localizedDescription) + lokinet = nil + completionHandler(error) + return + } + + var myself = self + let start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, &myself) + if start_ret != 0 { + NSLog("Lokinet failed to start!") + lokinet = nil + completionHandler(LokinetError.runtimeError("Lokinet failed to start")) + return + } + completionHandler(nil) + } + + override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { + if lokinet != nil { + llarp_apple_shutdown(lokinet) + lokinet = nil + } + completionHandler() + } + + override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { + if let handler = completionHandler { + handler(messageData) + } + } + + override func sleep(completionHandler: @escaping () -> Void) { + // FIXME - do we need to kick lokinet here? + completionHandler() + } + + override func wake() { + // FIXME - do we need to kick lokinet here? + } +} diff --git a/llarp/apple/apple_logger.mm b/llarp/apple/apple_logger.cpp similarity index 53% rename from llarp/apple/apple_logger.mm rename to llarp/apple/apple_logger.cpp index 52b544e58..4a41c78cf 100644 --- a/llarp/apple/apple_logger.mm +++ b/llarp/apple/apple_logger.cpp @@ -1,9 +1,6 @@ #include "apple_logger.hpp" -#include -#include - -namespace llarp +namespace llarp::apple { void NSLogStream::PreLog( @@ -22,15 +19,7 @@ namespace llarp void NSLogStream::Print(LogLevel, const char*, const std::string& msg) { - const char* msg_ptr = msg.c_str(); - const char* msg_fmt = "%s"; - NSString* fmt = [[NSString alloc] initWithUTF8String:msg_ptr]; - NSString* str = [[NSString alloc] initWithUTF8String:msg_fmt]; - NSLog(fmt, str); + ns_logger(msg.c_str()); } - void - NSLogStream::PostLog(std::stringstream&) const - {} - -} // namespace llarp +} // namespace llarp::apple diff --git a/llarp/apple/apple_logger.hpp b/llarp/apple/apple_logger.hpp index 1546392d1..b97810c76 100644 --- a/llarp/apple/apple_logger.hpp +++ b/llarp/apple/apple_logger.hpp @@ -1,11 +1,17 @@ #pragma once +#include #include -namespace llarp +namespace llarp::apple { struct NSLogStream : public ILogStream { + using ns_logger_callback = void (*)(const char* log_this); + + NSLogStream(ns_logger_callback logger) : ns_logger{logger} + {} + void PreLog( std::stringstream& s, @@ -18,13 +24,17 @@ namespace llarp Print(LogLevel lvl, const char* tag, const std::string& msg) override; void - PostLog(std::stringstream& ss) const override; + PostLog(std::stringstream& ss) const override + {} - virtual void + void ImmediateFlush() override {} void Tick(llarp_time_t) override {} + + private: + ns_logger_callback ns_logger; }; -} // namespace llarp +} // namespace llarp::apple diff --git a/llarp/apple/context.hpp b/llarp/apple/context.hpp new file mode 100644 index 000000000..e25090262 --- /dev/null +++ b/llarp/apple/context.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "vpn_platform.hpp" + +namespace llarp::apple +{ + struct Context : public llarp::Context + { + std::shared_ptr + makeVPNPlatform() override + { + return std::make_shared(*this, m_PacketWriter, m_OnReadable); + } + + // Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main + // point of these is to get passed through to VPNInterface, which will be called during setup, + // after construction. + VPNInterface::packet_write_callback m_PacketWriter; + VPNInterface::on_readable_callback m_OnReadable; + }; + +} // namespace llarp::apple diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp new file mode 100644 index 000000000..bd781fa89 --- /dev/null +++ b/llarp/apple/context_wrapper.cpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include "vpn_interface.hpp" +#include "context_wrapper.h" +#include "context.hpp" +#include "apple_logger.hpp" + +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; + std::thread runner; + + std::weak_ptr iface; + }; + +} // namespace + +void* +llarp_apple_init( + ns_logger_callback ns_logger, + const char* config_dir_, + const char* default_bootstrap, + char* ip, + char* netmask, + char* dns) +{ + llarp::LogContext::Instance().logStream = std::make_unique(ns_logger); + + try + { + auto config_dir = fs::u8path(config_dir_); + auto config = std::make_shared(config_dir); + std::optional config_path = config_dir / "lokinet.ini"; + if (!fs::exists(*config_path)) + config_path.reset(); + config->Load(config_path); + + // If no range is specified then go look for a free one, set that in the config, and then return + // it to the caller via the char* parameters. + auto& range = config->network.m_ifaddr; + if (!range.addr.h) + { + if (auto maybe = llarp::FindFreeRange()) + range = *maybe; + else + throw std::runtime_error{"Could not find any free IP range"}; + } + auto addr = llarp::net::TruncateV6(range.addr).ToString(); + auto mask = llarp::net::TruncateV6(range.netmask_bits).ToString(); + if (addr.size() > 15 || mask.size() > 15) + throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; + std::strcpy(ip, addr.c_str()); + std::strcpy(netmask, mask.c_str()); + // XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons? + std::strcpy(dns, addr.c_str()); + + // 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; + + // If no explicit bootstrap then set the system default one included with the app bundle + if (config->bootstrap.files.empty()) + config->bootstrap.files.push_back(fs::u8path(default_bootstrap)); + + auto inst = std::make_unique(); + inst->context.Configure(std::move(config)); + return inst.release(); + } + catch (const std::exception& e) + { + LogError("Failed to initialize lokinet from config: ", e.what()); + } + return nullptr; +} + +int +llarp_apple_start( + void* lokinet, + packet_writer_callback packet_writer, + start_reading_callback start_reading, + void* callback_context) +{ + auto* inst = static_cast(lokinet); + inst->context.m_PacketWriter = [inst, packet_writer, callback_context]( + int af_family, void* data, size_t size) { + packet_writer(af_family, data, size, callback_context); + return true; + }; + + inst->context.m_OnReadable = + [inst, start_reading, callback_context](llarp::apple::VPNInterface& iface) { + inst->iface = iface.weak_from_this(); + start_reading(callback_context); + }; + + std::promise result; + inst->runner = std::thread{[inst, &result] { + const llarp::RuntimeOptions opts{}; + try + { + inst->context.Setup(opts); + } + catch (...) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + inst->context.Run(opts); + }}; + + try + { + result.get_future().get(); + } + catch (const std::exception& e) + { + LogError("Failed to initialize lokinet: ", e.what()); + return -1; + } + + return 0; +} + +int +llarp_apple_incoming(void* lokinet, const void* bytes, size_t size) +{ + auto& inst = *static_cast(lokinet); + + auto iface = inst.iface.lock(); + if (!iface) + return -2; + + llarp_buffer_t buf{static_cast(bytes), size}; + if (iface->OfferReadPacket(buf)) + return 0; + + LogError("invalid IP packet: ", llarp::buffer_printer(buf)); + return -1; +} + +void +llarp_apple_shutdown(void* lokinet) +{ + auto* inst = static_cast(lokinet); + + inst->context.CloseAsync(); + inst->context.Wait(); + inst->runner.join(); + delete inst; +} diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h new file mode 100644 index 000000000..6522d641a --- /dev/null +++ b/llarp/apple/context_wrapper.h @@ -0,0 +1,94 @@ +#pragma once + +// C-linkage wrappers for interacting with a lokinet context, so that we can call them from Swift +// code (which currently doesn't support C++ interoperability at all). + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + + /// C callback function for us to invoke when we need to write a packet + typedef void(packet_writer_callback)(int af, const void* data, size_t size, void* ctx); + + /// C callback function to invoke once we are ready to start receiving packets + typedef void(start_reading_callback)(void* ctx); + + /// C callback that bridges things into NSLog + typedef void(ns_logger_callback)(const char* msg); + + /// Initializes a lokinet instance by initializing various objects and loading the configuration + /// (if {config_dir}/lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start + /// for that). + /// + /// Returns NULL if there was a problem initializing/loading the configuration, otherwise returns + /// an opaque void pointer that should be passed into the other llarp_apple_* functions. + /// + /// \param logger a logger callback that we pass log messages to to relay them (i.e. via NSLog). + /// + /// \param config_dir the lokinet configuration directory where lokinet.ini can be and the various + /// other lokinet state files go. + /// + /// \param default_bootstrap the path to the default bootstrap.signed included in installation, + /// which will be used if no explicit bootstrap is set in the config file. + /// + /// \param ip - char buffer where we will write the primary tunnel IP address as a string such as + /// "172.16.0.0". Will write up to 16 characters (including the null terminator). This will be + /// the tunnel IP from the lokinet.ini, if it exists and specifies a range, otherwise we'll + /// configure lokinet to use a currently-unused range and return that. + /// + /// \param netmask the tunnel netmask as a string such as "255.255.0.0". Will write up to 16 + /// characters (including the null terminator). + /// + /// \param dns the DNS address that should be configured to query lokinet, as a string such as + /// "172.16.0.1". Will write up to 16 characters (including the null terminator). + void* + llarp_apple_init( + ns_logger_callback ns_logger, + const char* config_dir, + const char* default_bootstrap, + char* ip, + char* netmask, + char* dns); + + /// Starts the lokinet instance in a new thread. + /// + /// \param packet_writer C function callback that will be called when we need to write a packet to + /// the packet tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, the size + /// of the data in bytes, and the opaque callback_context pointer. + /// + /// \param start_reading C function callback that will be called when lokinet is setup and ready + /// to start receiving packets from the packet tunnel. This should set up the read handler to + /// deliver packets via llarp_apple_incoming. This is called with a single argument of the opaque + /// callback_context pointer. + /// + /// \param callback_context Opaque pointer that is passed into the packet_writer and start_reading + /// callback, intended to allow context to be passed through to the callbacks. This code does + /// nothing with this pointer aside from passing it through to callbacks. + /// + /// \returns 0 on succesful startup, -1 on failure. + int + llarp_apple_start( + void* lokinet, + packet_writer_callback packet_writer, + start_reading_callback start_reading, + void* callback_context); + + /// 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). + int + llarp_apple_incoming(void* lokinet, const void* bytes, 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. + void + llarp_apple_shutdown(void* lokinet); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/llarp/apple/vpn_interface.cpp b/llarp/apple/vpn_interface.cpp new file mode 100644 index 000000000..079e24aa9 --- /dev/null +++ b/llarp/apple/vpn_interface.cpp @@ -0,0 +1,52 @@ + +#include "vpn_interface.hpp" +#include "context.hpp" + +namespace llarp::apple +{ + VPNInterface::VPNInterface( + Context& ctx, packet_write_callback packet_writer, on_readable_callback on_readable) + : m_PacketWriter{std::move(packet_writer)}, m_OnReadable{std::move(on_readable)} + { + ctx.loop->call_soon([this] { m_OnReadable(*this); }); + } + + bool + VPNInterface::OfferReadPacket(const llarp_buffer_t& buf) + { + llarp::net::IPPacket pkt; + if (!pkt.Load(buf)) + return false; + m_ReadQueue.tryPushBack(std::move(pkt)); + return true; + } + + int + VPNInterface::PollFD() const + { + return -1; + } + + std::string + VPNInterface::IfName() const + { + return ""; + } + + net::IPPacket + VPNInterface::ReadNextPacket() + { + net::IPPacket pkt{}; + if (not m_ReadQueue.empty()) + pkt = m_ReadQueue.popFront(); + return pkt; + } + + bool + VPNInterface::WritePacket(net::IPPacket pkt) + { + int af_family = pkt.IsV6() ? AF_INET6 : AF_INET; + return m_PacketWriter(af_family, pkt.buf, pkt.sz); + } + +} // namespace llarp::apple diff --git a/llarp/apple/vpn_interface.hpp b/llarp/apple/vpn_interface.hpp new file mode 100644 index 000000000..c1dff8dbf --- /dev/null +++ b/llarp/apple/vpn_interface.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include + +namespace llarp::apple +{ + struct Context; + + class VPNInterface final : public vpn::NetworkInterface, + public std::enable_shared_from_this + { + public: + using packet_write_callback = std::function; + using on_readable_callback = std::function; + + explicit VPNInterface( + Context& ctx, packet_write_callback packet_writer, on_readable_callback on_readable); + + // Method to call when a packet has arrived to deliver the packet to lokinet + bool + OfferReadPacket(const llarp_buffer_t& buf); + + int + PollFD() const override; + + std::string + IfName() const override; + + net::IPPacket + ReadNextPacket() override; + + bool + WritePacket(net::IPPacket pkt) override; + + private: + // Function for us to call when we have a packet to emit. Should return true if the packet was + // handed off to the OS successfully. + packet_write_callback m_PacketWriter; + + // Called when we are ready to start reading packets + on_readable_callback m_OnReadable; + + static inline constexpr auto PacketQueueSize = 1024; + + thread::Queue m_ReadQueue{PacketQueueSize}; + }; + +} // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp new file mode 100644 index 000000000..72018b509 --- /dev/null +++ b/llarp/apple/vpn_platform.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "vpn_interface.hpp" + +namespace llarp::apple +{ + class VPNPlatform final : public vpn::Platform + { + public: + explicit VPNPlatform( + Context& ctx, + VPNInterface::packet_write_callback packet_writer, + VPNInterface::on_readable_callback on_readable) + : m_Context{ctx} + , m_PacketWriter{std::move(packet_writer)} + , m_OnReadable{std::move(on_readable)} + {} + + std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override + { + return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); + } + + private: + Context& m_Context; + VPNInterface::packet_write_callback m_PacketWriter; + VPNInterface::on_readable_callback m_OnReadable; + }; + +} // namespace llarp::apple From 2964051f0da48b64cc406ff2297031cd086ff787 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 20:49:49 -0300 Subject: [PATCH 44/81] Remove swift version (do not squash) Don't squash this commit so that the swift version stays around in history in case we need to resurrect it again some day (i.e. when Apple decides to kill off Objective-C support). --- llarp/apple/PacketTunnelProvider.swift | 129 ------------------------- 1 file changed, 129 deletions(-) delete mode 100644 llarp/apple/PacketTunnelProvider.swift diff --git a/llarp/apple/PacketTunnelProvider.swift b/llarp/apple/PacketTunnelProvider.swift deleted file mode 100644 index 1cee28bed..000000000 --- a/llarp/apple/PacketTunnelProvider.swift +++ /dev/null @@ -1,129 +0,0 @@ -/// Lokinet network extension swift glue layer - -import NetworkExtension - -enum LokinetError: Error { - case runtimeError(String) -} - -func packet_writer(af: Int32, data: UnsafeRawPointer?, size: Int, ctx: UnsafeMutableRawPointer?) { - if ctx == nil || data == nil { - return - } - let tunnel = ctx!.assumingMemoryBound(to: PacketTunnelProvider.self).pointee - - let packet = NEPacket( - data: Data(bytes: data!, count: 1), - protocolFamily: sa_family_t(af)) - tunnel.packetFlow.writePacketObjects([packet]) -} - - -func start_packet_reader(ctx: UnsafeMutableRawPointer?) { - let tunnel = ctx?.assumingMemoryBound(to: PacketTunnelProvider.self).pointee - tunnel?.readHandler() -} - - -class PacketTunnelProvider: NEPacketTunnelProvider { - - var lokinet: UnsafeMutableRawPointer? - - func readHandler() { - packetFlow.readPacketObjects() { (packets: [NEPacket]) in - if self.lokinet == nil { - return - } - - for p in packets { - p.data.withUnsafeBytes { (buf: UnsafeRawBufferPointer) -> Void in - llarp_apple_incoming(self.lokinet, buf.baseAddress!, buf.count) - } - } - - self.readHandler() - } - } - - override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { - - var ip_buf = Array(repeating: 0, count: 16) - var mask_buf = Array(repeating: 0, count: 16) - var dns_buf = Array(repeating: 0, count: 16) - - lokinet = llarp_apple_init(NSHomeDirectory(), &ip_buf, &mask_buf, &dns_buf) - if lokinet == nil { - NSLog("Lokinet initialization failed!") - completionHandler(LokinetError.runtimeError("Lokinet initialization failed")) - return - } - - let ip = String(cString: ip_buf) - let mask = String(cString: mask_buf) - let dns_addr = String(cString: dns_buf) - - NSLog("Lokinet configured with address %s/%s, dns %s", ip, mask, dns_addr) - - let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") - settings.ipv4Settings = NEIPv4Settings(addresses: [ip], subnetMasks: [mask]) - let dns = NEDNSSettings(servers: [dns_addr]) - dns.domainName = "localhost.loki" - dns.matchDomains = ["snode", "loki"] - dns.matchDomainsNoSearch = true - dns.searchDomains = [] - settings.dnsSettings = dns - - let condition = NSCondition() - condition.lock() - defer { condition.unlock() } - - var system_error: Error? - - setTunnelNetworkSettings(settings) { error in - system_error = error - condition.signal() - } - - condition.wait() - - if let error = system_error { - NSLog("Failed to set up tunnel: %s", error.localizedDescription) - lokinet = nil - completionHandler(error) - return - } - - var myself = self - let start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, &myself) - if start_ret != 0 { - NSLog("Lokinet failed to start!") - lokinet = nil - completionHandler(LokinetError.runtimeError("Lokinet failed to start")) - return - } - completionHandler(nil) - } - - override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { - if lokinet != nil { - llarp_apple_shutdown(lokinet) - lokinet = nil - } - completionHandler() - } - - override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { - if let handler = completionHandler { - handler(messageData) - } - } - - override func sleep(completionHandler: @escaping () -> Void) { - // FIXME - do we need to kick lokinet here? - completionHandler() - } - - override func wake() { - // FIXME - do we need to kick lokinet here? - } -} From e39c473c886cb7f1af69a00ada2dc569ea93417c Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 20:54:08 -0300 Subject: [PATCH 45/81] format.sh: support macports clang-format macports names it clang-format-mp-N to avoid clashing with a system-installed one. --- contrib/format.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/format.sh b/contrib/format.sh index 785d9ba54..e514590bd 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -3,6 +3,9 @@ CLANG_FORMAT_DESIRED_VERSION=11 binary=$(which clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) +if [ $? -ne 0 ]; then + binary=$(which clang-format-mp-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) +fi if [ $? -ne 0 ]; then binary=$(which clang-format 2>/dev/null) if [ $? -ne 0 ]; then From fec3598e16a7db414ea5bfbd5a94b4b9bafafc9a Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 11:15:21 -0300 Subject: [PATCH 46/81] Remove no-longer-used framework.mm --- llarp/apple/framework.mm | 260 --------------------------------------- 1 file changed, 260 deletions(-) delete mode 100644 llarp/apple/framework.mm diff --git a/llarp/apple/framework.mm b/llarp/apple/framework.mm deleted file mode 100644 index be7af8022..000000000 --- a/llarp/apple/framework.mm +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"}; -const llarp::SockAddr DefaultUpstreamDNS{"9.9.9.9:53"}; - -namespace llarp::apple -{ - struct FrameworkContext : public llarp::Context - { - explicit FrameworkContext(NEPacketTunnelProvider* tunnel); - - ~FrameworkContext() - {} - - std::shared_ptr - makeVPNPlatform() override; - - void - Start(std::string_view bootstrap, std::string exit); - - private: - NEPacketTunnelProvider* const m_Tunnel; - std::unique_ptr m_Runner; - }; - - class VPNInterface final : public vpn::NetworkInterface - { - NEPacketTunnelProvider* const m_Tunnel; - - static inline constexpr auto PacketQueueSize = 1024; - - thread::Queue m_ReadQueue; - - void - OfferReadPacket(NSData* data) - { - llarp::net::IPPacket pkt; - const llarp_buffer_t buf{static_cast(data.bytes), data.length}; - if (pkt.Load(buf)) - { - m_ReadQueue.tryPushBack(std::move(pkt)); - } - else - { - LogError("invalid IP packet: ", llarp::buffer_printer(DataAsStringView(data))); - } - } - - public: - explicit VPNInterface(NEPacketTunnelProvider* tunnel, llarp::Context* context) - : m_Tunnel{tunnel}, m_ReadQueue{PacketQueueSize} - { - context->loop->call_soon([this]() { Read(); }); - } - - void - HandleReadEvent(NSArray* packets, NSArray* protos) - { - NSUInteger num = [packets count]; - for (NSUInteger idx = 0; idx < num; ++idx) - { - NSData* pkt = [packets objectAtIndex:idx]; - OfferReadPacket(pkt); - } - Read(); - } - - void - Read() - { - auto handler = [this](NSArray* packets, NSArray* protos) { - HandleReadEvent(packets, protos); - }; - [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; - } - - int - PollFD() const override - { - return -1; - } - - std::string - IfName() const override - { - return ""; - } - - net::IPPacket - ReadNextPacket() override - { - net::IPPacket pkt{}; - if (not m_ReadQueue.empty()) - pkt = m_ReadQueue.popFront(); - return pkt; - } - - bool - WritePacket(net::IPPacket pkt) override - { - NSNumber* fam = [NSNumber numberWithInteger:(pkt.IsV6() ? AF_INET6 : AF_INET)]; - void* pktbuf = pkt.buf; - const size_t pktsz = pkt.sz; - NSData* datapkt = [NSData dataWithBytesNoCopy:pktbuf length:pktsz]; - return [m_Tunnel.packetFlow writePackets:@[datapkt] withProtocols:@[fam]]; - } - }; - - class VPNPlatform final : public vpn::Platform - { - NEPacketTunnelProvider* const m_Tunnel; - Context* const m_Context; - - public: - explicit VPNPlatform(NEPacketTunnelProvider* tunnel, Context* context) - : m_Tunnel{tunnel}, m_Context{context} - {} - - std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override - { - return std::make_shared(m_Tunnel, m_Context); - } - }; - - FrameworkContext::FrameworkContext(NEPacketTunnelProvider* tunnel) - : llarp::Context{}, m_Tunnel{tunnel} - {} - - void - FrameworkContext::Start(std::string_view bootstrap, std::string exit) - { - std::promise result; - - m_Runner = - std::make_unique([&result, bootstrap = std::string{bootstrap}, exit, this]() { - const RuntimeOptions opts{}; - try - { - auto config = llarp::Config::NetworkExtensionConfig(exit); - config->bootstrap.files.emplace_back(bootstrap); - config->dns.m_bind = DefaultDNSBind; - config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); - Configure(std::move(config)); - Setup(opts); - } - catch (std::exception&) - { - result.set_exception(std::current_exception()); - return; - } - result.set_value(); - Run(opts); - }); - - auto ftr = result.get_future(); - ftr.get(); - } - - std::shared_ptr - FrameworkContext::makeVPNPlatform() - { - return std::make_shared(m_Tunnel, this); - } -} - -struct ContextWrapper -{ - std::unique_ptr m_Context; - - public: - explicit ContextWrapper(NEPacketTunnelProvider* tunnel) - : m_Context{std::make_unique(tunnel)} - {} - - void - Start(std::string_view bootstrap, std::string exit) - { - llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); - m_Context->Start(std::move(bootstrap), std::move(exit)); - } - - void - Stop() - { - m_Context->CloseAsync(); - m_Context->Wait(); - } -}; - -@implementation LLARPPacketTunnel - -- (void)startTunnelWithOptions:(NSDictionary*)options - completionHandler:(void (^)(NSError*))completionHandler -{ - llarp::huint32_t addr_{}; - llarp::huint32_t mask_{}; - if (auto maybe = llarp::FindFreeRange()) - { - addr_ = llarp::net::TruncateV6(maybe->addr); - mask_ = llarp::net::TruncateV6(maybe->netmask_bits); - } - NSString* addr = StringToNSString(addr_.ToString()); - NSString* mask = StringToNSString(mask_.ToString()); - llarp::huint32_t dnsaddr_{addr_ & mask_}; - NSString* dnsaddr = StringToNSString(dnsaddr_.ToString()); - NSLog(@"%@", dnsaddr); - - NSBundle* main = [NSBundle mainBundle]; - NSString* res = [main pathForResource:@"bootstrap" ofType:@"signed"]; - NSData* path = [res dataUsingEncoding:NSUTF8StringEncoding]; - - m_Context = new ContextWrapper{self}; - m_Context->Start(DataAsStringView(path), "exit.loki"); - - NEPacketTunnelNetworkSettings* settings = - [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; - NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]]; - dns.domainName = @"localhost.loki"; - dns.matchDomains = @[@"*.snode", @"*.loki"]; - dns.matchDomainsNoSearch = true; - dns.searchDomains = @[]; - // dns.dnsProtocol = NEDNSProtocolCleartext; - NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[addr] - subnetMasks:@[@"255.255.255.255"]]; - ipv4.includedRoutes = @[[NEIPv4Route defaultRoute]]; - // ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; - settings.IPv4Settings = ipv4; - settings.DNSSettings = dns; - [self setTunnelNetworkSettings:settings completionHandler:completionHandler]; -} - -- (void)stopTunnelWithReason:(NEProviderStopReason)reason - completionHandler:(void (^)(void))completionHandler -{ - if (m_Context) - { - m_Context->Stop(); - delete m_Context; - m_Context = nullptr; - } - completionHandler(); -} - -- (void)handleAppMessage:(NSData*)messageData - completionHandler:(void (^)(NSData* responseData))completionHandler -{ - const auto data = DataAsStringView(messageData); - completionHandler(StringViewToData("ok")); -} -@end From 58da228f620fe7f4ab191306d287c41d8c410707 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 11:33:46 -0300 Subject: [PATCH 47/81] Generate a default client lokinet.ini on startup if it doesn't exist Thus when a user goes looking for it they'll find the (commented out) default in the right place and can edit it. (That right place is: ~/Library/Containers/com.loki-project.lokinet.network-extension/Data/lokinet.ini) --- llarp/apple/context_wrapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index bd781fa89..3d1eb2a37 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -40,9 +40,9 @@ llarp_apple_init( { auto config_dir = fs::u8path(config_dir_); auto config = std::make_shared(config_dir); - std::optional config_path = config_dir / "lokinet.ini"; - if (!fs::exists(*config_path)) - config_path.reset(); + fs::path config_path = config_dir / "lokinet.ini"; + if (!fs::exists(config_path)) + llarp::ensureConfig(config_dir, config_path, /*overwrite=*/ false, /*router=*/ false); config->Load(config_path); // If no range is specified then go look for a free one, set that in the config, and then return From 3527c9cdb54786e40896870965c74e6549d77361 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 11:38:17 -0300 Subject: [PATCH 48/81] Remove more unused dns-proxy files --- contrib/macos/LokinetDNSProxy.Info.plist.in | 40 ----- .../macos/lokinet-dnsproxy.entitlements.plist | 29 ---- .../macos/lokinet-dnsproxy.provisionprofile | Bin 17128 -> 0 bytes llarp/apple/dnsproxy.mm | 154 ------------------ 4 files changed, 223 deletions(-) delete mode 100644 contrib/macos/LokinetDNSProxy.Info.plist.in delete mode 100644 contrib/macos/lokinet-dnsproxy.entitlements.plist delete mode 100644 contrib/macos/lokinet-dnsproxy.provisionprofile delete mode 100644 llarp/apple/dnsproxy.mm diff --git a/contrib/macos/LokinetDNSProxy.Info.plist.in b/contrib/macos/LokinetDNSProxy.Info.plist.in deleted file mode 100644 index 522b476ec..000000000 --- a/contrib/macos/LokinetDNSProxy.Info.plist.in +++ /dev/null @@ -1,40 +0,0 @@ - - - - - CFBundleDisplayName - Lokinet - - CFBundleExecutable - lokinet-dnsproxy - - CFBundleIdentifier - com.loki-project.lokinet.dns-proxy - - CFBundleInfoDictionaryVersion - 6.0 - - CFBundlePackageType - XPC! - - CFBundleName - lokinet - - CFBundleVersion - @LOKINET_VERSION@ - - ITSAppUsesNonExemptEncryption - - - LSMinimumSystemVersion - 11.0 - - NSExtension - - NSExtensionPointIdentifier - com.apple.networkextension.dns-proxy - NSExtensionPrincipalClass - DNSProvider - - - diff --git a/contrib/macos/lokinet-dnsproxy.entitlements.plist b/contrib/macos/lokinet-dnsproxy.entitlements.plist deleted file mode 100644 index fa43bbd2b..000000000 --- a/contrib/macos/lokinet-dnsproxy.entitlements.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - com.apple.application-identifier - SUQ8J2PCT7.com.loki-project.lokinet.dns-proxy - - com.apple.developer.networking.networkextension - - dns-proxy - - - com.apple.developer.team-identifier - SUQ8J2PCT7 - - com.apple.security.app-sandbox - - - com.apple.security.get-task-allow - - - com.apple.security.network.client - - - com.apple.security.network.server - - - - diff --git a/contrib/macos/lokinet-dnsproxy.provisionprofile b/contrib/macos/lokinet-dnsproxy.provisionprofile deleted file mode 100644 index 87cd403bb4919366f2e767f28b38cb0f168a60c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17128 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 Z?Z9=CJE$b@rw5OI`eOO=&%e0*zX6(qnR);K diff --git a/llarp/apple/dnsproxy.mm b/llarp/apple/dnsproxy.mm deleted file mode 100644 index 56663118c..000000000 --- a/llarp/apple/dnsproxy.mm +++ /dev/null @@ -1,154 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -struct DNSImpl -{ - oxenmq::OxenMQ m_MQ; - std::optional m_Conn; - - explicit DNSImpl(oxenmq::address rpc) - { - m_MQ.start(); - m_MQ.connect_remote( - rpc, [this](auto conn) { m_Conn = conn; }, nullptr); - } - - bool - ShouldHookFlow(NEAppProxyFlow* flow) const - { - LogInfo(NSObjectToString(flow)); - return true; - } - - void - RelayDNSData(NEAppProxyUDPFlow* flow, NWEndpoint* remote, NSData* data) - { - if (not m_Conn) - return; - auto view = DataAsStringView(data); - - llarp_buffer_t buf{view}; - llarp::dns::MessageHeader hdr{}; - if (not hdr.Decode(&buf)) - return; - llarp::dns::Message msg{hdr}; - if (not msg.Decode(&buf)) - return; - llarp::util::StatusObject request{ - {"qname", msg.questions[0].qname}, {"qtype", msg.questions[0].qtype}}; - m_MQ.request( - *m_Conn, - "llarp.dns_query", - [flow, remote, msg = std::make_shared(std::move(msg))]( - bool good, std::vector parts) { - auto closeHandler = [flow](NSError* err) { - [flow closeWriteWithError:err]; - [flow closeReadWithError:err]; - }; - if (good and parts.size() == 1) - { - try - { - const auto obj = nlohmann::json::parse(parts[0]); - const auto result = obj["result"]; - if (const auto itr = result.find("answers"); itr != result.end()) - { - for (const auto& result : (*itr)) - { - llarp::dns::RR_RData_t rdata; - if (const auto data_itr = result.find("rdata"); data_itr != result.end()) - { - const auto data = data_itr->get(); - rdata.resize(data.size()); - std::copy_n(data.begin(), data.size(), rdata.begin()); - } - else - continue; - - msg->answers.emplace_back( - result["name"].get(), - result["type"].get(), - rdata); - } - } - } - catch (std::exception& ex) - { - LogError("dns query failed: ", ex.what()); - return; - } - const auto buf = msg->ToBuffer(); - NSData* data = StringViewToData( - std::string_view{reinterpret_cast(buf.buf.get()), buf.sz}); - [flow writeDatagrams:@[data] sentByEndpoints:@[remote] completionHandler:closeHandler]; - } - else - closeHandler(nullptr); - }, - request.dump()); - } - - void - HandleUDPFlow(NEAppProxyUDPFlow* flow) - { - auto handler = - [this, flow]( - NSArray* datagrams, NSArray* remoteEndpoints, NSError* error) { - if (error) - return; - NSInteger num = [datagrams count]; - for (NSInteger idx = 0; idx < num; ++idx) - { - RelayDNSData(flow, [remoteEndpoints objectAtIndex:idx], [datagrams objectAtIndex:idx]); - } - }; - [flow readDatagramsWithCompletionHandler:handler]; - } -}; - -@implementation DNSProvider - -- (void)startProxyWithOptions:(NSDictionary*)options - completionHandler:(void (^)(NSError* error))completionHandler -{ - m_Impl = new DNSImpl{oxenmq::address{"tcp://127.0.0.1:1190"}}; - completionHandler(nil); -} - -- (void)stopProxyWithReason:(NEProviderStopReason)reason - completionHandler:(void (^)(void))completionHandler -{ - if (m_Impl) - { - delete m_Impl; - m_Impl = nullptr; - } - completionHandler(); -} - -- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow -{ - if (not [flow isKindOfClass:[NEAppProxyUDPFlow class]]) - return NO; - if (m_Impl->ShouldHookFlow(flow)) - { - NEAppProxyUDPFlow* udp = (NEAppProxyUDPFlow*)flow; - auto handler = [impl = m_Impl, udp](NSError* err) { - if (err) - return; - impl->HandleUDPFlow(udp); - }; - [flow openWithLocalEndpoint:nil completionHandler:handler]; - return YES; - } - return NO; -} - -@end From 9afa95cd7a3c078a35e71d5bd70083b0e77ee799 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 12:09:35 -0300 Subject: [PATCH 49/81] Remove unused/empty/no longer used apple headers --- llarp/apple.hpp | 40 ---------------------------------------- llarp/vpn/apple.hpp | 0 2 files changed, 40 deletions(-) delete mode 100644 llarp/apple.hpp delete mode 100644 llarp/vpn/apple.hpp diff --git a/llarp/apple.hpp b/llarp/apple.hpp deleted file mode 100644 index dc35a9d95..000000000 --- a/llarp/apple.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#ifdef __APPLE__ -#include -#include -#include - -static std::string_view -DataAsStringView(NSData* data) -{ - return std::string_view{reinterpret_cast(data.bytes), data.length}; -} - -static NSData* -StringViewToData(std::string_view data) -{ - const char* ptr = data.data(); - const size_t sz = data.size(); - return [NSData dataWithBytes:ptr length:sz]; -} - -static NSString* -StringToNSString(std::string data) -{ - NSData* ptr = StringViewToData(std::string_view{data}); - return [[NSString alloc] initWithData:ptr encoding:NSUTF8StringEncoding]; -} - -static std::string -NSStringToString(NSString* str) -{ - return std::string{[str UTF8String]}; -} - -static std::string -NSObjectToString(NSObject* obj) -{ - return NSStringToString([NSString stringWithFormat:@"%@", obj]); -} - -#endif diff --git a/llarp/vpn/apple.hpp b/llarp/vpn/apple.hpp deleted file mode 100644 index e69de29bb..000000000 From c74dcba463fe2e56fa268805d891f860f7045fcb Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 10:10:24 -0300 Subject: [PATCH 50/81] Add lokinet subnet to default routes Mac doesn't route to a tunnel's ip range by default. WTF. --- llarp/apple/PacketTunnelProvider.m | 1 + 1 file changed, 1 insertion(+) diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index b203095f9..1255f61c1 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -96,6 +96,7 @@ void start_packet_reader(void* ctx) { dns.searchDomains = @[]; NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] subnetMasks:@[mask]]; + ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]]; settings.IPv4Settings = ipv4; settings.DNSSettings = dns; [self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) { From e84390748d9a229261309af745c729573670f54d Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 14:55:33 -0300 Subject: [PATCH 51/81] Add RouteManager; make exit on/off work --- llarp/apple/CMakeLists.txt | 2 +- llarp/apple/PacketTunnelProvider.m | 170 +++++++++++++++++++++++++++-- llarp/apple/context.hpp | 5 +- llarp/apple/context_wrapper.cpp | 45 ++++---- llarp/apple/context_wrapper.h | 132 ++++++++++++++-------- llarp/apple/route_manager.cpp | 61 +++++++++++ llarp/apple/route_manager.hpp | 46 ++++++++ llarp/apple/vpn_platform.hpp | 9 +- 8 files changed, 390 insertions(+), 80 deletions(-) create mode 100644 llarp/apple/route_manager.cpp create mode 100644 llarp/apple/route_manager.hpp diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 8344e90a1..69a356020 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -15,7 +15,7 @@ find_library(COREFOUNDATION CoreFoundation REQUIRED) target_sources(lokinet-util PRIVATE apple_logger.cpp) target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -target_sources(lokinet-platform PRIVATE vpn_interface.cpp context_wrapper.cpp) +target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp context_wrapper.cpp) add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index 1255f61c1..56ef0ca22 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -7,6 +7,8 @@ NSString* error_domain = @"com.loki-project.lokinet"; @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; + @public NEPacketTunnelNetworkSettings* settings; + @public NEIPv4Route* tun_route4; } - (void)startTunnelWithOptions:(NSDictionary*)options @@ -20,6 +22,8 @@ NSString* error_domain = @"com.loki-project.lokinet"; - (void)readPackets; +- (void)updateNetworkSettings; + @end void nslogger(const char* msg) { NSLog(@"%s", msg); } @@ -42,6 +46,97 @@ void start_packet_reader(void* ctx) { [t readPackets]; } +void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { + NEIPv4Route* route = [[NEIPv4Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + subnetMask: [NSString stringWithUTF8String:netmask]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + for (NEIPv4Route* r in t->settings.IPv4Settings.includedRoutes) + if ([r.destinationAddress isEqualToString:route.destinationAddress] && + [r.destinationSubnetMask isEqualToString:route.destinationSubnetMask]) + return; // Already in the settings, nothing to add. + + t->settings.IPv4Settings.includedRoutes = + [t->settings.IPv4Settings.includedRoutes arrayByAddingObject:route]; + + [t updateNetworkSettings]; +} + +void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { + NEIPv4Route* route = [[NEIPv4Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + subnetMask: [NSString stringWithUTF8String:netmask]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + NSMutableArray* routes = [NSMutableArray arrayWithArray:t->settings.IPv4Settings.includedRoutes]; + for (int i = 0; i < routes.count; i++) { + if ([routes[i].destinationAddress isEqualToString:route.destinationAddress] && + [routes[i].destinationSubnetMask isEqualToString:route.destinationSubnetMask]) { + [routes removeObjectAtIndex:i]; + i--; + } + } + + if (routes.count != t->settings.IPv4Settings.includedRoutes.count) { + t->settings.IPv4Settings.includedRoutes = routes; + [t updateNetworkSettings]; + } +} + +void add_ipv6_route(const char* addr, int prefix, void* ctx) { + NEIPv6Route* route = [[NEIPv6Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + networkPrefixLength: [NSNumber numberWithInt:prefix]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + for (NEIPv6Route* r in t->settings.IPv6Settings.includedRoutes) + if ([r.destinationAddress isEqualToString:route.destinationAddress] && + [r.destinationNetworkPrefixLength isEqualToNumber:route.destinationNetworkPrefixLength]) + return; // Already in the settings, nothing to add. + + t->settings.IPv6Settings.includedRoutes = + [t->settings.IPv6Settings.includedRoutes arrayByAddingObject:route]; + + [t updateNetworkSettings]; +} +void del_ipv6_route(const char* addr, int prefix, void* ctx) { + NEIPv6Route* route = [[NEIPv6Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + networkPrefixLength: [NSNumber numberWithInt:prefix]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + NSMutableArray* routes = [NSMutableArray arrayWithArray:t->settings.IPv6Settings.includedRoutes]; + for (int i = 0; i < routes.count; i++) { + if ([routes[i].destinationAddress isEqualToString:route.destinationAddress] && + [routes[i].destinationNetworkPrefixLength isEqualToNumber:route.destinationNetworkPrefixLength]) { + [routes removeObjectAtIndex:i]; + i--; + } + } + + if (routes.count != t->settings.IPv6Settings.includedRoutes.count) { + t->settings.IPv6Settings.includedRoutes = routes; + [t updateNetworkSettings]; + } +} +void add_default_route(void* ctx) { + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + + t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute]; + t->settings.IPv6Settings.includedRoutes = @[NEIPv6Route.defaultRoute]; + + [t updateNetworkSettings]; +} +void del_default_route(void* ctx) { + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + + t->settings.IPv4Settings.includedRoutes = @[t->tun_route4]; + t->settings.IPv4Settings.includedRoutes = @[]; // No tun_route6 yet. + + [t updateNetworkSettings]; +} + @implementation LLARPPacketTunnel - (void)readPackets @@ -63,21 +158,39 @@ void start_packet_reader(void* ctx) { char mask_buf[16]; char dns_buf[16]; - NSString* default_bootstrap = [[NSBundle mainBundle] pathForResource:@"bootstrap" ofType:@"signed"]; + NSString* default_bootstrap = [NSBundle.mainBundle pathForResource:@"bootstrap" ofType:@"signed"]; + NSString* home = NSHomeDirectory(); - lokinet = llarp_apple_init(nslogger, NSHomeDirectory().UTF8String, default_bootstrap.UTF8String, ip_buf, mask_buf, dns_buf); + llarp_apple_config conf = { + .config_dir = home.UTF8String, + .default_bootstrap = default_bootstrap.UTF8String, + .ns_logger = nslogger, + .packet_writer = packet_writer, + .start_reading = start_packet_reader, + .route_callbacks = { + .add_ipv4_route = add_ipv4_route, + .del_ipv4_route = del_ipv4_route, + .add_ipv6_route = add_ipv6_route, + .del_ipv6_route = del_ipv6_route, + .add_default_route = add_default_route, + .del_default_route = del_default_route + }, + }; + + lokinet = llarp_apple_init(&conf); if (!lokinet) { NSError *init_failure = [NSError errorWithDomain:error_domain code:500 userInfo:@{@"Error": @"Failed to initialize lokinet"}]; NSLog(@"%@", [init_failure localizedDescription]); return completionHandler(init_failure); } - NSString* ip = [[NSString alloc] initWithUTF8String:ip_buf]; - NSString* mask = [[NSString alloc] initWithUTF8String:mask_buf]; - NSString* dnsaddr = [[NSString alloc] initWithUTF8String:dns_buf]; - - NEPacketTunnelNetworkSettings* settings = - [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; + NSString* ip = [NSString stringWithUTF8String:conf.tunnel_ipv4_ip]; + NSString* mask = [NSString stringWithUTF8String:conf.tunnel_ipv4_netmask]; + NSString* dnsaddr = [NSString stringWithUTF8String:conf.tunnel_dns]; + + // 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:@[dnsaddr]]; dns.domainName = @"localhost.loki"; // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems @@ -96,16 +209,21 @@ void start_packet_reader(void* ctx) { dns.searchDomains = @[]; NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] subnetMasks:@[mask]]; - ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]]; + tun_route4 = [[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]; + ipv4.includedRoutes = @[tun_route4]; settings.IPv4Settings = ipv4; settings.DNSSettings = dns; + __weak LLARPPacketTunnel* weakSelf = self; [self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) { if (err) { NSLog(@"Failed to configure lokinet tunnel: %@", err); return completionHandler(err); } - - int start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, (__bridge void*) self); + LLARPPacketTunnel* strongSelf = weakSelf; + if (!strongSelf) + return completionHandler(nil); + + int start_ret = llarp_apple_start(strongSelf->lokinet, (__bridge void*) strongSelf); if (start_ret != 0) { NSError *start_failure = [NSError errorWithDomain:error_domain code:start_ret userInfo:@{@"Error": @"Failed to start lokinet"}]; NSLog(@"%@", start_failure); @@ -132,4 +250,34 @@ void start_packet_reader(void* ctx) { NSData* response = [NSData dataWithBytesNoCopy:"ok" length:3 freeWhenDone:NO]; completionHandler(response); } + +- (void)updateNetworkSettings +{ + self.reasserting = YES; + __weak LLARPPacketTunnel* weakSelf = self; + // Apple documentation says that setting network settings to nil isn't required before setting it + // to a new value. Apple lies: both end up with a routing table that looks exactly the same (from + // both `netstat -rn` and from everything that happens in `route -n monitor`), but if we don't + // call with nil first then everything fails to route to either lokinet *and* clearnet through the + // exit, so there is apparently some special magic internal Apple state that actually *does* + // require the tunnel settings being reset with nil first. + // + // Thanks for the accurate documentation, Apple. + // + [self setTunnelNetworkSettings:nil completionHandler:^(NSError* err) { + if (err) + NSLog(@"Failed to clear lokinet tunnel settings: %@", err); + LLARPPacketTunnel* strongSelf = weakSelf; + if (strongSelf) { + [weakSelf setTunnelNetworkSettings:strongSelf->settings completionHandler:^(NSError* err) { + LLARPPacketTunnel* strongSelf = weakSelf; + if (strongSelf) + strongSelf.reasserting = NO; + if (err) + NSLog(@"Failed to reconfigure lokinet tunnel settings: %@", err); + }]; + } + }]; +} + @end diff --git a/llarp/apple/context.hpp b/llarp/apple/context.hpp index e25090262..a3b92ad75 100644 --- a/llarp/apple/context.hpp +++ b/llarp/apple/context.hpp @@ -2,6 +2,7 @@ #include #include "vpn_platform.hpp" +#include "route_manager.hpp" namespace llarp::apple { @@ -10,7 +11,7 @@ namespace llarp::apple std::shared_ptr makeVPNPlatform() override { - return std::make_shared(*this, m_PacketWriter, m_OnReadable); + return std::make_shared(*this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context); } // Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main @@ -18,6 +19,8 @@ namespace llarp::apple // after construction. VPNInterface::packet_write_callback m_PacketWriter; VPNInterface::on_readable_callback m_OnReadable; + llarp_route_callbacks route_callbacks{}; + void* callback_context = nullptr; }; } // namespace llarp::apple diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 3d1eb2a37..2ede9a498 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -19,6 +19,8 @@ namespace { llarp::apple::Context context; std::thread runner; + packet_writer_callback packet_writer; + start_reading_callback start_reading; std::weak_ptr iface; }; @@ -26,19 +28,13 @@ namespace } // namespace void* -llarp_apple_init( - ns_logger_callback ns_logger, - const char* config_dir_, - const char* default_bootstrap, - char* ip, - char* netmask, - char* dns) +llarp_apple_init(llarp_apple_config* appleconf) { - llarp::LogContext::Instance().logStream = std::make_unique(ns_logger); + llarp::LogContext::Instance().logStream = std::make_unique(appleconf->ns_logger); try { - auto config_dir = fs::u8path(config_dir_); + auto config_dir = fs::u8path(appleconf->config_dir); auto config = std::make_shared(config_dir); fs::path config_path = config_dir / "lokinet.ini"; if (!fs::exists(config_path)) @@ -59,10 +55,10 @@ llarp_apple_init( auto mask = llarp::net::TruncateV6(range.netmask_bits).ToString(); if (addr.size() > 15 || mask.size() > 15) throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; - std::strcpy(ip, addr.c_str()); - std::strcpy(netmask, mask.c_str()); + std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str()); + std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); // XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons? - std::strcpy(dns, addr.c_str()); + std::strcpy(appleconf->tunnel_dns, addr.c_str()); // 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. @@ -71,10 +67,16 @@ llarp_apple_init( // If no explicit bootstrap then set the system default one included with the app bundle if (config->bootstrap.files.empty()) - config->bootstrap.files.push_back(fs::u8path(default_bootstrap)); + config->bootstrap.files.push_back(fs::u8path(appleconf->default_bootstrap)); auto inst = std::make_unique(); inst->context.Configure(std::move(config)); + inst->context.route_callbacks = appleconf->route_callbacks; + + inst->packet_writer = appleconf->packet_writer; + inst->start_reading = appleconf->start_reading; + + return inst.release(); } catch (const std::exception& e) @@ -87,21 +89,22 @@ llarp_apple_init( int llarp_apple_start( void* lokinet, - packet_writer_callback packet_writer, - start_reading_callback start_reading, void* callback_context) { auto* inst = static_cast(lokinet); - inst->context.m_PacketWriter = [inst, packet_writer, callback_context]( - int af_family, void* data, size_t size) { - packet_writer(af_family, data, size, callback_context); - return true; + + inst->context.callback_context = callback_context; + + inst->context.m_PacketWriter = [inst, callback_context]( + int af_family, void* data, size_t size) { + inst->packet_writer(af_family, data, size, callback_context); + return true; }; inst->context.m_OnReadable = - [inst, start_reading, callback_context](llarp::apple::VPNInterface& iface) { + [inst, callback_context](llarp::apple::VPNInterface& iface) { inst->iface = iface.weak_from_this(); - start_reading(callback_context); + inst->start_reading(callback_context); }; std::promise result; diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 6522d641a..279dd7cf1 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -12,70 +12,112 @@ extern "C" #include /// C callback function for us to invoke when we need to write a packet - typedef void(packet_writer_callback)(int af, const void* data, size_t size, void* ctx); + typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); /// C callback function to invoke once we are ready to start receiving packets - typedef void(start_reading_callback)(void* ctx); + typedef void(*start_reading_callback)(void* ctx); /// C callback that bridges things into NSLog - typedef void(ns_logger_callback)(const char* msg); + typedef void(*ns_logger_callback)(const char* msg); + + /// C callbacks to add/remove specific and default routes to the tunnel + typedef void(*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx); + typedef void(*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx); + typedef void(*llarp_default_route_callback)(void* ctx); + typedef struct llarp_route_callbacks { + /// Callback invoked to set up an IPv4 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv4_callback add_ipv4_route; + + /// Callback invoked to set the tunnel as the default IPv4 route. + llarp_default_route_callback add_ipv4_default_route; + + /// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the + /// address and netmask. + llarp_route_ipv4_callback del_ipv4_route; + + /// Callback invoked to set up an IPv6 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv6_callback add_ipv6_route; + + /// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the + /// address and netmask. + llarp_route_ipv6_callback del_ipv6_route; + + /// Callback invoked to set the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback add_default_route; + + /// Callback invoked to remove the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback del_default_route; + } llarp_route_callbacks; + + /// Pack of crap to be passed into llarp_apple_init to initialize + typedef struct llarp_apple_config + { + /// lokinet configuration directory, expected to be the application-specific "home" directory, + /// which is where state files are stored and the lokinet.ini will be loaded (or created if it + /// doesn't exist). + const char* config_dir; + /// path to the default bootstrap.signed file included in installation, which will be used by + /// default when no specific bootstrap is in the config file. + const char* default_bootstrap; + /// llarp_apple_init writes the IP address for the primary tunnel IP address here, + /// null-terminated. + char tunnel_ipv4_ip[16]; + /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. + char tunnel_ipv4_netmask[16]; + /// The DNS server IPv4 address the OS should use. Null-terminated. + char tunnel_dns[16]; + + /// \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 + /// llarp_apple_start when invoked. + /// @{ + + /// simple wrapper around NSLog for lokinet message logging + ns_logger_callback ns_logger; + + /// C function callback that will be called when we need to write a packet to the packet + /// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of + /// the data in bytes. + packet_writer_callback packet_writer; + + /// C function callback that will be called when lokinet is setup and ready to start receiving + /// packets from the packet tunnel. This should set up the read handler to deliver packets + /// via llarp_apple_incoming. + start_reading_callback start_reading; + + /// Callbacks invoked to add/remove routes to the tunnel. + llarp_route_callbacks route_callbacks; + + /// @} + } llarp_apple_config; + /// Initializes a lokinet instance by initializing various objects and loading the configuration - /// (if {config_dir}/lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start + /// (if /lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start /// for that). /// /// Returns NULL if there was a problem initializing/loading the configuration, otherwise returns /// an opaque void pointer that should be passed into the other llarp_apple_* functions. /// - /// \param logger a logger callback that we pass log messages to to relay them (i.e. via NSLog). - /// - /// \param config_dir the lokinet configuration directory where lokinet.ini can be and the various - /// other lokinet state files go. - /// - /// \param default_bootstrap the path to the default bootstrap.signed included in installation, - /// which will be used if no explicit bootstrap is set in the config file. - /// - /// \param ip - char buffer where we will write the primary tunnel IP address as a string such as - /// "172.16.0.0". Will write up to 16 characters (including the null terminator). This will be - /// the tunnel IP from the lokinet.ini, if it exists and specifies a range, otherwise we'll - /// configure lokinet to use a currently-unused range and return that. - /// - /// \param netmask the tunnel netmask as a string such as "255.255.0.0". Will write up to 16 - /// characters (including the null terminator). - /// - /// \param dns the DNS address that should be configured to query lokinet, as a string such as - /// "172.16.0.1". Will write up to 16 characters (including the null terminator). + /// \param config pointer to a llarp_apple_config where we get the various settings needed + /// and return the ip/mask/dns fields needed for the tunnel. void* - llarp_apple_init( - ns_logger_callback ns_logger, - const char* config_dir, - const char* default_bootstrap, - char* ip, - char* netmask, - char* dns); + llarp_apple_init(llarp_apple_config* config); /// Starts the lokinet instance in a new thread. /// - /// \param packet_writer C function callback that will be called when we need to write a packet to - /// the packet tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, the size - /// of the data in bytes, and the opaque callback_context pointer. - /// - /// \param start_reading C function callback that will be called when lokinet is setup and ready - /// to start receiving packets from the packet tunnel. This should set up the read handler to - /// deliver packets via llarp_apple_incoming. This is called with a single argument of the opaque - /// callback_context pointer. + /// \param lokinet the void pointer returned by llarp_apple_init /// - /// \param callback_context Opaque pointer that is passed into the packet_writer and start_reading - /// callback, intended to allow context to be passed through to the callbacks. This code does - /// nothing with this pointer aside from passing it through to callbacks. + /// \param callback_context Opaque pointer that is passed into the various callbacks provided to + /// llarp_apple_init. This code does nothing with this pointer aside from passing it through to + /// callbacks. /// /// \returns 0 on succesful startup, -1 on failure. int - llarp_apple_start( - void* lokinet, - packet_writer_callback packet_writer, - start_reading_callback start_reading, - void* callback_context); + llarp_apple_start(void* lokinet, void* callback_context); /// 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 diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp new file mode 100644 index 000000000..72310e953 --- /dev/null +++ b/llarp/apple/route_manager.cpp @@ -0,0 +1,61 @@ +#include "route_manager.hpp" + +namespace llarp::apple { + +void RouteManager::AddDefaultRouteViaInterface(std::string) +{ + LogWarn("AddDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", adr=", (bool) route_callbacks.add_default_route); + if (callback_context and route_callbacks.add_default_route) + route_callbacks.add_default_route(callback_context); +} + +void RouteManager::DelDefaultRouteViaInterface(std::string) +{ + LogWarn("DelDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", ddr=", (bool) route_callbacks.del_default_route); + if (callback_context and route_callbacks.del_default_route) + route_callbacks.del_default_route(callback_context); +} + +void +RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) +{ + LogWarn("AddRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.add_ipv4_route, + "a6r", (bool) route_callbacks.add_ipv6_route); + + if (callback_context) + { + if (range.IsV4()) { + if (route_callbacks.add_ipv4_route) + route_callbacks.add_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } else { + if (route_callbacks.add_ipv6_route) + route_callbacks.add_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } + } +} + +void +RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) +{ + LogWarn("DelRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.del_ipv4_route, + "a6r", (bool) route_callbacks.del_ipv6_route); + + if (callback_context) + { + if (range.IsV4()) { + if (route_callbacks.del_ipv4_route) + route_callbacks.del_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } else { + if (route_callbacks.del_ipv6_route) + route_callbacks.del_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } + } +} + +} diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp new file mode 100644 index 000000000..575408888 --- /dev/null +++ b/llarp/apple/route_manager.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include "context_wrapper.h" + +namespace llarp::apple { + +class RouteManager final : public llarp::vpn::IRouteManager { +public: + RouteManager(llarp_route_callbacks rcs, void* callback_context) + : route_callbacks{std::move(rcs)}, callback_context{callback_context} {} + + /// These are called for poking route holes, but we don't have to do that at all on macos + /// because the appex isn't subject to its own rules. + void + AddRoute(IPVariant_t ip, IPVariant_t gateway) override {} + + void + DelRoute(IPVariant_t ip, IPVariant_t gateway) override {} + + void + AddDefaultRouteViaInterface(std::string ifname) override; + + void + DelDefaultRouteViaInterface(std::string ifname) override; + + void + AddRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override; + + void + DelRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override; + + virtual std::vector + GetGatewaysNotOnInterface(std::string ifname) override { + // We can't get this on mac from our sandbox, but we don't actually need it because we + // ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP. + std::vector ret; + ret.push_back(huint32_t{0}); + return ret; + } + + void* callback_context = nullptr; + llarp_route_callbacks route_callbacks; +}; + +} diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 72018b509..2f56974fd 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -2,6 +2,7 @@ #include #include "vpn_interface.hpp" +#include "route_manager.hpp" namespace llarp::apple { @@ -11,8 +12,11 @@ namespace llarp::apple explicit VPNPlatform( Context& ctx, VPNInterface::packet_write_callback packet_writer, - VPNInterface::on_readable_callback on_readable) + VPNInterface::on_readable_callback on_readable, + llarp_route_callbacks route_callbacks, + void* callback_context) : m_Context{ctx} + , m_RouteManager{std::move(route_callbacks), callback_context} , m_PacketWriter{std::move(packet_writer)} , m_OnReadable{std::move(on_readable)} {} @@ -22,8 +26,11 @@ namespace llarp::apple return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); } + vpn::IRouteManager& RouteManager() override { return m_RouteManager; } + private: Context& m_Context; + apple::RouteManager m_RouteManager; VPNInterface::packet_write_callback m_PacketWriter; VPNInterface::on_readable_callback m_OnReadable; }; From fd759914b69d7320a3d848fb8db9d1791d6820f2 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 17:25:06 -0300 Subject: [PATCH 52/81] Remove unused vars --- llarp/apple/PacketTunnelProvider.m | 4 ---- llarp/apple/context_wrapper.cpp | 1 - 2 files changed, 5 deletions(-) diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index 56ef0ca22..26e35953c 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -154,10 +154,6 @@ void del_default_route(void* ctx) { - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { - char ip_buf[16]; - char mask_buf[16]; - char dns_buf[16]; - NSString* default_bootstrap = [NSBundle.mainBundle pathForResource:@"bootstrap" ofType:@"signed"]; NSString* home = NSHomeDirectory(); diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 2ede9a498..8d66911d0 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -57,7 +57,6 @@ llarp_apple_init(llarp_apple_config* appleconf) throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str()); std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); - // XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons? std::strcpy(appleconf->tunnel_dns, addr.c_str()); // The default DNS bind setting just isn't something we can use as a non-root network extension From f00e78c1a3b0f551688a21aacfebac3a72287269 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 31 Aug 2021 20:15:48 -0300 Subject: [PATCH 53/81] Add DNS trampoline This runs a DNS listener on localhost:1053 that bounces requests to the upstream DNS through the tunnel. The idea here is that, when we turn on exit mode, we start libunbound bouncing the requests through the trampoline (since if it makes direct requests they won't go through the tunnel). (The actual libunbound configuration is still to follow). --- llarp/apple/CMakeLists.txt | 1 + llarp/apple/DNSTrampoline.h | 48 ++++++++++ llarp/apple/DNSTrampoline.m | 136 +++++++++++++++++++++++++++++ llarp/apple/PacketTunnelProvider.m | 49 ++++++++--- llarp/apple/context_wrapper.cpp | 21 ++++- llarp/apple/context_wrapper.h | 11 ++- 6 files changed, 250 insertions(+), 16 deletions(-) create mode 100644 llarp/apple/DNSTrampoline.h create mode 100644 llarp/apple/DNSTrampoline.m diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 69a356020..32c4f989b 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp cont add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m + DNSTrampoline.m ) target_link_libraries(lokinet-extension PRIVATE liblokinet diff --git a/llarp/apple/DNSTrampoline.h b/llarp/apple/DNSTrampoline.h new file mode 100644 index 000000000..9e3446d76 --- /dev/null +++ b/llarp/apple/DNSTrampoline.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include + +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. + * + * 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). + * 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. + * (This assumes a non-lokinet DNS; .loki and .snode get handled before either of these). + */ +@interface LLARPDNSTrampoline : NSObject +{ + // The socket libunbound talks with: + uv_udp_t request_socket; + // The reply address. This is a bit hacky: we configure libunbound to just use single address + // (rather than a range) so that we don't have to worry about tracking different reply addresses. + @public struct sockaddr reply_addr; + // UDP "session" aimed at the upstream DNS + @public NWUDPSession* upstream; + // Apple docs say writes could take time *and* the crappy Apple datagram write methods aren't + // callable again until the previous write finishes. Deal with this garbage API by queuing + // everything than using a uv_async to process the queue. + @public int write_ready; + @public NSMutableArray* pending_writes; + uv_async_t write_trigger; +} +- (void)startWithUpstreamDns:(NWUDPSession*) dns + listenPort:(uint16_t) listenPort + uvLoop:(uv_loop_t*) loop + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)flushWrites; + +- (void)dealloc; + +@end + diff --git a/llarp/apple/DNSTrampoline.m b/llarp/apple/DNSTrampoline.m new file mode 100644 index 000000000..b0aad0121 --- /dev/null +++ b/llarp/apple/DNSTrampoline.m @@ -0,0 +1,136 @@ +#include "DNSTrampoline.h" +#include + +NSString* error_domain = @"com.loki-project.lokinet"; + + +// Receiving an incoming packet, presumably from libunbound. NB: this is called from the libuv +// event loop. +static void on_request(uv_udp_t* socket, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { + if (nread < 0) { + NSLog(@"Read error: %s", uv_strerror(nread)); + free(buf->base); + return; + } + + if (nread == 0 || !addr) { + if (buf) + free(buf->base); + return; + } + + LLARPDNSTrampoline* t = (__bridge LLARPDNSTrampoline*) socket->data; + + // We configure libunbound to use just one single port so we'll just send replies to the last port + // to talk to us. (And we're only listening on localhost in the first place). + t->reply_addr = *addr; + + // NSData takes care of calling free(buf->base) for us with this constructor: + [t->pending_writes addObject:[NSData dataWithBytesNoCopy:buf->base length:nread]]; + + [t flushWrites]; +} + +static void on_sent(uv_udp_send_t* req, int status) { + NSArray* datagrams = (__bridge_transfer NSArray*) req->data; + free(req); +} + +// NB: called from the libuv event loop (so we don't have to worry about the above and this one +// running at once from different threads). +static void write_flusher(uv_async_t* async) { + LLARPDNSTrampoline* t = (__bridge LLARPDNSTrampoline*) async->data; + if (t->pending_writes.count == 0) + return; + + NSArray* data = [NSArray arrayWithArray:t->pending_writes]; + [t->pending_writes removeAllObjects]; + __weak LLARPDNSTrampoline* weakSelf = t; + [t->upstream writeMultipleDatagrams:data completionHandler: ^(NSError* error) + { + if (error) + NSLog(@"Failed to send request to upstream DNS: %@", error); + + // Trigger another flush in case anything built up while Apple was doing its things. Just + // call it unconditionally (rather than checking the queue) because this handler is probably + // running in some other thread. + [weakSelf flushWrites]; + } + ]; +} + + +static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +@implementation LLARPDNSTrampoline + +- (void)startWithUpstreamDns:(NWUDPSession*) dns + listenPort:(uint16_t) listenPort + uvLoop:(uv_loop_t*) loop + completionHandler:(void (^)(NSError* error))completionHandler +{ + pending_writes = [[NSMutableArray alloc] init]; + write_trigger.data = (__bridge void*) self; + uv_async_init(loop, &write_trigger, write_flusher); + + 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); + 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)]; + NSError *err = [NSError errorWithDomain:error_domain code:ret userInfo:@{@"Error": errstr}]; + NSLog(@"%@", err); + return completionHandler(err); + } + uv_udp_recv_start(&request_socket, alloc_buffer, on_request); + + NSLog(@"Starting DNS trampoline"); + + upstream = dns; + __weak LLARPDNSTrampoline* weakSelf = self; + [upstream setReadHandler: ^(NSArray* datagrams, NSError* error) { + // Reading a reply back from the UDP socket used to talk to upstream + if (error) { + NSLog(@"Reader handler failed: %@", error); + return; + } + LLARPDNSTrampoline* strongSelf = weakSelf; + if (!strongSelf || datagrams.count == 0) + return; + + uv_buf_t* buffers = malloc(datagrams.count * sizeof(uv_buf_t)); + size_t buf_count = 0; + for (NSData* packet in datagrams) { + buffers[buf_count].base = (void*) packet.bytes; + buffers[buf_count].len = packet.length; + buf_count++; + } + uv_udp_send_t* uvsend = malloc(sizeof(uv_udp_send_t)); + uvsend->data = (__bridge_retained void*) datagrams; + int ret = uv_udp_send(uvsend, &strongSelf->request_socket, buffers, buf_count, &strongSelf->reply_addr, on_sent); + free(buffers); + if (ret < 0) + NSLog(@"Error returning DNS responses to unbound: %s", uv_strerror(ret)); + } maxDatagrams:NSUIntegerMax]; + + completionHandler(nil); +} + +- (void)flushWrites +{ + uv_async_send(&write_trigger); +} + +- (void) dealloc +{ + NSLog(@"Shutting down DNS trampoline"); + uv_close((uv_handle_t*) &request_socket, NULL); + uv_close((uv_handle_t*) &write_trigger, NULL); +} + +@end diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index 26e35953c..a8fcf2845 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -1,14 +1,18 @@ #include #include #include "context_wrapper.h" +#include "DNSTrampoline.h" -NSString* error_domain = @"com.loki-project.lokinet"; +// Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route when +// in exit mode. +const uint16_t dns_trampoline_port = 1053; @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; @public NEPacketTunnelNetworkSettings* settings; @public NEIPv4Route* tun_route4; + LLARPDNSTrampoline* dns_tramp; } - (void)startTunnelWithOptions:(NSDictionary*)options @@ -26,9 +30,9 @@ NSString* error_domain = @"com.loki-project.lokinet"; @end -void nslogger(const char* msg) { NSLog(@"%s", msg); } +static void nslogger(const char* msg) { NSLog(@"%s", msg); } -void packet_writer(int af, const void* data, size_t size, void* ctx) { +static void packet_writer(int af, const void* data, size_t size, void* ctx) { if (ctx == nil || data == nil) return; @@ -38,7 +42,7 @@ void packet_writer(int af, const void* data, size_t size, void* ctx) { [t.packetFlow writePacketObjects:@[packet]]; } -void start_packet_reader(void* ctx) { +static void start_packet_reader(void* ctx) { if (ctx == nil) return; @@ -46,7 +50,7 @@ void start_packet_reader(void* ctx) { [t readPackets]; } -void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { +static void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { NEIPv4Route* route = [[NEIPv4Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] subnetMask: [NSString stringWithUTF8String:netmask]]; @@ -63,7 +67,7 @@ void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { [t updateNetworkSettings]; } -void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { +static void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { NEIPv4Route* route = [[NEIPv4Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] subnetMask: [NSString stringWithUTF8String:netmask]]; @@ -84,7 +88,7 @@ void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { } } -void add_ipv6_route(const char* addr, int prefix, void* ctx) { +static void add_ipv6_route(const char* addr, int prefix, void* ctx) { NEIPv6Route* route = [[NEIPv6Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] networkPrefixLength: [NSNumber numberWithInt:prefix]]; @@ -100,7 +104,8 @@ void add_ipv6_route(const char* addr, int prefix, void* ctx) { [t updateNetworkSettings]; } -void del_ipv6_route(const char* addr, int prefix, void* ctx) { + +static void del_ipv6_route(const char* addr, int prefix, void* ctx) { NEIPv6Route* route = [[NEIPv6Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] networkPrefixLength: [NSNumber numberWithInt:prefix]]; @@ -120,7 +125,8 @@ void del_ipv6_route(const char* addr, int prefix, void* ctx) { [t updateNetworkSettings]; } } -void add_default_route(void* ctx) { + +static void add_default_route(void* ctx) { LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute]; @@ -128,7 +134,8 @@ void add_default_route(void* ctx) { [t updateNetworkSettings]; } -void del_default_route(void* ctx) { + +static void del_default_route(void* ctx) { LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; t->settings.IPv4Settings.includedRoutes = @[t->tun_route4]; @@ -182,13 +189,13 @@ void del_default_route(void* ctx) { NSString* ip = [NSString stringWithUTF8String:conf.tunnel_ipv4_ip]; NSString* mask = [NSString stringWithUTF8String:conf.tunnel_ipv4_netmask]; - NSString* dnsaddr = [NSString stringWithUTF8String:conf.tunnel_dns]; // 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:@[dnsaddr]]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[ip]]; dns.domainName = @"localhost.loki"; + dns.matchDomains = @[@""]; // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems // highly unreliable, though: often it just doesn't work at all (perhaps only if we make ourselves // the default route?), and even when it does work, it seems there are secret reasons that some @@ -203,6 +210,11 @@ void del_default_route(void* ctx) { dns.matchDomains = @[@""]; dns.matchDomainsNoSearch = true; dns.searchDomains = @[]; + + NWHostEndpoint* upstreamdns_ep; + if (strlen(conf.upstream_dns)) + upstreamdns_ep = [NWHostEndpoint endpointWithHostname:[NSString stringWithUTF8String:conf.upstream_dns] port:@(conf.upstream_dns_port).stringValue]; + NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] subnetMasks:@[mask]]; tun_route4 = [[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]; @@ -226,7 +238,18 @@ void del_default_route(void* ctx) { lokinet = nil; return completionHandler(start_failure); } - completionHandler(nil); + + NWUDPSession* upstreamdns = [strongSelf createUDPSessionThroughTunnelToEndpoint:upstreamdns_ep fromEndpoint:nil]; + strongSelf->dns_tramp = [LLARPDNSTrampoline alloc]; + [strongSelf->dns_tramp + startWithUpstreamDns:upstreamdns + listenPort:dns_trampoline_port + uvLoop:llarp_apple_get_uv_loop(strongSelf->lokinet) + completionHandler:^(NSError* error) { + if (error) + NSLog(@"Error starting dns trampoline: %@", error); + return completionHandler(error); + }]; }]; } diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 8d66911d0..84d98e67c 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -1,9 +1,11 @@ #include #include +#include #include #include #include #include +#include #include "vpn_interface.hpp" #include "context_wrapper.h" #include "context.hpp" @@ -57,7 +59,15 @@ llarp_apple_init(llarp_apple_config* appleconf) throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str()); std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); - std::strcpy(appleconf->tunnel_dns, addr.c_str()); + + appleconf->upstream_dns[0] = '\0'; + for (auto& upstream : config->dns.m_upstreamDNS) { + if (upstream.isIPv4()) { + std::strcpy(appleconf->upstream_dns, upstream.hostString().c_str()); + appleconf->upstream_dns_port = upstream.getPort(); + break; + } + } // 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. @@ -135,6 +145,15 @@ llarp_apple_start( return 0; } +uv_loop_t* +llarp_apple_get_uv_loop(void* lokinet) +{ + auto& inst = *static_cast(lokinet); + auto uvw = inst.context.loop->MaybeGetUVWLoop(); + assert(uvw); + return uvw->raw(); +} + int llarp_apple_incoming(void* lokinet, const void* bytes, size_t size) { diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 279dd7cf1..425986015 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -10,6 +10,7 @@ extern "C" #include #include +#include /// C callback function for us to invoke when we need to write a packet typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); @@ -66,8 +67,10 @@ extern "C" char tunnel_ipv4_ip[16]; /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. char tunnel_ipv4_netmask[16]; - /// The DNS server IPv4 address the OS should use. Null-terminated. - char tunnel_dns[16]; + /// The first upstream DNS server's IPv4 address the OS should use when in exit mode. + /// (Currently on mac in exit mode we only support querying the first such configured server). + char upstream_dns[16]; + uint16_t upstream_dns_port; /// \defgroup callbacks Callbacks /// Callbacks we invoke for various operations that require glue into the Apple network @@ -119,6 +122,10 @@ extern "C" int llarp_apple_start(void* lokinet, void* callback_context); + /// Returns a pointer to the uv event loop. Must have called llarp_apple_start already. + 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 From 0f097450d74d296252cfd7c09f7a58aed885dfa3 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 31 Aug 2021 21:15:20 -0300 Subject: [PATCH 54/81] Remove debug --- llarp/apple/route_manager.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp index 72310e953..9ec9253e2 100644 --- a/llarp/apple/route_manager.cpp +++ b/llarp/apple/route_manager.cpp @@ -4,14 +4,12 @@ namespace llarp::apple { void RouteManager::AddDefaultRouteViaInterface(std::string) { - LogWarn("AddDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", adr=", (bool) route_callbacks.add_default_route); if (callback_context and route_callbacks.add_default_route) route_callbacks.add_default_route(callback_context); } void RouteManager::DelDefaultRouteViaInterface(std::string) { - LogWarn("DelDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", ddr=", (bool) route_callbacks.del_default_route); if (callback_context and route_callbacks.del_default_route) route_callbacks.del_default_route(callback_context); } @@ -19,9 +17,6 @@ void RouteManager::DelDefaultRouteViaInterface(std::string) void RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) { - LogWarn("AddRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.add_ipv4_route, - "a6r", (bool) route_callbacks.add_ipv6_route); - if (callback_context) { if (range.IsV4()) { @@ -40,9 +35,6 @@ RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) void RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) { - LogWarn("DelRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.del_ipv4_route, - "a6r", (bool) route_callbacks.del_ipv6_route); - if (callback_context) { if (range.IsV4()) { From 9dd604820f8e0859528902e7f50c28df83ea7c44 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:10:08 -0300 Subject: [PATCH 55/81] Unleak exit mode DNS via unbound DNS trampoline on (macOS) When we enable/disable exit mode on this restarts the unbound DNS responder with the DNS trampoline (or restores upstream, when disabling) to properly route DNS requests through the tunnel (because libunbound's direct requests don't get tunneled because unbound is inside the network extension). --- llarp/apple/CMakeLists.txt | 2 +- llarp/apple/DNSTrampoline.m | 2 +- llarp/apple/PacketTunnelProvider.m | 5 +---- llarp/apple/context_wrapper.cpp | 2 ++ llarp/apple/context_wrapper.h | 4 ++++ llarp/apple/route_manager.cpp | 36 ++++++++++++++++++++++++++++++ llarp/apple/route_manager.hpp | 12 ++++++++-- llarp/apple/vpn_platform.cpp | 22 ++++++++++++++++++ llarp/apple/vpn_platform.hpp | 12 ++-------- llarp/dns/server.cpp | 13 ++++++----- llarp/dns/server.hpp | 4 ++++ llarp/dns/unbound_resolver.cpp | 21 ++++++++++++++++- llarp/handlers/tun.cpp | 29 ++++++++++++++++++++++-- llarp/handlers/tun.hpp | 5 +++++ llarp/service/endpoint.hpp | 1 - 15 files changed, 142 insertions(+), 28 deletions(-) create mode 100644 llarp/apple/vpn_platform.cpp diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 32c4f989b..a2799167e 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -15,7 +15,7 @@ find_library(COREFOUNDATION CoreFoundation REQUIRED) target_sources(lokinet-util PRIVATE apple_logger.cpp) target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp context_wrapper.cpp) +target_sources(lokinet-platform PRIVATE vpn_platform.cpp vpn_interface.cpp route_manager.cpp context_wrapper.cpp) add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m diff --git a/llarp/apple/DNSTrampoline.m b/llarp/apple/DNSTrampoline.m index b0aad0121..0a78a13e2 100644 --- a/llarp/apple/DNSTrampoline.m +++ b/llarp/apple/DNSTrampoline.m @@ -128,7 +128,7 @@ static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* b - (void) dealloc { - NSLog(@"Shutting down DNS trampoline"); + NSLog(@"Stopping DNS trampoline"); uv_close((uv_handle_t*) &request_socket, NULL); uv_close((uv_handle_t*) &write_trigger, NULL); } diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index a8fcf2845..7e03d5693 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -3,10 +3,6 @@ #include "context_wrapper.h" #include "DNSTrampoline.h" -// Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route when -// in exit mode. -const uint16_t dns_trampoline_port = 1053; - @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; @@ -239,6 +235,7 @@ 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); NWUDPSession* upstreamdns = [strongSelf createUDPSessionThroughTunnelToEndpoint:upstreamdns_ep fromEndpoint:nil]; strongSelf->dns_tramp = [LLARPDNSTrampoline alloc]; [strongSelf->dns_tramp diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 84d98e67c..6d6cbd0c8 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -29,6 +29,8 @@ namespace } // namespace +const uint16_t dns_trampoline_port = 1053; + void* llarp_apple_init(llarp_apple_config* appleconf) { diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 425986015..74ac38eed 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -12,6 +12,10 @@ extern "C" #include #include + // Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route + // when in exit mode. + extern const uint16_t dns_trampoline_port; + /// C callback function for us to invoke when we need to write a packet typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp index 9ec9253e2..87376f576 100644 --- a/llarp/apple/route_manager.cpp +++ b/llarp/apple/route_manager.cpp @@ -1,15 +1,49 @@ #include "route_manager.hpp" +#include +#include +#include +#include namespace llarp::apple { +void RouteManager::check_trampoline(bool enable) { + if (trampoline_active == enable) + return; + auto router = context.router; + if (!router) { + LogError("Cannot reconfigure to use DNS trampoline: no router"); + return; + } + + std::shared_ptr tun; + router->hiddenServiceContext().ForEachService([&tun] (const auto& name, const auto ep) { + tun = std::dynamic_pointer_cast(ep); + return !tun; + }); + + if (!tun) { + LogError("Cannot reconfigure to use DNS trampoline: no tun endpoint found (!?)"); + return; + } + + if (enable) + saved_upstream_dns = tun->ReconfigureDNS({SockAddr{127, 0, 0, 1, huint16_t{dns_trampoline_port}}}); + else + tun->ReconfigureDNS(std::move(saved_upstream_dns)); + trampoline_active = enable; +} + + void RouteManager::AddDefaultRouteViaInterface(std::string) { + check_trampoline(true); if (callback_context and route_callbacks.add_default_route) route_callbacks.add_default_route(callback_context); } void RouteManager::DelDefaultRouteViaInterface(std::string) { + check_trampoline(false); if (callback_context and route_callbacks.del_default_route) route_callbacks.del_default_route(callback_context); } @@ -17,6 +51,7 @@ void RouteManager::DelDefaultRouteViaInterface(std::string) void RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) { + check_trampoline(true); if (callback_context) { if (range.IsV4()) { @@ -35,6 +70,7 @@ RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) void RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) { + check_trampoline(false); if (callback_context) { if (range.IsV4()) { diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp index 575408888..e012c3dc0 100644 --- a/llarp/apple/route_manager.hpp +++ b/llarp/apple/route_manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "context_wrapper.h" @@ -7,8 +8,8 @@ namespace llarp::apple { class RouteManager final : public llarp::vpn::IRouteManager { public: - RouteManager(llarp_route_callbacks rcs, void* callback_context) - : route_callbacks{std::move(rcs)}, callback_context{callback_context} {} + RouteManager(llarp::Context& ctx, llarp_route_callbacks rcs, void* callback_context) + : context{ctx}, route_callbacks{std::move(rcs)}, callback_context{callback_context} {} /// These are called for poking route holes, but we don't have to do that at all on macos /// because the appex isn't subject to its own rules. @@ -39,6 +40,13 @@ public: return ret; } +private: + + llarp::Context& context; + bool trampoline_active = false; + std::vector saved_upstream_dns; + void check_trampoline(bool enable); + void* callback_context = nullptr; llarp_route_callbacks route_callbacks; }; diff --git a/llarp/apple/vpn_platform.cpp b/llarp/apple/vpn_platform.cpp new file mode 100644 index 000000000..b11c0b05b --- /dev/null +++ b/llarp/apple/vpn_platform.cpp @@ -0,0 +1,22 @@ +#include "vpn_platform.hpp" +#include "context.hpp" + +namespace llarp::apple +{ + VPNPlatform::VPNPlatform( + Context& ctx, + VPNInterface::packet_write_callback packet_writer, + VPNInterface::on_readable_callback on_readable, + llarp_route_callbacks route_callbacks, + void* callback_context) + : m_Context{ctx} + , m_RouteManager{ctx, std::move(route_callbacks), callback_context} + , m_PacketWriter{std::move(packet_writer)} + , m_OnReadable{std::move(on_readable)} + {} + + std::shared_ptr VPNPlatform::ObtainInterface(vpn::InterfaceInfo) + { + return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); + } +} // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 2f56974fd..974a79305 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -14,17 +14,9 @@ namespace llarp::apple VPNInterface::packet_write_callback packet_writer, VPNInterface::on_readable_callback on_readable, llarp_route_callbacks route_callbacks, - void* callback_context) - : m_Context{ctx} - , m_RouteManager{std::move(route_callbacks), callback_context} - , m_PacketWriter{std::move(packet_writer)} - , m_OnReadable{std::move(on_readable)} - {} + void* callback_context); - std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override - { - return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); - } + std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override; vpn::IRouteManager& RouteManager() override { return m_RouteManager; } diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index 5c8d6b4ca..e22a51db2 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -70,6 +70,7 @@ namespace llarp::dns m_UnboundResolver = std::make_shared(m_Loop, std::move(replyFunc), std::move(failFunc)); + m_Resolvers.clear(); if (not m_UnboundResolver->Init()) { llarp::LogError("Failed to initialize upstream DNS resolver."); @@ -102,9 +103,13 @@ namespace llarp::dns llarp::LogError("dns reply failed"); } + bool PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const { + return m_Resolvers.count(to); + } + bool PacketHandler::ShouldHandlePacket( - const SockAddr& to, [[maybe_unused]] const SockAddr& from, llarp_buffer_t buf) const + const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) const { MessageHeader hdr; if (not hdr.Decode(&buf)) @@ -121,11 +126,7 @@ namespace llarp::dns if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg)) return true; - if (m_Resolvers.find(to) != m_Resolvers.end()) - { - return false; - } - return true; + return !IsUpstreamResolver(to, from); } void diff --git a/llarp/dns/server.hpp b/llarp/dns/server.hpp index 21f45ed54..2242ba450 100644 --- a/llarp/dns/server.hpp +++ b/llarp/dns/server.hpp @@ -56,6 +56,10 @@ namespace llarp virtual void SendServerMessageBufferTo(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) = 0; + // Returns true if this packet is something that looks like it's going to an upstream + // resolver, i.e. matches a configured resolver. + virtual bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const; + private: void HandleUpstreamFailure(const SockAddr& from, const SockAddr& to, Message msg); diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index a6e747523..9df195095 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -140,7 +140,8 @@ namespace llarp::dns UnboundResolver::AddUpstreamResolver(const SockAddr& upstreamResolver) { std::stringstream ss; - ss << upstreamResolver.hostString(); + auto hoststr = upstreamResolver.hostString(); + ss << hoststr; if (const auto port = upstreamResolver.getPort(); port != 53) ss << "@" << port; @@ -151,6 +152,24 @@ namespace llarp::dns 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") { + // 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"); + } +#endif + return true; } diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 8da523b22..f0a754cf4 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -35,8 +35,8 @@ namespace llarp namespace handlers { // Intercepts DNS IP packets going to an IP on the tun interface; this is currently used on - // Android where binding to a DNS port (i.e. via llarp::dns::Proxy) isn't possible because of OS - // restrictions, but a tun interface *is* available. + // Android and macOS where binding to a DNS port (i.e. via llarp::dns::Proxy) isn't possible + // because of OS restrictions, but a tun interface *is* available. class DnsInterceptor : public dns::PacketHandler { public: @@ -61,6 +61,20 @@ namespace llarp m_Endpoint->HandleWriteIPPacket( pkt.ConstBuffer(), net::ExpandV4(from.asIPv4()), net::ExpandV4(to.asIPv4()), 0); } + +#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. + bool + IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override + { + LogError("IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); + return to.asIPv6() != m_Endpoint->GetIfAddr(); + } +#endif }; TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent) @@ -136,6 +150,17 @@ namespace llarp m_Resolver->Restart(); } + std::vector + TunEndpoint::ReconfigureDNS(std::vector servers) + { + std::swap(m_UpstreamResolvers, servers); + m_Resolver->Stop(); + if (!m_Resolver->Start( + m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles)) + llarp::LogError(Name(), " failed to reconfigure DNS server"); + return servers; + } + bool TunEndpoint::Configure(const NetworkConfig& conf, const DnsConfig& dnsConf) { diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index 4be9ba909..6ea44b794 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -43,6 +43,11 @@ namespace llarp void Thaw() override; + // Reconfigures DNS servers and restarts libunbound with the new servers. Returns the old set + // of configured dns servers. + std::vector + ReconfigureDNS(std::vector servers); + bool Configure(const NetworkConfig& conf, const DnsConfig& dnsConf) override; diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 0fd8c625c..cfb5a2ef9 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -11,7 +11,6 @@ #include "identity.hpp" #include "pendingbuffer.hpp" #include "protocol.hpp" -#include "quic/server.hpp" #include "sendcontext.hpp" #include "service/protocol_type.hpp" #include "session.hpp" From e11efe9bc5413d9ec4202579926fa54044843c96 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:31:45 -0300 Subject: [PATCH 56/81] Reformat --- llarp/apple/DNSTrampoline.h | 19 +++-- llarp/apple/context.hpp | 3 +- llarp/apple/context_wrapper.cpp | 32 ++++--- llarp/apple/context_wrapper.h | 144 ++++++++++++++++---------------- llarp/apple/route_manager.cpp | 142 +++++++++++++++++-------------- llarp/apple/route_manager.hpp | 41 +++++---- llarp/apple/vpn_platform.hpp | 6 +- llarp/dns/server.cpp | 4 +- llarp/dns/server.hpp | 3 +- llarp/dns/unbound_resolver.cpp | 21 ++--- llarp/handlers/tun.cpp | 17 ++-- 11 files changed, 230 insertions(+), 202 deletions(-) diff --git a/llarp/apple/DNSTrampoline.h b/llarp/apple/DNSTrampoline.h index 9e3446d76..4935d43c8 100644 --- a/llarp/apple/DNSTrampoline.h +++ b/llarp/apple/DNSTrampoline.h @@ -25,19 +25,23 @@ extern NSString* error_domain; uv_udp_t request_socket; // The reply address. This is a bit hacky: we configure libunbound to just use single address // (rather than a range) so that we don't have to worry about tracking different reply addresses. - @public struct sockaddr reply_addr; + @public + struct sockaddr reply_addr; // UDP "session" aimed at the upstream DNS - @public NWUDPSession* upstream; + @public + NWUDPSession* upstream; // Apple docs say writes could take time *and* the crappy Apple datagram write methods aren't // callable again until the previous write finishes. Deal with this garbage API by queuing // everything than using a uv_async to process the queue. - @public int write_ready; - @public NSMutableArray* pending_writes; + @public + int write_ready; + @public + NSMutableArray* pending_writes; uv_async_t write_trigger; } -- (void)startWithUpstreamDns:(NWUDPSession*) dns - listenPort:(uint16_t) listenPort - uvLoop:(uv_loop_t*) loop +- (void)startWithUpstreamDns:(NWUDPSession*)dns + listenPort:(uint16_t)listenPort + uvLoop:(uv_loop_t*)loop completionHandler:(void (^)(NSError* error))completionHandler; - (void)flushWrites; @@ -45,4 +49,3 @@ extern NSString* error_domain; - (void)dealloc; @end - diff --git a/llarp/apple/context.hpp b/llarp/apple/context.hpp index a3b92ad75..4fc808874 100644 --- a/llarp/apple/context.hpp +++ b/llarp/apple/context.hpp @@ -11,7 +11,8 @@ namespace llarp::apple std::shared_ptr makeVPNPlatform() override { - return std::make_shared(*this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context); + return std::make_shared( + *this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context); } // Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 6d6cbd0c8..ce9354540 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -34,7 +34,8 @@ const uint16_t dns_trampoline_port = 1053; void* llarp_apple_init(llarp_apple_config* appleconf) { - llarp::LogContext::Instance().logStream = std::make_unique(appleconf->ns_logger); + llarp::LogContext::Instance().logStream = + std::make_unique(appleconf->ns_logger); try { @@ -42,7 +43,7 @@ llarp_apple_init(llarp_apple_config* appleconf) auto config = std::make_shared(config_dir); fs::path config_path = config_dir / "lokinet.ini"; if (!fs::exists(config_path)) - llarp::ensureConfig(config_dir, config_path, /*overwrite=*/ false, /*router=*/ false); + llarp::ensureConfig(config_dir, config_path, /*overwrite=*/false, /*router=*/false); config->Load(config_path); // If no range is specified then go look for a free one, set that in the config, and then return @@ -63,8 +64,10 @@ llarp_apple_init(llarp_apple_config* appleconf) std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); appleconf->upstream_dns[0] = '\0'; - for (auto& upstream : config->dns.m_upstreamDNS) { - if (upstream.isIPv4()) { + for (auto& upstream : config->dns.m_upstreamDNS) + { + if (upstream.isIPv4()) + { std::strcpy(appleconf->upstream_dns, upstream.hostString().c_str()); appleconf->upstream_dns_port = upstream.getPort(); break; @@ -87,7 +90,6 @@ llarp_apple_init(llarp_apple_config* appleconf) inst->packet_writer = appleconf->packet_writer; inst->start_reading = appleconf->start_reading; - return inst.release(); } catch (const std::exception& e) @@ -98,25 +100,21 @@ llarp_apple_init(llarp_apple_config* appleconf) } int -llarp_apple_start( - void* lokinet, - void* callback_context) +llarp_apple_start(void* lokinet, void* callback_context) { auto* inst = static_cast(lokinet); inst->context.callback_context = callback_context; - inst->context.m_PacketWriter = [inst, callback_context]( - int af_family, void* data, size_t size) { - inst->packet_writer(af_family, data, size, callback_context); - return true; + inst->context.m_PacketWriter = [inst, callback_context](int af_family, void* data, size_t size) { + inst->packet_writer(af_family, data, size, callback_context); + return true; }; - inst->context.m_OnReadable = - [inst, callback_context](llarp::apple::VPNInterface& iface) { - inst->iface = iface.weak_from_this(); - inst->start_reading(callback_context); - }; + inst->context.m_OnReadable = [inst, callback_context](llarp::apple::VPNInterface& iface) { + inst->iface = iface.weak_from_this(); + inst->start_reading(callback_context); + }; std::promise result; inst->runner = std::thread{[inst, &result] { diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 74ac38eed..914446741 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -17,91 +17,91 @@ extern "C" extern const uint16_t dns_trampoline_port; /// C callback function for us to invoke when we need to write a packet - typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); + typedef void (*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); /// C callback function to invoke once we are ready to start receiving packets - typedef void(*start_reading_callback)(void* ctx); + typedef void (*start_reading_callback)(void* ctx); /// C callback that bridges things into NSLog - typedef void(*ns_logger_callback)(const char* msg); + typedef void (*ns_logger_callback)(const char* msg); /// C callbacks to add/remove specific and default routes to the tunnel - typedef void(*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx); - typedef void(*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx); - typedef void(*llarp_default_route_callback)(void* ctx); - typedef struct llarp_route_callbacks { - /// Callback invoked to set up an IPv4 range that should be routed through the tunnel - /// interface. Called with the address and netmask. - llarp_route_ipv4_callback add_ipv4_route; - - /// Callback invoked to set the tunnel as the default IPv4 route. - llarp_default_route_callback add_ipv4_default_route; - - /// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the - /// address and netmask. - llarp_route_ipv4_callback del_ipv4_route; - - /// Callback invoked to set up an IPv6 range that should be routed through the tunnel - /// interface. Called with the address and netmask. - llarp_route_ipv6_callback add_ipv6_route; - - /// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the - /// address and netmask. - llarp_route_ipv6_callback del_ipv6_route; - - /// Callback invoked to set the tunnel as the default IPv4/IPv6 route. - llarp_default_route_callback add_default_route; - - /// Callback invoked to remove the tunnel as the default IPv4/IPv6 route. - llarp_default_route_callback del_default_route; + typedef void (*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx); + typedef void (*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx); + typedef void (*llarp_default_route_callback)(void* ctx); + typedef struct llarp_route_callbacks + { + /// Callback invoked to set up an IPv4 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv4_callback add_ipv4_route; + + /// Callback invoked to set the tunnel as the default IPv4 route. + llarp_default_route_callback add_ipv4_default_route; + + /// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the + /// address and netmask. + llarp_route_ipv4_callback del_ipv4_route; + + /// Callback invoked to set up an IPv6 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv6_callback add_ipv6_route; + + /// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the + /// address and netmask. + llarp_route_ipv6_callback del_ipv6_route; + + /// Callback invoked to set the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback add_default_route; + + /// Callback invoked to remove the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback del_default_route; } llarp_route_callbacks; /// Pack of crap to be passed into llarp_apple_init to initialize typedef struct llarp_apple_config { - /// lokinet configuration directory, expected to be the application-specific "home" directory, - /// which is where state files are stored and the lokinet.ini will be loaded (or created if it - /// doesn't exist). - const char* config_dir; - /// path to the default bootstrap.signed file included in installation, which will be used by - /// default when no specific bootstrap is in the config file. - const char* default_bootstrap; - /// llarp_apple_init writes the IP address for the primary tunnel IP address here, - /// null-terminated. - char tunnel_ipv4_ip[16]; - /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. - char tunnel_ipv4_netmask[16]; - /// The first upstream DNS server's IPv4 address the OS should use when in exit mode. - /// (Currently on mac in exit mode we only support querying the first such configured server). - char upstream_dns[16]; - uint16_t upstream_dns_port; - - /// \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 - /// llarp_apple_start when invoked. - /// @{ - - /// simple wrapper around NSLog for lokinet message logging - ns_logger_callback ns_logger; - - /// C function callback that will be called when we need to write a packet to the packet - /// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of - /// the data in bytes. - packet_writer_callback packet_writer; - - /// C function callback that will be called when lokinet is setup and ready to start receiving - /// packets from the packet tunnel. This should set up the read handler to deliver packets - /// via llarp_apple_incoming. - start_reading_callback start_reading; - - /// Callbacks invoked to add/remove routes to the tunnel. - llarp_route_callbacks route_callbacks; - - /// @} + /// lokinet configuration directory, expected to be the application-specific "home" directory, + /// which is where state files are stored and the lokinet.ini will be loaded (or created if it + /// doesn't exist). + const char* config_dir; + /// path to the default bootstrap.signed file included in installation, which will be used by + /// default when no specific bootstrap is in the config file. + const char* default_bootstrap; + /// llarp_apple_init writes the IP address for the primary tunnel IP address here, + /// null-terminated. + char tunnel_ipv4_ip[16]; + /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. + char tunnel_ipv4_netmask[16]; + /// The first upstream DNS server's IPv4 address the OS should use when in exit mode. + /// (Currently on mac in exit mode we only support querying the first such configured server). + char upstream_dns[16]; + uint16_t upstream_dns_port; + + /// \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 + /// llarp_apple_start when invoked. + /// @{ + + /// simple wrapper around NSLog for lokinet message logging + ns_logger_callback ns_logger; + + /// C function callback that will be called when we need to write a packet to the packet + /// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of + /// the data in bytes. + packet_writer_callback packet_writer; + + /// C function callback that will be called when lokinet is setup and ready to start receiving + /// packets from the packet tunnel. This should set up the read handler to deliver packets + /// via llarp_apple_incoming. + start_reading_callback start_reading; + + /// Callbacks invoked to add/remove routes to the tunnel. + llarp_route_callbacks route_callbacks; + + /// @} } llarp_apple_config; - /// Initializes a lokinet instance by initializing various objects and loading the configuration /// (if /lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start /// for that). diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp index 87376f576..0bf170577 100644 --- a/llarp/apple/route_manager.cpp +++ b/llarp/apple/route_manager.cpp @@ -4,86 +4,98 @@ #include #include -namespace llarp::apple { - -void RouteManager::check_trampoline(bool enable) { - if (trampoline_active == enable) - return; - auto router = context.router; - if (!router) { - LogError("Cannot reconfigure to use DNS trampoline: no router"); - return; - } +namespace llarp::apple +{ + void + RouteManager::check_trampoline(bool enable) + { + if (trampoline_active == enable) + return; + auto router = context.router; + if (!router) + { + LogError("Cannot reconfigure to use DNS trampoline: no router"); + return; + } - std::shared_ptr tun; - router->hiddenServiceContext().ForEachService([&tun] (const auto& name, const auto ep) { + std::shared_ptr tun; + router->hiddenServiceContext().ForEachService([&tun](const auto& name, const auto ep) { tun = std::dynamic_pointer_cast(ep); return !tun; - }); + }); - if (!tun) { - LogError("Cannot reconfigure to use DNS trampoline: no tun endpoint found (!?)"); - return; - } - - if (enable) - saved_upstream_dns = tun->ReconfigureDNS({SockAddr{127, 0, 0, 1, huint16_t{dns_trampoline_port}}}); - else - tun->ReconfigureDNS(std::move(saved_upstream_dns)); - trampoline_active = enable; -} + if (!tun) + { + LogError("Cannot reconfigure to use DNS trampoline: no tun endpoint found (!?)"); + return; + } + if (enable) + saved_upstream_dns = + tun->ReconfigureDNS({SockAddr{127, 0, 0, 1, huint16_t{dns_trampoline_port}}}); + else + tun->ReconfigureDNS(std::move(saved_upstream_dns)); + trampoline_active = enable; + } -void RouteManager::AddDefaultRouteViaInterface(std::string) -{ - check_trampoline(true); + void RouteManager::AddDefaultRouteViaInterface(std::string) + { + check_trampoline(true); if (callback_context and route_callbacks.add_default_route) - route_callbacks.add_default_route(callback_context); -} + route_callbacks.add_default_route(callback_context); + } -void RouteManager::DelDefaultRouteViaInterface(std::string) -{ - check_trampoline(false); + void RouteManager::DelDefaultRouteViaInterface(std::string) + { + check_trampoline(false); if (callback_context and route_callbacks.del_default_route) - route_callbacks.del_default_route(callback_context); -} + route_callbacks.del_default_route(callback_context); + } -void -RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) -{ - check_trampoline(true); + void + RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) + { + check_trampoline(true); if (callback_context) { - if (range.IsV4()) { - if (route_callbacks.add_ipv4_route) - route_callbacks.add_ipv4_route( - range.BaseAddressString().c_str(), - net::TruncateV6(range.netmask_bits).ToString().c_str(), - callback_context); - } else { - if (route_callbacks.add_ipv6_route) - route_callbacks.add_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); - } + if (range.IsV4()) + { + if (route_callbacks.add_ipv4_route) + route_callbacks.add_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } + else + { + if (route_callbacks.add_ipv6_route) + route_callbacks.add_ipv6_route( + range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } } -} + } -void -RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) -{ - check_trampoline(false); + void + RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) + { + check_trampoline(false); if (callback_context) { - if (range.IsV4()) { - if (route_callbacks.del_ipv4_route) - route_callbacks.del_ipv4_route( - range.BaseAddressString().c_str(), - net::TruncateV6(range.netmask_bits).ToString().c_str(), - callback_context); - } else { - if (route_callbacks.del_ipv6_route) - route_callbacks.del_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); - } + if (range.IsV4()) + { + if (route_callbacks.del_ipv4_route) + route_callbacks.del_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } + else + { + if (route_callbacks.del_ipv6_route) + route_callbacks.del_ipv6_route( + range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } } -} + } -} +} // namespace llarp::apple diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp index e012c3dc0..cb8bb3f1b 100644 --- a/llarp/apple/route_manager.hpp +++ b/llarp/apple/route_manager.hpp @@ -4,20 +4,24 @@ #include #include "context_wrapper.h" -namespace llarp::apple { - -class RouteManager final : public llarp::vpn::IRouteManager { -public: +namespace llarp::apple +{ + class RouteManager final : public llarp::vpn::IRouteManager + { + public: RouteManager(llarp::Context& ctx, llarp_route_callbacks rcs, void* callback_context) - : context{ctx}, route_callbacks{std::move(rcs)}, callback_context{callback_context} {} + : context{ctx}, route_callbacks{std::move(rcs)}, callback_context{callback_context} + {} /// These are called for poking route holes, but we don't have to do that at all on macos /// because the appex isn't subject to its own rules. void - AddRoute(IPVariant_t ip, IPVariant_t gateway) override {} + AddRoute(IPVariant_t ip, IPVariant_t gateway) override + {} void - DelRoute(IPVariant_t ip, IPVariant_t gateway) override {} + DelRoute(IPVariant_t ip, IPVariant_t gateway) override + {} void AddDefaultRouteViaInterface(std::string ifname) override; @@ -32,23 +36,24 @@ public: DelRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override; virtual std::vector - GetGatewaysNotOnInterface(std::string ifname) override { - // We can't get this on mac from our sandbox, but we don't actually need it because we - // ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP. - std::vector ret; - ret.push_back(huint32_t{0}); - return ret; + GetGatewaysNotOnInterface(std::string ifname) override + { + // We can't get this on mac from our sandbox, but we don't actually need it because we + // ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP. + std::vector ret; + ret.push_back(huint32_t{0}); + return ret; } -private: - + private: llarp::Context& context; bool trampoline_active = false; std::vector saved_upstream_dns; - void check_trampoline(bool enable); + void + check_trampoline(bool enable); void* callback_context = nullptr; llarp_route_callbacks route_callbacks; -}; + }; -} +} // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 974a79305..04ce75646 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -18,7 +18,11 @@ namespace llarp::apple std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override; - vpn::IRouteManager& RouteManager() override { return m_RouteManager; } + vpn::IRouteManager& + RouteManager() override + { + return m_RouteManager; + } private: Context& m_Context; diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index e22a51db2..d2cac921b 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -103,7 +103,9 @@ namespace llarp::dns llarp::LogError("dns reply failed"); } - bool PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const { + bool + PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const + { return m_Resolvers.count(to); } diff --git a/llarp/dns/server.hpp b/llarp/dns/server.hpp index 2242ba450..025ec8ef6 100644 --- a/llarp/dns/server.hpp +++ b/llarp/dns/server.hpp @@ -58,7 +58,8 @@ namespace llarp // Returns true if this packet is something that looks like it's going to an upstream // resolver, i.e. matches a configured resolver. - virtual bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const; + virtual bool + IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const; private: void diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index 9df195095..d115c3f52 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -157,16 +157,17 @@ namespace llarp::dns // 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") { - // 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"); + if (hoststr == "127.0.0.1") + { + // 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"); } #endif diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index f0a754cf4..61553acff 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -71,8 +71,9 @@ namespace llarp bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override { - LogError("IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); - return to.asIPv6() != m_Endpoint->GetIfAddr(); + LogError( + "IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); + return to.asIPv6() != m_Endpoint->GetIfAddr(); } #endif }; @@ -153,12 +154,12 @@ namespace llarp std::vector TunEndpoint::ReconfigureDNS(std::vector servers) { - std::swap(m_UpstreamResolvers, servers); - m_Resolver->Stop(); - if (!m_Resolver->Start( - m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles)) - llarp::LogError(Name(), " failed to reconfigure DNS server"); - return servers; + std::swap(m_UpstreamResolvers, servers); + m_Resolver->Stop(); + if (!m_Resolver->Start( + m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles)) + llarp::LogError(Name(), " failed to reconfigure DNS server"); + return servers; } bool From a7decd5ec3e1855433682d9bb056d203a4da54e6 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:44:23 -0300 Subject: [PATCH 57/81] Silence warnings --- llarp/dns/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index d2cac921b..7bf6b1e34 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -104,7 +104,7 @@ namespace llarp::dns } bool - PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const + PacketHandler::IsUpstreamResolver(const SockAddr& to, [[maybe_unused]] const SockAddr& from) const { return m_Resolvers.count(to); } From 067fcf71d3457a598f9b3dd4ee6957ff53da88b0 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 16:00:37 -0300 Subject: [PATCH 58/81] Remove dead code --- daemon/lokinet.swift | 68 -------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 9ebf76940..69598e9d7 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -8,7 +8,6 @@ let app = NSApplication.shared class LokinetMain: NSObject, NSApplicationDelegate { var vpnManager = NETunnelProviderManager() let lokinetComponent = "com.loki-project.lokinet.network-extension" - var dnsComponent = "com.loki-project.lokinet.dns-proxy" func applicationDidFinishLaunching(_: Notification) { setupVPNJizz() @@ -18,63 +17,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { app.terminate(self) } - func setupDNSJizz() { - NSLog("setting up dns settings") - let dns = NEDNSSettingsManager.shared() - let settings = NEDNSSettings(servers: ["172.16.0.1"]) - settings.matchDomains = ["*.loki", "*.snode"] - settings.matchDomainsNoSearch = true - settings.domainName = "localhost.loki" - dns.dnsSettings = settings - dns.loadFromPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - dns.saveToPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - NSLog("dns setting set up probably") - } - } - } - - func setupDNSProxyJizz() { - NSLog("setting up dns proxy") - let dns = NEDNSProxyManager.shared() - let provider = NEDNSProxyProviderProtocol() - provider.providerBundleIdentifier = dnsComponent - provider.username = "Anonymous" - provider.serverAddress = "loki.loki" - provider.includeAllNetworks = true - provider.enforceRoutes = true - dns.providerProtocol = provider - dns.localizedDescription = "lokinet dns" - dns.loadFromPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - provider.includeAllNetworks = true - provider.enforceRoutes = true - dns.isEnabled = true - dns.saveToPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - self.initDNSObserver() - NSLog("dns is up probably") - } - } - } - func setupVPNJizz() { NSLog("Starting up lokinet") NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in @@ -104,9 +46,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true // self.vpnManager.isOnDemandEnabled = true - let rules = NEAppRule() - rules.matchDomains = ["*.snode", "*.loki"] - self.vpnManager.appRules = [rules] self.vpnManager.localizedDescription = "lokinet" self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { @@ -138,13 +77,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } - func initDNSObserver() { - NotificationCenter.default.addObserver(forName: NSNotification.Name.NEDNSProxyConfigurationDidChange, object: NEDNSProxyManager.shared(), queue: OperationQueue.main) { _ -> Void in - let dns = NEDNSProxyManager.shared() - NSLog("%@", dns) - } - } - func initializeConnectionObserver() { NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in if self.vpnManager.connection.status == .invalid { From 1315dabcb974d08a7a12e71b0521f1577ef2e0d4 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 1 Sep 2021 16:28:11 -0400 Subject: [PATCH 59/81] disable language ASM, yolo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af550c638..e1bf223fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Has to be set before `project()`, and ignored on non-macos: set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "macOS deployment target (Apple clang only)") -set(LANGS ASM C CXX) +set(LANGS C CXX) if(APPLE) set(LANGS ${LANGS} OBJC Swift) endif() From f51d0a80a240115c0ffe1ad0a234b3810832afdd Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 18:58:00 -0300 Subject: [PATCH 60/81] Forward-declare ub_ctx/ub_result Avoids needing unbound.h in the search path to include the unbound_resolver.hpp header. --- llarp/dns/unbound_resolver.cpp | 2 ++ llarp/dns/unbound_resolver.hpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index d115c3f52..50c56f5fc 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -5,6 +5,8 @@ #include #include +#include + namespace llarp::dns { struct PendingUnboundLookup diff --git a/llarp/dns/unbound_resolver.hpp b/llarp/dns/unbound_resolver.hpp index 5c67c3ed4..4d79569ce 100644 --- a/llarp/dns/unbound_resolver.hpp +++ b/llarp/dns/unbound_resolver.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -17,6 +16,12 @@ #include #endif +extern "C" +{ + struct ub_ctx; + struct ub_result; +} + namespace llarp::dns { using ReplyFunction = From 10cd3318632e62ff3a0e1e787be8a787eaf7a1ae Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 2 Sep 2021 15:23:13 -0400 Subject: [PATCH 61/81] invert logic for android dns hook --- llarp/dns/server.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index 7bf6b1e34..c43b79671 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -127,8 +127,11 @@ namespace llarp::dns if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg)) return true; - +#ifdef ANDROID + return IsUpstreamResolver(to, from); +#else return !IsUpstreamResolver(to, from); +#endif } void From 8aef5d742d30634a5802347088d4051eda9af6c8 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:07:40 -0300 Subject: [PATCH 62/81] Re-enable LTO; target macos 10.12+ --- CMakeLists.txt | 2 +- contrib/mac.sh | 2 +- daemon/CMakeLists.txt | 1 + llarp/apple/CMakeLists.txt | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1bf223fa..6b23ebe10 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.15 CACHE STRING "macOS deployment target (Apple clang only)") +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)") set(LANGS C CXX) if(APPLE) diff --git a/contrib/mac.sh b/contrib/mac.sh index 548c9f8b2..4719b40d2 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -28,7 +28,7 @@ cmake \ -DWITH_SYSTEMD=OFF \ -DFORCE_OXENMQ_SUBMODULE=ON \ -DSUBMODULE_CHECK=OFF \ - -DWITH_LTO=OFF \ + -DWITH_LTO=ON \ -DCMAKE_BUILD_TYPE=Release \ "$@" \ .. diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index febc7314a..deb60ed0f 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -5,6 +5,7 @@ if(APPLE) add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) + enable_lto(lokinet) else() add_executable(lokinet lokinet.cpp) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index a2799167e..58a54727a 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m DNSTrampoline.m ) +enable_lto(lokinet-extension) target_link_libraries(lokinet-extension PRIVATE liblokinet ${COREFOUNDATION} From 38335f13a28deac88c9ccd71a5d5ac0e1506938c Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:09:02 -0300 Subject: [PATCH 63/81] Remove debugging --- llarp/handlers/tun.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 61553acff..fbc726cf0 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -71,8 +71,6 @@ namespace llarp bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override { - LogError( - "IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); return to.asIPv6() != m_Endpoint->GetIfAddr(); } #endif From 92c7fb9872688a58096b3326519de3c8c21081af Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:11:41 -0300 Subject: [PATCH 64/81] LOKINET_VERSION -> built in lokinet_VERSION --- CMakeLists.txt | 2 -- contrib/macos/Info.plist.in | 4 ++-- contrib/macos/LokinetExtension.Info.plist.in | 2 +- daemon/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b23ebe10..105ce499d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,8 +41,6 @@ if(RELEASE_MOTTO AND CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]") add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}") endif() -set(LOKINET_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}") - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # Core options diff --git a/contrib/macos/Info.plist.in b/contrib/macos/Info.plist.in index 5e09e839b..9311f2404 100644 --- a/contrib/macos/Info.plist.in +++ b/contrib/macos/Info.plist.in @@ -17,8 +17,8 @@ CFBundlePackageType XPC! CFBundleShortVersionString - @LOKINET_VERSION@ + @lokinet_VERSION@ CFBundleVersion - @LOKINET_VERSION@.@LOKINET_APPLE_BUILD@ + @lokinet_VERSION@.@LOKINET_APPLE_BUILD@ diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in index 30dc5f8ea..80afb1b94 100644 --- a/contrib/macos/LokinetExtension.Info.plist.in +++ b/contrib/macos/LokinetExtension.Info.plist.in @@ -21,7 +21,7 @@ lokinet CFBundleVersion - @LOKINET_VERSION@ + @lokinet_VERSION@ ITSAppUsesNonExemptEncryption diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index deb60ed0f..b6fd20917 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -98,7 +98,7 @@ if(APPLE) 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_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" From 2b8ef416c302cf685f89837fff8364917bd5f57e Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:13:51 -0300 Subject: [PATCH 65/81] Remove old mac installer packaging --- CMakeLists.txt | 2 +- cmake/installer.cmake | 4 --- cmake/macos_installer_deps.cmake | 56 -------------------------------- 3 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 cmake/macos_installer_deps.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 105ce499d..bb2983c51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -357,6 +357,6 @@ if(NOT TARGET uninstall) endif() -if(BUILD_PACKAGE) +if(BUILD_PACKAGE AND NOT APPLE) include(cmake/installer.cmake) endif() diff --git a/cmake/installer.cmake b/cmake/installer.cmake index b08a9d7b4..b8c04e563 100644 --- a/cmake/installer.cmake +++ b/cmake/installer.cmake @@ -7,10 +7,6 @@ if(WIN32) include(cmake/win32_installer_deps.cmake) endif() -if(APPLE) - include(cmake/macos_installer_deps.cmake) -endif() - # This must always be last! include(CPack) diff --git a/cmake/macos_installer_deps.cmake b/cmake/macos_installer_deps.cmake deleted file mode 100644 index b315b389b..000000000 --- a/cmake/macos_installer_deps.cmake +++ /dev/null @@ -1,56 +0,0 @@ -# macos specific cpack stuff goes here - -return() - -# Here we build lokinet-network-control-panel into 'lokinet-gui.app' in "extra/" where a postinstall -# script will then move it to /Applications/. -set(LOKINET_GUI_REPO "https://github.com/oxen-io/loki-network-control-panel.git" - CACHE STRING "Can be set to override the default lokinet-gui git repository") -set(LOKINET_GUI_CHECKOUT "origin/master" - CACHE STRING "Can be set to specify a particular branch or tag to build from LOKINET_GUI_REPO") -set(MACOS_SIGN_APP "" # FIXME: it doesn't use a Apple Distribution key because WTF knows. - CACHE STRING "enable codesigning of the stuff inside the .app and the lokinet binary -- use a 'Apple Distribution' key (or description) from `security find-identity -v`") -set(MACOS_SIGN_PKG "" - CACHE STRING "enable codesigning of the .pkg -- use a 'Developer ID Installer' key (or description) from `security find-identity -v`") -set(MACOS_NOTARIZE_USER "" - CACHE STRING "set macos notarization username; can also set it in ~/.notarization.cmake") -set(MACOS_NOTARIZE_PASS "" - CACHE STRING "set macos notarization password; can also set it in ~/.notarization.cmake") -set(MACOS_NOTARIZE_ASC "" - CACHE STRING "set macos notarization asc provider; can also set it in ~/.notarization.cmake") - -if(NOT BUILD_STATIC_DEPS) - message(FATAL_ERROR "Building an installer on macos requires -DBUILD_STATIC_DEPS=ON") -endif() - -#set(CPACK_GENERATOR "Bundle") - -#set(MACOSX_BUNDLE_BUNDLE_NAME Lokinet) -#set(CPACK_BUNDLE_NAME Lokinet) -#set(CPACK_BUNDLE_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist) -#set(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns") -#set(CPACK_BUNDLE_STARTUP_COMMAND ${CMAKE_BINARY_DIR}/daemon/lokinet) -#set(MACOSX_BUNDLE_GUI_IDENTIFIER org.lokinet.lokinet) -#set(MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router") -#set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}) -#set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) -#set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) -#set(MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") -#set(CPACK_BUNDLE_APPLE_ENTITLEMENTS ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements) -#set(CPACK_BUNDLE_APPLE_CERT_APP "${MACOS_SIGN_APP}") - -if(MACOS_SIGN_APP AND MACOS_SIGN_PKG) - if(NOT MACOS_NOTARIZE_USER) - if(EXISTS "$ENV{HOME}/.notarization.cmake") - include("$ENV{HOME}/.notarization.cmake") - endif() - endif() - if(MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC) - message(STATUS "'notarization' target enabled") - configure_file(${CMAKE_SOURCE_DIR}/contrib/macos/notarize.py.in ${CMAKE_CURRENT_BINARY_DIR}/contrib/notarize.py ESCAPE_QUOTES @ONLY) - file(COPY ${CMAKE_CURRENT_BINARY_DIR}/contrib/notarize.py DESTINATION ${PROJECT_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE) - add_custom_target(notarize ./notarize.py) - else() - message(WARNING "Not enable 'notarization' target: signing is enabled but notarization info not provided. Create ~/.notarization.cmake or set cmake parameters directly") - endif() -endif() From 12e00b7a99eaea64cb3c171c794533201d6cb8b3 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:14:33 -0300 Subject: [PATCH 66/81] Remove advertising of big crappy company --- contrib/lokinet.svg | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/lokinet.svg b/contrib/lokinet.svg index f8e760248..896e74bbb 100644 --- a/contrib/lokinet.svg +++ b/contrib/lokinet.svg @@ -1,5 +1,4 @@ -