Initial commit
This code is absolutely horrendous in its current state, with poor error handling (where it's even present) and memory leaks galore. USE AT YOUR OWN RISK. I certainly won't be publishing it anywhere or speaking of it until it's in a much better state.
This commit is contained in:
commit
b88fba9644
15 changed files with 589 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
build/
|
||||||
|
*.o
|
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[submodule "cJSON"]
|
||||||
|
path = cJSON
|
||||||
|
url = https://github.com/DaveGamble/cJSON
|
||||||
|
[submodule "curl"]
|
||||||
|
path = curl
|
||||||
|
url = https://github.com/curl/curl
|
10
.vimrc
Normal file
10
.vimrc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
set colorcolumn=110
|
||||||
|
highlight ColorColumn ctermbg=darkgray
|
||||||
|
augroup project
|
||||||
|
autocmd!
|
||||||
|
autocmd BufRead,BufNewFile *.h,*.c set filetype=c.doxygen
|
||||||
|
augroup END
|
||||||
|
nnoremap <F4> :!mkdir -p build <bar> cmake -B build <bar> make -C build<cr>
|
||||||
|
nnoremap <F4> :!build/PiHelper/pihelper localhost<cr>
|
||||||
|
nnoremap <F9> :!rm -rf build<cr>
|
||||||
|
let &path.="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include,"
|
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
cmake_minimum_required (VERSION 3.15.5)
|
||||||
|
|
||||||
|
set(PIHELPER_VERSION 0.1.0)
|
||||||
|
|
||||||
|
project(
|
||||||
|
pihelper
|
||||||
|
VERSION ${PIHELPER_VERSION}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(PiHelper)
|
||||||
|
|
||||||
|
install(TARGETS pihelper libpihelper)
|
||||||
|
|
||||||
|
#target_link_libraries(PiHelper SHARED cJSON)
|
59
PiHelper/CMakeLists.txt
Normal file
59
PiHelper/CMakeLists.txt
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
set(PIHELPER_SOURCES
|
||||||
|
pihelper.c
|
||||||
|
log.c
|
||||||
|
network.c
|
||||||
|
config.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(libpihelper
|
||||||
|
${PIHELPER_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(libpihelper PROPERTIES OUTPUT_NAME "libpihelper")
|
||||||
|
|
||||||
|
add_executable(pihelper
|
||||||
|
${PIHELPER_SOURCES}
|
||||||
|
cli.c
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(/usr/local/include)
|
||||||
|
find_library (
|
||||||
|
CJSON
|
||||||
|
NAMES cjson libcjson
|
||||||
|
HINTS /usr/local/lib /usr/lib
|
||||||
|
)
|
||||||
|
find_library (
|
||||||
|
CRYPTO
|
||||||
|
NAMES crypto libcrypto
|
||||||
|
HINTS /usr/local/lib /usr/lib
|
||||||
|
)
|
||||||
|
find_library (
|
||||||
|
OPENSSL
|
||||||
|
NAMES ssl libssl
|
||||||
|
HINTS /usr/local/lib /usr/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT CJSON)
|
||||||
|
message(SEND_ERROR "Did not find cJSON")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT CRYPTO)
|
||||||
|
message(SEND_ERROR "Did not find OpenSSL")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT OPENSSL)
|
||||||
|
message(SEND_ERROR "Did not find OpenSSL")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(libpihelper curl)
|
||||||
|
target_link_libraries(pihelper curl)
|
||||||
|
|
||||||
|
target_link_libraries(libpihelper ${CJSON})
|
||||||
|
target_link_libraries(pihelper ${CJSON})
|
||||||
|
|
||||||
|
target_link_libraries(libpihelper ${CRYPTO})
|
||||||
|
target_link_libraries(pihelper ${CRYPTO})
|
||||||
|
|
||||||
|
target_link_libraries(libpihelper ${OPENSSL})
|
||||||
|
target_link_libraries(pihelper ${OPENSSL})
|
||||||
|
|
119
PiHelper/cli.c
Normal file
119
PiHelper/cli.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "cli.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "network.h"
|
||||||
|
#include "pihelper.h"
|
||||||
|
|
||||||
|
int main(int argc, char ** argv) {
|
||||||
|
|
||||||
|
bool configure, enable;
|
||||||
|
char * disable;
|
||||||
|
char * config_path;
|
||||||
|
char ch;
|
||||||
|
while ((ch = getopt_long(argc, argv, "cd:ef:hv", longopts, NULL)) != -1) {
|
||||||
|
switch(ch) {
|
||||||
|
case 'c':
|
||||||
|
configure = true;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
if (optarg != NULL) {
|
||||||
|
disable = malloc(strlen(optarg) + 1);
|
||||||
|
strncpy(disable, optarg, strlen(optarg));
|
||||||
|
disable[strlen(optarg)] = '\0';
|
||||||
|
} else {
|
||||||
|
disable = "";
|
||||||
|
}
|
||||||
|
write_log(LOG_DEBUG, "Disabling pi-hole for %s seconds", disable);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
enable = true;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (optarg == NULL) break;
|
||||||
|
if (strstr(optarg, "/") != optarg) {
|
||||||
|
// This is a relative path, prepend the current working directory
|
||||||
|
char * cwd = getcwd(NULL, 0);
|
||||||
|
int full_path_len = strlen(cwd) + 1 + strlen(optarg) + 1;
|
||||||
|
config_path = malloc(full_path_len);
|
||||||
|
strncpy(config_path, cwd, strlen(cwd));
|
||||||
|
config_path[strlen(cwd)] = '/';
|
||||||
|
strncpy(&(config_path[strlen(cwd) + 1]), optarg, strlen(optarg));
|
||||||
|
config_path[full_path_len] = '\0';
|
||||||
|
write_log(LOG_DEBUG, "Fixed config_path: %s", config_path);
|
||||||
|
} else {
|
||||||
|
// This is an absolute path, copy as-is
|
||||||
|
config_path = malloc(strlen(optarg) + 1);
|
||||||
|
strncpy(config_path, optarg, strlen(optarg));
|
||||||
|
config_path[strlen(optarg)] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
// TODO: Add log level and set here
|
||||||
|
//PIHELPER_DEBUG = true;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
print_usage();
|
||||||
|
return PIHELPER_HELP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config_path == NULL) {
|
||||||
|
char * home_dir = getenv("HOME");
|
||||||
|
int path_len = strlen(home_dir) + strlen(DEFAULT_CONFIG_PATH);
|
||||||
|
config_path = malloc(path_len + 1);
|
||||||
|
sprintf(config_path, "%s%s", home_dir, DEFAULT_CONFIG_PATH);
|
||||||
|
config_path[path_len + 1] = '\0';
|
||||||
|
}
|
||||||
|
FILE * config_file = fopen(config_path, "r+");
|
||||||
|
if (config_file == NULL) {
|
||||||
|
char * user_input = malloc(2);
|
||||||
|
printf("No Pi-Helper configuration found. Would you like to create it now? [Y/n] ");
|
||||||
|
fgets(user_input, 2, stdin);
|
||||||
|
if (strstr(user_input, "\n") == user_input
|
||||||
|
|| strstr(user_input, "Y") == user_input
|
||||||
|
|| strstr(user_input, "y") == user_input
|
||||||
|
) {
|
||||||
|
configure = true;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pihole_config * config;
|
||||||
|
if (configure) {
|
||||||
|
config = configure_pihole(config_path);
|
||||||
|
} else {
|
||||||
|
config = read_config(config_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config == NULL) {
|
||||||
|
printf("Failed to parse Pi-Helper config\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable && disable != 0) {
|
||||||
|
print_usage();
|
||||||
|
return PIHELPER_INVALID_COMMANDS;
|
||||||
|
} else if (enable) {
|
||||||
|
return enable_pihole(config);
|
||||||
|
} else if (disable != 0) {
|
||||||
|
return disable_pihole(config, disable);
|
||||||
|
} else {
|
||||||
|
return get_status(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_usage() {
|
||||||
|
printf("Usage: pihelper [options]\n");
|
||||||
|
printf(" -c, --configure Configure Pi-Helper\n");
|
||||||
|
printf(" -d, --disable <duration> Disable the Pi-hole for a given duration, or permanently if empty\n");
|
||||||
|
printf(" -e, --enable Enable the Pi-hole\n");
|
||||||
|
printf(" -f, --file <config-file> Use the given config file instead of the default\n");
|
||||||
|
printf(" -h, --help Display this message\n");
|
||||||
|
printf(" -q, --quiet Don't print anything\n");
|
||||||
|
printf(" -v, --verbose Print debug logs\n");
|
||||||
|
}
|
||||||
|
|
17
PiHelper/cli.h
Normal file
17
PiHelper/cli.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <getopt.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
static struct option longopts[] = {
|
||||||
|
{ "configure", no_argument, NULL, 'c' },
|
||||||
|
{ "disable", optional_argument, NULL, 'd' },
|
||||||
|
{ "enable", no_argument, NULL, 'e' },
|
||||||
|
{ "file", required_argument, NULL, 'f' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "quiet", no_argument, NULL, 'q' },
|
||||||
|
{ "verbose", no_argument, NULL, 'v' }
|
||||||
|
};
|
||||||
|
|
||||||
|
void print_usage();
|
||||||
|
|
||||||
|
pihole_config * configure_pihole(char * config_path);
|
||||||
|
|
110
PiHelper/config.c
Normal file
110
PiHelper/config.c
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int mkdirs(char * path) {
|
||||||
|
char * curPos = strstr(path, "/") + 1;
|
||||||
|
char parents[strlen(path)];
|
||||||
|
int retval = 0;
|
||||||
|
while (curPos != NULL) {
|
||||||
|
snprintf(parents, strlen(path) - strlen(curPos) + 1, "%s", path);
|
||||||
|
curPos = strstr(curPos + 1, "/");
|
||||||
|
if (access(parents, F_OK)) {
|
||||||
|
if ((retval = mkdir(parents, 0755)) != 0) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_config(pihole_config * config, char * config_path) {
|
||||||
|
if (mkdirs(config_path)) {
|
||||||
|
perror(config_path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
FILE * config_file = fopen(config_path, "w");
|
||||||
|
int config_len = strlen(config->host) + strlen(config->api_key) + 16;
|
||||||
|
char config_string[config_len + 1];
|
||||||
|
snprintf(config_string, config_len, "host=%s\napi-key=%s\n", config->host, config->api_key);
|
||||||
|
config_string[config_len + 1] = '\0';
|
||||||
|
fputs(config_string, config_file);
|
||||||
|
fclose(config_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the hash of the password
|
||||||
|
*/
|
||||||
|
static char * hash_string (char * raw_string) {
|
||||||
|
unsigned char bytes[SHA256_DIGEST_LENGTH];
|
||||||
|
SHA256((unsigned char *) raw_string, strlen(raw_string), bytes);
|
||||||
|
char * hash = malloc(65);
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
||||||
|
sprintf(hash + (i * 2), "%02x", bytes[i]);
|
||||||
|
}
|
||||||
|
hash[64] = '\0';
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
pihole_config * read_config(char * config_path) {
|
||||||
|
if (access(config_path, F_OK)) {
|
||||||
|
printf("ERROR: The specified config file doesn't exist\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pihole_config * config = calloc(1, sizeof(pihole_config));
|
||||||
|
FILE * config_file = fopen(config_path, "r");
|
||||||
|
char host[_POSIX_HOST_NAME_MAX + 7];
|
||||||
|
fgets(host, _POSIX_HOST_NAME_MAX + 7, config_file);
|
||||||
|
if (strstr(host, "host=") == NULL) {
|
||||||
|
printf("Invalid config file\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
config->host = calloc(1, strlen(host) - 7);
|
||||||
|
strncpy(config->host, host + 5, strlen(host) - 6);
|
||||||
|
char api_key[74];
|
||||||
|
fgets(api_key, 74, config_file);
|
||||||
|
if (strstr(api_key, "api-key=") == NULL) {
|
||||||
|
printf("Invalid config file\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
config->api_key = calloc(1, strlen(api_key) - 8);
|
||||||
|
strncpy(config->api_key, api_key + 8, strlen(api_key) - 9);
|
||||||
|
fclose(config_file);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
pihole_config * configure_pihole(char * config_path) {
|
||||||
|
if (access(config_path, F_OK) == 0) {
|
||||||
|
// TODO: Check if file is accessible for read/write (not just if it exists)
|
||||||
|
printf("WARNING: The config file already exists. Continuing will overwrite any existing configuration.\n");
|
||||||
|
}
|
||||||
|
pihole_config * config = malloc(sizeof(pihole_config));
|
||||||
|
config->host = calloc(1, _POSIX_HOST_NAME_MAX);
|
||||||
|
config->host[_POSIX_HOST_NAME_MAX] = '\0';
|
||||||
|
printf("Enter the hostname or ip address for your pi-hole: ");
|
||||||
|
fgets(config->host, _POSIX_HOST_NAME_MAX, stdin);
|
||||||
|
char * newline = strstr(config->host, "\n");
|
||||||
|
if (newline != NULL) {
|
||||||
|
config->host[strlen(config->host) - strlen(newline)] = '\0';
|
||||||
|
}
|
||||||
|
config->api_key = getpass("Enter the api key or web password for your pi-hole: ");
|
||||||
|
if (strlen(config->api_key) < 64) {
|
||||||
|
// This is definitely not an API key, so hash it
|
||||||
|
// The Pi-hole hashes twice so we do the same here
|
||||||
|
char * first = hash_string(config->api_key);
|
||||||
|
char * hash = hash_string(first);
|
||||||
|
free(first);
|
||||||
|
config->api_key = hash;
|
||||||
|
}
|
||||||
|
// TODO: Make an authenticated request to verify that the credentials are valid and save the config
|
||||||
|
save_config(config, config_path);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
19
PiHelper/config.h
Normal file
19
PiHelper/config.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef PIHELPER_CONFIG
|
||||||
|
#define PIHELPER_CONFIG
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
static char * DEFAULT_CONFIG_PATH = "/.config/pihelper.conf";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char * host;
|
||||||
|
char * api_key;
|
||||||
|
} pihole_config;
|
||||||
|
|
||||||
|
|
||||||
|
void save_config(pihole_config * config, char * config_path);
|
||||||
|
|
||||||
|
pihole_config * read_config(char * config_path);
|
||||||
|
|
||||||
|
pihole_config * configure_pihole(char * config_path);
|
||||||
|
#endif
|
||||||
|
|
20
PiHelper/log.c
Normal file
20
PiHelper/log.c
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
void write_log(int level, char * format, ...) {
|
||||||
|
if (level == LOG_DEBUG) return;
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int format_len = strlen(format);
|
||||||
|
char * new_format = malloc(format_len + 1);
|
||||||
|
memcpy(new_format, format, format_len);
|
||||||
|
new_format[format_len] = '\n';
|
||||||
|
new_format[format_len + 1] = '\0';
|
||||||
|
vprintf(new_format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
10
PiHelper/log.h
Normal file
10
PiHelper/log.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef PIHELPER_LOG
|
||||||
|
#define PIHELPER_LOG
|
||||||
|
|
||||||
|
static int LOG_ERROR = 0;
|
||||||
|
static int LOG_WARN = 1;
|
||||||
|
static int LOG_INFO = 2;
|
||||||
|
static int LOG_DEBUG = 3;
|
||||||
|
|
||||||
|
void write_log(int level, char * format, ...);
|
||||||
|
#endif
|
134
PiHelper/network.c
Normal file
134
PiHelper/network.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <cjson/cJSON.h>
|
||||||
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
|
static char * URL_FORMAT = "http://%s/admin/api.php";
|
||||||
|
static int URL_FORMAT_LEN = 22;
|
||||||
|
static char * AUTH_QUERY = "auth";
|
||||||
|
static char * ENABLE_QUERY = "enable";
|
||||||
|
static char * DISABLE_QUERY = "disable";
|
||||||
|
static char * HTTP_SCHEME = "http://";
|
||||||
|
static int HTTP_SCHEME_LEN = 8;
|
||||||
|
static char * HTTPS_SCHEME = "https://";
|
||||||
|
static int HTTPS_SCHEME_LEN = 9;
|
||||||
|
|
||||||
|
int get_status(pihole_config * config) {
|
||||||
|
char * formatted_host = prepend_scheme(config->host);
|
||||||
|
char * response = get(formatted_host);
|
||||||
|
if (response == NULL) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
parse_status(response);
|
||||||
|
free(response);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int enable_pihole(pihole_config * config) {
|
||||||
|
char * formatted_host = prepend_scheme(config->host);
|
||||||
|
append_query_parameter(&formatted_host, AUTH_QUERY, config->api_key);
|
||||||
|
append_query_parameter(&formatted_host, ENABLE_QUERY, NULL);
|
||||||
|
char * response = get(formatted_host);
|
||||||
|
if (response == NULL) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
parse_status(response);
|
||||||
|
free(response);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int disable_pihole(pihole_config * config, char * duration) {
|
||||||
|
char * formatted_host = prepend_scheme(config->host);
|
||||||
|
append_query_parameter(&formatted_host, AUTH_QUERY, config->api_key);
|
||||||
|
append_query_parameter(&formatted_host, DISABLE_QUERY, duration);
|
||||||
|
char * response = get(formatted_host);
|
||||||
|
if (response == NULL) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
parse_status(response);
|
||||||
|
free(response);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to handle curl data callbacks
|
||||||
|
*/
|
||||||
|
static size_t receive_data(char *ptr, size_t size, size_t nmemb, void *userdata) {
|
||||||
|
size_t realsize = size * nmemb;
|
||||||
|
http_response * response = (http_response *) userdata;
|
||||||
|
char * next = realloc(response->body, response->size + realsize + 1);
|
||||||
|
response->body = next;
|
||||||
|
memcpy(&(response->body[response->size]), ptr, realsize);
|
||||||
|
response->size += realsize;
|
||||||
|
response->body[response->size] = '\0';
|
||||||
|
return realsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * get(char endpoint[]) {
|
||||||
|
http_response response;
|
||||||
|
response.body = malloc(1);
|
||||||
|
response.size = 0;
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
CURL * curl = curl_easy_init();
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, endpoint);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_data);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
int res = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
if (res == CURLE_OK) {
|
||||||
|
return response.body;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a potentially unformatted host (missing scheme), prepends the scheme (http://) to the host. Note
|
||||||
|
* that the caller is responsible for freeing the memory allocated by this method.
|
||||||
|
* @return a pointer to the host with the scheme prepended
|
||||||
|
*/
|
||||||
|
static char * prepend_scheme(char * raw_host) {
|
||||||
|
char * formatted_host;
|
||||||
|
if (strnstr(raw_host, HTTP_SCHEME, HTTP_SCHEME_LEN) == NULL
|
||||||
|
&& strnstr(raw_host, HTTPS_SCHEME, HTTPS_SCHEME_LEN) == NULL) {
|
||||||
|
formatted_host = malloc(URL_FORMAT_LEN + strlen(raw_host));
|
||||||
|
sprintf(formatted_host, URL_FORMAT, raw_host);
|
||||||
|
} else {
|
||||||
|
formatted_host = malloc(strlen(raw_host));
|
||||||
|
strcpy(formatted_host, raw_host);
|
||||||
|
}
|
||||||
|
return formatted_host;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_status(char * raw_json) {
|
||||||
|
cJSON *json = cJSON_Parse(raw_json);
|
||||||
|
cJSON *status = cJSON_GetObjectItemCaseSensitive(json, "status");
|
||||||
|
if (cJSON_IsString(status) && (status->valuestring != NULL)) {
|
||||||
|
printf("Pi-hole status: %s\n", status->valuestring);
|
||||||
|
} else {
|
||||||
|
write_log(LOG_DEBUG, "Unable to parse response: %s", raw_json);
|
||||||
|
}
|
||||||
|
cJSON_Delete(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_query_parameter(char ** host, char * key, char * value) {
|
||||||
|
char separator = strstr(*host, "?") ? '&' : '?';
|
||||||
|
int host_len = strlen(*host);
|
||||||
|
int new_len = host_len + 1 + strlen(key) + 1;
|
||||||
|
if (value) {
|
||||||
|
// Add another byte for the '='
|
||||||
|
new_len += strlen(value) + 1;
|
||||||
|
}
|
||||||
|
*host = realloc(*host, new_len);
|
||||||
|
char * format = value ? "%c%s=%s" : "%c%s";
|
||||||
|
sprintf(&((*host)[host_len]), format, separator, key, value);
|
||||||
|
(*host)[strlen(*host)] = '\0';
|
||||||
|
}
|
||||||
|
|
42
PiHelper/network.h
Normal file
42
PiHelper/network.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef PIHELPER_NETWORK
|
||||||
|
#define PIHELPER_NETWORK
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
char * body;
|
||||||
|
} http_response;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t domains_being_blocked;
|
||||||
|
size_t dns_queries_today;
|
||||||
|
size_t ads_blocked_today;
|
||||||
|
double ads_percentage_today;
|
||||||
|
size_t unique_domains;
|
||||||
|
size_t queries_forwarded;
|
||||||
|
size_t queries_cached;
|
||||||
|
size_t clients_ever_seen;
|
||||||
|
size_t unique_clients;
|
||||||
|
size_t dns_queries_all_types;
|
||||||
|
size_t reply_NODATA;
|
||||||
|
size_t reply_NXDOMAIN;
|
||||||
|
size_t reply_CNAME;
|
||||||
|
size_t reply_IP;
|
||||||
|
size_t privacy_level;
|
||||||
|
char * status;
|
||||||
|
} pihole_status;
|
||||||
|
|
||||||
|
int get_status(pihole_config * config);
|
||||||
|
|
||||||
|
int enable_pihole(pihole_config * config);
|
||||||
|
|
||||||
|
int disable_pihole(pihole_config * config, char * duration);
|
||||||
|
|
||||||
|
static char * get(char endpoint[]);
|
||||||
|
|
||||||
|
static void parse_status(char * raw_json);
|
||||||
|
|
||||||
|
static void append_query_parameter(char ** host, char * key, char * value);
|
||||||
|
|
||||||
|
static char * prepend_scheme(char * raw_host);
|
||||||
|
#endif
|
||||||
|
|
17
PiHelper/pihelper.c
Normal file
17
PiHelper/pihelper.c
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* =====================================================================================
|
||||||
|
*
|
||||||
|
* Filename: pihelper.c
|
||||||
|
*
|
||||||
|
* Description: The main PiHelper class
|
||||||
|
*
|
||||||
|
* Version: 1.0
|
||||||
|
* Created: 12/20/2019 18:24:51
|
||||||
|
* Revision: none
|
||||||
|
* Compiler: gcc
|
||||||
|
*
|
||||||
|
* Author: William Brawner (Billy), billy@wbrawner.com
|
||||||
|
*
|
||||||
|
* =====================================================================================
|
||||||
|
*/
|
||||||
|
|
10
PiHelper/pihelper.h
Normal file
10
PiHelper/pihelper.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef PIHELPER
|
||||||
|
#define PIHELPER
|
||||||
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "network.h"
|
||||||
|
const int PIHELPER_OK = 0;
|
||||||
|
const int PIHELPER_HELP = 1;
|
||||||
|
const int PIHELPER_INVALID_COMMANDS = 2;
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue