Skip to content

Commit

Permalink
Merge pull request #2254 from pi-hole/tweak/local_api_ftl
Browse files Browse the repository at this point in the history
Tweak CHAOS TXT local.api.ftl
  • Loading branch information
DL6ER authored Feb 22, 2025
2 parents 4c4dd88 + 62676f3 commit e2297ea
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 22 deletions.
3 changes: 3 additions & 0 deletions patch/civetweb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ patch -p1 < patch/civetweb/0001-Register-CSRF-token-in-conn-request_info.patch
echo "Applying patch 0001-Log-debug-messages-to-webserver.log-when-debug.webse.patch"
patch -p1 < patch/civetweb/0001-Log-debug-messages-to-webserver.log-when-debug.webse.patch

echo "Applying patch 0001-Expose-bound-to-addresses-from-CivetWeb-to-the-front.patch"
patch -p1 < patch/civetweb/0001-Expose-bound-to-addresses-from-CivetWeb-to-the-front.patch

echo "ALL PATCHES APPLIED OKAY"
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
From 0bee9e9f7942c5b73a715eaeadf5ab2d09a8c74d Mon Sep 17 00:00:00 2001
From: DL6ER <[email protected]>
Date: Sat, 22 Feb 2025 18:33:25 +0100
Subject: [PATCH] Expose bound-to addresses from CivetWeb to the frontend

Signed-off-by: DL6ER <[email protected]>
---
src/webserver/civetweb/civetweb.c | 1 +
src/webserver/civetweb/civetweb.h | 6 ++++++
2 files changed, 7 insertions(+)

