View | Details | Raw Unified | Return to bug 277735
Collapse All | Expand All

(-)b/net/zerotier/Makefile (+1 lines)
Lines 1-5 Link Here
1
PORTNAME=	zerotier
1
PORTNAME=	zerotier
2
DISTVERSION=	1.12.2
2
DISTVERSION=	1.12.2
3
PORTREVISION=	1
3
CATEGORIES=	net
4
CATEGORIES=	net
4
5
5
MAINTAINER=	dch@FreeBSD.org
6
MAINTAINER=	dch@FreeBSD.org
(-)b/net/zerotier/files/patch-README.md (+26 lines)
Added Link Here
1
--- README.md.orig	2023-09-14 19:09:26 UTC
2
+++ README.md
3
@@ -169,3 +169,23 @@ If there are other metrics you'd like to see tracked, 
4
 | zt_peer_packet_errors | node_id | Counter | number of incoming packet errors from a peer |
5
 
6
 If there are other metrics you'd like to see tracked, ask us in an Issue or send us a Pull Request!
7
+
8
+### HTTP / App server
9
+
10
+There is a static http file server suitable for hosting Single Page Apps at http://localhost:9993/app/<app-path>
11
+
12
+Use `zerotier-cli info -j` to find your zerotier-one service's homeDir
13
+
14
+``` sh
15
+cd $ZT_HOME
16
+sudo mkdir -p app/app1
17
+sudo mkdir -p app/appB
18
+echo '<html><meta charset=utf-8><title>appA</title><body><h1>hello world A' | sudo tee app/appA/index.html 
19
+echo '<html><meta charset=utf-8><title>app2</title><body><h1>hello world 2' | sudo tee app/app2/index.html 
20
+curl -sL http://localhost:9993/app/appA http://localhost:9993/app/app2 
21
+```
22
+
23
+Then visit [http://localhost:9993/app/app1/](http://localhost:9993/app/app1/) and [http://localhost:9993/app/appB/](http://localhost:9993/app/appB/)
24
+
25
+Requests to paths don't exist return the app root index.html, as is customary for SPAs. 
26
+If you want, you can write some javascript that talks to the service or controller [api](https://docs.zerotier.com/service/v1).
(-)b/net/zerotier/files/patch-controller_EmbeddedNetworkController.cpp (+26 lines)
Added Link Here
1
--- controller/EmbeddedNetworkController.cpp.orig	2023-09-14 19:09:26 UTC
2
+++ controller/EmbeddedNetworkController.cpp
3
@@ -874,6 +874,7 @@ void EmbeddedNetworkController::configureHTTPControlPl
4
 	std::string memberListPath = "/controller/network/([0-9a-fA-F]{16})/member";
5
 	std::string memberPath = "/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})";
6
 
7
+
8
 	auto controllerGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
9
 		char tmp[4096];
10
 		const bool dbOk = _db.isReady();
11
@@ -885,11 +886,11 @@ void EmbeddedNetworkController::configureHTTPControlPl
12
 			(unsigned long long)OSUtils::now(),
13
 			dbOk ? "true" : "false");
14
 
15
-			if (!dbOk) {
16
-				res.status = 503;
17
-			}
18
+		if (!dbOk) {
19
+			res.status = 503;
20
+		}
21
 
22
-			setContent(req, res, tmp);
23
+		setContent(req, res, tmp);
24
 	};
25
 	s.Get(controllerPath, controllerGet);
26
 	sv6.Get(controllerPath, controllerGet);
(-)b/net/zerotier/files/patch-node_InetAddress.cpp (+23 lines)
Added Link Here
1
--- node/InetAddress.cpp.orig	2023-09-14 19:09:26 UTC
2
+++ node/InetAddress.cpp
3
@@ -132,7 +132,20 @@ InetAddress::IpScope InetAddress::ipScope() const
4
 					return IP_SCOPE_PRIVATE;        // fc00::/7
5
 				}
6
 			}
7
+
8
+			// :::ffff:127.0.0.1
9
+			// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1
10
 			unsigned int k = 0;
11
+			while ((!ip[k])&&(k < 9)) {
12
+				++k;
13
+			}
14
+			if (k == 9) {
15
+				if (ip[10] == 0xff && ip[11] == 0xff && ip[12] == 0x7f) {
16
+					return IP_SCOPE_LOOPBACK;
17
+				}
18
+			}
19
+
20
+			k = 0;
21
 			while ((!ip[k])&&(k < 15)) {
22
 				++k;
23
 			}
(-)b/net/zerotier/files/patch-service_OneService.cpp (-1 / +138 lines)
Added Link Here
0
- 
1
--- service/OneService.cpp.orig	2023-09-14 19:09:26 UTC
2
+++ service/OneService.cpp
3
@@ -795,6 +795,7 @@ class OneServiceImpl : public OneService (public)
4
     bool _allowTcpFallbackRelay;
5
 	bool _forceTcpRelay;
6
 	bool _allowSecondaryPort;
7
+	bool _enableWebServer;
8
 
9
 	unsigned int _primaryPort;
10
 	unsigned int _secondaryPort;
11
@@ -1557,6 +1558,7 @@ class OneServiceImpl : public OneService (public)
12
 
13
         std::vector<std::string> noAuthEndpoints { "/sso", "/health" };
14
 
