Skip to content

Commit f8c6a6c

Browse files
committed
Version 0.3.0
cloudflare-ddns now supports configuration using a YAML file
1 parent a8de806 commit f8c6a6c

File tree

5 files changed

+88
-11
lines changed

5 files changed

+88
-11
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ This tool is a oneshot program: you run it, it updates the DNS record, and it te
1111

1212
To run the tool you'll need an [API token](https://dash.cloudflare.com/profile/api-tokens) and the Zone ID of the DNS that you want to update; you can get the latter in the Overview panel of your zone.
1313

14+
Once you got the executable you can use it in two ways: you can pass the API Token, the Zone ID and the record name as command line arguments or you can use a YAML configuration file, located in `/etc/cloudflare-ddns/config.yaml` on Linux systems; [here's the template](config.yaml). If you prefer, you can even use a configuration file in a custom location, using `--config file-path`.
15+
1416
## Dependencies
1517

1618
cloudflare-ddns relies only on libcurl and simdjson. I recommend you to compile the program yourself, but I also provide a statically linked executable for every release. It is not 100% self-contained but it should work in most cases.

cloudflare-ddns/CMakeLists.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
cmake_minimum_required(VERSION 3.14)
22

33
project(cloudflare-ddns)
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_EXTENSIONS OFF)
46

57
include(CheckIPOSupported)
68
check_ipo_supported(RESULT ipo_result OUTPUT ipo_output)
@@ -16,7 +18,7 @@ find_package(Threads)
1618

1719
include(FetchContent)
1820

19-
FetchContent_Declare(curl GIT_REPOSITORY https://github.com/curl/curl.git GIT_TAG curl-7_75_0)
21+
FetchContent_Declare(curl GIT_REPOSITORY https://github.com/curl/curl.git GIT_TAG curl-7_75_0 GIT_SHALLOW TRUE)
2022
set(BUILD_CURL_EXE OFF CACHE BOOL "")
2123
set(BUILD_SHARED_LIBS OFF CACHE BOOL "")
2224
set(CURL_LTO ON CACHE BOOL "")
@@ -31,6 +33,12 @@ set(SIMDJSON_JUST_LIBRARY ON CACHE INTERNAL "")
3133
set(SIMDJSON_BUILD_STATIC ON CACHE INTERNAL "")
3234
FetchContent_MakeAvailable(simdjson)
3335

36+
FetchContent_Declare(yaml-cpp GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git GIT_TAG yaml-cpp-0.6.3 GIT_SHALLOW TRUE)
37+
set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "")
38+
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "")
39+
set(YAML_CPP_INSTALL OFF CACHE BOOL "")
40+
FetchContent_MakeAvailable(yaml-cpp)
41+
3442
add_executable(${PROJECT_NAME} cloudflare-ddns/main.cpp)
3543

36-
target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads simdjson libcurl)
44+
target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads simdjson libcurl yaml-cpp)

cloudflare-ddns/main.cpp

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,26 @@
33
#include <iostream>
44
#include <future>
55
#include <simdjson.h>
6+
#include <yaml-cpp/yaml.h>
67

78
/*
89
* Two handles for two theads.
910
* One for cdn-cgi/trace and one for DNS IP
1011
*/
1112

