From 58276b8fbe46b4f9ecc0119324ef26671c44ea32 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 5 Mar 2020 15:06:46 +0100 Subject: [PATCH 1/3] Switched hook order in certbot integration so it does not detect RENEWED_LINEAGE as CERTBOT_VALIDATION hook. --- src/utils/util_certbot.cpp | 96 +++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/utils/util_certbot.cpp b/src/utils/util_certbot.cpp index cce6bf44..1f40afaf 100644 --- a/src/utils/util_certbot.cpp +++ b/src/utils/util_certbot.cpp @@ -55,6 +55,54 @@ int main(int argc, char **argv){ Util::Config conf(argv[0]); conf.parseArgs(argc, argv); + //Handle --deploy-hook + if (getenv("RENEWED_LINEAGE")){ + INFO_MSG("Detected '--deploy-hook' calling. Installing certificate."); + std::string cbPath = getenv("RENEWED_LINEAGE"); + std::string cbCert = cbPath + "/fullchain.pem"; + std::string cbKey = cbPath + "/privkey.pem"; + Socket::UDPConnection uSock; + uSock.SetDestination(UDP_API_HOST, UDP_API_PORT); + Util::DTSCShmReader rProto(SHM_PROTO); + DTSC::Scan prtcls = rProto.getScan(); + unsigned int pro_cnt = prtcls.getSize(); + bool found = false; + for (unsigned int i = 0; i < pro_cnt; ++i){ + std::string ctor = prtcls.getIndice(i).getMember("connector").asString(); + if (ctor == "HTTPS"){ + found = true; + JSON::Value currConf = prtcls.getIndice(i).asJSON(); + JSON::Value cmd; + cmd["updateprotocol"].append(currConf); + cmd["updateprotocol"].append(currConf); + cmd["updateprotocol"][1u]["cert"] = cbCert; + cmd["updateprotocol"][1u]["key"] = cbKey; + INFO_MSG("Executing: %s", cmd.toString().c_str()); + uSock.SendNow(cmd.toString()); + Util::wait(500); + uSock.SendNow(cmd.toString()); + Util::wait(500); + uSock.SendNow(cmd.toString()); + } + } + if (!found){ + INFO_MSG("No HTTPS active; enabling on port 443"); + JSON::Value cmd; + cmd["addprotocol"]["connector"] = "HTTPS"; + cmd["addprotocol"]["port"] = 443; + cmd["addprotocol"]["cert"] = cbCert; + cmd["addprotocol"]["key"] = cbKey; + INFO_MSG("Executing: %s", cmd.toString().c_str()); + uSock.SendNow(cmd.toString()); + Util::wait(500); + uSock.SendNow(cmd.toString()); + Util::wait(500); + uSock.SendNow(cmd.toString()); + } + Util::wait(5000); + return 0; + } + //Handle --manual-auth-hook if (getenv("CERTBOT_VALIDATION") && getenv("CERTBOT_TOKEN")){ INFO_MSG("Detected '--manual-auth-hook' calling. Performing authentication."); @@ -118,54 +166,6 @@ int main(int argc, char **argv){ return 0; } - //Handle --deploy-hook - if (getenv("RENEWED_LINEAGE")){ - INFO_MSG("Detected '--deploy-hook' calling. Installing certificate."); - std::string cbPath = getenv("RENEWED_LINEAGE"); - std::string cbCert = cbPath + "/fullchain.pem"; - std::string cbKey = cbPath + "/privkey.pem"; - Socket::UDPConnection uSock; - uSock.SetDestination(UDP_API_HOST, UDP_API_PORT); - Util::DTSCShmReader rProto(SHM_PROTO); - DTSC::Scan prtcls = rProto.getScan(); - unsigned int pro_cnt = prtcls.getSize(); - bool found = false; - for (unsigned int i = 0; i < pro_cnt; ++i){ - std::string ctor = prtcls.getIndice(i).getMember("connector").asString(); - if (ctor == "HTTPS"){ - found = true; - JSON::Value currConf = prtcls.getIndice(i).asJSON(); - JSON::Value cmd; - cmd["updateprotocol"].append(currConf); - cmd["updateprotocol"].append(currConf); - cmd["updateprotocol"][1u]["cert"] = cbCert; - cmd["updateprotocol"][1u]["key"] = cbKey; - INFO_MSG("Executing: %s", cmd.toString().c_str()); - uSock.SendNow(cmd.toString()); - Util::wait(500); - uSock.SendNow(cmd.toString()); - Util::wait(500); - uSock.SendNow(cmd.toString()); - } - } - if (!found){ - INFO_MSG("No HTTPS active; enabling on port 443"); - JSON::Value cmd; - cmd["addprotocol"]["connector"] = "HTTPS"; - cmd["addprotocol"]["port"] = 443; - cmd["addprotocol"]["cert"] = cbCert; - cmd["addprotocol"]["key"] = cbKey; - INFO_MSG("Executing: %s", cmd.toString().c_str()); - uSock.SendNow(cmd.toString()); - Util::wait(500); - uSock.SendNow(cmd.toString()); - Util::wait(500); - uSock.SendNow(cmd.toString()); - } - Util::wait(5000); - return 0; - } - //Print usage message to help point users in the right direction FAIL_MSG("This utility is meant to be ran by certbot, not by hand."); FAIL_MSG("Sample usage: certbot certonly --manual --preferred-challenges=http --manual-auth-hook MistUtilCertbot --deploy-hook MistUtilCertbot -d yourdomain.example.com"); From 131eb58c6a7a6a1e4fed762e09a833a262afae6f Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 23 Jan 2020 15:09:11 +0100 Subject: [PATCH 2/3] Backport of public URL setting to Open Source edition --- src/output/output_http.cpp | 33 +++++++++++++++++------------ src/output/output_http_internal.cpp | 30 ++++++++++++++++++++++++++ src/output/output_https.cpp | 10 +++++++++ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/output/output_http.cpp b/src/output/output_http.cpp index 11eed5ee..a0fd37a6 100644 --- a/src/output/output_http.cpp +++ b/src/output/output_http.cpp @@ -309,15 +309,13 @@ namespace Mist { DTSC::Scan prots = rProto.getScan(); unsigned int prots_ctr = prots.getSize(); - //find connector in config - for (unsigned int i=0; i < prots_ctr; ++i){ - if (prots.getIndice(i).getMember("connector").asString() == connector) { - id = i; - break; //pick the first protocol in the list that matches the connector + if (connector == "HTTP" || connector == "HTTP.exe"){ + //restore from values in the environment, regardless of configged settings + if (getenv("MIST_HTTP_pubaddr")){ + p["pubaddr"] = getenv("MIST_HTTP_pubaddr"); } - } - if (id == -1) { - connector = connector + ".exe"; + }else{ + //find connector in config for (unsigned int i=0; i < prots_ctr; ++i){ if (prots.getIndice(i).getMember("connector").asString() == connector) { id = i; @@ -325,13 +323,22 @@ namespace Mist { } } if (id == -1) { - connector = connector.substr(0, connector.size() - 4); - ERROR_MSG("No connector found for: %s", connector.c_str()); - return; + connector = connector + ".exe"; + for (unsigned int i=0; i < prots_ctr; ++i){ + if (prots.getIndice(i).getMember("connector").asString() == connector) { + id = i; + break; //pick the first protocol in the list that matches the connector + } + } + if (id == -1) { + connector = connector.substr(0, connector.size() - 4); + ERROR_MSG("No connector found for: %s", connector.c_str()); + return; + } } + //read options from found connector + p = prots.getIndice(id).asJSON(); } - //read options from found connector - p = prots.getIndice(id).asJSON(); HIGH_MSG("Connector found: %s", connector.c_str()); Util::DTSCShmReader rCapa(SHM_CAPA); diff --git a/src/output/output_http_internal.cpp b/src/output/output_http_internal.cpp index d09df3ab..2dcc0ef4 100644 --- a/src/output/output_http_internal.cpp +++ b/src/output/output_http_internal.cpp @@ -45,6 +45,9 @@ namespace Mist { myConn.open(STDOUT_FILENO, STDIN_FILENO); myConn.setHost(host); } + if (config->getString("pubaddr").size()){ + setenv("MIST_HTTP_pubaddr", config->getString("pubaddr").c_str(), 1); + } if (config->getOption("wrappers",true).size() == 0 || config->getString("wrappers") == ""){ JSON::Value & wrappers = config->getOption("wrappers",true); wrappers.shrink(0); @@ -142,6 +145,12 @@ namespace Mist { capa["optional"]["certbot"]["option"] = "--certbot"; capa["optional"]["certbot"]["short"] = "C"; cfg->addConnectorOptions(8080, capa); + cfg->addOption("pubaddr", JSON::fromString("{\"arg\":\"string\", \"default\":\"\", \"short\":\"A\",\"long\":\"public-address\",\"help\":\"Full public address this output is available as.\"}")); + capa["optional"]["pubaddr"]["name"] = "Public address"; + capa["optional"]["pubaddr"]["help"] = "Full public address this output is available as, if being proxied"; + capa["optional"]["pubaddr"]["default"] = ""; + capa["optional"]["pubaddr"]["type"] = "str"; + capa["optional"]["pubaddr"]["option"] = "--public-address"; } /// Sorts the JSON::Value objects that hold source information by preference. @@ -282,6 +291,13 @@ namespace Mist { if (!fullURL.protocol.size()){ fullURL.protocol = getProtocolForPort(fullURL.getPort()); } + if (config->getString("pubaddr") != ""){ + HTTP::URL altURL(config->getString("pubaddr")); + fullURL.protocol = altURL.protocol; + if (altURL.host.size()){fullURL.host = altURL.host;} + fullURL.port = altURL.port; + fullURL.path = altURL.path; + } std::string uAgent = H.GetHeader("User-Agent"); std::string forceType = ""; @@ -438,6 +454,13 @@ namespace Mist { if (outURL.protocol.find(':') != std::string::npos){ outURL.protocol.erase(outURL.protocol.find(':')); } + if (prots.getIndice(i).hasMember("pubaddr") && prots.getIndice(i).getMember("pubaddr").asString().size()){ + HTTP::URL altURL(prots.getIndice(i).getMember("pubaddr").asString()); + outURL.protocol = altURL.protocol; + if (altURL.host.size()){outURL.host = altURL.host;} + outURL.port = altURL.port; + outURL.path = altURL.path; + } //and a URL - then list the URL JSON::Value capa_json = capa.asJSON(); if (capa.getMember("url_rel") || capa.getMember("methods")){ @@ -652,6 +675,13 @@ namespace Mist { if (!fullURL.protocol.size()){ fullURL.protocol = getProtocolForPort(fullURL.getPort()); } + if (config->getString("pubaddr") != ""){ + HTTP::URL altURL(config->getString("pubaddr")); + fullURL.protocol = altURL.protocol; + if (altURL.host.size()){fullURL.host = altURL.host;} + fullURL.port = altURL.port; + fullURL.path = altURL.path; + } std::string response; std::string rURL = H.url; H.Clean(); diff --git a/src/output/output_https.cpp b/src/output/output_https.cpp index 8aa3666e..12ac051f 100644 --- a/src/output/output_https.cpp +++ b/src/output/output_https.cpp @@ -41,6 +41,12 @@ namespace Mist{ capa["optional"]["wrappers"]["option"] = "--wrappers"; capa["optional"]["wrappers"]["short"] = "w"; cfg->addConnectorOptions(4433, capa); + cfg->addOption("pubaddr", JSON::fromString("{\"arg\":\"string\", \"default\":\"\", \"short\":\"A\",\"long\":\"public-address\",\"help\":\"Full public address this output is available as.\"}")); + capa["optional"]["pubaddr"]["name"] = "Public address"; + capa["optional"]["pubaddr"]["help"] = "Full public address this output is available as, if being proxied"; + capa["optional"]["pubaddr"]["default"] = ""; + capa["optional"]["pubaddr"]["type"] = "str"; + capa["optional"]["pubaddr"]["option"] = "--public-address"; config = cfg; } @@ -96,6 +102,10 @@ namespace Mist{ args.push_back(Util::getMyPath() + "MistOutHTTP"); args.push_back("--ip"); args.push_back(myConn.getHost()); + if (config->getString("pubaddr").size()){ + args.push_back("--public-address"); + args.push_back(config->getString("pubaddr")); + } args.push_back(""); Util::Procs::socketList.insert(fd[0]); pid_t http_proc = Util::Procs::StartPiped(args, &(fd[1]), &(fd[1]), &fderr); From cd19cca36b1f93877c56cfdd7713bdfda3c0e315 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 23 Jan 2020 16:51:15 +0100 Subject: [PATCH 3/3] Support for multiple public addresses, as well as proxy-overridden public addresses --- src/output/output_http.cpp | 11 +++++- src/output/output_http_internal.cpp | 59 ++++++++++++++++++++--------- src/output/output_http_internal.h | 2 + src/output/output_https.cpp | 11 ++++-- 4 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/output/output_http.cpp b/src/output/output_http.cpp index a0fd37a6..5e6e4d2a 100644 --- a/src/output/output_http.cpp +++ b/src/output/output_http.cpp @@ -282,6 +282,14 @@ namespace Mist { if ((*it)["type"].asStringRef() == "uint" || (*it)["type"].asStringRef() == "int" || (*it)["type"].asStringRef() == "debug"){ p[it.key()] = JSON::Value(p[it.key()].asInt()).asString(); } + if ((*it)["type"].asStringRef() == "inputlist" && p[it.key()].isArray()){ + jsonForEach(p[it.key()], iVal){ + (*iVal) = iVal->asString(); + argarr[argnum++] = (char*)((*it)["option"].c_str()); + argarr[argnum++] = (char*)((*iVal).c_str()); + } + continue; + } } if (p[it.key()].asStringRef().size() > 0){ argarr[argnum++] = (char*)((*it)["option"].c_str()); @@ -312,7 +320,8 @@ namespace Mist { if (connector == "HTTP" || connector == "HTTP.exe"){ //restore from values in the environment, regardless of configged settings if (getenv("MIST_HTTP_pubaddr")){ - p["pubaddr"] = getenv("MIST_HTTP_pubaddr"); + std::string pubAddrs = getenv("MIST_HTTP_pubaddr"); + p["pubaddr"] = JSON::fromString(pubAddrs); } }else{ //find connector in config diff --git a/src/output/output_http_internal.cpp b/src/output/output_http_internal.cpp index 2dcc0ef4..712f2c82 100644 --- a/src/output/output_http_internal.cpp +++ b/src/output/output_http_internal.cpp @@ -46,7 +46,8 @@ namespace Mist { myConn.setHost(host); } if (config->getString("pubaddr").size()){ - setenv("MIST_HTTP_pubaddr", config->getString("pubaddr").c_str(), 1); + std::string pubAddrs = config->getOption("pubaddr", true).toString(); + setenv("MIST_HTTP_pubaddr", pubAddrs.c_str(), 1); } if (config->getOption("wrappers",true).size() == 0 || config->getString("wrappers") == ""){ JSON::Value & wrappers = config->getOption("wrappers",true); @@ -149,7 +150,7 @@ namespace Mist { capa["optional"]["pubaddr"]["name"] = "Public address"; capa["optional"]["pubaddr"]["help"] = "Full public address this output is available as, if being proxied"; capa["optional"]["pubaddr"]["default"] = ""; - capa["optional"]["pubaddr"]["type"] = "str"; + capa["optional"]["pubaddr"]["type"] = "inputlist"; capa["optional"]["pubaddr"]["option"] = "--public-address"; } @@ -196,15 +197,12 @@ namespace Mist { if (conncapa.isMember("player_url")){tmp["player_url"] = conncapa["player_url"].asStringRef();} tmp["simul_tracks"] = most_simul; tmp["total_matches"] = total_matches; - if (url.path.size()){ - tmp["url"] = url.protocol + "://" + url.host + ":" + url.port + "/" + url.path + rel; - }else{ - tmp["url"] = url.protocol + "://" + url.host + ":" + url.port + rel; - } + tmp["url"] = url.link(rel).getUrl(); sources.insert(tmp); } void addSources(std::string & streamname, std::set & sources, HTTP::URL url, JSON::Value & conncapa, JSON::Value & strmMeta, const std::string & useragent){ + url.path += "/"; if (strmMeta.isMember("live") && conncapa.isMember("exceptions") && conncapa["exceptions"].isObject() && conncapa["exceptions"].size()){ jsonForEach(conncapa["exceptions"], ex){ if (ex.key() == "live"){ @@ -264,15 +262,15 @@ namespace Mist { std::string relurl; size_t found = rel.find('$'); if (found != std::string::npos){ - relurl = rel.substr(0, found) + Encodings::URL::encode(streamname) + rel.substr(found+1); + relurl = rel.substr(1, found-1) + Encodings::URL::encode(streamname) + rel.substr(found+1); }else{ - relurl = "/"; + relurl = ""; } jsonForEach(conncapa["methods"], it) { if (it->isMember("url_rel")){ size_t foundb = (*it)["url_rel"].asStringRef().find('$'); if (foundb != std::string::npos){ - relurl = (*it)["url_rel"].asStringRef().substr(0, foundb) + Encodings::URL::encode(streamname) + (*it)["url_rel"].asStringRef().substr(foundb+1); + relurl = (*it)["url_rel"].asStringRef().substr(1, foundb-1) + Encodings::URL::encode(streamname) + (*it)["url_rel"].asStringRef().substr(foundb+1); } } if (!strmMeta.isMember("live") || !it->isMember("nolive")){ @@ -298,6 +296,7 @@ namespace Mist { fullURL.port = altURL.port; fullURL.path = altURL.path; } + if (mistPath.size()){fullURL = mistPath;} std::string uAgent = H.GetHeader("User-Agent"); std::string forceType = ""; @@ -454,17 +453,30 @@ namespace Mist { if (outURL.protocol.find(':') != std::string::npos){ outURL.protocol.erase(outURL.protocol.find(':')); } - if (prots.getIndice(i).hasMember("pubaddr") && prots.getIndice(i).getMember("pubaddr").asString().size()){ - HTTP::URL altURL(prots.getIndice(i).getMember("pubaddr").asString()); - outURL.protocol = altURL.protocol; - if (altURL.host.size()){outURL.host = altURL.host;} - outURL.port = altURL.port; - outURL.path = altURL.path; + JSON::Value pubAddrs; + pubAddrs.append(""); + if (prots.getIndice(i).hasMember("pubaddr") && prots.getIndice(i).getMember("pubaddr").getType() == DTSC_STR){ + if (prots.getIndice(i).getMember("pubaddr").asString().size()){ + pubAddrs[0u] = prots.getIndice(i).getMember("pubaddr").asString(); + } + } + if (prots.getIndice(i).hasMember("pubaddr") && prots.getIndice(i).getMember("pubaddr").getType() == DTSC_ARR){ + pubAddrs = prots.getIndice(i).getMember("pubaddr").asJSON(); + } + if (mistPath.size()){ + pubAddrs.null(); + pubAddrs.append(mistPath); } //and a URL - then list the URL JSON::Value capa_json = capa.asJSON(); if (capa.getMember("url_rel") || capa.getMember("methods")){ - addSources(streamName, sources, outURL, capa_json, json_resp["meta"], useragent); + jsonForEach(pubAddrs, jit){ + HTTP::URL altURL = outURL; + if (jit->asString().size()){altURL = jit->asString();} + if (!altURL.host.size()){altURL.host = outURL.host;} + if (!altURL.protocol.size()){altURL.protocol = outURL.protocol;} + addSources(streamName, sources, altURL, capa_json, json_resp["meta"], useragent); + } } //Make note if this connector can be depended upon by other connectors if (capa.getMember("provides")){ @@ -476,7 +488,14 @@ namespace Mist { //if it depends on this connector and has a URL, list it if (conns.count(connectors.getIndiceName(j)) && connectors.getIndice(j).getMember("deps").asString() == cProv && connectors.getIndice(j).getMember("methods")){ JSON::Value subcapa_json = connectors.getIndice(j).asJSON(); - addSources(streamName, sources, outURL, subcapa_json, json_resp["meta"], useragent); + + jsonForEach(pubAddrs, jit){ + HTTP::URL altURL = outURL; + if (jit->asString().size()){altURL = jit->asString();} + if (!altURL.host.size()){altURL.host = outURL.host;} + if (!altURL.protocol.size()){altURL.protocol = outURL.protocol;} + addSources(streamName, sources, altURL, subcapa_json, json_resp["meta"], useragent); + } } } } @@ -495,6 +514,8 @@ namespace Mist { void OutHTTP::onHTTP(){ std::string method = H.method; + if (H.GetHeader("X-Mst-Path").size()){mistPath = H.GetHeader("X-Mst-Path");} + //Handle certbot validations if (H.url.substr(0, 28) == "/.well-known/acme-challenge/"){ std::string cbToken = H.url.substr(28); @@ -682,6 +703,7 @@ namespace Mist { fullURL.port = altURL.port; fullURL.path = altURL.path; } + if (mistPath.size()){fullURL = mistPath;} std::string response; std::string rURL = H.url; H.Clean(); @@ -864,6 +886,7 @@ namespace Mist { bool OutHTTP::websocketHandler(){ stayConnected = true; std::string reqHost = HTTP::URL(H.GetHeader("Host")).host; + if (H.GetHeader("X-Mst-Path").size()){mistPath = H.GetHeader("X-Mst-Path");} std::string useragent = H.GetVar("ua"); if (!useragent.size()){ useragent = H.GetHeader("User-Agent"); diff --git a/src/output/output_http_internal.h b/src/output/output_http_internal.h index f0342f68..5fb25412 100644 --- a/src/output/output_http_internal.h +++ b/src/output/output_http_internal.h @@ -20,6 +20,8 @@ namespace Mist { virtual bool onFinish(){ return stayConnected; } + private: + std::string mistPath; }; } diff --git a/src/output/output_https.cpp b/src/output/output_https.cpp index 12ac051f..3b2fd15c 100644 --- a/src/output/output_https.cpp +++ b/src/output/output_https.cpp @@ -45,7 +45,7 @@ namespace Mist{ capa["optional"]["pubaddr"]["name"] = "Public address"; capa["optional"]["pubaddr"]["help"] = "Full public address this output is available as, if being proxied"; capa["optional"]["pubaddr"]["default"] = ""; - capa["optional"]["pubaddr"]["type"] = "str"; + capa["optional"]["pubaddr"]["type"] = "inputlist"; capa["optional"]["pubaddr"]["option"] = "--public-address"; config = cfg; } @@ -102,9 +102,12 @@ namespace Mist{ args.push_back(Util::getMyPath() + "MistOutHTTP"); args.push_back("--ip"); args.push_back(myConn.getHost()); - if (config->getString("pubaddr").size()){ - args.push_back("--public-address"); - args.push_back(config->getString("pubaddr")); + if (config->getOption("pubaddr", true).size()){ + JSON::Value pubAddrs = config->getOption("pubaddr", true); + jsonForEach(pubAddrs, jIt){ + args.push_back("--public-address"); + args.push_back(jIt->asStringRef()); + } } args.push_back(""); Util::Procs::socketList.insert(fd[0]);