15
+
16
 		auto setContent = [=] (const httplib::Request &req, httplib::Response &res, std::string content) {
17
 			if (req.has_param("jsonp")) {
18
 				if (content.length() > 0) {
19
@@ -1573,8 +1575,98 @@ class OneServiceImpl : public OneService (public)
20
 			}
21
 		};
22
 
23
+		//
24
+		// static file server for app ui'
25
+		//
26
+		if (_enableWebServer) {
27
+			static std::string appUiPath = "/app";
28
+			static char appUiDir[16384];
29
+			sprintf(appUiDir,"%s%s",_homePath.c_str(),appUiPath.c_str());
30
 
31
-        auto authCheck = [=] (const httplib::Request &req, httplib::Response &res) {
32
+			auto ret = _controlPlane.set_mount_point(appUiPath, appUiDir);
33
+			_controlPlaneV6.set_mount_point(appUiPath, appUiDir);
34
+			if (!ret) {
35
+				fprintf(stderr, "Mounting app directory failed. Creating it. Path: %s - Dir: %s\n", appUiPath.c_str(), appUiDir);
36
+				if (!OSUtils::mkdir(appUiDir)) {
37
+					fprintf(stderr, "Could not create app directory either. Path: %s - Dir: %s\n", appUiPath.c_str(), appUiDir);
38
+				} else {
39
+					ret = _controlPlane.set_mount_point(appUiPath, appUiDir);
40
+					_controlPlaneV6.set_mount_point(appUiPath, appUiDir);
41
+					if (!ret) {
42
+						fprintf(stderr, "Really could not create and mount directory. Path: %s - Dir: %s\nWeb apps won't work.\n", appUiPath.c_str(), appUiDir);
43
+					}
44
+				}
45
+			}
46
+
47
+			if (ret) {
48
+				// fallback to /index.html for paths that don't exist for SPAs
49
+				auto indexFallbackGet = [](const httplib::Request &req, httplib::Response &res) {
50
+					// fprintf(stderr, "fallback \n");
51
+
52
+					auto match = req.matches[1];
53
+					if (match.matched) {
54
+
55
+						// fallback
56
+						char indexHtmlPath[16384];
57
+						sprintf(indexHtmlPath,"%s/%s/%s", appUiDir, match.str().c_str(), "index.html");
58
+						// fprintf(stderr, "fallback path %s\n", indexHtmlPath);
59
+
60
+						std::string indexHtml;
61
+
62
+						if (!OSUtils::readFile(indexHtmlPath, indexHtml)) {
63
+							res.status = 500;
64
+							return;
65
+						}
66
+
67
+						res.set_content(indexHtml.c_str(), "text/html");
68
+					} else {
69
+						res.status = 500;
70
+						return;
71
+					}
72
+				};
73
+
74
+				auto slashRedirect = [](const httplib::Request &req, httplib::Response &res) {
75
+					// fprintf(stderr, "redirect \n");
76
+
77
+					// add .html
78
+					std::string htmlFile;
79
+					char htmlPath[16384];
80
+					sprintf(htmlPath,"%s%s%s", appUiDir, (req.path).substr(appUiPath.length()).c_str(), ".html");
81
+					// fprintf(stderr, "path: %s\n", htmlPath);
82
+					if (OSUtils::readFile(htmlPath, htmlFile)) {
83
+						res.set_content(htmlFile.c_str(), "text/html");
84
+						return;
85
+					} else {
86
+						res.status = 301;
87
+						res.set_header("location", req.path + "/");
88
+					}
89
+				};
90
+
91
+				// auto missingAssetGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
92
+				// 	fprintf(stderr, "missing \n");
93
+				// 	res.status = 404;
94
+				// 	std::string html = "oops";
95
+				// 	res.set_content(html, "text/plain");
96
+				// 	res.set_header("Content-Type", "text/plain");
97
+				// 	return;
98
+				// };
99
+
100
+				// auto fix no trailing slash by adding .html or redirecting to path/
101
+				_controlPlane.Get(appUiPath + R"((/[\w|-]+)+$)", slashRedirect);
102
+				_controlPlaneV6.Get(appUiPath + R"((/[\w|-]+)+$)", slashRedirect);
103
+
104
+				// // 404 missing assets for *.ext paths
105
+				//   s.Get(appUiPath + R"(/\.\w+$)", missingAssetGet);
106
+				// sv6.Get(appUiPath + R"(/\.\w+$)", missingAssetGet);
107
+
108
+				// fallback to index.html for unknown paths/files
109
+				_controlPlane.Get(appUiPath + R"((/[\w|-]+)(/[\w|-]+)*/$)", indexFallbackGet);
110
+				_controlPlaneV6.Get(appUiPath + R"((/[\w|-]+)(/[\w|-]+)*/$)", indexFallbackGet);
111
+
112
+			}
113
+		}
114
+
115
+		auto authCheck = [=] (const httplib::Request &req, httplib::Response &res) {
116
 			if (req.path == "/metrics") {
117
 
118
 				if (req.has_header("x-zt1-auth")) {
119
@@ -1624,6 +1716,11 @@ class OneServiceImpl : public OneService (public)
120
 						isAuth = true;
121
 					}
122
 
123
+					// Web Apps base path
124
+					if (req.path.rfind("/app", 0) == 0) { //starts with /app
125
+						isAuth = true;
126
+					}
127
+
128
 					if (!isAuth) {
129
 						// check auth token
130
 						if (req.has_header("x-zt1-auth")) {
131
@@ -2429,6 +2526,7 @@ class OneServiceImpl : public OneService (public)
132
 		// bondingPolicy cannot be used with allowTcpFallbackRelay
133
 		_allowTcpFallbackRelay = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],true);
134
 		_forceTcpRelay = OSUtils::jsonBool(settings["forceTcpRelay"],false);
135
+		_enableWebServer = (OSUtils::jsonBool(settings["enableWebServer"],false));
136
 
137
 #ifdef ZT_TCP_FALLBACK_RELAY
138
 		_fallbackRelayAddress = InetAddress(OSUtils::jsonString(settings["tcpFallbackRelay"], ZT_TCP_FALLBACK_RELAY).c_str());

Return to bug 277735