diff --git a/src/webserver/civetweb/civetweb.c b/src/webserver/civetweb/civetweb.c
index fa908e54..66fcab01 100644
--- a/src/webserver/civetweb/civetweb.c
+++ b/src/webserver/civetweb/civetweb.c
@@ -3339,6 +3339,7 @@ mg_get_server_ports(const struct mg_context *ctx,
ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
ports[cnt].is_optional = ctx->listening_sockets[i].is_optional;
+ memcpy(&ports[cnt].addr, &ctx->listening_sockets[i].lsa, sizeof(ports[cnt].addr));

if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
/* IPv4 */
diff --git a/src/webserver/civetweb/civetweb.h b/src/webserver/civetweb/civetweb.h
index eee958b4..6dcfa457 100644
--- a/src/webserver/civetweb/civetweb.h
+++ b/src/webserver/civetweb/civetweb.h
@@ -23,6 +23,8 @@
#ifndef CIVETWEB_HEADER_INCLUDED
#define CIVETWEB_HEADER_INCLUDED

+#include <netinet/in.h> /* Pi-hole extension */
+
#define CIVETWEB_VERSION "1.17"
#define CIVETWEB_VERSION_MAJOR (1)
#define CIVETWEB_VERSION_MINOR (17)
@@ -721,6 +723,10 @@ struct mg_server_port {
int _reserved2;
int _reserved3;
int _reserved4;
+ union {
+ struct sockaddr_in sa4; /* Pi-hole extension */
+ struct sockaddr_in6 sa6; /* Pi-hole extension */
+ } addr;
};

/* Legacy name */
--
2.43.0

1 change: 1 addition & 0 deletions src/webserver/civetweb/civetweb.c
Original file line number Diff line number Diff line change
Expand Up @@ -3339,6 +3339,7 @@ mg_get_server_ports(const struct mg_context *ctx,
ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
ports[cnt].is_optional = ctx->listening_sockets[i].is_optional;
memcpy(&ports[cnt].addr, &ctx->listening_sockets[i].lsa, sizeof(ports[cnt].addr));

if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
/* IPv4 */
Expand Down
6 changes: 6 additions & 0 deletions src/webserver/civetweb/civetweb.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#ifndef CIVETWEB_HEADER_INCLUDED
#define CIVETWEB_HEADER_INCLUDED

#include <netinet/in.h> /* Pi-hole extension */

#define CIVETWEB_VERSION "1.17"
#define CIVETWEB_VERSION_MAJOR (1)
#define CIVETWEB_VERSION_MINOR (17)
Expand Down Expand Up @@ -721,6 +723,10 @@ struct mg_server_port {
int _reserved2;
int _reserved3;
int _reserved4;
union {
struct sockaddr_in sa4; /* Pi-hole extension */
struct sockaddr_in6 sa6; /* Pi-hole extension */
} addr;
};

/* Legacy name */
Expand Down
62 changes: 41 additions & 21 deletions src/webserver/webserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,9 @@ static struct serverports
bool is_secure :1;
bool is_redirect :1;
bool is_optional :1;
unsigned char protocol; // 1 = IPv4, 2 = IPv4+IPv6, 3 = IPv6
in_port_t port;
char addr[INET6_ADDRSTRLEN + 2]; // +2 for square brackets around IPv6 address
int port;
int protocol; // 1 = IPv4, 3 = IPv6
} server_ports[MAXPORTS] = { 0 };
static in_port_t https_port = 0;
/**
Expand Down Expand Up @@ -252,20 +253,37 @@ static void get_server_ports(void)
server_ports[i].is_secure = mgports[i].is_ssl;
server_ports[i].is_redirect = mgports[i].is_redirect;
server_ports[i].is_optional = mgports[i].is_optional;
// 1 = IPv4, 3 = IPv6 (can also be a combo-socker serving both),
// the documentation in civetweb.h is wrong
server_ports[i].protocol = mgports[i].protocol;

// Convert listening address to string
if(server_ports[i].protocol == 1)
inet_ntop(AF_INET, &mgports[i].addr.sa4.sin_addr, server_ports[i].addr, INET_ADDRSTRLEN);
else if(server_ports[i].protocol == 3)
{
char tmp[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET6, &mgports[i].addr.sa6.sin6_addr, tmp, INET6_ADDRSTRLEN);
// Enclose IPv6 address in square brackets
snprintf(server_ports[i].addr, sizeof(server_ports[i].addr), "[%s]", tmp);
}
else
log_warn("Unsupported protocol for port %d", mgports[i].port);

// Store (first) HTTPS port if not already set
if(mgports[i].is_ssl && https_port == 0)
https_port = mgports[i].port;

// Print port information
if(i == 0)
log_info("Web server ports:");
log_info(" - %d (HTTP%s, IPv%s%s%s)",
mgports[i].port, mgports[i].is_ssl ? "S" : "",
mgports[i].protocol == 1 ? "4" : (mgports[i].protocol == 3 ? "6" : "4+6"),
mgports[i].is_redirect ? ", redirecting" : "",
mgports[i].is_optional ? ", optional" : "");
log_info(" - %s:%d (HTTP%s, IPv%s%s%s)",
server_ports[i].addr,
server_ports[i].port,
server_ports[i].is_secure ? "S" : "",
server_ports[i].protocol == 1 ? "4" : "6",
server_ports[i].is_redirect ? ", redirecting" : "",
server_ports[i].is_optional ? ", optional" : "");

}
}
Expand All @@ -275,21 +293,13 @@ in_port_t __attribute__((pure)) get_https_port(void)
return https_port;
}

#define MAX_URL_LEN 255
unsigned short get_api_string(char **buf, const bool domain)
{
// Initialize buffer to empty string
size_t len = 0;
// First byte has the length of the first string
**buf = 0;
const char *domain_str = domain ? config.webserver.domain.v.s : "pi.hole";
size_t api_str_size = strlen(domain_str) + 20;

// Check if the string is too long for the TXT record
if(api_str_size > 255)
{
log_err("API URL too long for TXT record!");
return 0;
}

// TXT record format:
//
Expand All @@ -311,20 +321,30 @@ unsigned short get_api_string(char **buf, const bool domain)
continue;

// Reallocate additional memory for every port
if((*buf = realloc(*buf, (i+1)*api_str_size)) == NULL)
const size_t bufsz = (i + 1) * MAX_URL_LEN;
if((*buf = realloc(*buf, bufsz)) == NULL)
{
log_err("Failed to reallocate API URL buffer!");
return 0;
}
const size_t bufsz = (i+1)*api_str_size;

// Use appropriate domain
const char *addr = domain ? config.webserver.domain.v.s : server_ports[i].addr;

// If we bound to the wildcard address, substitute it with
// 127.0.0.1
if(strcmp(addr, "0.0.0.0") == 0)
addr = "127.0.0.1";
else if(strcasecmp(addr, "[::]") == 0)
addr = "[::1]";

// Append API URL to buffer
// We add this at buffer + 1 because the first byte is the
// length of the string, which we don't know yet
char *api_str = calloc(api_str_size, sizeof(char));
const ssize_t this_len = snprintf(api_str, bufsz - len - 1, "http%s://%s:%d/api/",
char *api_str = calloc(MAX_URL_LEN, sizeof(char));
const ssize_t this_len = snprintf(api_str, MAX_URL_LEN, "http%s://%s:%d/api/",
server_ports[i].is_secure ? "s" : "",
domain_str, server_ports[i].port);
addr, server_ports[i].port);
// Check if snprintf() failed
if(this_len < 0)
{
Expand Down
2 changes: 1 addition & 1 deletion test/test_suite.bats
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,7 @@
@test "API addresses reported correctly by CHAOS TXT local.api.ftl" {
run bash -c 'dig CHAOS TXT local.api.ftl +short @127.0.0.1'
printf "dig (full): %s\n" "${lines[@]}"
[[ ${lines[0]} == '"http://pi.hole:80/api/" "https://pi.hole:443/api/"' ]]
[[ ${lines[0]} == '"http://127.0.0.1:80/api/" "https://127.0.0.1:443/api/" "http://[::1]:80/api/" "https://[::1]:443/api/"' ]]
}

@test "API addresses reported by CHAOS TXT api.ftl identical to domain.api.ftl" {
Expand Down

0 comments on commit e2297ea

Please sign in to comment.