12-
std::size_t writeData(char* incomingBuffer, std::size_t size, std::size_t count, std::string* data) {
13+
static constexpr const char* configPath {[]() {
14+
#if (defined(__linux__) || defined(__unix__) || defined(__unix)) && !defined(__FreeBSD__)
15+
return "/etc/cloudflare-ddns/config.yaml";
16+
#elif defined(__FreeBSD__)
17+
return "/usr/local/etc/cloudflare-ddns/config.yaml";
18+
#elif defined(_WIN32)
19+
return "Where should I store the config file?";
20+
#else
21+
return "Unknown";
22+
#endif
23+
}()};
24+
25+
std::size_t writeData(char* incomingBuffer, const std::size_t size, const std::size_t count, std::string* data) {
1326
data->append(incomingBuffer, size * count);
1427
return size * count;
1528
}
@@ -46,20 +59,61 @@ std::string getLocalIp() {
4659
}
4760

4861
// NOT thread-safe, writes into a buffer and uses an handle both owned elsewhere
49-
void getDnsRecordResponse(CURL** curlHandle, std::string_view requestUri) {
62+
void getDnsRecordResponse(CURL** curlHandle, const std::string_view requestUri) {
5063
curl_easy_setopt(*curlHandle, CURLOPT_HTTPGET, 1L);
5164
curl_easy_setopt(*curlHandle, CURLOPT_URL, requestUri.data());
5265
curl_easy_perform(*curlHandle);
5366
}
5467

5568
int main(int argc, char* argv[]) {
56-
if (argc != 4) {
57-
std::cerr << "Usage: cloudflare-ddns <API token> <Zone ID> <DNS record name>\n";
69+
std::string apiToken;
70+
std::string zoneId;
71+
std::string recordName;
72+
73+
if (argc == 1) {
74+
try {
75+
const YAML::Node config {YAML::LoadFile(configPath)};
76+
apiToken = config["api-token"].as<std::string>();
77+
zoneId = config["zone-id"].as<std::string>();
78+
recordName = config["record-name"].as<std::string>();
79+
}
80+
catch (const YAML::BadFile&) {
81+
std::cerr << "No config file found in " << configPath << '\n';
82+
return EXIT_FAILURE;
83+
}
84+
catch (const YAML::Exception&) {
85+
std::cerr << "Bad config file\n";
86+
return EXIT_FAILURE;
87+
}
88+
}
89+
else if (argc == 3) {
90+
const std::string_view configPath {argv[2]};
91+
try {
92+
const YAML::Node config {YAML::LoadFile(configPath.data())};
93+
apiToken = config["api-token"].as<std::string>();
94+
zoneId = config["zone-id"].as<std::string>();
95+
recordName = config["record-name"].as<std::string>();
96+
}
97+
catch (const YAML::BadFile&) {
98+
std::cerr << "No config file found in " << configPath << '\n';
99+
return EXIT_FAILURE;
100+
}
101+
catch (const YAML::Exception&) {
102+
std::cerr << "Bad config file\n";
103+
return EXIT_FAILURE;
104+
}
105+
}
106+
else if (argc == 4) {
107+
apiToken = argv[1];
108+
zoneId = argv[2];
109+
recordName = argv[3];
110+
}
111+
else {
112+
std::cerr
113+
<< "Bad usage! You can run the program without arguments and load the config in" << configPath
114+
<< " or pass the API token, the Zone ID and the DNS record name as arguments\n";
58115
return EXIT_FAILURE;
59116
}
60-
const std::string_view apiToken {argv[1]};
61-
const std::string zoneId {argv[2]};
62-
const std::string recordName {argv[3]};
63117

64118
curl_global_init(CURL_GLOBAL_SSL);
65119

config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
api-token:
2+
zone-id:
3+
record-name:

meson.build

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ project(
88
'b_lto=true'
99
],
1010
version: '0.2.1',
11-
license: 'AGPL-3.0-or-later'
11+
license: 'AGPL-3.0-or-later',
12+
meson_version: '>=0.46.0'
1213
)
1314

1415
simdjson_dep = dependency('simdjson', required: false)
@@ -29,8 +30,17 @@ executable(
2930
dependencies: [
3031
dependency('libcurl'),
3132
simdjson_dep,
32-
dependency('threads')
33+
dependency('threads'),
34+
dependency('yaml-cpp')
3335
],
3436
cpp_args: '-DOPENSSL_NO_SSL3_METHOD',
3537
install: true
3638
)
39+
40+
if host_machine.system() == 'linux' or host_machine.system() == 'openbsd'
41+
install_data('config.yaml', install_dir: '/etc/cloudflare-ddns')
42+
elif host_machine.system() == 'freebsd'
43+
install_data('config.yaml', install_dir: '/usr/local/etc/cloudflare-ddns')
44+
else
45+
install_data('config.yaml')
46+
endif

0 commit comments

Comments
 (0)