mirror of
https://github.com/pi-hole/FTL.git
synced 2025-12-24 13:00:25 +00:00
Move /api/ftl/gateway -> /api/network/gateway, /api/ftl/interfaces -> /api/network/interfaces, /api/ftl/network -> /api/network/devices, and /api/ftl/config -> /api/config and add documentation for /api/network/devices
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -15,8 +15,8 @@ set(sources
|
||||
dns.c
|
||||
dns.h
|
||||
ftl.c
|
||||
ftl/config.c
|
||||
ftl/network.c
|
||||
config.c
|
||||
network.c
|
||||
history.c
|
||||
list.c
|
||||
queries.c
|
||||
|
||||
@@ -35,10 +35,6 @@ static struct {
|
||||
{ "/api/ftl/logs/dns", api_ftl_logs_dns, { false, false } },
|
||||
{ "/api/ftl/sysinfo", api_ftl_sysinfo, { false, false } },
|
||||
{ "/api/ftl/dbinfo", api_ftl_dbinfo, { false, false } },
|
||||
{ "/api/ftl/config", api_ftl_config, { false, false } },
|
||||
{ "/api/ftl/gateway", api_ftl_gateway, { false, false } },
|
||||
{ "/api/ftl/interfaces", api_ftl_interfaces, { false, false } },
|
||||
{ "/api/ftl/network", api_ftl_network, { false, false } },
|
||||
{ "/api/ftl/endpoints", api_ftl_endpoints, { false, false } },
|
||||
{ "/api/history/clients", api_history_clients, { false, false } },
|
||||
{ "/api/history", api_history, { false, false } },
|
||||
@@ -63,6 +59,10 @@ static struct {
|
||||
{ "/api/version", api_version, { false, false } },
|
||||
{ "/api/auth", api_auth, { false, false } },
|
||||
{ "/api/settings/web", api_settings_web, { false, false } },
|
||||
{ "/api/config", api_config, { false, false } },
|
||||
{ "/api/network/gateway", api_network_gateway, { false, false } },
|
||||
{ "/api/network/interfaces", api_network_interfaces, { false, false } },
|
||||
{ "/api/network/devices", api_network_devices, { false, false } },
|
||||
{ "/api/docs", api_docs, { false, false } },
|
||||
};
|
||||
|
||||
@@ -130,9 +130,7 @@ static int api_ftl_endpoints(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
cJSON *endpoints = JSON_NEW_ARRAY();
|
||||
|
||||
@@ -50,12 +50,12 @@ int api_ftl_dbinfo(struct ftl_conn *api);
|
||||
int api_ftl_sysinfo(struct ftl_conn *api);
|
||||
int get_ftl_obj(struct ftl_conn *api, cJSON *ftl, const bool is_locked);
|
||||
int get_system_obj(struct ftl_conn *api, cJSON *system);
|
||||
int api_ftl_config(struct ftl_conn *api);
|
||||
int api_ftl_gateway(struct ftl_conn *api);
|
||||
int api_ftl_interfaces(struct ftl_conn *api);
|
||||
int api_ftl_network(struct ftl_conn *api);
|
||||
int api_config(struct ftl_conn *api);
|
||||
|
||||
// Network methods
|
||||
int api_network_gateway(struct ftl_conn *api);
|
||||
int api_network_interfaces(struct ftl_conn *api);
|
||||
int api_network_devices(struct ftl_conn *api);
|
||||
|
||||
// DNS methods
|
||||
int api_dns_blocking(struct ftl_conn *api);
|
||||
|
||||
@@ -37,13 +37,11 @@
|
||||
// Interate through directories
|
||||
#include <dirent.h>
|
||||
|
||||
int api_ftl_config(struct ftl_conn *api)
|
||||
int api_config(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *config_j = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(config_j, "debug",config.debug); /* TODO: Split into individual fields */
|
||||
@@ -51,9 +51,7 @@ static int set_blocking(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to access this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
if (api->payload.json == NULL) {
|
||||
return send_json_error(api, 400,
|
||||
@@ -125,9 +123,7 @@ int api_dns_cache(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to access this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
struct cache_info ci = { 0 };
|
||||
get_dnsmasq_cache_info(&ci);
|
||||
|
||||
238
src/api/docs/content/specs/config.yaml
Normal file
238
src/api/docs/content/specs/config.yaml
Normal file
@@ -0,0 +1,238 @@
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
config:
|
||||
get:
|
||||
summary: Get info about the config of your Pi-hole
|
||||
tags:
|
||||
- "FTL information"
|
||||
operationId: "get_config"
|
||||
description: |
|
||||
This API hook returns infos about the config of your Pi-hole.
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'config.yaml#/components/schemas/config'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
schemas:
|
||||
config:
|
||||
type: object
|
||||
properties:
|
||||
config:
|
||||
type: object
|
||||
properties:
|
||||
debug:
|
||||
type: integer
|
||||
example: 0
|
||||
dns:
|
||||
type: object
|
||||
properties:
|
||||
CNAMEdeepInspect:
|
||||
type: boolean
|
||||
example: true
|
||||
blockESNI:
|
||||
type: boolean
|
||||
example: true
|
||||
EDN0ECS:
|
||||
type: boolean
|
||||
example: true
|
||||
ignoreLocalhost:
|
||||
type: boolean
|
||||
example: false
|
||||
showDNSSEC:
|
||||
type: boolean
|
||||
example: true
|
||||
analyzeAAAA:
|
||||
type: boolean
|
||||
example: true
|
||||
analyzeOnlyAandAAAA:
|
||||
type: boolean
|
||||
example: false
|
||||
piholePTR:
|
||||
type: string
|
||||
example: "PI.HOLE"
|
||||
replyWhenBusy:
|
||||
type: string
|
||||
example: "ALLOW"
|
||||
blockTTL:
|
||||
type: integer
|
||||
example: 2
|
||||
blockingmode:
|
||||
type: string
|
||||
example: "NULL"
|
||||
port:
|
||||
type: integer
|
||||
example: 53
|
||||
specialDomains:
|
||||
type: object
|
||||
properties:
|
||||
mozillaCanary:
|
||||
type: boolean
|
||||
example: true
|
||||
iCloudPrivateRelay:
|
||||
type: boolean
|
||||
example: true
|
||||
reply:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: object
|
||||
properties:
|
||||
ipv4:
|
||||
type: string
|
||||
example: ""
|
||||
ipv6:
|
||||
type: string
|
||||
example: ""
|
||||
blocking:
|
||||
type: object
|
||||
properties:
|
||||
ipv4:
|
||||
type: string
|
||||
example: ""
|
||||
ipv6:
|
||||
type: string
|
||||
example: ""
|
||||
rateLimit:
|
||||
type: object
|
||||
properties:
|
||||
count:
|
||||
type: integer
|
||||
example: 1000
|
||||
interval:
|
||||
type: integer
|
||||
example: 60
|
||||
resolver:
|
||||
type: object
|
||||
properties:
|
||||
resolveIPv4:
|
||||
type: boolean
|
||||
example: true
|
||||
resolveIPv6:
|
||||
type: boolean
|
||||
example: true
|
||||
networkNames:
|
||||
type: boolean
|
||||
example: true
|
||||
refreshNames:
|
||||
type: string
|
||||
example: "IPV4_ONLY"
|
||||
database:
|
||||
type: object
|
||||
properties:
|
||||
DBimport:
|
||||
type: boolean
|
||||
example: true
|
||||
DBexport:
|
||||
type: boolean
|
||||
example: true
|
||||
maxHistory:
|
||||
type: integer
|
||||
example: 86400
|
||||
maxDBdays:
|
||||
type: integer
|
||||
example: 365
|
||||
DBinterval:
|
||||
type: integer
|
||||
example: 60
|
||||
network:
|
||||
type: object
|
||||
properties:
|
||||
parseARPcache:
|
||||
type: boolean
|
||||
example: true
|
||||
expire:
|
||||
type: integer
|
||||
example: 365
|
||||
http:
|
||||
type: object
|
||||
properties:
|
||||
localAPIauth:
|
||||
type: boolean
|
||||
example: true
|
||||
prettyJSON:
|
||||
type: boolean
|
||||
example: false
|
||||
sessionTimeout:
|
||||
type: integer
|
||||
example: 300
|
||||
domain:
|
||||
type: string
|
||||
example: "pi.hole"
|
||||
acl:
|
||||
type: string
|
||||
example: "+0.0.0.0/0"
|
||||
port:
|
||||
type: string
|
||||
example: "8080,[::]:8080"
|
||||
paths:
|
||||
type: object
|
||||
properties:
|
||||
webroot:
|
||||
type: string
|
||||
example: "/var/www/html"
|
||||
webhome:
|
||||
type: string
|
||||
example: "/admin/"
|
||||
files:
|
||||
type: object
|
||||
properties:
|
||||
log:
|
||||
type: string
|
||||
example: "/var/log/pihole/FTL.log"
|
||||
pid:
|
||||
type: string
|
||||
example: "/run/pihole-FTL.pid"
|
||||
database:
|
||||
type: string
|
||||
example: "/etc/pihole/pihole-FTL.db"
|
||||
gravity:
|
||||
type: string
|
||||
example: "/etc/pihole/gravity.db"
|
||||
macvendor:
|
||||
type: string
|
||||
example: "/etc/pihole/macvendor.db"
|
||||
setupVars:
|
||||
type: string
|
||||
example: "/etc/pihole/setupVars.conf"
|
||||
http_info:
|
||||
type: string
|
||||
example: "/var/log/pihole/HTTP_info.log"
|
||||
ph7_error:
|
||||
type: string
|
||||
example: "/var/log/pihole/PH7_error.log"
|
||||
misc:
|
||||
type: object
|
||||
properties:
|
||||
nice:
|
||||
type: integer
|
||||
example: -10
|
||||
delay_startup:
|
||||
type: integer
|
||||
example: 0
|
||||
addr2line:
|
||||
type: boolean
|
||||
example: true
|
||||
privacylevel:
|
||||
type: integer
|
||||
example: 0
|
||||
check:
|
||||
type: object
|
||||
properties:
|
||||
load:
|
||||
type: boolean
|
||||
example: true
|
||||
shmem:
|
||||
type: integer
|
||||
example: 90
|
||||
disk:
|
||||
type: integer
|
||||
example: 90
|
||||
@@ -113,69 +113,6 @@ components:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
gateway:
|
||||
get:
|
||||
summary: Get info about the gateway of your Pi-hole
|
||||
tags:
|
||||
- "FTL information"
|
||||
operationId: "get_gateway"
|
||||
description: |
|
||||
This API hook returns infos about the gateway of your Pi-hole.
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'ftl.yaml#/components/schemas/gateway'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
interfaces:
|
||||
get:
|
||||
summary: Get info about the interfaces of your Pi-hole
|
||||
tags:
|
||||
- "FTL information"
|
||||
operationId: "get_interfaces"
|
||||
description: |
|
||||
This API hook returns infos about the networking interfaces of your Pi-hole.
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'ftl.yaml#/components/schemas/interfaces'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
config:
|
||||
get:
|
||||
summary: Get info about the config of your Pi-hole
|
||||
tags:
|
||||
- "FTL information"
|
||||
operationId: "get_config"
|
||||
description: |
|
||||
This API hook returns infos about the config of your Pi-hole.
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'ftl.yaml#/components/schemas/config'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
schemas:
|
||||
client:
|
||||
remote_addr:
|
||||
@@ -482,316 +419,6 @@ components:
|
||||
items:
|
||||
type: string
|
||||
example: ["/api/dns/blocking", "/api/dns/cache", "/api/dns/port", "/api/domains", "/api/groups", "/api/lists"]
|
||||
gateway:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
description: Address of the gateway
|
||||
example: "192.168.0.1"
|
||||
interface:
|
||||
type: string
|
||||
description: Interface of your Pi-hole connected to the gateway
|
||||
example: "eth0"
|
||||
interfaces:
|
||||
type: object
|
||||
properties:
|
||||
interfaces:
|
||||
type: array
|
||||
description: Interface information
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Interface name
|
||||
carrier:
|
||||
type: boolean
|
||||
description: If the interface is connected
|
||||
speed:
|
||||
type: integer
|
||||
description: Speed of the interface in Mbit/s (-1 if not applicable)
|
||||
tx:
|
||||
type: object
|
||||
properties:
|
||||
num:
|
||||
type: number
|
||||
description: Number of transmitted data since boot
|
||||
unit:
|
||||
type: string
|
||||
description: Unit of transmitted data since boot
|
||||
rx:
|
||||
type: object
|
||||
properties:
|
||||
num:
|
||||
type: number
|
||||
description: Number of received data since boot
|
||||
unit:
|
||||
type: string
|
||||
description: Unit of received data since boot
|
||||
ipv4:
|
||||
type: array
|
||||
nullable: true
|
||||
description: Array of associated IPv4 addresses
|
||||
items:
|
||||
type: string
|
||||
ipv6:
|
||||
type: array
|
||||
nullable: true
|
||||
description: Array of associated IPv6 addresses
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
- name: "eth0"
|
||||
default: true
|
||||
carrier: true
|
||||
speed: 1000
|
||||
tx:
|
||||
num: 10.4
|
||||
unit: "MB"
|
||||
rx:
|
||||
num: 8.1
|
||||
unit: "MB"
|
||||
ipv4: ["192.168.0.123"]
|
||||
ipv6: ["fe80::1234:5678:9abc:def0", "2001:db8::1234:5678:9abc:def0"]
|
||||
- name: "wlan0"
|
||||
default: false
|
||||
carrier: false
|
||||
speed: -1
|
||||
tx:
|
||||
num: 0
|
||||
unit: "B"
|
||||
rx:
|
||||
num: 0
|
||||
unit: "B"
|
||||
ipv4: []
|
||||
ipv6: []
|
||||
- name: "wg0"
|
||||
default: false
|
||||
carrier: true
|
||||
speed: -1
|
||||
tx:
|
||||
num: 170.3
|
||||
unit: "kB"
|
||||
rx:
|
||||
num: 222.3
|
||||
unit: "kB"
|
||||
ipv4: ["10.1.0.1"]
|
||||
ipv6: ["fd00:4711::1"]
|
||||
config:
|
||||
type: object
|
||||
properties:
|
||||
config:
|
||||
type: object
|
||||
properties:
|
||||
debug:
|
||||
type: integer
|
||||
example: 0
|
||||
dns:
|
||||
type: object
|
||||
properties:
|
||||
CNAMEdeepInspect:
|
||||
type: boolean
|
||||
example: true
|
||||
blockESNI:
|
||||
type: boolean
|
||||
example: true
|
||||
EDN0ECS:
|
||||
type: boolean
|
||||
example: true
|
||||
ignoreLocalhost:
|
||||
type: boolean
|
||||
example: false
|
||||
showDNSSEC:
|
||||
type: boolean
|
||||
example: true
|
||||
analyzeAAAA:
|
||||
type: boolean
|
||||
example: true
|
||||
analyzeOnlyAandAAAA:
|
||||
type: boolean
|
||||
example: false
|
||||
piholePTR:
|
||||
type: string
|
||||
example: "PI.HOLE"
|
||||
replyWhenBusy:
|
||||
type: string
|
||||
example: "ALLOW"
|
||||
blockTTL:
|
||||
type: integer
|
||||
example: 2
|
||||
blockingmode:
|
||||
type: string
|
||||
example: "NULL"
|
||||
port:
|
||||
type: integer
|
||||
example: 53
|
||||
specialDomains:
|
||||
type: object
|
||||
properties:
|
||||
mozillaCanary:
|
||||
type: boolean
|
||||
example: true
|
||||
iCloudPrivateRelay:
|
||||
type: boolean
|
||||
example: true
|
||||
reply:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: object
|
||||
properties:
|
||||
ipv4:
|
||||
type: string
|
||||
example: ""
|
||||
ipv6:
|
||||
type: string
|
||||
example: ""
|
||||
blocking:
|
||||
type: object
|
||||
properties:
|
||||
ipv4:
|
||||
type: string
|
||||
example: ""
|
||||
ipv6:
|
||||
type: string
|
||||
example: ""
|
||||
rateLimit:
|
||||
type: object
|
||||
properties:
|
||||
count:
|
||||
type: integer
|
||||
example: 1000
|
||||
interval:
|
||||
type: integer
|
||||
example: 60
|
||||
resolver:
|
||||
type: object
|
||||
properties:
|
||||
resolveIPv4:
|
||||
type: boolean
|
||||
example: true
|
||||
resolveIPv6:
|
||||
type: boolean
|
||||
example: true
|
||||
networkNames:
|
||||
type: boolean
|
||||
example: true
|
||||
refreshNames:
|
||||
type: string
|
||||
example: "IPV4_ONLY"
|
||||
database:
|
||||
type: object
|
||||
properties:
|
||||
DBimport:
|
||||
type: boolean
|
||||
example: true
|
||||
DBexport:
|
||||
type: boolean
|
||||
example: true
|
||||
maxHistory:
|
||||
type: integer
|
||||
example: 86400
|
||||
maxDBdays:
|
||||
type: integer
|
||||
example: 365
|
||||
DBinterval:
|
||||
type: integer
|
||||
example: 60
|
||||
network:
|
||||
type: object
|
||||
properties:
|
||||
parseARPcache:
|
||||
type: boolean
|
||||
example: true
|
||||
expire:
|
||||
type: integer
|
||||
example: 365
|
||||
http:
|
||||
type: object
|
||||
properties:
|
||||
localAPIauth:
|
||||
type: boolean
|
||||
example: true
|
||||
prettyJSON:
|
||||
type: boolean
|
||||
example: false
|
||||
sessionTimeout:
|
||||
type: integer
|
||||
example: 300
|
||||
domain:
|
||||
type: string
|
||||
example: "pi.hole"
|
||||
acl:
|
||||
type: string
|
||||
example: "+0.0.0.0/0"
|
||||
port:
|
||||
type: string
|
||||
example: "8080,[::]:8080"
|
||||
paths:
|
||||
type: object
|
||||
properties:
|
||||
webroot:
|
||||
type: string
|
||||
example: "/var/www/html"
|
||||
webhome:
|
||||
type: string
|
||||
example: "/admin/"
|
||||
files:
|
||||
type: object
|
||||
properties:
|
||||
log:
|
||||
type: string
|
||||
example: "/var/log/pihole/FTL.log"
|
||||
pid:
|
||||
type: string
|
||||
example: "/run/pihole-FTL.pid"
|
||||
database:
|
||||
type: string
|
||||
example: "/etc/pihole/pihole-FTL.db"
|
||||
gravity:
|
||||
type: string
|
||||
example: "/etc/pihole/gravity.db"
|
||||
macvendor:
|
||||
type: string
|
||||
example: "/etc/pihole/macvendor.db"
|
||||
setupVars:
|
||||
type: string
|
||||
example: "/etc/pihole/setupVars.conf"
|
||||
http_info:
|
||||
type: string
|
||||
example: "/var/log/pihole/HTTP_info.log"
|
||||
ph7_error:
|
||||
type: string
|
||||
example: "/var/log/pihole/PH7_error.log"
|
||||
misc:
|
||||
type: object
|
||||
properties:
|
||||
nice:
|
||||
type: integer
|
||||
example: -10
|
||||
delay_startup:
|
||||
type: integer
|
||||
example: 0
|
||||
addr2line:
|
||||
type: boolean
|
||||
example: true
|
||||
privacylevel:
|
||||
type: integer
|
||||
example: 0
|
||||
check:
|
||||
type: object
|
||||
properties:
|
||||
load:
|
||||
type: boolean
|
||||
example: true
|
||||
shmem:
|
||||
type: integer
|
||||
example: 90
|
||||
disk:
|
||||
type: integer
|
||||
example: 90
|
||||
|
||||
parameters:
|
||||
logs:
|
||||
|
||||
@@ -15,7 +15,6 @@ info:
|
||||
Most (but not all) endpoints require authentication.
|
||||
API endpoints requiring authentication will fail with code `401 Unauthorized` when used outside a valid session.
|
||||
servers:
|
||||
- url: http://pi.hole:8080/api
|
||||
- url: 'http://{url}:{port}/{path}'
|
||||
variables:
|
||||
url:
|
||||
@@ -45,6 +44,8 @@ tags:
|
||||
description: Methods used to manage lists on your Pi-hole
|
||||
- name: "FTL information"
|
||||
description: Methods used to gather advanced data from your Pi-hole
|
||||
- name: "Network information"
|
||||
description: Methods used to gather advanced information about your network
|
||||
|
||||
paths:
|
||||
/auth:
|
||||
@@ -110,14 +111,17 @@ paths:
|
||||
/ftl/endpoints:
|
||||
$ref: 'ftl.yaml#/components/paths/endpoints'
|
||||
|
||||
/ftl/gateway:
|
||||
$ref: 'ftl.yaml#/components/paths/gateway'
|
||||
/config:
|
||||
$ref: 'config.yaml#/components/paths/config'
|
||||
|
||||
/ftl/interfaces:
|
||||
$ref: 'ftl.yaml#/components/paths/interfaces'
|
||||
/network/devices:
|
||||
$ref: 'network.yaml#/components/paths/devices'
|
||||
|
||||
/ftl/config:
|
||||
$ref: 'ftl.yaml#/components/paths/config'
|
||||
/network/gateway:
|
||||
$ref: 'network.yaml#/components/paths/gateway'
|
||||
|
||||
/network/interfaces:
|
||||
$ref: 'network.yaml#/components/paths/interfaces'
|
||||
|
||||
/version:
|
||||
$ref: 'version.yaml#/components/paths/version'
|
||||
|
||||
244
src/api/docs/content/specs/network.yaml
Normal file
244
src/api/docs/content/specs/network.yaml
Normal file
@@ -0,0 +1,244 @@
|
||||
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
gateway:
|
||||
get:
|
||||
summary: Get info about the gateway of your Pi-hole
|
||||
tags:
|
||||
- "Network information"
|
||||
operationId: "get_gateway"
|
||||
description: |
|
||||
This API hook returns infos about the gateway of your Pi-hole.
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'network.yaml#/components/schemas/gateway'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
interfaces:
|
||||
get:
|
||||
summary: Get info about the interfaces of your Pi-hole
|
||||
tags:
|
||||
- "Network information"
|
||||
operationId: "get_interfaces"
|
||||
description: |
|
||||
This API hook returns infos about the networking interfaces of your Pi-hole.
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'network.yaml#/components/schemas/interfaces'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
devices:
|
||||
get:
|
||||
summary: Get info about the devices in your local network as seen by your Pi-hole
|
||||
tags:
|
||||
- "Network information"
|
||||
operationId: "get_network"
|
||||
description: |
|
||||
This API hook returns infos about the devices in your local network as seen by your Pi-hole. By default, this number of shown devices is limited to 10. Devices are ordered by when your Pi-hole has received the last query from this device (most recent first)
|
||||
parameters:
|
||||
- $ref: 'network.yaml#/components/parameters/devices/max_devices'
|
||||
- $ref: 'network.yaml#/components/parameters/devices/max_addresses'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'network.yaml#/components/schemas/devices'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'common.yaml#/components/errors/unauthorized'
|
||||
schemas:
|
||||
gateway:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
description: Address of the gateway
|
||||
example: "192.168.0.1"
|
||||
interface:
|
||||
type: string
|
||||
description: Interface of your Pi-hole connected to the gateway
|
||||
example: "eth0"
|
||||
interfaces:
|
||||
type: object
|
||||
properties:
|
||||
interfaces:
|
||||
type: array
|
||||
description: Interface information
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Interface name
|
||||
carrier:
|
||||
type: boolean
|
||||
description: If the interface is connected
|
||||
speed:
|
||||
type: integer
|
||||
description: Speed of the interface in Mbit/s (-1 if not applicable)
|
||||
tx:
|
||||
type: object
|
||||
properties:
|
||||
num:
|
||||
type: number
|
||||
description: Number of transmitted data since boot
|
||||
unit:
|
||||
type: string
|
||||
description: Unit of transmitted data since boot
|
||||
rx:
|
||||
type: object
|
||||
properties:
|
||||
num:
|
||||
type: number
|
||||
description: Number of received data since boot
|
||||
unit:
|
||||
type: string
|
||||
description: Unit of received data since boot
|
||||
ipv4:
|
||||
type: array
|
||||
nullable: true
|
||||
description: Array of associated IPv4 addresses
|
||||
items:
|
||||
type: string
|
||||
ipv6:
|
||||
type: array
|
||||
nullable: true
|
||||
description: Array of associated IPv6 addresses
|
||||
items:
|
||||
type: string
|
||||
example:
|
||||
- name: "eth0"
|
||||
default: true
|
||||
carrier: true
|
||||
speed: 1000
|
||||
tx:
|
||||
num: 10.4
|
||||
unit: "MB"
|
||||
rx:
|
||||
num: 8.1
|
||||
unit: "MB"
|
||||
ipv4: ["192.168.0.123"]
|
||||
ipv6: ["fe80::1234:5678:9abc:def0", "2001:db8::1234:5678:9abc:def0"]
|
||||
- name: "wlan0"
|
||||
default: false
|
||||
carrier: false
|
||||
speed: -1
|
||||
tx:
|
||||
num: 0
|
||||
unit: "B"
|
||||
rx:
|
||||
num: 0
|
||||
unit: "B"
|
||||
ipv4: []
|
||||
ipv6: []
|
||||
- name: "wg0"
|
||||
default: false
|
||||
carrier: true
|
||||
speed: -1
|
||||
tx:
|
||||
num: 170.3
|
||||
unit: "kB"
|
||||
rx:
|
||||
num: 222.3
|
||||
unit: "kB"
|
||||
ipv4: ["10.1.0.1"]
|
||||
ipv6: ["fd00:4711::1"]
|
||||
devices:
|
||||
type: object
|
||||
properties:
|
||||
devices:
|
||||
type: array
|
||||
description: Array of devices
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
description: Device network table ID
|
||||
example: 1
|
||||
hwaddr:
|
||||
type: string
|
||||
description: MAC address of this device
|
||||
example: 00:11:22:33:44:55
|
||||
interface:
|
||||
type: string
|
||||
description: Interface this device is connected to
|
||||
example: enp2s0
|
||||
firstSeen:
|
||||
type: interger
|
||||
description: Unix timestamp when this device was first seen by your Pi-hole
|
||||
example: 1664623620
|
||||
lastQuery:
|
||||
type: interger
|
||||
description: Unix timestamp when your Pi-hole received the last query from this device
|
||||
example: 1664688620
|
||||
numQueries:
|
||||
type: integer
|
||||
description: Total number of queries your Pi-hole has received from this device
|
||||
example: 585462
|
||||
macVendor:
|
||||
type: string
|
||||
description: Vendor name associated with the device's MAC address
|
||||
example: "Digital Data Communications Asia Co.,Ltd"
|
||||
ips:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
ip:
|
||||
type: string
|
||||
description: Associated IP address (can be IPv4 or IPv6)
|
||||
example: "192.168.1.51"
|
||||
name:
|
||||
type: string
|
||||
description: Associated hostname (can be null)
|
||||
example: ubuntu-server
|
||||
lastSeen:
|
||||
description: Unix timestamp when your Pi-hole has seen this address the last time
|
||||
example: 1664688620
|
||||
nameUpdated:
|
||||
description: Unix timestamp when device updated its hostname the last time
|
||||
example: 1664688620
|
||||
|
||||
|
||||
parameters:
|
||||
devices:
|
||||
max_devices:
|
||||
in: query
|
||||
description: (Optional) Maximum number of devices to show
|
||||
name: max_devices
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
example: 10
|
||||
max_addresses:
|
||||
in: query
|
||||
description: (Optional) Maximum number of addresses to show per device
|
||||
name: max_addresses
|
||||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
example: 3
|
||||
309
src/api/ftl.c
309
src/api/ftl.c
@@ -32,10 +32,6 @@
|
||||
#include "../config/config.h"
|
||||
// struct clientsData
|
||||
#include "../datastructure.h"
|
||||
// Routing information and flags
|
||||
#include <net/route.h>
|
||||
// Interate through directories
|
||||
#include <dirent.h>
|
||||
|
||||
int api_ftl_client(struct ftl_conn *api)
|
||||
{
|
||||
@@ -70,9 +66,7 @@ int api_ftl_logs_dns(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
unsigned int start = 0u;
|
||||
if(api->request->query_string != NULL)
|
||||
@@ -134,9 +128,7 @@ int api_ftl_dbinfo(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
|
||||
@@ -417,9 +409,7 @@ int get_ftl_obj(struct ftl_conn *api, cJSON *ftl, const bool is_locked)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *database = JSON_NEW_OBJECT();
|
||||
|
||||
@@ -475,9 +465,7 @@ int api_ftl_sysinfo(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
|
||||
@@ -498,300 +486,3 @@ int api_ftl_sysinfo(struct ftl_conn *api)
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "ftl", ftl);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
static bool getDefaultInterface(char iface[IF_NAMESIZE], in_addr_t *gw)
|
||||
{
|
||||
// Get IPv4 default route gateway and associated interface
|
||||
long dest_r = 0, gw_r = 0;
|
||||
int flags = 0, metric = 0, minmetric = __INT_MAX__;
|
||||
char iface_r[IF_NAMESIZE] = { 0 };
|
||||
char buf[1024] = { 0 };
|
||||
|
||||
FILE *file;
|
||||
if((file = fopen("/proc/net/route", "r")))
|
||||
{
|
||||
// Parse /proc/net/route - the kernel's IPv4 routing table
|
||||
while(fgets(buf, sizeof(buf), file))
|
||||
{
|
||||
if(sscanf(buf, "%s %lx %lx %x %*i %*i %i", iface_r, &dest_r, &gw_r, &flags, &metric) != 5)
|
||||
continue;
|
||||
|
||||
// Only anaylze routes which are UP and whose
|
||||
// destinations are a gateway
|
||||
if(!(flags & RTF_UP) || !(flags & RTF_GATEWAY))
|
||||
continue;
|
||||
|
||||
// Only analyze "catch all" routes (destination 0.0.0.0)
|
||||
if(dest_r != 0)
|
||||
continue;
|
||||
|
||||
// Store default gateway, overwrite if we find a route with
|
||||
// a lower metric
|
||||
if(metric < minmetric)
|
||||
{
|
||||
minmetric = metric;
|
||||
*gw = gw_r;
|
||||
strcpy(iface, iface_r);
|
||||
|
||||
log_debug(DEBUG_API, "Reading interfaces: flags: %i, addr: %s, iface: %s, metric: %i, minmetric: %i",
|
||||
flags, inet_ntoa(*(struct in_addr *) gw), iface, metric, minmetric);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read /proc/net/route: %s", strerror(errno));
|
||||
|
||||
// Return success based on having found the default gateway's address
|
||||
return gw != 0;
|
||||
}
|
||||
|
||||
int api_ftl_gateway(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
in_addr_t gw = 0;
|
||||
char iface[IF_NAMESIZE] = { 0 };
|
||||
|
||||
// Get default interface
|
||||
getDefaultInterface(iface, &gw);
|
||||
|
||||
// Generate JSON response
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
const char *gwaddr = inet_ntoa(*(struct in_addr *) &gw);
|
||||
JSON_COPY_STR_TO_OBJECT(json, "address", gwaddr);
|
||||
JSON_REF_STR_IN_OBJECT(json, "interface", iface);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_ftl_interfaces(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
|
||||
// Get interface with default route
|
||||
in_addr_t gw = 0;
|
||||
char default_iface[IF_NAMESIZE] = { 0 };
|
||||
getDefaultInterface(default_iface, &gw);
|
||||
|
||||
// Enumerate and list interfaces
|
||||
// Loop over interfaces and extract information
|
||||
DIR *dfd;
|
||||
FILE *f;
|
||||
struct dirent *dp;
|
||||
size_t tx_sum = 0, rx_sum = 0;
|
||||
char fname[64 + IF_NAMESIZE] = { 0 };
|
||||
char readbuffer[1024] = { 0 };
|
||||
|
||||
// Open /sys/class/net directory
|
||||
if ((dfd = opendir("/sys/class/net")) == NULL)
|
||||
{
|
||||
log_err("API: Cannot access /sys/class/net");
|
||||
return 500;
|
||||
}
|
||||
|
||||
// Get IP addresses of all interfaces on this machine
|
||||
struct ifaddrs *ifap = NULL;
|
||||
if(getifaddrs(&ifap) == -1)
|
||||
log_err("API: Cannot get interface addresses: %s", strerror(errno));
|
||||
|
||||
cJSON *interfaces = JSON_NEW_ARRAY();
|
||||
// Walk /sys/class/net directory
|
||||
while ((dp = readdir(dfd)) != NULL)
|
||||
{
|
||||
// Skip "." and ".."
|
||||
if(!dp->d_name || strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
// Create new interface record
|
||||
cJSON *iface = JSON_NEW_OBJECT();
|
||||
|
||||
// Extract interface name
|
||||
const char *iface_name = dp->d_name;
|
||||
JSON_COPY_STR_TO_OBJECT(iface, "name", iface_name);
|
||||
|
||||
// Is this the default interface?
|
||||
const bool is_default_iface = strcmp(iface_name, default_iface) == 0;
|
||||
JSON_ADD_BOOL_TO_OBJECT(iface, "default", is_default_iface);
|
||||
|
||||
// Extract carrier status
|
||||
bool carrier = false;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/carrier", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fgets(readbuffer, sizeof(readbuffer)-1, f) != NULL)
|
||||
carrier = readbuffer[0] == '1';
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
JSON_ADD_BOOL_TO_OBJECT(iface, "carrier", carrier);
|
||||
|
||||
// Extract link speed (may not be possible, e.g., for WiFi devices with dynamic link speeds)
|
||||
int speed = -1;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/speed", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fscanf(f, "%i", &(speed)) != 1)
|
||||
speed = -1;
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
JSON_ADD_NUMBER_TO_OBJECT(iface, "speed", speed);
|
||||
|
||||
// Get total transmitted bytes
|
||||
ssize_t tx_bytes = -1;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/statistics/tx_bytes", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fscanf(f, "%zi", &(tx_bytes)) != 1)
|
||||
tx_bytes = -1;
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
|
||||
// Format transmitted bytes
|
||||
double tx = 0.0;
|
||||
char tx_unit[3] = { 0 };
|
||||
format_memory_size(tx_unit, tx_bytes, &tx);
|
||||
if(tx_unit[0] != '\0')
|
||||
tx_unit[1] = 'B';
|
||||
|
||||
// Add transmitted bytes to interface record
|
||||
cJSON *tx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(tx_json, "num", tx);
|
||||
JSON_COPY_STR_TO_OBJECT(tx_json, "unit", tx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "tx", tx_json);
|
||||
|
||||
// Get total received bytes
|
||||
ssize_t rx_bytes = -1;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/statistics/rx_bytes", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fscanf(f, "%zi", &(rx_bytes)) != 1)
|
||||
rx_bytes = -1;
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
|
||||
// Format received bytes
|
||||
double rx = 0.0;
|
||||
char rx_unit[3] = { 0 };
|
||||
format_memory_size(rx_unit, rx_bytes, &rx);
|
||||
if(rx_unit[0] != '\0')
|
||||
rx_unit[1] = 'B';
|
||||
|
||||
// Add received bytes to JSON object
|
||||
cJSON *rx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(rx_json, "num", rx);
|
||||
JSON_COPY_STR_TO_OBJECT(rx_json, "unit", rx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "rx", rx_json);
|
||||
|
||||
// Get IP address(es) of this interface
|
||||
if(ifap)
|
||||
{
|
||||
// Walk through linked list of interface addresses
|
||||
cJSON *ipv4 = JSON_NEW_ARRAY();
|
||||
cJSON *ipv6 = JSON_NEW_ARRAY();
|
||||
for(struct ifaddrs *ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
|
||||
{
|
||||
// Skip interfaces without an address and those
|
||||
// not matching the current interface
|
||||
if(ifa->ifa_addr == NULL || strcmp(ifa->ifa_name, iface_name) != 0)
|
||||
continue;
|
||||
|
||||
// If we reach this point, we found the correct interface
|
||||
const sa_family_t family = ifa->ifa_addr->sa_family;
|
||||
char host[NI_MAXHOST] = { 0 };
|
||||
if(family == AF_INET || family == AF_INET6)
|
||||
{
|
||||
// Get IP address
|
||||
const int s = getnameinfo(ifa->ifa_addr,
|
||||
(family == AF_INET) ?
|
||||
sizeof(struct sockaddr_in) :
|
||||
sizeof(struct sockaddr_in6),
|
||||
host, NI_MAXHOST,
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
if (s != 0)
|
||||
{
|
||||
log_warn("API: getnameinfo() failed: %s\n", gai_strerror(s));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(family == AF_INET)
|
||||
{
|
||||
JSON_COPY_STR_TO_ARRAY(ipv4, host);
|
||||
}
|
||||
else if(family == AF_INET6)
|
||||
{
|
||||
JSON_COPY_STR_TO_ARRAY(ipv6, host);
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "ipv4", ipv4);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "ipv6", ipv6);
|
||||
}
|
||||
|
||||
// Sum up transmitted and received bytes
|
||||
tx_sum += tx_bytes;
|
||||
rx_sum += rx_bytes;
|
||||
|
||||
// Add interface to array
|
||||
JSON_ADD_ITEM_TO_ARRAY(interfaces, iface);
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
|
||||
cJSON *sum = JSON_NEW_OBJECT();
|
||||
JSON_COPY_STR_TO_OBJECT(sum, "name", "sum");
|
||||
JSON_ADD_BOOL_TO_OBJECT(sum, "carrier", true);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(sum, "speed", 0);
|
||||
|
||||
// Format transmitted bytes
|
||||
double tx = 0.0;
|
||||
char tx_unit[3] = { 0 };
|
||||
format_memory_size(tx_unit, tx_sum, &tx);
|
||||
if(tx_unit[0] != '\0')
|
||||
tx_unit[1] = 'B';
|
||||
|
||||
// Add transmitted bytes to interface record
|
||||
cJSON *tx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(tx_json, "num", tx);
|
||||
JSON_COPY_STR_TO_OBJECT(tx_json, "unit", tx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "tx", tx_json);
|
||||
|
||||
// Format received bytes
|
||||
double rx = 0.0;
|
||||
char rx_unit[3] = { 0 };
|
||||
format_memory_size(rx_unit, rx_sum, &rx);
|
||||
if(rx_unit[0] != '\0')
|
||||
rx_unit[1] = 'B';
|
||||
|
||||
// Add received bytes to JSON object
|
||||
cJSON *rx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(rx_json, "num", rx);
|
||||
JSON_COPY_STR_TO_OBJECT(rx_json, "unit", rx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "rx", rx_json);
|
||||
|
||||
cJSON *ipv4 = JSON_NEW_ARRAY();
|
||||
cJSON *ipv6 = JSON_NEW_ARRAY();
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "ipv4", ipv4);
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "ipv6", ipv6);
|
||||
|
||||
// Add interface to array
|
||||
JSON_ADD_ITEM_TO_ARRAY(interfaces, sum);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "interfaces", interfaces);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/* 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/network
|
||||
*
|
||||
* 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/api.h"
|
||||
// networkrecord
|
||||
#include "database/network-table.h"
|
||||
// dbopen()
|
||||
#include "database/common.h"
|
||||
|
||||
int api_ftl_network(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Open pihole-FTL.db database file
|
||||
sqlite3_stmt *device_stmt = NULL, *ip_stmt = NULL;
|
||||
sqlite3 *db = dbopen(false);
|
||||
if(db == NULL)
|
||||
{
|
||||
log_warn("Failed to open database in networkTable_readDevices()");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *sql_msg = NULL;
|
||||
if(!networkTable_readDevices(db, &device_stmt, &sql_msg))
|
||||
{
|
||||
// Add SQL message (may be NULL = not available)
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table",
|
||||
sql_msg);
|
||||
}
|
||||
|
||||
// Read record for a single device
|
||||
cJSON *json = JSON_NEW_ARRAY();
|
||||
network_record network;
|
||||
while(networkTable_readDevicesGetRecord(device_stmt, &network, &sql_msg))
|
||||
{
|
||||
cJSON *item = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "id", network.id);
|
||||
JSON_COPY_STR_TO_OBJECT(item, "hwaddr", network.hwaddr);
|
||||
JSON_COPY_STR_TO_OBJECT(item, "interface", network.iface);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "firstSeen", network.firstSeen);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "lastQuery", network.lastQuery);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "numQueries", network.numQueries);
|
||||
JSON_COPY_STR_TO_OBJECT(item, "macVendor", network.macVendor);
|
||||
|
||||
// Build array of all IP addresses known associated to this client
|
||||
cJSON *ips = JSON_NEW_ARRAY();
|
||||
if(networkTable_readIPs(db, &ip_stmt, network.id, &sql_msg))
|
||||
{
|
||||
// Walk known IP addresses + names
|
||||
network_addresses_record network_address;
|
||||
while(networkTable_readIPsGetRecord(ip_stmt, &network_address, &sql_msg))
|
||||
{
|
||||
cJSON *ip = JSON_NEW_OBJECT();
|
||||
JSON_COPY_STR_TO_OBJECT(ip, "ip", network_address.ip);
|
||||
JSON_COPY_STR_TO_OBJECT(ip, "name", network_address.name);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(ip, "lastSeen", network_address.lastSeen);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(ip, "nameUpdated", network_address.nameUpdated);
|
||||
JSON_ADD_ITEM_TO_ARRAY(ips, ip);
|
||||
}
|
||||
|
||||
// Possible error handling
|
||||
if(sql_msg != NULL)
|
||||
{
|
||||
cJSON_Delete(ips);
|
||||
cJSON_Delete(json);
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table (getting IP records)",
|
||||
sql_msg);
|
||||
}
|
||||
|
||||
// Finalize sub-query
|
||||
networkTable_readIPsFinalize(ip_stmt);
|
||||
}
|
||||
|
||||
// Add array of IP addresses to device
|
||||
JSON_ADD_ITEM_TO_OBJECT(item, "ips", ips);
|
||||
|
||||
// Add device to array of all devices
|
||||
JSON_ADD_ITEM_TO_ARRAY(json, item);
|
||||
}
|
||||
|
||||
if(sql_msg != NULL)
|
||||
{
|
||||
cJSON_Delete(json);
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table (step)",
|
||||
sql_msg);
|
||||
}
|
||||
|
||||
// Finalize query
|
||||
networkTable_readDevicesFinalize(device_stmt);
|
||||
|
||||
dbclose(&db);
|
||||
|
||||
// Return data to user
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
@@ -88,9 +88,7 @@ int api_history_clients(struct ftl_conn *api)
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Find minimum ID to send
|
||||
for(int slot = 0; slot < OVERTIME_SLOTS; slot++)
|
||||
|
||||
@@ -353,9 +353,7 @@ int api_list(struct ftl_conn *api)
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
char payload[MAX_PAYLOAD_BYTES] = { 0 };
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
enum gravity_list_type listtype;
|
||||
bool can_modify = false;
|
||||
|
||||
426
src/api/network.c
Normal file
426
src/api/network.c
Normal file
@@ -0,0 +1,426 @@
|
||||
/* 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/network
|
||||
*
|
||||
* 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/api.h"
|
||||
// Routing information and flags
|
||||
#include <net/route.h>
|
||||
// Interate through directories
|
||||
#include <dirent.h>
|
||||
// networkrecord
|
||||
#include "database/network-table.h"
|
||||
// dbopen()
|
||||
#include "database/common.h"
|
||||
|
||||
static bool getDefaultInterface(char iface[IF_NAMESIZE], in_addr_t *gw)
|
||||
{
|
||||
// Get IPv4 default route gateway and associated interface
|
||||
long dest_r = 0, gw_r = 0;
|
||||
int flags = 0, metric = 0, minmetric = __INT_MAX__;
|
||||
char iface_r[IF_NAMESIZE] = { 0 };
|
||||
char buf[1024] = { 0 };
|
||||
|
||||
FILE *file;
|
||||
if((file = fopen("/proc/net/route", "r")))
|
||||
{
|
||||
// Parse /proc/net/route - the kernel's IPv4 routing table
|
||||
while(fgets(buf, sizeof(buf), file))
|
||||
{
|
||||
if(sscanf(buf, "%s %lx %lx %x %*i %*i %i", iface_r, &dest_r, &gw_r, &flags, &metric) != 5)
|
||||
continue;
|
||||
|
||||
// Only anaylze routes which are UP and whose
|
||||
// destinations are a gateway
|
||||
if(!(flags & RTF_UP) || !(flags & RTF_GATEWAY))
|
||||
continue;
|
||||
|
||||
// Only analyze "catch all" routes (destination 0.0.0.0)
|
||||
if(dest_r != 0)
|
||||
continue;
|
||||
|
||||
// Store default gateway, overwrite if we find a route with
|
||||
// a lower metric
|
||||
if(metric < minmetric)
|
||||
{
|
||||
minmetric = metric;
|
||||
*gw = gw_r;
|
||||
strcpy(iface, iface_r);
|
||||
|
||||
log_debug(DEBUG_API, "Reading interfaces: flags: %i, addr: %s, iface: %s, metric: %i, minmetric: %i",
|
||||
flags, inet_ntoa(*(struct in_addr *) gw), iface, metric, minmetric);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read /proc/net/route: %s", strerror(errno));
|
||||
|
||||
// Return success based on having found the default gateway's address
|
||||
return gw != 0;
|
||||
}
|
||||
|
||||
int api_network_gateway(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
return send_json_unauthorized(api);
|
||||
|
||||
in_addr_t gw = 0;
|
||||
char iface[IF_NAMESIZE] = { 0 };
|
||||
|
||||
// Get default interface
|
||||
getDefaultInterface(iface, &gw);
|
||||
|
||||
// Generate JSON response
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
const char *gwaddr = inet_ntoa(*(struct in_addr *) &gw);
|
||||
JSON_COPY_STR_TO_OBJECT(json, "address", gwaddr);
|
||||
JSON_REF_STR_IN_OBJECT(json, "interface", iface);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_network_interfaces(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
return send_json_unauthorized(api);
|
||||
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
|
||||
// Get interface with default route
|
||||
in_addr_t gw = 0;
|
||||
char default_iface[IF_NAMESIZE] = { 0 };
|
||||
getDefaultInterface(default_iface, &gw);
|
||||
|
||||
// Enumerate and list interfaces
|
||||
// Loop over interfaces and extract information
|
||||
DIR *dfd;
|
||||
FILE *f;
|
||||
struct dirent *dp;
|
||||
size_t tx_sum = 0, rx_sum = 0;
|
||||
char fname[64 + IF_NAMESIZE] = { 0 };
|
||||
char readbuffer[1024] = { 0 };
|
||||
|
||||
// Open /sys/class/net directory
|
||||
if ((dfd = opendir("/sys/class/net")) == NULL)
|
||||
{
|
||||
log_err("API: Cannot access /sys/class/net");
|
||||
return 500;
|
||||
}
|
||||
|
||||
// Get IP addresses of all interfaces on this machine
|
||||
struct ifaddrs *ifap = NULL;
|
||||
if(getifaddrs(&ifap) == -1)
|
||||
log_err("API: Cannot get interface addresses: %s", strerror(errno));
|
||||
|
||||
cJSON *interfaces = JSON_NEW_ARRAY();
|
||||
// Walk /sys/class/net directory
|
||||
while ((dp = readdir(dfd)) != NULL)
|
||||
{
|
||||
// Skip "." and ".."
|
||||
if(!dp->d_name || strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
// Create new interface record
|
||||
cJSON *iface = JSON_NEW_OBJECT();
|
||||
|
||||
// Extract interface name
|
||||
const char *iface_name = dp->d_name;
|
||||
JSON_COPY_STR_TO_OBJECT(iface, "name", iface_name);
|
||||
|
||||
// Is this the default interface?
|
||||
const bool is_default_iface = strcmp(iface_name, default_iface) == 0;
|
||||
JSON_ADD_BOOL_TO_OBJECT(iface, "default", is_default_iface);
|
||||
|
||||
// Extract carrier status
|
||||
bool carrier = false;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/carrier", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fgets(readbuffer, sizeof(readbuffer)-1, f) != NULL)
|
||||
carrier = readbuffer[0] == '1';
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
JSON_ADD_BOOL_TO_OBJECT(iface, "carrier", carrier);
|
||||
|
||||
// Extract link speed (may not be possible, e.g., for WiFi devices with dynamic link speeds)
|
||||
int speed = -1;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/speed", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fscanf(f, "%i", &(speed)) != 1)
|
||||
speed = -1;
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
JSON_ADD_NUMBER_TO_OBJECT(iface, "speed", speed);
|
||||
|
||||
// Get total transmitted bytes
|
||||
ssize_t tx_bytes = -1;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/statistics/tx_bytes", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fscanf(f, "%zi", &(tx_bytes)) != 1)
|
||||
tx_bytes = -1;
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
|
||||
// Format transmitted bytes
|
||||
double tx = 0.0;
|
||||
char tx_unit[3] = { 0 };
|
||||
format_memory_size(tx_unit, tx_bytes, &tx);
|
||||
if(tx_unit[0] != '\0')
|
||||
tx_unit[1] = 'B';
|
||||
|
||||
// Add transmitted bytes to interface record
|
||||
cJSON *tx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(tx_json, "num", tx);
|
||||
JSON_COPY_STR_TO_OBJECT(tx_json, "unit", tx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "tx", tx_json);
|
||||
|
||||
// Get total received bytes
|
||||
ssize_t rx_bytes = -1;
|
||||
snprintf(fname, sizeof(fname)-1, "/sys/class/net/%s/statistics/rx_bytes", iface_name);
|
||||
if((f = fopen(fname, "r")) != NULL)
|
||||
{
|
||||
if(fscanf(f, "%zi", &(rx_bytes)) != 1)
|
||||
rx_bytes = -1;
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
log_err("Cannot read %s: %s", fname, strerror(errno));
|
||||
|
||||
// Format received bytes
|
||||
double rx = 0.0;
|
||||
char rx_unit[3] = { 0 };
|
||||
format_memory_size(rx_unit, rx_bytes, &rx);
|
||||
if(rx_unit[0] != '\0')
|
||||
rx_unit[1] = 'B';
|
||||
|
||||
// Add received bytes to JSON object
|
||||
cJSON *rx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(rx_json, "num", rx);
|
||||
JSON_COPY_STR_TO_OBJECT(rx_json, "unit", rx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "rx", rx_json);
|
||||
|
||||
// Get IP address(es) of this interface
|
||||
if(ifap)
|
||||
{
|
||||
// Walk through linked list of interface addresses
|
||||
cJSON *ipv4 = JSON_NEW_ARRAY();
|
||||
cJSON *ipv6 = JSON_NEW_ARRAY();
|
||||
for(struct ifaddrs *ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
|
||||
{
|
||||
// Skip interfaces without an address and those
|
||||
// not matching the current interface
|
||||
if(ifa->ifa_addr == NULL || strcmp(ifa->ifa_name, iface_name) != 0)
|
||||
continue;
|
||||
|
||||
// If we reach this point, we found the correct interface
|
||||
const sa_family_t family = ifa->ifa_addr->sa_family;
|
||||
char host[NI_MAXHOST] = { 0 };
|
||||
if(family == AF_INET || family == AF_INET6)
|
||||
{
|
||||
// Get IP address
|
||||
const int s = getnameinfo(ifa->ifa_addr,
|
||||
(family == AF_INET) ?
|
||||
sizeof(struct sockaddr_in) :
|
||||
sizeof(struct sockaddr_in6),
|
||||
host, NI_MAXHOST,
|
||||
NULL, 0, NI_NUMERICHOST);
|
||||
if (s != 0)
|
||||
{
|
||||
log_warn("API: getnameinfo() failed: %s\n", gai_strerror(s));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(family == AF_INET)
|
||||
{
|
||||
JSON_COPY_STR_TO_ARRAY(ipv4, host);
|
||||
}
|
||||
else if(family == AF_INET6)
|
||||
{
|
||||
JSON_COPY_STR_TO_ARRAY(ipv6, host);
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "ipv4", ipv4);
|
||||
JSON_ADD_ITEM_TO_OBJECT(iface, "ipv6", ipv6);
|
||||
}
|
||||
|
||||
// Sum up transmitted and received bytes
|
||||
tx_sum += tx_bytes;
|
||||
rx_sum += rx_bytes;
|
||||
|
||||
// Add interface to array
|
||||
JSON_ADD_ITEM_TO_ARRAY(interfaces, iface);
|
||||
}
|
||||
|
||||
freeifaddrs(ifap);
|
||||
|
||||
cJSON *sum = JSON_NEW_OBJECT();
|
||||
JSON_COPY_STR_TO_OBJECT(sum, "name", "sum");
|
||||
JSON_ADD_BOOL_TO_OBJECT(sum, "carrier", true);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(sum, "speed", 0);
|
||||
|
||||
// Format transmitted bytes
|
||||
double tx = 0.0;
|
||||
char tx_unit[3] = { 0 };
|
||||
format_memory_size(tx_unit, tx_sum, &tx);
|
||||
if(tx_unit[0] != '\0')
|
||||
tx_unit[1] = 'B';
|
||||
|
||||
// Add transmitted bytes to interface record
|
||||
cJSON *tx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(tx_json, "num", tx);
|
||||
JSON_COPY_STR_TO_OBJECT(tx_json, "unit", tx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "tx", tx_json);
|
||||
|
||||
// Format received bytes
|
||||
double rx = 0.0;
|
||||
char rx_unit[3] = { 0 };
|
||||
format_memory_size(rx_unit, rx_sum, &rx);
|
||||
if(rx_unit[0] != '\0')
|
||||
rx_unit[1] = 'B';
|
||||
|
||||
// Add received bytes to JSON object
|
||||
cJSON *rx_json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(rx_json, "num", rx);
|
||||
JSON_COPY_STR_TO_OBJECT(rx_json, "unit", rx_unit);
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "rx", rx_json);
|
||||
|
||||
cJSON *ipv4 = JSON_NEW_ARRAY();
|
||||
cJSON *ipv6 = JSON_NEW_ARRAY();
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "ipv4", ipv4);
|
||||
JSON_ADD_ITEM_TO_OBJECT(sum, "ipv6", ipv6);
|
||||
|
||||
// Add interface to array
|
||||
JSON_ADD_ITEM_TO_ARRAY(interfaces, sum);
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "interfaces", interfaces);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
|
||||
int api_network_devices(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
return send_json_unauthorized(api);
|
||||
|
||||
// Does the user request a custom number of devices to be included?
|
||||
unsigned int device_count = 10;
|
||||
get_uint_var(api->request->query_string, "device_count", &device_count);
|
||||
|
||||
// Does the user request a custom number of addresses per device to be included?
|
||||
unsigned int address_count = 3;
|
||||
get_uint_var(api->request->query_string, "address_count", &address_count);
|
||||
|
||||
// Open pihole-FTL.db database file
|
||||
sqlite3_stmt *device_stmt = NULL, *ip_stmt = NULL;
|
||||
sqlite3 *db = dbopen(false);
|
||||
if(db == NULL)
|
||||
{
|
||||
log_warn("Failed to open database in networkTable_readDevices()");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *sql_msg = NULL;
|
||||
if(!networkTable_readDevices(db, &device_stmt, &sql_msg))
|
||||
{
|
||||
// Add SQL message (may be NULL = not available)
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table",
|
||||
sql_msg);
|
||||
}
|
||||
|
||||
// Read record for a single device
|
||||
cJSON *devices = JSON_NEW_ARRAY();
|
||||
network_record network;
|
||||
unsigned int device_counter = 1;
|
||||
while(networkTable_readDevicesGetRecord(device_stmt, &network, &sql_msg))
|
||||
{
|
||||
cJSON *item = JSON_NEW_OBJECT();
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "id", network.id);
|
||||
JSON_COPY_STR_TO_OBJECT(item, "hwaddr", network.hwaddr);
|
||||
JSON_COPY_STR_TO_OBJECT(item, "interface", network.iface);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "firstSeen", network.firstSeen);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "lastQuery", network.lastQuery);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(item, "numQueries", network.numQueries);
|
||||
JSON_COPY_STR_TO_OBJECT(item, "macVendor", network.macVendor);
|
||||
|
||||
// Build array of all IP addresses known associated to this client
|
||||
cJSON *ips = JSON_NEW_ARRAY();
|
||||
if(networkTable_readIPs(db, &ip_stmt, network.id, &sql_msg))
|
||||
{
|
||||
// Walk known IP addresses + names
|
||||
network_addresses_record network_address;
|
||||
unsigned int address_counter = 1;
|
||||
while(networkTable_readIPsGetRecord(ip_stmt, &network_address, &sql_msg))
|
||||
{
|
||||
cJSON *ip = JSON_NEW_OBJECT();
|
||||
JSON_COPY_STR_TO_OBJECT(ip, "ip", network_address.ip);
|
||||
JSON_COPY_STR_TO_OBJECT(ip, "name", network_address.name);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(ip, "lastSeen", network_address.lastSeen);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(ip, "nameUpdated", network_address.nameUpdated);
|
||||
JSON_ADD_ITEM_TO_ARRAY(ips, ip);
|
||||
if(++address_counter > address_count)
|
||||
break;
|
||||
}
|
||||
|
||||
// Possible error handling
|
||||
if(sql_msg != NULL)
|
||||
{
|
||||
cJSON_Delete(ips);
|
||||
cJSON_Delete(devices);
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table (getting IP records)",
|
||||
sql_msg);
|
||||
}
|
||||
|
||||
// Finalize sub-query
|
||||
networkTable_readIPsFinalize(ip_stmt);
|
||||
|
||||
if(++device_counter > device_count)
|
||||
break;
|
||||
}
|
||||
|
||||
// Add array of IP addresses to device
|
||||
JSON_ADD_ITEM_TO_OBJECT(item, "ips", ips);
|
||||
|
||||
// Add device to array of all devices
|
||||
JSON_ADD_ITEM_TO_ARRAY(devices, item);
|
||||
}
|
||||
|
||||
if(sql_msg != NULL)
|
||||
{
|
||||
cJSON_Delete(devices);
|
||||
return send_json_error(api, 500,
|
||||
"database_error",
|
||||
"Could not read network details from database table (step)",
|
||||
sql_msg);
|
||||
}
|
||||
|
||||
// Finalize query
|
||||
networkTable_readDevicesFinalize(device_stmt);
|
||||
dbclose(&db);
|
||||
|
||||
// Return data to user
|
||||
cJSON *json = JSON_NEW_OBJECT();
|
||||
JSON_ADD_ITEM_TO_OBJECT(json, "devices", devices);
|
||||
JSON_SEND_OBJECT(json);
|
||||
}
|
||||
@@ -71,9 +71,7 @@ int api_queries_suggestions(struct ftl_conn *api)
|
||||
int rc;
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
@@ -206,9 +204,7 @@ int api_queries(struct ftl_conn *api)
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
@@ -142,9 +142,7 @@ int api_stats_top_domains(struct ftl_conn *api)
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Exit before processing any data if requested via config setting
|
||||
if(config.misc.privacylevel >= PRIVACY_HIDE_DOMAINS)
|
||||
@@ -300,9 +298,7 @@ int api_stats_top_clients(struct ftl_conn *api)
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Exit before processing any data if requested via config setting
|
||||
if(config.misc.privacylevel >= PRIVACY_HIDE_DOMAINS_CLIENTS)
|
||||
@@ -429,9 +425,7 @@ int api_stats_upstreams(struct ftl_conn *api)
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
@@ -539,9 +533,7 @@ int api_stats_query_types(struct ftl_conn *api)
|
||||
{
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
lock_shm();
|
||||
|
||||
@@ -566,9 +558,7 @@ int api_stats_recentblocked(struct ftl_conn *api)
|
||||
|
||||
// Verify requesting client is allowed to see this ressource
|
||||
if(check_client_auth(api) == API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
return send_json_unauthorized(api);
|
||||
}
|
||||
|
||||
// Exit before processing any data if requested via config setting
|
||||
if(config.misc.privacylevel >= PRIVACY_HIDE_DOMAINS)
|
||||
|
||||
@@ -103,6 +103,8 @@ int send_http_internal_error(struct ftl_conn *api)
|
||||
bool get_bool_var(const char *source, const char *var, bool *boolean)
|
||||
{
|
||||
char buffer[16] = { 0 };
|
||||
if(!source)
|
||||
return false;
|
||||
if(GET_VAR(var, buffer, source) > 0)
|
||||
{
|
||||
*boolean = (strcasecmp(buffer, "true") == 0);
|
||||
@@ -204,6 +206,8 @@ bool get_int_var_msg(const char *source, const char *var, int *num, const char *
|
||||
bool get_int_var(const char *source, const char *var, int *num)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
if(!source)
|
||||
return false;
|
||||
return get_int_var_msg(source, var, num, &msg);
|
||||
}
|
||||
|
||||
@@ -232,12 +236,16 @@ bool get_uint_var_msg(const char *source, const char *var, unsigned int *num, co
|
||||
bool get_uint_var(const char *source, const char *var, unsigned int *num)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
if(!source)
|
||||
return false;
|
||||
return get_uint_var_msg(source, var, num, &msg);
|
||||
}
|
||||
|
||||
bool get_double_var_msg(const char *source, const char *var, double *num, const char **msg)
|
||||
{
|
||||
char buffer[128] = { 0 };
|
||||
if(!source)
|
||||
return false;
|
||||
if(GET_VAR(var, buffer, source) < 1)
|
||||
{
|
||||
// Parameter not found
|
||||
@@ -271,6 +279,8 @@ bool get_double_var_msg(const char *source, const char *var, double *num, const
|
||||
bool get_double_var(const char *source, const char *var, double *num)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
if(!source)
|
||||
return false;
|
||||
return get_double_var_msg(source, var, num, &msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ except Exception as e:
|
||||
exit(1)
|
||||
|
||||
# Resolve a reference
|
||||
def resolveSingleReference(ref: str, k: str):
|
||||
def resolveSingleReference(ref_str: str, k: str):
|
||||
# Read and parse the referenced file
|
||||
ref = ref.partition("#")
|
||||
ref = ref_str.partition("#")
|
||||
if len(ref[0]) == 0:
|
||||
# Empty references are not allowed
|
||||
raise Exception("Empty reference, always specify a file in the API specification")
|
||||
@@ -57,12 +57,12 @@ def resolveSingleReference(ref: str, k: str):
|
||||
# Reduce to what we want to import
|
||||
for x in ref[2].split("/"):
|
||||
if len(x) > 0:
|
||||
#if x not in refYML:
|
||||
refYML = refYML[x]
|
||||
return refYML
|
||||
except Exception as e:
|
||||
print("Exception when reading " + file + ": " + e)
|
||||
print("Tried to read" + ref + " in:\n" + json.dumps(refYML, indent=2))
|
||||
print("Tried to resolve " + k + " pointing to " + ref)
|
||||
print("Exception when reading " + file + ": " + str(e))
|
||||
print("Tried to resolve " + ref_str + " in:\n" + json.dumps(refYML, indent=2))
|
||||
exit(1)
|
||||
|
||||
# Recursively resolve references, this can take a few seconds
|
||||
|
||||
Reference in New Issue
Block a user