Add FIFO buffer endpoint at /admin/api/ftl/dnsmasq_log. This is a FIFO buffer collecting and returning up to 32 messages from memory (compile-time option). The API endpoint can be continuously polled with the last returned ID to only show new messages that can be appended to a log on the web interface.

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER 2019-11-23 19:02:33 +01:00
parent 50e2736ef3
commit e4c7cec349
No known key found for this signature in database
GPG Key ID: 00135ACBD90B28DD
8 changed files with 131 additions and 26 deletions

View File

@ -139,4 +139,7 @@ extern pthread_t timerthread;
// Intentionally ignore result of function declared warn_unused_result
#define igr(x) {__typeof__(x) __attribute__((unused)) d=(x);}
#define max(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; })
#define min(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
#endif // FTL_H

View File

@ -11,12 +11,15 @@
#include "FTL.h"
#include "http-common.h"
#include "routes.h"
#include "ftl.h"
#include "json_macros.h"
#include "datastructure.h"
// get_FTL_version()
#include "log.h"
// git constants
#include "version.h"
// config struct
#include "config.h"
int api_ftl_clientIP(struct mg_connection *conn)
{
@ -25,3 +28,95 @@ int api_ftl_clientIP(struct mg_connection *conn)
JSON_OBJ_REF_STR(json,"remote_addr", request->remote_addr);
JSON_SEND_OBJECT(json);
}
static char dnsmasq_log_messages[LOG_SIZE][MAX_MESSAGE] = { 0 };
static time_t dnsmasq_log_stamps[LOG_SIZE] = { 0 };
static int dnsmasq_next_id = 0;
int api_ftl_dnsmasq_log(struct mg_connection *conn)
{
// Verify requesting client is allowed to see this ressource
if(check_client_auth(conn) < 0)
{
return send_json_unauthorized(conn, NULL);
}
unsigned int start = 0u;
const struct mg_request_info *request = mg_get_request_info(conn);
if(request->query_string != NULL)
{
// Does the user request an ID to sent from?
int num;
if((num = get_int_var(request->query_string, "nextID")) > 0)
{
if(num >= dnsmasq_next_id)
{
// Do not return any data
start = LOG_SIZE;
}
else if(num < max(dnsmasq_next_id - LOG_SIZE, 0))
{
// Requested an ID smaller than the lowest one we have
// We return the entire buffer
start = 0;
}
else
{
// Reply with partial buffer
start = LOG_SIZE - (dnsmasq_next_id - num);
}
}
}
// Process data
cJSON *json = JSON_NEW_OBJ();
cJSON *log = JSON_NEW_ARRAY();
unsigned int idx = 0u;
for(unsigned int i = start; i < LOG_SIZE; i++)
{
// Reconstruct log message identification number
if(dnsmasq_next_id < LOG_SIZE)
{
idx = i;
}
else
{
idx = dnsmasq_next_id - LOG_SIZE + i;
}
cJSON *entry = JSON_NEW_OBJ();
JSON_OBJ_ADD_NUMBER(entry, "id", idx);
JSON_OBJ_ADD_NUMBER(entry, "timestamp", dnsmasq_log_stamps[i]);
JSON_OBJ_REF_STR(entry, "message", dnsmasq_log_messages[i]);
JSON_ARRAY_ADD_ITEM(log, entry);
}
JSON_OBJ_ADD_ITEM(json, "log", log);
JSON_OBJ_ADD_NUMBER(json, "nextID", dnsmasq_next_id);
JSON_SEND_OBJECT(json);
}
void add_to_dnsmasq_log_fifo_buffer(const char *payload, const int length)
{
unsigned int idx = dnsmasq_next_id++;
if(idx >= LOG_SIZE)
{
// Log is full, move everything one slot forward to make space
memmove(dnsmasq_log_messages[0], dnsmasq_log_messages[1], (LOG_SIZE - 1u) * MAX_MESSAGE);
idx = LOG_SIZE - 1u;
}
// Copy relevant string into temporary buffer
memcpy(dnsmasq_log_messages[idx], payload, length);
// Zero-terminate buffer, truncate newline if found
if(dnsmasq_log_messages[idx][length - 1u] == '\n')
{
dnsmasq_log_messages[idx][length - 1u] = '\0';
}
else
{
dnsmasq_log_messages[idx][length] = '\0';
}
// Set timestamp
dnsmasq_log_stamps[idx] = time(NULL);
}

23
src/api/ftl.h Normal file
View File

@ -0,0 +1,23 @@
/* Pi-hole: A black hole for Internet advertisements
* (c) 2019 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* FTL Engine
* API FTL prototypes
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
#ifndef API_FTL_H
#define API_FTL_H
/* From RFC 3164 */
#define MAX_MESSAGE 1024
// How many messages do we keep in memory (FIFO message buffer)?
// The memory required is the set number in kilobytes
// Defaults to 32 [uses 32 KB of memory]
#define LOG_SIZE 32
void add_to_dnsmasq_log_fifo_buffer(const char *payload, const int length);
#endif // API_FTL_H

View File

@ -44,6 +44,10 @@ int api_handler(struct mg_connection *conn, void *ignored)
{
return api_ftl_clientIP(conn);
}
else if(startsWith("/api/ftl/dnsmasq_log", request->local_uri))
{
return api_ftl_dnsmasq_log(conn);
}
/******************************** api/stats **************************/
else if(startsWith("/api/stats/summary", request->local_uri))
{

View File

@ -29,8 +29,7 @@ int api_stats_recentblocked(struct mg_connection *conn);
// FTL methods
int api_ftl_clientIP(struct mg_connection *conn);
int api_ftl_version(struct mg_connection *conn);
int api_ftl_db(struct mg_connection *conn);
int api_ftl_dnsmasq_log(struct mg_connection *conn);
// DNS methods
int api_dns_status(struct mg_connection *conn);

View File

@ -27,8 +27,6 @@
// enum REGEX
#include "regex_r.h"
#define min(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
/* qsort comparision function (count field), sort ASC
static int __attribute__((pure)) cmpasc(const void *a, const void *b)
{

View File

@ -300,8 +300,8 @@ void my_syslog(int priority, const char *format, ...)
#endif
/*************************** Pi-hole specific logging **************************/
va_start(ap, format);
char buffer[MAX_MESSAGE + 1u];
va_start(ap, format);
len = vsnprintf(buffer, MAX_MESSAGE, format, ap) + 1u; /* include zero-terminator */
va_end(ap);
FTL_dnsmasq_log(buffer, len > MAX_MESSAGE ? MAX_MESSAGE : len);

View File

@ -34,6 +34,8 @@
#include "args.h"
// http_init()
#include "api/http-common.h"
// add_to_dnsmasq_log_buffer()
#include "api/ftl.h"
static void print_flags(const unsigned int flags);
static void save_reply_type(const unsigned int flags, const union all_addr *addr,
@ -1813,24 +1815,5 @@ void FTL_TCP_worker_terminating(void)
void FTL_dnsmasq_log(const char *payload, const int length)
{
// Get temporary space for dnsmasq's log message
char log_str[length + 1u];
// Copy relevant string into temporary buffer
memcpy(log_str, payload, length);
// Zero-terminate buffer, truncate newline if found
if(log_str[length - 1u] == '\n')
{
log_str[length - 1u] = '\0';
}
else
{
log_str[length] = '\0';
}
if(config.debug & DEBUG_API)
{
logg("DNSMASQ LOG: \"%s\"", log_str);
}
}
add_to_dnsmasq_log_fifo_buffer(payload, length);
}