-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Now cloudflare-ddns is faster and much lighter. It now checks and updates a DNS record with less than 20 allocations and using roughly 20 kilobyes of RAM, that is nothing compared to the 300+ allocations of the previous version, that used cpr. cloudflare-ddns now depends only on libcurl and libsimdjson, and should be much easier to package.
- Loading branch information
Showing
7 changed files
with
90 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: CMake | ||
|
||
on: [push] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-20.04 | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Install dependencies | ||
run: | | ||
sudo rm /etc/apt/sources.list /etc/apt/sources.list.d/* | ||
printf "Enabled: yes\nTypes: deb\nURIs: http://azure.archive.ubuntu.com/ubuntu/\nSuites: focal focal-updates focal-backports focal-security\nComponents: main universe\n" | sudo tee /etc/apt/sources.list.d/system.sources | ||
sudo apt-get -qq update && sudo apt-get -qq install --assume-yes cmake libssl-dev | ||
- name: Configure CMake | ||
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release | ||
|
||
- name: Build | ||
run: cmake --build build | ||
|
||
- name: Test | ||
run: ctest -C build | ||
|
||
- name: Store compiled program | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: cloudflare-ddns-static-main | ||
path: ${{runner.workspace}}/cloudflare-ddns/build/cloudflare-ddns |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,61 @@ | ||
#include <cpr/cpr.h> | ||
#include <curl/curl.h> | ||
#include <string> | ||
#include <iostream> | ||
#include <simdjson.h> | ||
#include <nlohmann/json.hpp> | ||
|
||
void libcurlSucks() { | ||
curl_global_init(CURL_GLOBAL_SSL); | ||
|
||
CURL* curlHandle {curl_easy_init()}; | ||
curl_easy_setopt(curlHandle, CURLOPT_NOPROGRESS, 1L); | ||
curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1L); | ||
curl_easy_setopt(curlHandle, CURLOPT_HTTPGET, 1L); | ||
|
||
curl_global_cleanup(); | ||
std::size_t writeData(char* incomingBuffer, std::size_t size, std::size_t count, std::string* data) { | ||
data->append(incomingBuffer, size * count); | ||
return size * count; | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
if (argc != 4) { | ||
std::cerr << "Usage: cloudflare-ddns <API token> <Zone ID> <DNS record name>\n"; | ||
return EXIT_FAILURE; | ||
} | ||
const std::string apiToken {argv[1]}; | ||
const std::string_view apiToken {argv[1]}; | ||
const std::string zoneId {argv[2]}; | ||
const std::string recordName {argv[3]}; | ||
|
||
CURL* curlHandle {curl_easy_init()}; | ||
std::string response; | ||
response.reserve(600); // Tipical size of largest response (GET to fetch the DNS IP) | ||
curl_easy_setopt(curlHandle, CURLOPT_NOPROGRESS, 1L); | ||
curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1L); | ||
curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, writeData); | ||
curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &response); | ||
curl_easy_setopt(curlHandle, CURLOPT_HTTPGET, 1L); | ||
curl_easy_setopt(curlHandle, CURLOPT_URL, "https://1.1.1.1/cdn-cgi/trace"); | ||
|
||
simdjson::dom::parser parser; | ||
const simdjson::dom::element parsed { | ||
parser.parse( | ||
cpr::Get( | ||
cpr::Url{"https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records?type=A&name=" + recordName}, | ||
cpr::Header{ | ||
{"Content-Type", "application/json"}, | ||
{"Authorization", "Bearer " + apiToken} | ||
} | ||
// cpr::Bearer{apiToken} in cpr 1.6 | ||
).text | ||
) | ||
}; | ||
curl_easy_perform(curlHandle); | ||
const std::size_t ipBegin {response.find("ip=") + 3}; // + 3 because "ip=" is 3 chars | ||
const std::size_t ipEnd {response.find('\n', ipBegin)}; | ||
const std::string localIp {response.substr(ipBegin, ipEnd - ipBegin)}; | ||
response.clear(); | ||
|
||
curl_easy_setopt(curlHandle, CURLOPT_URL, std::string{"https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records?type=A&name=" + recordName}.data()); | ||
curl_easy_setopt(curlHandle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER); | ||
curl_easy_setopt(curlHandle, CURLOPT_XOAUTH2_BEARER, apiToken.data()); | ||
struct curl_slist* headers {nullptr}; | ||
headers = curl_slist_append(headers, "Content-Type: application/json"); | ||
curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headers); | ||
|
||
const std::string trace {cpr::Get(cpr::Url{"https://1.1.1.1/cdn-cgi/trace"}).text}; | ||
const std::size_t ipBegin {trace.find("ip=") + 3}; // + 3 because "ip=" is 3 chars | ||
const std::size_t ipEnd {trace.find('\n', ipBegin)}; | ||
const std::string_view currentIp {std::string_view{trace}.substr(ipBegin, ipEnd - ipBegin)}; // Begin, length | ||
curl_easy_perform(curlHandle); | ||
simdjson::dom::parser parser; | ||
const simdjson::dom::element parsed {parser.parse(response)}; | ||
|
||
if (currentIp != static_cast<std::string_view>((*parsed["result"].begin())["content"])) { | ||
std::cout << "New IP: " << (parser.parse(cpr::Patch( | ||
cpr::Url{"https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records/" + std::string{static_cast<std::string_view>((*parsed["result"].begin())["id"])}}, | ||
cpr::Header{ | ||
{"Content-Type", "application/json"}, | ||
{"Authorization", "Bearer " + apiToken} | ||
}, | ||
cpr::Body{nlohmann::json{{"content", currentIp}}.dump()} | ||
).text))["result"]["content"] << '\n'; | ||
if (localIp != static_cast<std::string_view>((*parsed["result"].begin())["content"])) { | ||
response.clear(); | ||
curl_easy_setopt(curlHandle, CURLOPT_URL, std::string{"https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records/" + std::string{static_cast<std::string_view>((*parsed["result"].begin())["id"])}}.c_str()); | ||
// curl_easy_setopt(curlHandle, CURLOPT_NOBODY, 0L); | ||
curl_easy_setopt(curlHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); | ||
std::string request {R"({"content": ")" + localIp + "\"}"}; | ||
curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, request.c_str()); | ||
curl_easy_perform(curlHandle); | ||
std::cout << "New IP: " << parser.parse(response)["result"]["content"] << '\n'; | ||
} | ||
else { | ||
std::cout << "The DNS is up to date\n"; | ||
} | ||
curl_easy_cleanup(curlHandle); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.