feat: initial build
This commit is contained in:
commit
ac436fae7e
5 changed files with 210 additions and 0 deletions
9
.dockerignore
Normal file
9
.dockerignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
build
|
||||||
|
cmake-build-*
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.log
|
||||||
15
CMakeLists.txt
Normal file
15
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(ipv6)
|
||||||
|
|
||||||
|
# Fügen Sie die folgenden Zeilen hinzu, um cURL zu Ihrem Projekt hinzuzufügen
|
||||||
|
find_package(CURL REQUIRED)
|
||||||
|
include_directories(${CURL_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# Setzen Sie das Ausgabeverzeichnis für ausführbare Dateien
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
|
# Fügen Sie Ihre C++-Quelldateien hinzu
|
||||||
|
add_executable(ipv6 src/main.cpp)
|
||||||
|
|
||||||
|
# Linken Sie Ihr ausführbares Programm mit der cURL-Bibliothek
|
||||||
|
target_link_libraries(ipv6 ${CURL_LIBRARIES})
|
||||||
41
Dockerfile
Normal file
41
Dockerfile
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# ---- Build stage ------------------------------------------------------------
|
||||||
|
FROM debian:bookworm-slim AS build
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
build-essential cmake pkg-config \
|
||||||
|
libcurl4-openssl-dev ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY CMakeLists.txt .
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
# Build
|
||||||
|
RUN mkdir -p build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && cmake --build . --config Release
|
||||||
|
|
||||||
|
# ---- Runtime stage ----------------------------------------------------------
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# nur Runtime-Libs
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libcurl4 ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# non-root User
|
||||||
|
RUN useradd -r -u 10001 appuser
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/build/ipv6_logger /app/ipv6_logger
|
||||||
|
|
||||||
|
# Standard-Env (kannst du per Compose/CLI überschreiben)
|
||||||
|
ENV URL="http://j-massing.de:19121/logs" \
|
||||||
|
INTERVAL="60"
|
||||||
|
|
||||||
|
# Healthcheck: prüft IPv6-Erreichbarkeit von 1.1.1.1 (via curl connect-only)
|
||||||
|
HEALTHCHECK --interval=60s --timeout=5s --start-period=10s --retries=3 \
|
||||||
|
CMD curl --connect-timeout 3 --silent --head http://1.1.1.1 || exit 1
|
||||||
|
|
||||||
|
USER appuser
|
||||||
|
|
||||||
|
# Loggt Hostname beim Start und läuft als Daemon-Loop
|
||||||
|
ENTRYPOINT ["/app/ipv6_logger"]
|
||||||
13
docker-compose.yaml
Normal file
13
docker-compose.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
ipv6-client:
|
||||||
|
build: .
|
||||||
|
image: ipv6-client:latest
|
||||||
|
container_name: ipv6-client
|
||||||
|
network_mode: host # <<< sieht Host-Interfaces u. echte IPv6
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
HOSTNAME: "${HOSTNAME:jenspi}"
|
||||||
|
URL: "http://j-massing.de:19121/logs"
|
||||||
|
INTERVAL: "60" # Seconds
|
||||||
|
# Keine Ports nötig, da client-only
|
||||||
132
src/main.cpp
Normal file
132
src/main.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
bool isPhysicalInterface(const char *interfaceName)
|
||||||
|
{
|
||||||
|
return (std::strncmp(interfaceName, "eth", 3) == 0 || std::strncmp(interfaceName, "wlan", 4) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getGlobalIpv6()
|
||||||
|
{
|
||||||
|
std::string ipv6;
|
||||||
|
struct ifaddrs *handle, *addressInfo;
|
||||||
|
if (getifaddrs(&handle) == -1)
|
||||||
|
{
|
||||||
|
std::cerr << "Error getting interface addresses" << std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (addressInfo = handle; addressInfo != nullptr; addressInfo = addressInfo->ifa_next)
|
||||||
|
{
|
||||||
|
if (addressInfo->ifa_addr == nullptr || addressInfo->ifa_addr->sa_family != AF_INET6 || !isPhysicalInterface(addressInfo->ifa_name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char addr[INET6_ADDRSTRLEN];
|
||||||
|
if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addressInfo->ifa_addr)->sin6_addr, addr, sizeof(addr)) == nullptr)
|
||||||
|
{
|
||||||
|
perror("inet_ntop");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* INFO: Check if is GUA (Global unique address) currently only reserved are 2xxx and 3xxx */
|
||||||
|
if (addr[0] != '2' && addr[0] != '3')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((addressInfo->ifa_flags & IFF_UP) && !(addressInfo->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) && !IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)addressInfo->ifa_addr)->sin6_addr))
|
||||||
|
{
|
||||||
|
ipv6 = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeifaddrs(handle);
|
||||||
|
return ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(const std::string &url, const std::string &data)
|
||||||
|
{
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if (!curl)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to initialize CURL" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct curl_slist *headers = nullptr;
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: text/plain");
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
|
||||||
|
|
||||||
|
CURLcode res = curl_easy_perform(curl);
|
||||||
|
if (res != CURLE_OK)
|
||||||
|
{
|
||||||
|
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_slist_free_all(headers);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple function to check internet connectivity by pinging a public DNS server
|
||||||
|
bool internetAvailable()
|
||||||
|
{
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
if (!curl)
|
||||||
|
return false;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "http://1.1.1.1");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
|
||||||
|
CURLcode res = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
return (res == CURLE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getEnv(const std::string &var, const std::string &defaultValue = "")
|
||||||
|
{
|
||||||
|
const char *val = std::getenv(var.c_str());
|
||||||
|
return val == nullptr ? defaultValue : std::string(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hostName = getEnv("HOSTNAME");
|
||||||
|
std::string url = getEnv("URL", "http://j-massing.de:19121/logs");
|
||||||
|
long interval = std::stol(getEnv("INTERVAL", "60"));
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("using hostname '%s'\n", hostName.c_str());
|
||||||
|
|
||||||
|
std::string lastIpv6;
|
||||||
|
lastIpv6.reserve(INET6_ADDRSTRLEN);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (internetAvailable())
|
||||||
|
{
|
||||||
|
std::string ipv6 = getGlobalIpv6();
|
||||||
|
if (!ipv6.empty())
|
||||||
|
{
|
||||||
|
send(url, hostName + "#" + ipv6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(interval));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue