Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
2353e4b420 | |||
81d85a51f8 | |||
3936d9b949 | |||
a127fc4893 | |||
b72f9749a4 | |||
98f181fd6d | |||
ae9aa1d423 | |||
2505e2cbf4 | |||
cf49bf7bc5 | |||
78d07ac95b | |||
53e59e9931 | |||
4bc836c971 | |||
7f83203dfd |
17
.gitlab-ci.yml
Normal file
17
.gitlab-ci.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
image: luki42/dynuiprefresher_build:latest
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- cmake -S . -B build
|
||||||
|
- cd build
|
||||||
|
- make
|
||||||
|
- make package
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- "build/bin/*"
|
||||||
|
- "build/packages/*"
|
@ -1,16 +1,25 @@
|
|||||||
|
# @author Lukas Heiligenbrunner
|
||||||
|
# main CMake file
|
||||||
|
#
|
||||||
|
# Build lib dependencies:
|
||||||
|
## libcurl (with sources)
|
||||||
|
## libconfig (with sources)
|
||||||
|
#
|
||||||
|
# documenation build needs doxygen to be installed.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(iprefresher DESCRIPTION "Dynu ip refresher")
|
project(iprefresher DESCRIPTION "Dynu ip refresher")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
SET(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
set(CMAKE_BUILD_TYPE Release) # manually set build type (Release / Debug)
|
SET(CMAKE_BUILD_TYPE Release) # manually SET build type (Release / Debug)
|
||||||
set(LIB_METHOD STATIC) #SHARED / STATIC
|
SET(LIB_METHOD STATIC) #SHARED / STATIC
|
||||||
set(PROJECT_VERSION 1.2.3)
|
SET(PROJECT_VERSION 1.3.2)
|
||||||
option(BUILD_DOC "Build documentation" ON)
|
option(BUILD_DOC "Build documentation" ON)
|
||||||
|
|
||||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
# config libs
|
# config libs
|
||||||
message(STATUS "Config of Libraries")
|
message(STATUS "Config of Libraries")
|
||||||
@ -45,31 +54,42 @@ include_directories(${LIBCONFIG_INCLUDE_DIR})
|
|||||||
|
|
||||||
message("")
|
message("")
|
||||||
|
|
||||||
|
#read sample config
|
||||||
|
FILE(READ ${CMAKE_SOURCE_DIR}/config/iprefresher.cfg SAMPLECONFIG)
|
||||||
#add version header
|
#add version header
|
||||||
FILE(WRITE ${CMAKE_SOURCE_DIR}/inc/Version.h
|
FILE(WRITE ${CMAKE_SOURCE_DIR}/inc/Version.h
|
||||||
"\#pragma once\nclass Version {\npublic:\n static const std::string VERSION;\n};\n\nstd::string const Version::VERSION = \"${PROJECT_VERSION}\";"
|
"\#pragma once
|
||||||
|
#include <string>
|
||||||
|
namespace Version {
|
||||||
|
const std::string VERSION = \"${PROJECT_VERSION}\";
|
||||||
|
const std::string SAMPLECONFIG = R\"(${SAMPLECONFIG})\";
|
||||||
|
}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# generate post script for checking if configuration already exists
|
||||||
|
FILE(WRITE ${CMAKE_SOURCE_DIR}/postinst
|
||||||
|
"#!/bin/bash
|
||||||
|
if [ ! -f /etc/iprefresher.cfg ]; then
|
||||||
|
cat > /etc/iprefresher.cfg <<- EOM
|
||||||
|
${SAMPLECONFIG}EOM
|
||||||
|
fi\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(api ${LIB_METHOD}
|
add_library(api ${LIB_METHOD}
|
||||||
src/api/API.cpp
|
src/api/API.cpp
|
||||||
|
|
||||||
src/api/TelegramAPI.cpp
|
src/api/TelegramAPI.cpp
|
||||||
|
|
||||||
src/api/DynuAPI.cpp
|
src/api/DynuAPI.cpp
|
||||||
|
src/api/IPAPI.cpp)
|
||||||
src/api/IPAPI.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(logger ${LIB_METHOD}
|
add_library(logger ${LIB_METHOD}
|
||||||
src/FileLogger.cpp
|
src/FileLogger.cpp
|
||||||
src/Logger.cpp
|
src/Logger.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
set(SOURCE
|
SET(SOURCE
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/IPRefresher.cpp
|
src/IPRefresher.cpp
|
||||||
src/Credentials.cpp)
|
src/Config.cpp)
|
||||||
|
|
||||||
add_executable(iprefresher ${SOURCE})
|
add_executable(iprefresher ${SOURCE})
|
||||||
|
|
||||||
@ -77,17 +97,18 @@ add_executable(iprefresher ${SOURCE})
|
|||||||
target_link_libraries(iprefresher api logger ${CURL_LIBRARIES} config++)
|
target_link_libraries(iprefresher api logger ${CURL_LIBRARIES} config++)
|
||||||
|
|
||||||
# INSTALL to SYSTEM #
|
# INSTALL to SYSTEM #
|
||||||
set(CMAKE_INSTALL_PREFIX "/")
|
SET(CMAKE_INSTALL_PREFIX "/")
|
||||||
install(TARGETS iprefresher DESTINATION usr/local/bin)
|
# install binaries
|
||||||
|
install(TARGETS iprefresher DESTINATION usr/bin)
|
||||||
|
# install systemd service and enable it
|
||||||
install(FILES service/iprefresher.service DESTINATION lib/systemd/system)
|
install(FILES service/iprefresher.service DESTINATION lib/systemd/system)
|
||||||
install(FILES config/iprefresher.cfg DESTINATION etc)
|
|
||||||
|
|
||||||
|
|
||||||
IF (UNIX)
|
IF (UNIX)
|
||||||
message(STATUS "config of Package build")
|
message(STATUS "config of Package build")
|
||||||
SET(CPACK_DEB_COMPONENT_INSTALL 1)
|
SET(CPACK_DEB_COMPONENT_INSTALL 1)
|
||||||
SET(CPACK_OUTPUT_FILE_PREFIX packages)
|
SET(CPACK_OUTPUT_FILE_PREFIX packages)
|
||||||
set(CPACK_PACKAGING_INSTALL_PREFIX "/") # no prefix for package structure
|
SET(CPACK_PACKAGING_INSTALL_PREFIX "/") # no prefix for package structure
|
||||||
|
|
||||||
FIND_PROGRAM(RPMBUILD_EXECUTABLE rpmbuild)
|
FIND_PROGRAM(RPMBUILD_EXECUTABLE rpmbuild)
|
||||||
FIND_PROGRAM(DEB_EXECUTABLE dpkg)
|
FIND_PROGRAM(DEB_EXECUTABLE dpkg)
|
||||||
@ -97,8 +118,10 @@ IF (UNIX)
|
|||||||
#check if rpm build is possible
|
#check if rpm build is possible
|
||||||
if (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND")
|
if (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND")
|
||||||
message(STATUS "found rpm build executeable --> able to build rpm")
|
message(STATUS "found rpm build executeable --> able to build rpm")
|
||||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
SET(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||||
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/lib/systemd/system" "/lib/systemd" "/lib" "/usr/local/bin" "/usr/local") # --> needed to not override existing folders
|
SET(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||||
|
SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/lib/systemd/system" "/lib/systemd" "/lib" "/usr/local/bin" "/usr/local") # --> needed to not override existing folders
|
||||||
|
set(CPACK_RPM_PACKAGE_REQUIRES "libcurl,libconfig")
|
||||||
else (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND")
|
else (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND")
|
||||||
message(STATUS "not found rpm build tools --> not building rpm")
|
message(STATUS "not found rpm build tools --> not building rpm")
|
||||||
endif (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND")
|
endif (NOT ${RPMBUILD_EXECUTABLE} STREQUAL "RPMBUILD_EXECUTABLE-NOTFOUND")
|
||||||
@ -106,7 +129,9 @@ IF (UNIX)
|
|||||||
#check if deb build is possible
|
#check if deb build is possible
|
||||||
if (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND")
|
if (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND")
|
||||||
message(STATUS "found deb build tools --> able to build deb")
|
message(STATUS "found deb build tools --> able to build deb")
|
||||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB")
|
SET(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") # add deb generator
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst") # set post inst file
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libcurl4,libconfig++9v5") # add debian dependencies
|
||||||
else (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND")
|
else (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND")
|
||||||
message(STATUS "not found deb build tools --> not building deb")
|
message(STATUS "not found deb build tools --> not building deb")
|
||||||
endif (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND")
|
endif (NOT ${DEB_EXECUTABLE} STREQUAL "DEB_EXECUTABLE-NOTFOUND")
|
||||||
@ -122,7 +147,6 @@ IF (UNIX)
|
|||||||
SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}")
|
SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}")
|
||||||
SET(CPACK_PACKAGE_CONTACT "Lukas Heiligenbrunner <lukas.heiligenbrunner@gmail.com>")
|
SET(CPACK_PACKAGE_CONTACT "Lukas Heiligenbrunner <lukas.heiligenbrunner@gmail.com>")
|
||||||
SET(CPACK_PACKAGE_SECTION "games")
|
SET(CPACK_PACKAGE_SECTION "games")
|
||||||
set(CPACK_PACKAGE_DEPENDS "libcurl (>= 7.0.0-1), libconfig (>= 1.5.0)")
|
|
||||||
|
|
||||||
INCLUDE(CPack)
|
INCLUDE(CPack)
|
||||||
|
|
||||||
@ -138,9 +162,9 @@ if (BUILD_DOC)
|
|||||||
message(STATUS "config of DOxygen build")
|
message(STATUS "config of DOxygen build")
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
if (DOXYGEN_FOUND)
|
if (DOXYGEN_FOUND)
|
||||||
# set input and output files
|
# SET input and output files
|
||||||
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in)
|
SET(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in)
|
||||||
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
SET(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||||
|
|
||||||
# request to configure the file
|
# request to configure the file
|
||||||
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
|
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
|
||||||
|
36
README.md
36
README.md
@ -1,5 +1,19 @@
|
|||||||
# DynuIPRefresher
|
# DynuIPRefresher
|
||||||
A lightweight C++ application to setup a service for refreshing a dynamic IP to the Dynu servers.
|
A lightweight C++ application to setup a service for refreshing a dynamic IP to the Dynu servers.
|
||||||
|
Dynu.com is a free DDns service and provides an API.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
Download the latest Release at [Release_Page](https://github.com/Lukas-Heiligenbrunner/DynuIPRefresher/releases).
|
||||||
|
I'm providing executables for Debian/Ubuntu (.deb) and RHEL/Debian (.rpm).
|
||||||
|
But you can still compile the code my your own (see build section).
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
There is a configuration file `/etc/iprefresher.cfg` where you have to specify the DYNU API key (get it from their homepage), the domainid and your domain.
|
||||||
|
Furthermore, you can optionally specify a Telegram API key and a Chat ID if you want to be notfied when your local ip changes.
|
||||||
|
|
||||||
|
To enable and start the service:
|
||||||
|
`systemctl enable iprefresher.service` and `systemctl start iprefresher.service`
|
||||||
|
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
## Basic Build
|
## Basic Build
|
||||||
@ -10,16 +24,28 @@ A lightweight C++ application to setup a service for refreshing a dynamic IP to
|
|||||||
### install build dependencies
|
### install build dependencies
|
||||||
|
|
||||||
`libcurl`
|
`libcurl`
|
||||||
`libcurl-devel`
|
|
||||||
`libconfig`
|
`libconfig`
|
||||||
`libconfig-devel`
|
|
||||||
|
|
||||||
Debian:
|
#### Debian:
|
||||||
`apt install libcurl4-openssl-dev`
|
`apt install libcurl4-openssl-dev`
|
||||||
|
|
||||||
Fedora:
|
#### Fedora:
|
||||||
`dnf install libcurl-devel libconfig-devel`
|
`dnf install libcurl-devel libconfig-devel`
|
||||||
|
|
||||||
|
#### Alpine Linux:
|
||||||
|
Compiler dependencies:
|
||||||
|
|
||||||
|
`apk add make cmake g++`
|
||||||
|
|
||||||
|
Lib dependencies:
|
||||||
|
|
||||||
|
`apk add libcurl curl-dev libconfig libconfig-dev`
|
||||||
|
|
||||||
|
Packaging dependencies:
|
||||||
|
|
||||||
|
`apk add dpkg rpm`
|
||||||
|
|
||||||
|
|
||||||
#### dependencies for package build
|
#### dependencies for package build
|
||||||
`dpkg` --> debian/ubuntu package
|
`dpkg` --> debian/ubuntu package
|
||||||
|
|
||||||
@ -38,7 +64,7 @@ cd into downloaded files and Generate makefiles:
|
|||||||
|
|
||||||
`make install`
|
`make install`
|
||||||
|
|
||||||
[root] or create Linux packages
|
(optional) create Linux packages
|
||||||
|
|
||||||
`make package`
|
`make package`
|
||||||
|
|
||||||
|
@ -9,4 +9,4 @@ domainname = ""
|
|||||||
|
|
||||||
## Telegram API Config (optional)
|
## Telegram API Config (optional)
|
||||||
#telegramApiKey = ""
|
#telegramApiKey = ""
|
||||||
#chatId =""
|
#chatId = ""
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Credentials {
|
class Config {
|
||||||
public:
|
public:
|
||||||
static std::string dynuapikey;
|
static std::string dynuapikey;
|
||||||
|
|
||||||
@ -16,7 +16,19 @@ public:
|
|||||||
static std::string telegramApiKey;
|
static std::string telegramApiKey;
|
||||||
static std::string chatId;
|
static std::string chatId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read configuration out of config file
|
||||||
|
*
|
||||||
|
* @return success of config read
|
||||||
|
*/
|
||||||
static bool readCredentials();
|
static bool readCredentials();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate config file
|
||||||
|
*
|
||||||
|
* @return validity of config file
|
||||||
|
*/
|
||||||
|
static bool validateConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
@ -11,6 +11,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void checkIPAdress(bool force);
|
void checkIPAdress(bool force);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor
|
||||||
|
*/
|
||||||
IPRefresher();
|
IPRefresher();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
33
inc/Logger.h
33
inc/Logger.h
@ -8,15 +8,40 @@
|
|||||||
|
|
||||||
class Logger {
|
class Logger {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* a debug message
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
static void debug(std::string message);
|
static void debug(std::string message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a default message
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
static void message(std::string message);
|
static void message(std::string message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a warning message
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
static void warning(std::string message);
|
static void warning(std::string message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a error message
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
static void error(std::string message);
|
static void error(std::string message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a log message with manual level set
|
||||||
|
* @param message message
|
||||||
|
* @param level loglevel (1-4) or predefined labels
|
||||||
|
*/
|
||||||
static void log(const std::string &message, int level);
|
static void log(const std::string &message, int level);
|
||||||
|
|
||||||
static const int Debug;
|
|
||||||
static const int Message;
|
static const int Debug = 4;
|
||||||
static const int Warning;
|
static const int Message = 3;
|
||||||
static const int Error;
|
static const int Warning = 2;
|
||||||
|
static const int Error = 1;
|
||||||
};
|
};
|
||||||
|
@ -21,9 +21,9 @@ public:
|
|||||||
* @param domainId ID of domain received by Dynu
|
* @param domainId ID of domain received by Dynu
|
||||||
* @param domainName domainname to refresh
|
* @param domainName domainname to refresh
|
||||||
*/
|
*/
|
||||||
void init(std::string dynuApiKey, std::string domainId, std::string domainName);
|
void init(const std::string& dynuApiKey, const std::string& domainId, const std::string& domainName);
|
||||||
private:
|
private:
|
||||||
std::string dynuapikey;
|
std::string dynuapikey; // Dynu API key
|
||||||
|
|
||||||
std::string domainid; //id of the dynu domain
|
std::string domainid; //id of the dynu domain
|
||||||
std::string domainname;
|
std::string domainname;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ public:
|
|||||||
* send telegram Message to predefined destination
|
* send telegram Message to predefined destination
|
||||||
* @param text message
|
* @param text message
|
||||||
*/
|
*/
|
||||||
void sendMessage(std::string text);
|
int sendMessage(const std::string& text);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init Telegram api with apikey and chatid
|
* init Telegram api with apikey and chatid
|
||||||
|
108
src/Config.cpp
Normal file
108
src/Config.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//
|
||||||
|
// Created by lukas on 11.02.20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Config.h>
|
||||||
|
#include <Logger.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <libconfig.h++>
|
||||||
|
#include <Version.h>
|
||||||
|
|
||||||
|
std::string Config::dynuapikey;
|
||||||
|
std::string Config::domainid; //id of the dynu domain
|
||||||
|
std::string Config::domainname;
|
||||||
|
|
||||||
|
std::string Config::telegramApiKey;
|
||||||
|
std::string Config::chatId;
|
||||||
|
|
||||||
|
bool Config::readCredentials() {
|
||||||
|
libconfig::Config cfg;
|
||||||
|
try {
|
||||||
|
cfg.readFile("/etc/iprefresher.cfg");
|
||||||
|
}
|
||||||
|
catch (const libconfig::FileIOException &fioex) {
|
||||||
|
std::cout << "I/O error while reading config file." << std::endl << "creating new config file!" << std::endl;
|
||||||
|
|
||||||
|
std::ofstream myfile;
|
||||||
|
myfile.open("/etc/iprefresher.cfg");
|
||||||
|
if (myfile.is_open()) {
|
||||||
|
myfile << Version::SAMPLECONFIG;
|
||||||
|
myfile.close();
|
||||||
|
} else {
|
||||||
|
std::cout << "error creating file" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (const libconfig::ParseException &pex) {
|
||||||
|
std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
|
||||||
|
<< " - " << pex.getError() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// needed parameters
|
||||||
|
dynuapikey = (std::string) cfg.lookup("dynuapikey");
|
||||||
|
domainid = (std::string) cfg.lookup("domainid");
|
||||||
|
domainname = (std::string) cfg.lookup("domainname");
|
||||||
|
// optional parameters
|
||||||
|
telegramApiKey = (std::string) cfg.lookup("telegramApiKey");
|
||||||
|
chatId = (std::string) cfg.lookup("chatId");
|
||||||
|
}
|
||||||
|
catch (const libconfig::SettingNotFoundException &nfex) {
|
||||||
|
// triggered if setting is missing in config
|
||||||
|
if (!(std::strcmp("telegramApiKey", nfex.getPath()) == 0 || std::strcmp("chatId", nfex.getPath()) == 0)) {
|
||||||
|
std::cerr << "No '" << nfex.getPath() << "' setting in configuration file." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check if needed values aren't empty
|
||||||
|
return !(Config::dynuapikey.empty() || Config::domainid.empty() || Config::domainname.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Config::validateConfig() {
|
||||||
|
libconfig::Config cfg;
|
||||||
|
try {
|
||||||
|
Logger::message("reading config file");
|
||||||
|
cfg.readFile("/etc/iprefresher.cfg");
|
||||||
|
}
|
||||||
|
catch (const libconfig::FileIOException &fioex) {
|
||||||
|
Logger::warning("config file doesn't exist or permission denied!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (const libconfig::ParseException &pex) {
|
||||||
|
std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
|
||||||
|
<< " - " << pex.getError() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Logger::message("Syntax and Permission is OK");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// needed parameters
|
||||||
|
if (((std::string) cfg.lookup("dynuapikey")).empty()) {
|
||||||
|
Logger::warning("required parameter dynuapikey seems to be empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (((std::string) cfg.lookup("domainid")).empty()) {
|
||||||
|
Logger::warning("required parameter domainid seems to be empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (((std::string) cfg.lookup("domainname")).empty()) {
|
||||||
|
Logger::warning("required parameter domainname seems to be empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// optional parameters
|
||||||
|
cfg.lookup("telegramApiKey");
|
||||||
|
cfg.lookup("chatId");
|
||||||
|
}
|
||||||
|
catch (const libconfig::SettingNotFoundException &nfex) {
|
||||||
|
// triggered if setting is missing in config
|
||||||
|
if (!(std::strcmp("telegramApiKey", nfex.getPath()) == 0 || std::strcmp("chatId", nfex.getPath()) == 0)) {
|
||||||
|
std::cerr << "No '" << nfex.getPath() << "' setting in configuration file." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by lukas on 11.02.20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <Credentials.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "libconfig.h++"
|
|
||||||
|
|
||||||
std::string Credentials::dynuapikey;
|
|
||||||
std::string Credentials::domainid; //id of the dynu domain
|
|
||||||
std::string Credentials::domainname;
|
|
||||||
|
|
||||||
std::string Credentials::telegramApiKey;
|
|
||||||
std::string Credentials::chatId;
|
|
||||||
|
|
||||||
bool Credentials::readCredentials() {
|
|
||||||
libconfig::Config cfg;
|
|
||||||
try {
|
|
||||||
cfg.readFile("/etc/iprefresher.cfg");
|
|
||||||
}
|
|
||||||
catch (const libconfig::FileIOException &fioex) {
|
|
||||||
std::cout << "I/O error while reading config file." << std::endl << "creating new config file!" << std::endl;
|
|
||||||
cfg.writeFile("/etc/iprefresher.cfg");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (const libconfig::ParseException &pex) {
|
|
||||||
std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
|
|
||||||
<< " - " << pex.getError() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the store name.
|
|
||||||
try {
|
|
||||||
// needed parameters
|
|
||||||
dynuapikey = (std::string) cfg.lookup("dynuapikey");
|
|
||||||
domainid = (std::string) cfg.lookup("domainid");
|
|
||||||
domainname = (std::string) cfg.lookup("domainname");
|
|
||||||
// optional parameters
|
|
||||||
telegramApiKey = (std::string) cfg.lookup("telegramApiKey");
|
|
||||||
chatId = (std::string) cfg.lookup("chatId");
|
|
||||||
std::cout << "Store name: " << dynuapikey << std::endl;
|
|
||||||
}
|
|
||||||
catch (const libconfig::SettingNotFoundException &nfex) {
|
|
||||||
// triggered if setting is missing in config
|
|
||||||
if (!(std::strcmp("telegramApiKey", nfex.getPath()) == 0 || std::strcmp("chatId", nfex.getPath()) == 0)) {
|
|
||||||
std::cerr << "No '" << nfex.getPath() << "' setting in configuration file." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if needed values aren't empty
|
|
||||||
return !(Credentials::dynuapikey.empty() || Credentials::domainid.empty() || Credentials::domainname.empty());
|
|
||||||
}
|
|
@ -14,7 +14,8 @@
|
|||||||
#include <Logger.h>
|
#include <Logger.h>
|
||||||
|
|
||||||
#include <IPRefresher.h>
|
#include <IPRefresher.h>
|
||||||
#include <Credentials.h>
|
#include <Config.h>
|
||||||
|
#include <Version.h>
|
||||||
|
|
||||||
void IPRefresher::checkIPAdress(bool force) {
|
void IPRefresher::checkIPAdress(bool force) {
|
||||||
FileLogger logger;
|
FileLogger logger;
|
||||||
@ -34,11 +35,11 @@ void IPRefresher::checkIPAdress(bool force) {
|
|||||||
Logger::message("ip changed! -- from :" + oldip + "to: " + ip);
|
Logger::message("ip changed! -- from :" + oldip + "to: " + ip);
|
||||||
|
|
||||||
DynuAPI dynu;
|
DynuAPI dynu;
|
||||||
dynu.init(Credentials::dynuapikey, Credentials::domainid, Credentials::domainname);
|
dynu.init(Config::dynuapikey, Config::domainid, Config::domainname);
|
||||||
|
|
||||||
if (dynu.refreshIp(ip)) {
|
if (dynu.refreshIp(ip)) {
|
||||||
TelegramAPI tele;
|
TelegramAPI tele;
|
||||||
tele.init(Credentials::telegramApiKey, Credentials::chatId);
|
tele.init(Config::telegramApiKey, Config::chatId);
|
||||||
tele.sendMessage(oldip + " moved to " + ip);
|
tele.sendMessage(oldip + " moved to " + ip);
|
||||||
} else {
|
} else {
|
||||||
//error
|
//error
|
||||||
@ -53,14 +54,17 @@ void IPRefresher::checkIPAdress(bool force) {
|
|||||||
IPRefresher::IPRefresher() = default;
|
IPRefresher::IPRefresher() = default;
|
||||||
|
|
||||||
IPRefresher::IPRefresher(bool loop) {
|
IPRefresher::IPRefresher(bool loop) {
|
||||||
if (Credentials::readCredentials()) {
|
if (loop) {
|
||||||
Logger::message("startup of service");
|
Logger::message("startup of service");
|
||||||
while (loop) {
|
Logger::message("Version: " + Version::VERSION);
|
||||||
Logger::message("starting check");
|
if (Config::readCredentials()) {
|
||||||
checkIPAdress(false);
|
while (true) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(300000));
|
Logger::message("starting check");
|
||||||
|
checkIPAdress(false);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(300000));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "incorrect credentials!" << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
std::cout << "incorrect credentials!" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,6 @@
|
|||||||
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
|
||||||
|
|
||||||
const int Logger::Warning = 1;
|
|
||||||
const int Logger::Debug = 2;
|
|
||||||
const int Logger::Message = 3;
|
|
||||||
const int Logger::Error = 4;
|
|
||||||
|
|
||||||
void Logger::debug(const std::string message) {
|
void Logger::debug(const std::string message) {
|
||||||
log(message, Logger::Debug);
|
log(message, Logger::Debug);
|
||||||
}
|
}
|
||||||
@ -45,6 +39,9 @@ void Logger::log(const std::string &message, int level) {
|
|||||||
case Error:
|
case Error:
|
||||||
out << "ERROR";
|
out << "ERROR";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
out << "UNDEFINED";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
out << "] ";
|
out << "] ";
|
||||||
out << message;
|
out << message;
|
||||||
|
@ -3,10 +3,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "api/API.h"
|
#include "api/API.h"
|
||||||
#include "api/Hashmap.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
@ -5,19 +5,16 @@
|
|||||||
#include "api/DynuAPI.h"
|
#include "api/DynuAPI.h"
|
||||||
|
|
||||||
int DynuAPI::refreshIp(std:: string ip) {
|
int DynuAPI::refreshIp(std:: string ip) {
|
||||||
|
|
||||||
Hashmap<std::string, std::string> args;
|
Hashmap<std::string, std::string> args;
|
||||||
args.add("name", domainname);
|
args.add("name", domainname);
|
||||||
args.add("ipv4Address", ip);
|
args.add("ipv4Address", ip);
|
||||||
|
|
||||||
std::vector<std::string> headers;
|
std::vector<std::string> headers;
|
||||||
headers.push_back("accept: application/json");
|
headers.emplace_back("accept: application/json");
|
||||||
headers.push_back("User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com)");
|
headers.emplace_back("User-Agent: Mozilla/5.0 (compatible; Rigor/1.0.0; http://rigor.com)");
|
||||||
headers.push_back("API-Key: " + dynuapikey);
|
headers.emplace_back("API-Key: " + dynuapikey);
|
||||||
|
|
||||||
std::string dynurepl = request("https://api.dynu.com/v2/dns/" + domainid, true, args, headers);
|
const std::string dynurepl = request("https://api.dynu.com/v2/dns/" + domainid, true, args, headers);
|
||||||
|
|
||||||
// std::cout << "[DEBUG] api reply:: " << dynurepl << std::endl;
|
|
||||||
|
|
||||||
if (dynurepl != "{\"statusCode\":200}") {
|
if (dynurepl != "{\"statusCode\":200}") {
|
||||||
return -1;
|
return -1;
|
||||||
@ -26,7 +23,7 @@ int DynuAPI::refreshIp(std:: string ip) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynuAPI::init(std::string dynuApiKey, std::string domainId, std::string domainName) {
|
void DynuAPI::init(const std::string& dynuApiKey, const std::string& domainId, const std::string& domainName) {
|
||||||
this->dynuapikey=dynuApiKey;
|
this->dynuapikey=dynuApiKey;
|
||||||
this->domainid=domainId;
|
this->domainid=domainId;
|
||||||
this->domainname=domainName;
|
this->domainname=domainName;
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
#include "api/TelegramAPI.h"
|
#include "api/TelegramAPI.h"
|
||||||
|
|
||||||
void TelegramAPI::sendMessage(std::string text) {
|
#include <Logger.h>
|
||||||
|
|
||||||
|
int TelegramAPI::sendMessage(const std::string& text) {
|
||||||
Hashmap<std::string, std::string> args;
|
Hashmap<std::string, std::string> args;
|
||||||
args.add("chat_id", chatid);
|
args.add("chat_id", chatid);
|
||||||
args.add("text", text);
|
args.add("text", text);
|
||||||
@ -12,10 +14,16 @@ void TelegramAPI::sendMessage(std::string text) {
|
|||||||
std::vector<std::string> headers;
|
std::vector<std::string> headers;
|
||||||
|
|
||||||
std::string reply = request("https://api.telegram.org/bot" + apikey + "/sendmessage", false, args, headers);
|
std::string reply = request("https://api.telegram.org/bot" + apikey + "/sendmessage", false, args, headers);
|
||||||
// std::cout << "[DEBUG] " << reply << std::endl;
|
|
||||||
|
unsigned const long ULONG_MAX = -1;
|
||||||
|
if (reply.find("\"error_code\"") != ULONG_MAX) {
|
||||||
|
Logger::error("failed to refresh the ip (Dynu API)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TelegramAPI::init(std::string apikey, std::string chatid) {
|
void TelegramAPI::init(const std::string apikey, const std::string chatid) {
|
||||||
this->apikey = apikey;
|
this->apikey = apikey;
|
||||||
this->chatid = chatid;
|
this->chatid = chatid;
|
||||||
}
|
}
|
||||||
|
30
src/main.cpp
30
src/main.cpp
@ -1,9 +1,16 @@
|
|||||||
#include <iostream>
|
//
|
||||||
#include <IPRefresher.h>
|
// Created by lukas on 18.06.19.
|
||||||
#include <Version.h>
|
//
|
||||||
#include <Logger.h>
|
|
||||||
#include <Credentials.h>
|
|
||||||
|
|
||||||
|
#include <Version.h>
|
||||||
|
#include <IPRefresher.h>
|
||||||
|
#include <Logger.h>
|
||||||
|
#include <Config.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
/**
|
||||||
|
* application entry point
|
||||||
|
*/
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
std::string firstarg(argv[1]);
|
std::string firstarg(argv[1]);
|
||||||
@ -12,12 +19,13 @@ int main(int argc, char *argv[]) {
|
|||||||
<< "[-v] [--version] print the software version" << std::endl
|
<< "[-v] [--version] print the software version" << std::endl
|
||||||
<< "[-f] [--force] force refresh of ip" << std::endl
|
<< "[-f] [--force] force refresh of ip" << std::endl
|
||||||
<< "[-l] [--loop] infinite loop to refresh ip every five minutes" << std::endl
|
<< "[-l] [--loop] infinite loop to refresh ip every five minutes" << std::endl
|
||||||
|
<< "[-c] [--checkconfig] validate configuration" << std::endl
|
||||||
<< "[no argument] normal ip check and refresh" << std::endl;
|
<< "[no argument] normal ip check and refresh" << std::endl;
|
||||||
} else if (firstarg == "-v" || firstarg == "--version") {
|
} else if (firstarg == "-v" || firstarg == "--version") {
|
||||||
std::cout << "Version " << Version::VERSION << std::endl;
|
std::cout << "Version " << Version::VERSION << std::endl;
|
||||||
} else if (firstarg == "-f" || firstarg == "--force") {
|
} else if (firstarg == "-f" || firstarg == "--force") {
|
||||||
IPRefresher ipr;
|
IPRefresher ipr;
|
||||||
if (Credentials::readCredentials()) {
|
if (Config::readCredentials()) {
|
||||||
ipr.checkIPAdress(true);
|
ipr.checkIPAdress(true);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "incorrect credentials!" << std::endl;
|
std::cout << "incorrect credentials!" << std::endl;
|
||||||
@ -25,18 +33,24 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
} else if (firstarg == "-l" || firstarg == "--loop") {
|
} else if (firstarg == "-l" || firstarg == "--loop") {
|
||||||
IPRefresher(true);
|
IPRefresher(true);
|
||||||
|
} else if (firstarg == "-c" || firstarg == "--checkconfig") {
|
||||||
|
if (Config::validateConfig()) {
|
||||||
|
Logger::message("Config file is OK");
|
||||||
|
} else {
|
||||||
|
Logger::warning("There are errors in config file!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger::message("wrong arguments! -h for help");
|
Logger::message("wrong arguments! -h for help");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
IPRefresher ipr;
|
IPRefresher ipr;
|
||||||
Logger::message("starting check");
|
Logger::message("starting check");
|
||||||
if (Credentials::readCredentials()) {
|
if (Config::readCredentials()) {
|
||||||
ipr.checkIPAdress(false);
|
ipr.checkIPAdress(false);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "incorrect credentials!" << std::endl;
|
std::cout << "incorrect credentials!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user