mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Add new GET /api/padd endpoint
Build, Test, Deploy / smoke-tests (push) Has been cancelled
Codespell / spell-check (push) Has been cancelled
Check for merge conflicts / merge-conflict (push) Has been cancelled
API validation / Node (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-386, , linux/386) (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-amd64, , linux/amd64) (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-amd64-clang, clang, linux/amd64) (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-riscv64, , linux/riscv64) (push) Has been cancelled
Build, Test, Deploy / self-hosted (pihole-FTL-arm64, linux/arm64/v8) (push) Has been cancelled
Build, Test, Deploy / self-hosted (pihole-FTL-armv6, linux/arm/v6) (push) Has been cancelled
Build, Test, Deploy / self-hosted (pihole-FTL-armv7, linux/arm/v7) (push) Has been cancelled
Build, Test, Deploy / smoke-tests (push) Has been cancelled
Codespell / spell-check (push) Has been cancelled
Check for merge conflicts / merge-conflict (push) Has been cancelled
API validation / Node (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-386, , linux/386) (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-amd64, , linux/amd64) (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-amd64-clang, clang, linux/amd64) (push) Has been cancelled
Build, Test, Deploy / gha (pihole-FTL-riscv64, , linux/riscv64) (push) Has been cancelled
Build, Test, Deploy / self-hosted (pihole-FTL-arm64, linux/arm64/v8) (push) Has been cancelled
Build, Test, Deploy / self-hosted (pihole-FTL-armv6, linux/arm/v6) (push) Has been cancelled
Build, Test, Deploy / self-hosted (pihole-FTL-armv7, linux/arm/v7) (push) Has been cancelled
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -11,3 +11,4 @@ mmapped
|
||||
dnsmasq
|
||||
iif
|
||||
prefered
|
||||
padd
|
||||
|
||||
@@ -20,6 +20,7 @@ set(sources
|
||||
dhcp.c
|
||||
dns.c
|
||||
network.c
|
||||
padd.c
|
||||
history.c
|
||||
info.c
|
||||
list.c
|
||||
|
||||
@@ -102,6 +102,7 @@ static struct {
|
||||
{ "/api/action/restartdns", "", api_action_restartDNS, { API_PARSE_JSON, 0 }, true, HTTP_POST },
|
||||
{ "/api/action/flush/logs", "", api_action_flush_logs, { API_PARSE_JSON, 0 }, true, HTTP_POST },
|
||||
{ "/api/action/flush/arp", "", api_action_flush_arp, { API_PARSE_JSON, 0 }, true, HTTP_POST },
|
||||
{ "/api/padd", "", api_padd, { API_PARSE_JSON, 0 }, true, HTTP_GET },
|
||||
{ "/api/docs", "", api_docs, { API_PARSE_JSON, 0 }, false, HTTP_GET },
|
||||
};
|
||||
|
||||
|
||||
+14
-1
@@ -17,6 +17,8 @@
|
||||
#include "webserver/http-common.h"
|
||||
// regex_t
|
||||
#include "regex_r.h"
|
||||
// enum conf_type
|
||||
#include "config/config.h"
|
||||
|
||||
// Common definitions
|
||||
#define LOCALHOSTv4 "127.0.0.1"
|
||||
@@ -27,6 +29,7 @@ int api_handler(struct mg_connection *conn, void *ignored);
|
||||
|
||||
// Statistic methods
|
||||
int __attribute__((pure)) cmpdesc(const void *a, const void *b);
|
||||
unsigned int get_active_clients(void);
|
||||
int api_stats_summary(struct ftl_conn *api);
|
||||
int api_stats_query_types(struct ftl_conn *api);
|
||||
int api_stats_upstreams(struct ftl_conn *api);
|
||||
@@ -37,7 +40,7 @@ cJSON *get_top_domains(struct ftl_conn *api, const int count,
|
||||
const bool blocked, const bool domains_only);
|
||||
cJSON *get_top_clients(struct ftl_conn *api, const int count,
|
||||
const bool blocked, const bool clients_only,
|
||||
const bool names_only);
|
||||
const bool names_only, const bool ip_if_no_name);
|
||||
cJSON *get_top_upstreams(struct ftl_conn *api, const bool upstreams_only);
|
||||
|
||||
// History methods
|
||||
@@ -71,9 +74,15 @@ int api_info_messages_count(struct ftl_conn *api);
|
||||
int api_info_messages(struct ftl_conn *api);
|
||||
int api_info_metrics(struct ftl_conn *api);
|
||||
int api_info_login(struct ftl_conn *api);
|
||||
cJSON *read_sys_property(const char *path);
|
||||
int get_system_obj(struct ftl_conn *api, cJSON *system);
|
||||
int get_sensors_obj(struct ftl_conn *api, cJSON *sensors, const bool add_list);
|
||||
int get_version_obj(struct ftl_conn *api, cJSON *version);
|
||||
|
||||
// Config methods
|
||||
int api_config(struct ftl_conn *api);
|
||||
int get_json_config(struct ftl_conn *api, cJSON *json, const bool detailed);
|
||||
cJSON *addJSONConfValue(const enum conf_type conf_type, union conf_value *val);
|
||||
|
||||
// Log methods
|
||||
int api_logs(struct ftl_conn *api);
|
||||
@@ -84,6 +93,7 @@ int api_network_routes(struct ftl_conn *api);
|
||||
int api_network_interfaces(struct ftl_conn *api);
|
||||
int api_network_devices(struct ftl_conn *api);
|
||||
int api_client_suggestions(struct ftl_conn *api);
|
||||
int get_gateway(struct ftl_conn *api, cJSON * json, const bool detailed);
|
||||
|
||||
// DNS methods
|
||||
int api_dns_blocking(struct ftl_conn *api);
|
||||
@@ -132,4 +142,7 @@ int api_search(struct ftl_conn *api);
|
||||
int api_dhcp_leases_GET(struct ftl_conn *api);
|
||||
int api_dhcp_leases_DELETE(struct ftl_conn *api);
|
||||
|
||||
// PADD methods
|
||||
int api_padd(struct ftl_conn *api);
|
||||
|
||||
#endif // ROUTES_H
|
||||
|
||||
+24
-16
@@ -92,7 +92,7 @@ static cJSON *get_or_create_object(cJSON *parent, const char *path_element)
|
||||
|
||||
// This function is used to add a property to the JSON output using the
|
||||
// appropriate type of the config item to add.
|
||||
static cJSON *addJSONvalue(const enum conf_type conf_type, union conf_value *val)
|
||||
cJSON *addJSONConfValue(const enum conf_type conf_type, union conf_value *val)
|
||||
{
|
||||
switch(conf_type)
|
||||
{
|
||||
@@ -464,17 +464,9 @@ static const char *getJSONvalue(struct conf_item *conf_item, cJSON *elem, struct
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int api_config_get(struct ftl_conn *api)
|
||||
int get_json_config(struct ftl_conn *api, cJSON *json, const bool detailed)
|
||||
{
|
||||
// Parse query string parameters
|
||||
bool detailed = false;
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Check if we should return detailed config information
|
||||
get_bool_var(api->request->query_string, "detailed", &detailed);
|
||||
}
|
||||
|
||||
// Create root JSON object
|
||||
// Create root config object
|
||||
cJSON *config_j = JSON_NEW_OBJECT();
|
||||
|
||||
// Does the user request only a subset of /config?
|
||||
@@ -552,7 +544,7 @@ static int api_config_get(struct ftl_conn *api)
|
||||
else
|
||||
{
|
||||
// Add current value
|
||||
cJSON *val = addJSONvalue(conf_item->t, &conf_item->v);
|
||||
cJSON *val = addJSONConfValue(conf_item->t, &conf_item->v);
|
||||
if(val == NULL)
|
||||
{
|
||||
log_warn("Cannot format config item type %s of type %i",
|
||||
@@ -563,7 +555,7 @@ static int api_config_get(struct ftl_conn *api)
|
||||
}
|
||||
|
||||
// Add default value
|
||||
cJSON *dval = addJSONvalue(conf_item->t, &conf_item->d);
|
||||
cJSON *dval = addJSONConfValue(conf_item->t, &conf_item->d);
|
||||
if(dval == NULL)
|
||||
{
|
||||
log_warn("Cannot format config item type %s of type %i",
|
||||
@@ -592,7 +584,7 @@ static int api_config_get(struct ftl_conn *api)
|
||||
else
|
||||
{
|
||||
// Create the config item leaf object
|
||||
cJSON *leaf = addJSONvalue(conf_item->t, &conf_item->v);
|
||||
cJSON *leaf = addJSONConfValue(conf_item->t, &conf_item->v);
|
||||
if(leaf == NULL)
|
||||
{
|
||||
log_warn("Cannot format config item type %s of type %i",
|
||||
@@ -607,8 +599,6 @@ static int api_config_get(struct ftl_conn *api)
|
||||
// Release allocated memory
|
||||
free_config_path(requested_path);
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
|
||||
// Add topics and DNS server suggestions if in detailed mode
|
||||
if(detailed)
|
||||
{
|
||||
@@ -650,6 +640,24 @@ static int api_config_get(struct ftl_conn *api)
|
||||
|
||||
// Build and return JSON response
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "config", config_j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int api_config_get(struct ftl_conn *api)
|
||||
{
|
||||
// Parse query string parameters
|
||||
bool detailed = false;
|
||||
if(api->request->query_string != NULL)
|
||||
{
|
||||
// Check if we should return detailed config information
|
||||
get_bool_var(api->request->query_string, "detailed", &detailed);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
get_json_config(api, json, detailed);
|
||||
|
||||
// Build and return JSON response
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
|
||||
+2
-15
@@ -31,21 +31,8 @@ static int get_blocking(struct ftl_conn *api)
|
||||
// Return current status
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
const enum blocking_status blocking = get_blockingstatus();
|
||||
switch(blocking)
|
||||
{
|
||||
case BLOCKING_ENABLED:
|
||||
JSON_REF_STR_IN_OBJECT(json, "blocking", "enabled");
|
||||
break;
|
||||
case BLOCKING_DISABLED:
|
||||
JSON_REF_STR_IN_OBJECT(json, "blocking", "disabled");
|
||||
break;
|
||||
case DNS_FAILED:
|
||||
JSON_REF_STR_IN_OBJECT(json, "blocking", "failure");
|
||||
break;
|
||||
case BLOCKING_UNKNOWN:
|
||||
JSON_REF_STR_IN_OBJECT(json, "blocking", "unknown");
|
||||
break;
|
||||
}
|
||||
const char *status = get_blocking_status_str(blocking);
|
||||
JSON_REF_STR_IN_OBJECT(json, "blocking", status);
|
||||
|
||||
// Get timer information (if applicable)
|
||||
double delay;
|
||||
|
||||
@@ -34,6 +34,7 @@ set(sources
|
||||
hex/specs/logs.yaml
|
||||
hex/specs/main.yaml
|
||||
hex/specs/network.yaml
|
||||
hex/specs/padd.yaml
|
||||
hex/specs/queries.yaml
|
||||
hex/specs/search.yaml
|
||||
hex/specs/stats.yaml
|
||||
|
||||
@@ -63,6 +63,8 @@ tags:
|
||||
description: Methods used to gather advanced information about your network
|
||||
- name: "Actions"
|
||||
description: Methods used to trigger certain actions on your Pi-hole
|
||||
- name: "PADD"
|
||||
description: Methods used to query Pi-hole from PADD
|
||||
|
||||
|
||||
|
||||
@@ -274,6 +276,9 @@ paths:
|
||||
/docs:
|
||||
$ref: 'docs.yaml#/components/paths/docs'
|
||||
|
||||
/padd:
|
||||
$ref: 'padd.yaml#/components/paths/padd'
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
query_sid:
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
padd:
|
||||
get:
|
||||
summary: Get summarized data for PADD
|
||||
tags:
|
||||
- "PADD"
|
||||
operationId: "get_padd"
|
||||
parameters:
|
||||
- in: query
|
||||
description: (Optional) Return full data
|
||||
name: full
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
example: true
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: 'padd.yaml#/components/schemas/padd'
|
||||
- $ref: 'info.yaml#/components/schemas/system'
|
||||
- $ref: 'info.yaml#/components/schemas/version'
|
||||
- $ref: 'common.yaml#/components/schemas/took'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: 'common.yaml#/components/errors/unauthorized'
|
||||
- $ref: 'common.yaml#/components/schemas/took'
|
||||
|
||||
schemas:
|
||||
padd:
|
||||
type: object
|
||||
properties:
|
||||
recent_blocked:
|
||||
type: string
|
||||
description: "Most recent blocked domain"
|
||||
nullable: true
|
||||
example: "bad.example.com"
|
||||
top_domain:
|
||||
type: string
|
||||
description: "Most requested domain"
|
||||
nullable: true
|
||||
example: "good.example.com"
|
||||
top_blocked:
|
||||
type: string
|
||||
description: "Most blocked domain"
|
||||
nullable: true
|
||||
example: "bad.example.com"
|
||||
top_client:
|
||||
type: string
|
||||
description: "Most active client"
|
||||
nullable: true
|
||||
example: "localhost"
|
||||
active_clients:
|
||||
type: integer
|
||||
description: "Number of active clients"
|
||||
example: 22
|
||||
gravity_size:
|
||||
type: integer
|
||||
description: "Gravity list size"
|
||||
example: 225382
|
||||
blocking:
|
||||
type: string
|
||||
description: "Blocking status"
|
||||
example: "enabled"
|
||||
queries:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
description: "Total number of queries within the last 24 hours"
|
||||
example: 92258
|
||||
blocked:
|
||||
type: integer
|
||||
description: "Number of blocked queries"
|
||||
example: 4784
|
||||
percent_blocked:
|
||||
type: number
|
||||
description: "Percentage of blocked queries"
|
||||
example: 5.18
|
||||
cache:
|
||||
type: object
|
||||
properties:
|
||||
size:
|
||||
type: integer
|
||||
description: "Total cache size"
|
||||
example: 10000
|
||||
inserted:
|
||||
type: integer
|
||||
description: "Number of inserted cache entries"
|
||||
example: 233
|
||||
evicted:
|
||||
type: integer
|
||||
description: "Number of evicted cache entries"
|
||||
example: 0
|
||||
iface:
|
||||
type: object
|
||||
description: "Default interfaces"
|
||||
properties:
|
||||
v4:
|
||||
type: object
|
||||
description: "IPv4 interface"
|
||||
properties:
|
||||
addr:
|
||||
type: string
|
||||
description: "Primary address"
|
||||
nullable: true # there may be no IPv4 address
|
||||
example: "192.168.2.11"
|
||||
rx_bytes:
|
||||
type: object
|
||||
description: "Received bytes"
|
||||
properties:
|
||||
value:
|
||||
type: number
|
||||
example: 76.46
|
||||
unit:
|
||||
type: string
|
||||
example: "G"
|
||||
tx_bytes:
|
||||
type: object
|
||||
description: "Transmitted bytes"
|
||||
properties:
|
||||
value:
|
||||
type: number
|
||||
example: 68.58
|
||||
unit:
|
||||
type: string
|
||||
example: "G"
|
||||
num_addrs:
|
||||
type: integer
|
||||
description: "Number of addresses on the interface"
|
||||
example: 1
|
||||
name:
|
||||
type: string
|
||||
description: "Interface name"
|
||||
example: "eth0"
|
||||
gw_addr:
|
||||
type: string
|
||||
description: "Gateway address"
|
||||
nullable: true # there may be no IPv4 gateway
|
||||
example: "192.168.2.1"
|
||||
v6:
|
||||
type: object
|
||||
description: "IPv6 interface"
|
||||
properties:
|
||||
addr:
|
||||
type: string
|
||||
description: "Primary address"
|
||||
nullable: true # there may be no IPv6 address
|
||||
example: "fe80::b0e4:1b1e:7b7d:5855"
|
||||
num_addrs:
|
||||
type: integer
|
||||
description: "Number of addresses on the interface"
|
||||
example: 3
|
||||
name:
|
||||
type: string
|
||||
description: "Interface name"
|
||||
example: "eth0"
|
||||
gw_addr:
|
||||
type: string
|
||||
description: "Gateway address"
|
||||
nullable: true # there may be no IPv6 gateway
|
||||
example: "fe80::b0e4:1b1e:7b7d:1b1e"
|
||||
node_name:
|
||||
type: string
|
||||
description: "Pi-hole host's name"
|
||||
example: "pihole"
|
||||
host_model:
|
||||
type: string
|
||||
description: "Host model"
|
||||
example: "Raspberry Pi 3 Model B Plus Rev 1.3"
|
||||
nullable: true
|
||||
config:
|
||||
type: object
|
||||
description: "Pi-hole configuration (excerpt)"
|
||||
properties:
|
||||
dhcp_active:
|
||||
type: boolean
|
||||
description: "DHCP server status"
|
||||
example: true
|
||||
dhcp_start:
|
||||
type: string
|
||||
description: "DHCP start address"
|
||||
example: "192.168.0.1"
|
||||
dhcp_end:
|
||||
type: string
|
||||
description: "DHCP end address"
|
||||
example: "192.168.0.254"
|
||||
dhcp_ipv6:
|
||||
type: boolean
|
||||
description: "DHCPv6 server status"
|
||||
example: false
|
||||
dns_domain:
|
||||
type: string
|
||||
description: "DNS domain"
|
||||
example: "lan"
|
||||
dns_port:
|
||||
type: integer
|
||||
description: "DNS port"
|
||||
example: 53
|
||||
dns_num_upstreams:
|
||||
type: integer
|
||||
description: "Number of upstream DNS servers"
|
||||
example: 1
|
||||
dns_dnssec:
|
||||
type: boolean
|
||||
description: "DNSSEC status"
|
||||
example: true
|
||||
dns_revServer_active:
|
||||
type: boolean
|
||||
description: "Reverse DNS server status"
|
||||
example: false
|
||||
"%cpu":
|
||||
type: number
|
||||
description: "CPU usage"
|
||||
example: 0.0
|
||||
"%mem":
|
||||
type: number
|
||||
description: "Memory usage"
|
||||
example: 1.5
|
||||
pid:
|
||||
type: integer
|
||||
description: "FTL's process ID"
|
||||
example: 1639
|
||||
sensors:
|
||||
type: object
|
||||
properties:
|
||||
cpu_temp:
|
||||
type: number
|
||||
description: "CPU temperature"
|
||||
nullable: true
|
||||
example: 45.0
|
||||
hot_limit:
|
||||
type: number
|
||||
description: "Temperature limit"
|
||||
example: 80.0
|
||||
unit:
|
||||
type: string
|
||||
description: "Temperature unit"
|
||||
example: "C"
|
||||
@@ -132,6 +132,10 @@ static const unsigned char specs_action_yaml[] = {
|
||||
#include "hex/specs/action.yaml"
|
||||
};
|
||||
|
||||
static const unsigned char specs_padd_yaml[] = {
|
||||
#include "hex/specs/padd.yaml"
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *path;
|
||||
const char *mime_type;
|
||||
@@ -168,6 +172,7 @@ struct {
|
||||
{"specs/stats.yaml", "text/plain", (const char*)specs_stats_yaml, sizeof(specs_stats_yaml)},
|
||||
{"specs/teleporter.yaml", "text/plain", (const char*)specs_teleporter_yaml, sizeof(specs_teleporter_yaml)},
|
||||
{"specs/action.yaml", "text/plain", (const char*)specs_action_yaml, sizeof(specs_action_yaml)},
|
||||
{"specs/padd.yaml", "text/plain", (const char*)specs_padd_yaml, sizeof(specs_padd_yaml)},
|
||||
};
|
||||
|
||||
#endif // API_DOCS_H
|
||||
|
||||
+26
-9
@@ -157,7 +157,7 @@ int api_info_database(struct ftl_conn *api)
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
static int get_system_obj(struct ftl_conn *api, cJSON *system)
|
||||
int get_system_obj(struct ftl_conn *api, cJSON *system)
|
||||
{
|
||||
const int nprocs = get_nprocs();
|
||||
struct sysinfo info;
|
||||
@@ -465,7 +465,7 @@ static int get_hwmon_sensors(struct ftl_conn *api, cJSON *sensors)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cJSON *read_sys_property(const char *path)
|
||||
cJSON *read_sys_property(const char *path)
|
||||
{
|
||||
if(!file_exists(path))
|
||||
return cJSON_CreateNull();
|
||||
@@ -641,16 +641,15 @@ int api_info_host(struct ftl_conn *api)
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_info_sensors(struct ftl_conn *api)
|
||||
int get_sensors_obj(struct ftl_conn *api, cJSON *sensors, const bool add_list)
|
||||
{
|
||||
cJSON *sensors = JSON_NEW_OBJECT();
|
||||
|
||||
// Get sensors array
|
||||
cJSON *list = JSON_NEW_ARRAY();
|
||||
int ret = get_hwmon_sensors(api, list);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
JSON_ADD_ITEM_TO_OBJECT(sensors, "list", list);
|
||||
if(add_list)
|
||||
JSON_ADD_ITEM_TO_OBJECT(sensors, "list", list);
|
||||
|
||||
// Loop over available sensors and try to identify the most suitable CPU temperature sensor
|
||||
int cpu_temp_sensor = -1;
|
||||
@@ -708,12 +707,25 @@ int api_info_sensors(struct ftl_conn *api)
|
||||
unit = "K";
|
||||
JSON_REF_STR_IN_OBJECT(sensors, "unit", unit);
|
||||
|
||||
if(!add_list)
|
||||
cJSON_Delete(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int api_info_sensors(struct ftl_conn *api)
|
||||
{
|
||||
cJSON *sensors = JSON_NEW_OBJECT();
|
||||
int ret = get_sensors_obj(api, sensors, true);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "sensors", sensors);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_info_version(struct ftl_conn *api)
|
||||
int get_version_obj(struct ftl_conn *api, cJSON *version)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
@@ -802,8 +814,6 @@ int api_info_version(struct ftl_conn *api)
|
||||
JSON_REF_STR_IN_OBJECT(ftl_local, "version", get_FTL_version());
|
||||
JSON_REF_STR_IN_OBJECT(ftl_local, "date", GIT_DATE);
|
||||
|
||||
cJSON *version = JSON_NEW_OBJECT();
|
||||
|
||||
cJSON *core = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NULL_IF_NOT_EXISTS(core_local, "branch");
|
||||
JSON_ADD_NULL_IF_NOT_EXISTS(core_local, "version");
|
||||
@@ -839,7 +849,14 @@ int api_info_version(struct ftl_conn *api)
|
||||
JSON_ADD_NULL_IF_NOT_EXISTS(docker, "remote");
|
||||
JSON_ADD_ITEM_TO_OBJECT(version, "docker", docker);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int api_info_version(struct ftl_conn *api)
|
||||
{
|
||||
// Send reply
|
||||
cJSON *version = JSON_NEW_OBJECT();
|
||||
get_version_obj(api, version);
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "version", version);
|
||||
JSON_SEND_OBJECT(json);
|
||||
|
||||
+13
-5
@@ -32,11 +32,8 @@
|
||||
// nlroutes(), nladdrs(), nllinks()
|
||||
#include "tools/netlink.h"
|
||||
|
||||
int api_network_gateway(struct ftl_conn *api)
|
||||
int get_gateway(struct ftl_conn *api, cJSON * json, const bool detailed)
|
||||
{
|
||||
// Get ?detailed parameter
|
||||
bool detailed = false;
|
||||
get_bool_var(api->request->query_string, "detailed", &detailed);
|
||||
|
||||
// Get routing information
|
||||
cJSON *routes = JSON_NEW_ARRAY();
|
||||
@@ -106,7 +103,6 @@ int api_network_gateway(struct ftl_conn *api)
|
||||
}
|
||||
|
||||
// Send gateway information
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "gateway", gateway);
|
||||
|
||||
if(detailed)
|
||||
@@ -121,6 +117,18 @@ int api_network_gateway(struct ftl_conn *api)
|
||||
cJSON_Delete(interfaces);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int api_network_gateway(struct ftl_conn *api)
|
||||
{
|
||||
// Get ?detailed parameter
|
||||
bool detailed = false;
|
||||
get_bool_var(api->request->query_string, "detailed", &detailed);
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
get_gateway(api, json, detailed);
|
||||
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
/* 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 Implementation /api/dns
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
#include "FTL.h"
|
||||
#include "webserver/http-common.h"
|
||||
#include "webserver/json_macros.h"
|
||||
#include "api.h"
|
||||
// lock_shm() and unlock_shm()
|
||||
#include "shmem.h"
|
||||
// counters
|
||||
#include "datastructure.h"
|
||||
// get_dnsmasq_metrics(&metrics)
|
||||
#include "metrics.h"
|
||||
// get_blockingstatus()
|
||||
#include "config/config.h"
|
||||
// uname()
|
||||
#include <sys/utsname.h>
|
||||
// nlroutes(), nladdrs(), nllinks()
|
||||
#include "tools/netlink.h"
|
||||
// struct proc_mem, getProcessMemory()
|
||||
#include "procps.h"
|
||||
// getcpu_percentage()
|
||||
#include "daemon.h"
|
||||
|
||||
int api_padd(struct ftl_conn *api)
|
||||
{
|
||||
// Parse parameters
|
||||
bool full = true;
|
||||
if(api->request->query_string != NULL)
|
||||
get_bool_var(api->request->query_string, "full", &full);
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
const int total = counters->queries;
|
||||
const int blocked = get_blocked_count();
|
||||
const unsigned int active_clients = get_active_clients();
|
||||
const int num_gravity = counters->database.gravity;
|
||||
|
||||
// If privacy level is set to hide domains, do not return the most
|
||||
// recent blocked domain
|
||||
if(config.misc.privacylevel.v.privacy_level < PRIVACY_HIDE_DOMAINS)
|
||||
{
|
||||
// Find most recently blocked query
|
||||
for(int queryID = counters->queries - 1; queryID > 0 ; queryID--)
|
||||
{
|
||||
const queriesData* query = getQuery(queryID, true);
|
||||
if(query == NULL)
|
||||
continue;
|
||||
|
||||
if(query->flags.blocked)
|
||||
{
|
||||
// Ask subroutine for domain. It may return "hidden" depending on
|
||||
// the privacy settings at the time the query was made
|
||||
const char *domain = getDomainString(query);
|
||||
if(domain == NULL)
|
||||
continue;
|
||||
|
||||
JSON_COPY_STR_TO_OBJECT(json, "recent_blocked", domain);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock shared memory
|
||||
unlock_shm();
|
||||
|
||||
// Add the number of active clients, the size of the gravity list
|
||||
JSON_ADD_NUMBER_TO_OBJECT(json, "active_clients", active_clients);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(json, "gravity_size", num_gravity);
|
||||
|
||||
cJSON *top_domains = get_top_domains(api, 1, false, true);
|
||||
if(cJSON_GetArraySize(top_domains) == 0)
|
||||
{
|
||||
JSON_ADD_NULL_TO_OBJECT(json, "top_domain");
|
||||
}
|
||||
else
|
||||
{
|
||||
cJSON *top_domain = cJSON_GetArrayItem(top_domains, 0);
|
||||
const char *domain = cJSON_GetStringValue(top_domain);
|
||||
JSON_COPY_STR_TO_OBJECT(json, "top_domain", domain);
|
||||
}
|
||||
cJSON_Delete(top_domains);
|
||||
cJSON *top_blocked = get_top_domains(api, 1, true, true);
|
||||
if(cJSON_GetArraySize(top_blocked) == 0)
|
||||
{
|
||||
JSON_ADD_NULL_TO_OBJECT(json, "top_blocked");
|
||||
}
|
||||
else
|
||||
{
|
||||
cJSON *top_block = cJSON_GetArrayItem(top_blocked, 0);
|
||||
const char *domain = cJSON_GetStringValue(top_block);
|
||||
JSON_COPY_STR_TO_OBJECT(json, "top_blocked", domain);
|
||||
}
|
||||
cJSON *top_clients = get_top_clients(api, 1, false, true, false, true);
|
||||
if(cJSON_GetArraySize(top_clients) == 0)
|
||||
{
|
||||
JSON_ADD_NULL_TO_OBJECT(json, "top_client");
|
||||
}
|
||||
else
|
||||
{
|
||||
cJSON *top_client = cJSON_GetArrayItem(top_clients, 0);
|
||||
const char *client = cJSON_GetStringValue(top_client);
|
||||
JSON_COPY_STR_TO_OBJECT(json, "top_client", client);
|
||||
}
|
||||
|
||||
// Add a null entry if the domain is hidden or there is no recent
|
||||
// blocked domain (e.g. when blocking is disabled)
|
||||
JSON_ADD_NULL_IF_NOT_EXISTS(json, "recent_blocked");
|
||||
|
||||
// Calculate percentage of blocked queries
|
||||
float percent_blocked = 0.0f;
|
||||
// Avoid 1/0 condition
|
||||
if(total > 0)
|
||||
percent_blocked = 1e2f*blocked/total;
|
||||
|
||||
// Add the blocking status
|
||||
const char *blocking = get_blocking_status_str(get_blockingstatus());
|
||||
JSON_REF_STR_IN_OBJECT(json, "blocking", blocking);
|
||||
|
||||
// Add query statistics
|
||||
cJSON *queries = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "total", total);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "blocked", blocked);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "percent_blocked", percent_blocked);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "queries", queries);
|
||||
|
||||
// Add cache statistics
|
||||
cJSON *cache = JSON_NEW_OBJECT();
|
||||
struct metrics metrics = { 0 };
|
||||
get_dnsmasq_metrics(&metrics);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(cache, "size", metrics.dns.cache.size);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(cache, "inserted", metrics.dns.cache.inserted);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(cache, "evicted", metrics.dns.cache.live_freed);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "cache", cache);
|
||||
|
||||
// info/system
|
||||
cJSON *system = JSON_NEW_OBJECT();
|
||||
get_system_obj(api, system);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "system", system);
|
||||
|
||||
// info/host
|
||||
struct utsname un = { 0 };
|
||||
uname(&un);
|
||||
JSON_COPY_STR_TO_OBJECT(json, "node_name", un.nodename);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "host_model", read_sys_property("/sys/firmware/devicetree/base/model"));
|
||||
|
||||
// Expensive calls, do only if full is requested
|
||||
if(full)
|
||||
{
|
||||
// network/gateway
|
||||
cJSON *gateway_ = JSON_NEW_OBJECT();
|
||||
get_gateway(api, gateway_, true);
|
||||
|
||||
cJSON *gateway = cJSON_GetObjectItemCaseSensitive(gateway_, "gateway");
|
||||
cJSON *interfaces = cJSON_GetObjectItemCaseSensitive(gateway_, "interfaces");
|
||||
|
||||
// Loop over gateway and find first entry with family == "inet"
|
||||
cJSON *entry = NULL;
|
||||
const char *gw_v4_name = NULL, *gw_v6_name = NULL;
|
||||
const char *gw_v4_addr = NULL, *gw_v6_addr = NULL;
|
||||
cJSON_ArrayForEach(entry, gateway)
|
||||
{
|
||||
cJSON *family = cJSON_GetObjectItemCaseSensitive(entry, "family");
|
||||
if(gw_v4_name == NULL && strcmp(cJSON_GetStringValue(family), "inet") == 0)
|
||||
{
|
||||
gw_v4_name = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(entry, "interface"));
|
||||
gw_v4_addr = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(entry, "address"));
|
||||
}
|
||||
if(gw_v6_name == NULL && strcmp(cJSON_GetStringValue(family), "inet6") == 0)
|
||||
{
|
||||
gw_v6_name = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(entry, "interface"));
|
||||
gw_v6_addr = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(entry, "address"));
|
||||
}
|
||||
|
||||
// Break if both addresses are found
|
||||
if(gw_v4_name && gw_v6_name)
|
||||
break;
|
||||
}
|
||||
|
||||
// If no IPv6 gateway is found, use the IPv4 gateway
|
||||
if(gw_v6_name == NULL)
|
||||
gw_v6_name = gw_v4_name;
|
||||
|
||||
// Iterate over all interfaces until we find the one associated
|
||||
// with the IPv4 gateway
|
||||
cJSON *iface_v4 = JSON_NEW_OBJECT();
|
||||
cJSON *iface_v6 = JSON_NEW_OBJECT();
|
||||
unsigned int v4_addrs = 0, v6_addrs = 0;
|
||||
cJSON_ArrayForEach(entry, interfaces)
|
||||
{
|
||||
if(strcmp(cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(entry, "name")), gw_v4_name) == 0)
|
||||
{
|
||||
// Add first interface address with family == inet
|
||||
cJSON *addr = NULL;
|
||||
cJSON *addrs = cJSON_GetObjectItemCaseSensitive(entry, "addresses");
|
||||
cJSON_ArrayForEach(addr, addrs)
|
||||
{
|
||||
cJSON *family = cJSON_GetObjectItemCaseSensitive(addr, "family");
|
||||
if(strcmp(cJSON_GetStringValue(family), "inet") == 0)
|
||||
{
|
||||
if(v4_addrs == 0)
|
||||
{
|
||||
cJSON *_addr = cJSON_GetObjectItemCaseSensitive(addr, "address");
|
||||
JSON_COPY_STR_TO_OBJECT(iface_v4, "addr", cJSON_GetStringValue(_addr));
|
||||
}
|
||||
v4_addrs++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add NULL if no IPv4 address is found
|
||||
if(v4_addrs == 0)
|
||||
JSON_ADD_NULL_TO_OBJECT(iface_v4, "addr");
|
||||
|
||||
// Also add IPv4 interface statistics
|
||||
cJSON *stats = cJSON_GetObjectItemCaseSensitive(entry, "stats");
|
||||
cJSON *rx_bytes = cJSON_GetObjectItemCaseSensitive(stats, "rx_bytes");
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface_v4, "rx_bytes", cJSON_Duplicate(rx_bytes, true));
|
||||
cJSON *tx_bytes = cJSON_GetObjectItemCaseSensitive(stats, "tx_bytes");
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface_v4, "tx_bytes", cJSON_Duplicate(tx_bytes, true));
|
||||
}
|
||||
if(strcmp(cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(entry, "name")), gw_v6_name) == 0)
|
||||
{
|
||||
// Add first interface address with family == inet
|
||||
cJSON *addr = NULL;
|
||||
cJSON *addrs = cJSON_GetObjectItemCaseSensitive(entry, "addresses");
|
||||
cJSON_ArrayForEach(addr, addrs)
|
||||
{
|
||||
cJSON *family = cJSON_GetObjectItemCaseSensitive(addr, "family");
|
||||
if(strcmp(cJSON_GetStringValue(family), "inet6") == 0)
|
||||
{
|
||||
if(v6_addrs == 0)
|
||||
{
|
||||
cJSON *_addr = cJSON_GetObjectItemCaseSensitive(addr, "address");
|
||||
JSON_COPY_STR_TO_OBJECT(iface_v6, "addr", cJSON_GetStringValue(_addr));
|
||||
}
|
||||
v6_addrs++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add NULL if no IPv6 address is found
|
||||
if(v6_addrs == 0)
|
||||
JSON_ADD_NULL_TO_OBJECT(iface_v6, "addr");
|
||||
}
|
||||
}
|
||||
|
||||
// Add the number of addresses found
|
||||
JSON_ADD_NUMBER_TO_OBJECT(iface_v4, "num_addrs", v4_addrs);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(iface_v6, "num_addrs", v6_addrs);
|
||||
|
||||
// Add the interfaces to the gateway object
|
||||
JSON_COPY_STR_TO_OBJECT(iface_v4, "name", gw_v4_name);
|
||||
JSON_COPY_STR_TO_OBJECT(iface_v4, "gw_addr", gw_v4_addr);
|
||||
JSON_COPY_STR_TO_OBJECT(iface_v6, "name", gw_v6_name);
|
||||
JSON_COPY_STR_TO_OBJECT(iface_v6, "gw_addr", gw_v6_addr);
|
||||
|
||||
// Create interface object
|
||||
cJSON *iface = JSON_NEW_OBJECT();
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "v4", iface_v4);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "v6", iface_v6);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "iface", iface);
|
||||
|
||||
// Free memory
|
||||
cJSON_Delete(gateway_);
|
||||
|
||||
// info/version
|
||||
cJSON *version = JSON_NEW_OBJECT();
|
||||
get_version_obj(api, version);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "version", version);
|
||||
}
|
||||
|
||||
// subset of config
|
||||
cJSON *jconfig = JSON_NEW_OBJECT();
|
||||
JSON_ADD_BOOL_TO_OBJECT(jconfig, "dhcp_active", config.dhcp.active.v.b);
|
||||
JSON_ADD_ITEM_TO_OBJECT(jconfig, "dhcp_start", addJSONConfValue(config.dhcp.start.t, &config.dhcp.start.v));
|
||||
JSON_ADD_ITEM_TO_OBJECT(jconfig, "dhcp_end", addJSONConfValue(config.dhcp.end.t, &config.dhcp.end.v));
|
||||
JSON_ADD_BOOL_TO_OBJECT(jconfig, "dhcp_ipv6", config.dhcp.ipv6.v.b);
|
||||
JSON_COPY_STR_TO_OBJECT(jconfig, "dns_domain", config.dns.domain.v.s);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(jconfig, "dns_port", config.dns.port.v.u16);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(jconfig, "dns_num_upstreams", cJSON_GetArraySize(config.dns.upstreams.v.json));
|
||||
JSON_ADD_BOOL_TO_OBJECT(jconfig, "dns_dnssec", config.dns.dnssec.v.b);
|
||||
JSON_ADD_BOOL_TO_OBJECT(jconfig, "dns_revServer_active", cJSON_GetArraySize(config.dns.revServers.v.json) > 0);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "config", jconfig);
|
||||
|
||||
// subset of info/ftl
|
||||
struct proc_mem pmem = { 0 };
|
||||
struct proc_meminfo mem = { 0 };
|
||||
parse_proc_meminfo(&mem);
|
||||
getProcessMemory(&pmem, mem.total);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(json, "%mem", pmem.VmRSS_percent);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(json, "%cpu", get_cpu_percentage());
|
||||
JSON_ADD_NUMBER_TO_OBJECT(json, "pid", getpid());
|
||||
|
||||
// info/sensors -> CPU temp sensor
|
||||
cJSON *sensors = JSON_NEW_OBJECT();
|
||||
get_sensors_obj(api, sensors, false);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "sensors", sensors);
|
||||
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
+2
-2
@@ -114,8 +114,8 @@ int api_queries_suggestions(struct ftl_conn *api)
|
||||
cJSON_Delete(blocked);
|
||||
|
||||
// Get clients, both by IP and names
|
||||
cJSON *client_ip = get_top_clients(api, count, false, true, false);
|
||||
cJSON *client_name = get_top_clients(api, count, false, true, true);
|
||||
cJSON *client_ip = get_top_clients(api, count, false, true, false, false);
|
||||
cJSON *client_name = get_top_clients(api, count, false, true, true, false);
|
||||
|
||||
// Delete duplicate entries from client_name
|
||||
cJSON_unique_array(client_name);
|
||||
|
||||
+49
-30
@@ -92,26 +92,54 @@ static int get_query_types_obj(struct ftl_conn *api, cJSON *types)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// shmem needs to be locked while calling this function
|
||||
unsigned int get_active_clients(void)
|
||||
{
|
||||
unsigned int activeclients = 0;
|
||||
for(int clientID=0; clientID < counters->clients; clientID++)
|
||||
{
|
||||
// Get client pointer
|
||||
const clientsData* client = getClient(clientID, true);
|
||||
if(client == NULL)
|
||||
continue;
|
||||
|
||||
if(client->count > 0)
|
||||
activeclients++;
|
||||
}
|
||||
|
||||
return activeclients;
|
||||
}
|
||||
|
||||
int api_stats_summary(struct ftl_conn *api)
|
||||
{
|
||||
const int blocked = get_blocked_count();
|
||||
const int forwarded = get_forwarded_count();
|
||||
const int cached = get_cached_count();
|
||||
const int total = counters->queries;
|
||||
float percent_blocked = 0.0f;
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
const int blocked = get_blocked_count();
|
||||
const int forwarded = get_forwarded_count();
|
||||
const int cached = get_cached_count();
|
||||
const int total = counters->queries;
|
||||
const int num_gravity = counters->database.gravity;
|
||||
const int num_clients = counters->clients;
|
||||
const int num_domains = counters->domains;
|
||||
|
||||
// Count clients that have been active within the most recent 24 hours
|
||||
unsigned int activeclients = get_active_clients();
|
||||
|
||||
// Unlock shared memory
|
||||
unlock_shm();
|
||||
|
||||
// Calculate percentage of blocked queries
|
||||
float percent_blocked = 0.0f;
|
||||
// Avoid 1/0 condition
|
||||
if(total > 0)
|
||||
percent_blocked = 1e2f*blocked/total;
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
cJSON *queries = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "total", total);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "blocked", blocked);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "percent_blocked", percent_blocked);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "unique_domains", counters->domains);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "unique_domains", num_domains);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "forwarded", forwarded);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(queries, "cached", cached);
|
||||
|
||||
@@ -131,28 +159,12 @@ int api_stats_summary(struct ftl_conn *api)
|
||||
JSON_ADD_NUMBER_TO_OBJECT(replies, get_query_reply_str(reply), counters->reply[reply]);
|
||||
JSON_ADD_ITEM_TO_OBJECT(queries, "replies", replies);
|
||||
|
||||
// Count clients that have been active within the most recent 24 hours
|
||||
unsigned int activeclients = 0;
|
||||
for(int clientID=0; clientID < counters->clients; clientID++)
|
||||
{
|
||||
// Get client pointer
|
||||
const clientsData* client = getClient(clientID, true);
|
||||
if(client == NULL)
|
||||
continue;
|
||||
|
||||
if(client->count > 0)
|
||||
activeclients++;
|
||||
}
|
||||
|
||||
cJSON *clients = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(clients, "active", activeclients);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(clients, "total", counters->clients);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(clients, "total", num_clients);
|
||||
|
||||
cJSON *gravity = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(gravity, "domains_being_blocked", counters->database.gravity);
|
||||
|
||||
// Unlock shared memory
|
||||
unlock_shm();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(gravity, "domains_being_blocked", num_gravity);
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "queries", queries);
|
||||
@@ -335,7 +347,7 @@ int api_stats_top_domains(struct ftl_conn *api)
|
||||
|
||||
cJSON *get_top_clients(struct ftl_conn *api, const int count,
|
||||
const bool blocked, const bool clients_only,
|
||||
const bool names_only)
|
||||
const bool names_only, const bool ip_if_no_name)
|
||||
{
|
||||
// Exit before processing any data if requested via config setting
|
||||
if(config.misc.privacylevel.v.privacy_level >= PRIVACY_HIDE_DOMAINS_CLIENTS)
|
||||
@@ -449,7 +461,14 @@ cJSON *get_top_clients(struct ftl_conn *api, const int count,
|
||||
|
||||
if(clients_only)
|
||||
{
|
||||
if(names_only)
|
||||
if(ip_if_no_name)
|
||||
{
|
||||
if(strlen(client_name) > 0)
|
||||
cJSON_AddStringToArray(jtop_clients, client_name);
|
||||
else
|
||||
cJSON_AddStringToArray(jtop_clients, client_ip);
|
||||
}
|
||||
else if(names_only)
|
||||
{
|
||||
if(strlen(client_name) > 0)
|
||||
cJSON_AddStringToArray(jtop_clients, client_name);
|
||||
@@ -516,7 +535,7 @@ int api_stats_top_clients(struct ftl_conn *api)
|
||||
get_int_var(api->request->query_string, "count", &count);
|
||||
}
|
||||
|
||||
cJSON *json = get_top_clients(api, count, blocked, false, false);
|
||||
cJSON *json = get_top_clients(api, count, blocked, false, false, false);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
|
||||
@@ -835,6 +835,22 @@ int __attribute__ ((pure)) get_blocking_mode_val(const char *blocking_mode)
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char * __attribute__ ((const)) get_blocking_status_str(const enum blocking_status blocking)
|
||||
{
|
||||
switch(blocking)
|
||||
{
|
||||
case BLOCKING_ENABLED:
|
||||
return "enabled";
|
||||
case BLOCKING_DISABLED:
|
||||
return "disabled";
|
||||
case DNS_FAILED:
|
||||
return "failure";
|
||||
case BLOCKING_UNKNOWN:
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool __attribute__ ((const)) is_blocked(const enum query_status status)
|
||||
{
|
||||
switch (status)
|
||||
|
||||
@@ -159,6 +159,7 @@ const char *get_refresh_hostnames_str(const enum refresh_hostnames refresh) __at
|
||||
int get_refresh_hostnames_val(const char *refresh_hostnames) __attribute__ ((pure));
|
||||
const char *get_blocking_mode_str(const enum blocking_mode mode) __attribute__ ((const));
|
||||
int get_blocking_mode_val(const char *blocking_mode) __attribute__ ((pure));
|
||||
const char * __attribute__ ((const)) get_blocking_status_str(const enum blocking_status blocking);
|
||||
const char *get_ptr_type_str(const enum ptr_type piholePTR) __attribute__ ((const));
|
||||
int get_ptr_type_val(const char *piholePTR) __attribute__ ((pure));
|
||||
const char *get_busy_reply_str(const enum busy_reply replyWhenBusy) __attribute__ ((const));
|
||||
|
||||
Reference in New Issue
Block a user