Remove HTTP API specific code so it can be replaced with a new protocol

Adjusted tests to fit the current lack of output on the unix socket.
Added TELNET enum and used it in place of the old SOCKET to better fit
with the rest of the code base.

Signed-off-by: Mcat12 <newtoncat12@yahoo.com>
This commit is contained in:
Mcat12
2018-01-03 20:16:50 -05:00
parent 3d78cc3644
commit 595ab259ca
13 changed files with 228 additions and 816 deletions
+2 -2
View File
@@ -203,8 +203,8 @@ typedef struct {
int querytypedata;
} memoryStruct;
enum { QUERIES, FORWARDED, CLIENTS, DOMAINS, OVERTIME, WILDCARD, AUTHDATA };
enum { SOCKET, API, APIH };
enum { QUERIES, FORWARDED, CLIENTS, DOMAINS, OVERTIME, WILDCARD };
enum { TELNET, SOCKET };
enum { WHITELIST, BLACKLIST, WILDLIST };
enum { DNSSEC_UNSPECIFIED, DNSSEC_SECURE, DNSSEC_INSECURE, DNSSEC_BOGUS, DNSSEC_ABANDONED, DNSSEC_UNKNOWN };
+2 -2
View File
@@ -8,8 +8,8 @@
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
DEPS = FTL.h routines.h api.h version.h cJSON.h
OBJ = main.o structs.o log.o daemon.o parser.o signals.o socket.o request.o grep.o setupVars.o args.o flush.o threads.o gc.o config.o database.o api.o api_stats.o api_dns.o cJSON.o
DEPS = FTL.h routines.h api.h version.h
OBJ = main.o structs.o log.o daemon.o parser.o signals.o socket.o request.o grep.o setupVars.o args.o flush.o threads.o gc.o config.o database.o api.o api_stats.o api_dns.o
# Get git commit version and date
GIT_BRANCH := $(shell git branch | sed -n 's/^\* //p')
-175
View File
@@ -10,181 +10,6 @@
#include "FTL.h"
#include "api.h"
#include "cJSON.h"
void sendAPIResponse(int sock, char type, char http_code) {
sendAPIResponseWithCookie(sock, type, http_code, NULL);
}
void sendAPIResponseWithCookie(int sock, char type, char http_code, const long *session) {
char *http_status;
switch(http_code) {
default:
case OK:
http_status = "200 OK";
break;
case BAD_REQUEST:
http_status = "400 Bad Request";
break;
case INTERNAL_ERROR:
http_status = "500 Internal Server Error";
break;
case NOT_FOUND:
http_status = "404 Not Found";
break;
case UNAUTHORIZED:
http_status = "401 Unauthorized";
break;
}
// Send header only for full HTTP requests
if(type == APIH)
{
if(session == NULL) {
// No cookie to send
ssend(sock,
"HTTP/1.0 %s\nServer: FTL\nCache-Control: no-cache\nAccess-Control-Allow-Origin: *\n"
"Content-Type: application/json\n\n{", http_status);
}
else {
// Send cookie
ssend(sock,
"HTTP/1.0 %s\nServer: FTL\nCache-Control: no-cache\nAccess-Control-Allow-Origin: *\n"
"Set-Cookie: FTL_SESSION=%ld\nContent-Type: application/json\n\n{", http_status, *session);
}
}
}
// session will have the client's valid session written to, if it's not unauthorized
enum Auth authenticate(char *with_headers, char *payload, long *session, int sock) {
// First figure out if the client has authenticated before.
char *sessionStr;
AuthData *auth = NULL;
// Find the cookie header (will contain a long int value)
if(strstr(with_headers, "Cookie: ") != NULL && (sessionStr = strstr(with_headers, "FTL_SESSION=")) != NULL) {
// Find the start of the cookie (strtol will stop once it gets to a non-numeric character)
sessionStr += 12;
// Convert to int
*session = strtol(sessionStr, NULL, 10);
if(errno == ERANGE) {
logg("Failed to decode the authentication cookie");
return AUTH_UNAUTHORIZED;
}
int i;
for(i = 0; i < authLength; i++) {
// Check if the authentication is still valid, has the same session token, and is coming from the same IP
if(authData[i].valid && authData[i].session == *session && strcmp(clientip[sock], authData[i].ip) == 0) {
auth = &authData[i];
time_t currentTime = time(NULL);
// Check to see if the session had expired (24 minutes)
if(currentTime > auth->lastQueryTime + 1440) {
authData[i].valid = false;
return AUTH_UNAUTHORIZED;
}
auth->lastQueryTime = currentTime;
}
}
// auth will be null if we didn't find a matching session
if(auth == NULL)
return AUTH_UNAUTHORIZED;
return AUTH_PREVIOUS;
}
// Otherwise, check if they are trying to authenticate
cJSON *input_root = cJSON_Parse(payload);
cJSON *password_json = cJSON_GetObjectItemCaseSensitive(input_root, "password");
if(!cJSON_IsString(password_json)) {
cJSON_Delete(input_root);
return AUTH_UNAUTHORIZED;
}
char *password = password_json->valuestring;
// todo: use real password
if(strcmp(password, "password") == 0) {
auth = malloc(sizeof(AuthData));
auth->lastQueryTime = time(NULL);
auth->ip = strdup(clientip[sock]);
// Find a unique session number
while(true) {
auth->session = random();
bool unique = true;
int i;
for(i = 0; i < authLength; i++) {
if(authData[i].session == auth->session) {
unique = false;
break;
}
}
// Found a unique session number
if(unique)
break;
}
auth->valid = true;
// Add to auth storage
bool found = false;
int i;
for(i = 0; i < authLength; i++) {
if(!authData[i].valid) {
// Found an invalid auth we can reuse
found = true;
free(authData[i].ip);
authData[i] = *auth;
break;
}
}
if(!found) {
// Couldn't reuse any existing auth structures
memory_check(AUTHDATA);
authData[authLength] = *auth;
authLength++;
}
*session = auth->session;
free(auth);
cJSON_Delete(input_root);
return AUTH_NEW;
}
cJSON_Delete(input_root);
return AUTH_UNAUTHORIZED;
}
char* getPayload(char *http_message) {
char *data_start;
char *unix_newline = strstr(http_message, "\n\n");
char *win_newline = strstr(http_message, "\r\n\r\n");
if(unix_newline != NULL)
data_start = unix_newline + 2;
else if(win_newline != NULL)
data_start = win_newline + 4;
else
return NULL;
if(strlen(data_start) == 0)
return NULL;
return data_start;
}
bool matchesRegex(char *regex_expression, char *input) {
regex_t regex;
+8 -25
View File
@@ -8,50 +8,33 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
// Endpoints under /stats/
// Statistic methods
void getStats(int *sock, char type);
void getOverTime(int *sock, char type);
void getTopDomains (char *client_message, int *sock, char type);
void getTopClients(char *client_message, int *sock, char type);
void getForwardDestinations(char *client_message, int *sock, char type);
void getQueryTypes(int *sock, char type);
void getAllQueries(char *client_message, int *sock, char type);
void getRecentBlocked(char *client_message, int *sock, char type);
void getMemoryUsage(int *sock, char type);
void getForwardDestinationsOverTime(int *sock, char type);
void getClientID(int *sock, char type);
void getQueryTypesOverTime(int *sock, char type);
void getVersion(int *sock, char type);
void getDBstats(int *sock, char type);
void getClientsOverTime(int *sock);
void getClientNames(int *sock);
// FTL methods
void getMemoryUsage(int *sock, char type);
void getClientID(int *sock, char type);
void getVersion(int *sock, char type);
void getDBstats(int *sock, char type);
void getUnknownQueries(int *sock);
// Endpoints under /dns/
// DNS methods
void getList(int *sock, char type, char list_type);
void addList(int *sock, char type, char list_type, char *data);
void removeList(int *sock, char type, char list_type, char *client_message);
void getPiholeStatus(int *sock, char type);
// HTTP Response Codes
enum { OK, BAD_REQUEST, INTERNAL_ERROR, NOT_FOUND, UNAUTHORIZED };
// Authentication
typedef struct {
time_t lastQueryTime;
long session;
char *ip;
bool valid;
} AuthData;
AuthData *authData;
int authLength;
enum Auth { AUTH_UNAUTHORIZED, AUTH_PREVIOUS, AUTH_NEW };
// General API commands
enum Auth authenticate(char *with_headers, char *payload, long *session, int sock);
char* getPayload(char *http_message);
void sendAPIResponse(int sock, char type, char http_code);
void sendAPIResponseWithCookie(int sock, char type, char http_code, const long *session);
bool matchesRegex(char *regex_expression, char *input);
bool isValidDomain(char *domain);
+20 -20
View File
@@ -32,7 +32,7 @@ void getList(int *sock, char type, char list_type) {
name = "wildlist";
}
sendAPIResponse(*sock, type, OK);
// sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"%s\":[", name);
if((fp = fopen(file, "r")) != NULL)
@@ -111,28 +111,28 @@ void getList(int *sock, char type, char list_type) {
void getPiholeStatus(int *sock, char type) {
int status = countlineswith("#addn-hosts=/etc/pihole/gravity.list", files.dnsmasqconf);
sendAPIResponse(*sock, type, OK);
// sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"status\":%i", status == 1 ? 0 : 1);
}
void addList(int *sock, char type, char list_type, char *data) {
cJSON *input_root = cJSON_Parse(data);
cJSON *domain_json = cJSON_GetObjectItemCaseSensitive(input_root, "domain");
// cJSON *input_root = cJSON_Parse(data);
// cJSON *domain_json = cJSON_GetObjectItemCaseSensitive(input_root, "domain");
char *domain;
// Validate domain
if(!cJSON_IsString(domain_json)) {
// No domain found
sendAPIResponse(*sock, type, BAD_REQUEST);
ssend(*sock, "\"status\":\"no_domain\"");
return;
}
// if(!cJSON_IsString(domain_json)) {
// // No domain found
// sendAPIResponse(*sock, type, BAD_REQUEST);
// ssend(*sock, "\"status\":\"no_domain\"");
// return;
// }
domain = domain_json->valuestring;
// domain = domain_json->valuestring;
if(!isValidDomain(domain)) {
// Invalid domain
sendAPIResponse(*sock, type, BAD_REQUEST);
// sendAPIResponse(*sock, type, BAD_REQUEST);
ssend(*sock, "\"status\":\"invalid_domain\"");
return;
}
@@ -160,16 +160,16 @@ void addList(int *sock, char type, char list_type, char *data) {
if(return_code == 0) {
// Successfully added to list
sendAPIResponse(*sock, type, OK);
// sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"status\":\"success\"");
}
else {
// Failed to add to list
sendAPIResponse(*sock, type, INTERNAL_ERROR);
// sendAPIResponse(*sock, type, INTERNAL_ERROR);
ssend(*sock, "\"status\":\"unknown_error\"");
}
cJSON_Delete(input_root);
// cJSON_Delete(input_root);
}
void removeList(int *sock, char type, char list_type, char *client_message) {
@@ -178,7 +178,7 @@ void removeList(int *sock, char type, char list_type, char *client_message) {
// Validate domain
if(domain == NULL) {
// No domain found
sendAPIResponse(*sock, type, NOT_FOUND);
// sendAPIResponse(*sock, type, NOT_FOUND);
ssend(*sock, "\"status\":\"not_found\"");
return;
}
@@ -208,7 +208,7 @@ void removeList(int *sock, char type, char list_type, char *client_message) {
if(!strstr(client_message, expected_route)) {
// Invalid route
free(expected_route);
sendAPIResponse(*sock, type, NOT_FOUND);
// sendAPIResponse(*sock, type, NOT_FOUND);
ssend(*sock, "\"status\":\"not_found\"");
return;
}
@@ -217,7 +217,7 @@ void removeList(int *sock, char type, char list_type, char *client_message) {
if(!isValidDomain(domain)) {
// Invalid domain
sendAPIResponse(*sock, type, BAD_REQUEST);
// sendAPIResponse(*sock, type, BAD_REQUEST);
ssend(*sock, "\"status\":\"invalid_domain\"");
return;
}
@@ -241,12 +241,12 @@ void removeList(int *sock, char type, char list_type, char *client_message) {
if(return_code == 0) {
// Successfully removed from list
sendAPIResponse(*sock, type, OK);
// sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"status\":\"success\"");
}
else {
// Failed to remove from list
sendAPIResponse(*sock, type, INTERNAL_ERROR);
// sendAPIResponse(*sock, type, INTERNAL_ERROR);
ssend(*sock, "\"status\":\"unknown_error\"");
}
}
+173 -173
View File
@@ -59,7 +59,7 @@ void getStats(int *sock, char type)
switch(blockingstatus)
{
case 0: // Blocking disabled
if(type == SOCKET)
if(type == TELNET)
strncpy(domains_blocked, "N/A", 4);
else
strncpy(domains_blocked, "\"N/A\"", 6);
@@ -85,7 +85,7 @@ void getStats(int *sock, char type)
activeclients++;
}
if(type == SOCKET) {
if(type == TELNET) {
ssend(*sock, "domains_being_blocked %s\ndns_queries_today %i\nads_blocked_today %i\nads_percentage_today %f\n",
domains_blocked, total, blocked, percentage);
ssend(*sock, "unique_domains %i\nqueries_forwarded %i\nqueries_cached %i\n",
@@ -96,30 +96,30 @@ void getStats(int *sock, char type)
}
else
{
sendAPIResponse(*sock, type, OK);
ssend(
*sock,
"\"domains_being_blocked\":%s,"
"\"dns_queries_today\":%i,"
"\"ads_blocked_today\":%i,"
"\"ads_percentage_today\":%.4f,"
"\"unique_domains\":%i,"
"\"queries_forwarded\":%i,"
"\"queries_cached\":%i,"
"\"clients_ever_seen\":%i,"
"\"unique_clients\":%i,"
"\"status\":\"%s\"",
domains_blocked,
total,
blocked,
percentage,
counters.domains,
counters.forwardedqueries,
counters.cached,
counters.clients,
activeclients,
status
);
// sendAPIResponse(*sock, type, OK);
// ssend(
// *sock,
// "\"domains_being_blocked\":%s,"
// "\"dns_queries_today\":%i,"
// "\"ads_blocked_today\":%i,"
// "\"ads_percentage_today\":%.4f,"
// "\"unique_domains\":%i,"
// "\"queries_forwarded\":%i,"
// "\"queries_cached\":%i,"
// "\"clients_ever_seen\":%i,"
// "\"unique_clients\":%i,"
// "\"status\":\"%s\"",
// domains_blocked,
// total,
// blocked,
// percentage,
// counters.domains,
// counters.forwardedqueries,
// counters.cached,
// counters.clients,
// activeclients,
// status
// );
}
if(debugclients)
@@ -142,7 +142,7 @@ void getOverTime(int *sock, char type)
}
// Send data in socket format if requested
if(type == SOCKET)
if(type == TELNET)
{
for(i = j; i < counters.overTime; i++)
{
@@ -151,25 +151,25 @@ void getOverTime(int *sock, char type)
}
else
{
// First send header with unspecified content-length outside of the for-loop
sendAPIResponse(*sock, type, OK);
ssend(*sock,"\"domains_over_time\":{");
// Send "domains_over_time" data
for(i = j; i < counters.overTime; i++)
{
if(i != j) ssend(*sock, ",");
ssend(*sock,"\"%i\":%i",overTime[i].timestamp,overTime[i].total);
}
ssend(*sock,"},\"ads_over_time\":{");
// Send "ads_over_time" data
for(i = j; i < counters.overTime; i++)
{
if(i != j) ssend(*sock, ",");
ssend(*sock,"\"%i\":%i",overTime[i].timestamp,overTime[i].blocked);
}
ssend(*sock,"}");
// // First send header with unspecified content-length outside of the for-loop
// sendAPIResponse(*sock, type, OK);
// ssend(*sock,"\"domains_over_time\":{");
//
// // Send "domains_over_time" data
// for(i = j; i < counters.overTime; i++)
// {
// if(i != j) ssend(*sock, ",");
// ssend(*sock,"\"%i\":%i",overTime[i].timestamp,overTime[i].total);
// }
// ssend(*sock,"},\"ads_over_time\":{");
//
// // Send "ads_over_time" data
// for(i = j; i < counters.overTime; i++)
// {
// if(i != j) ssend(*sock, ",");
// ssend(*sock,"\"%i\":%i",overTime[i].timestamp,overTime[i].blocked);
// }
// ssend(*sock,"}");
}
if(debugclients)
@@ -181,7 +181,7 @@ void getTopDomains(char *client_message, int *sock, char type)
int i, temparray[counters.domains][2], count=10, num;
bool blocked, audit = false, desc = false;
if(type == SOCKET)
if(type == TELNET)
blocked = command(client_message, ">top-ads");
else
blocked = command(client_message, "/top_ads");
@@ -191,9 +191,9 @@ void getTopDomains(char *client_message, int *sock, char type)
return;
// Match both top-domains and top-ads
// SOCKET: >top-domains (15)
// TELNET: >top-domains (15)
// API: /stats/top_domains?limit=15
if(type == SOCKET)
if(type == TELNET)
{
if(sscanf(client_message, "%*[^(](%i)", &num) > 0)
{
@@ -215,19 +215,19 @@ void getTopDomains(char *client_message, int *sock, char type)
}
// Apply Audit Log filtering?
// SOCKET: >top-domains for audit
// TELNET: >top-domains for audit
// API: /stats/top_domains?audit
if(type == SOCKET && command(client_message, " for audit"))
if(type == TELNET && command(client_message, " for audit"))
audit = true;
else if(type != SOCKET && command(client_message, "audit"))
else if(type != TELNET && command(client_message, "audit"))
audit = true;
// Sort in descending order?
// SOCKET: >top-domains desc
// TELNET: >top-domains desc
// API: /stats/top_domains?order=desc
if(type == SOCKET && command(client_message, " desc"))
if(type == TELNET && command(client_message, " desc"))
desc = true;
else if(type != SOCKET && command(client_message, "order=desc"))
else if(type != TELNET && command(client_message, "order=desc"))
desc = true;
for(i=0; i < counters.domains; i++)
@@ -279,15 +279,15 @@ void getTopDomains(char *client_message, int *sock, char type)
}
}
if(type != SOCKET)
if(type != TELNET)
{
// First send header with unspecified content-length outside of the for-loop
sendAPIResponse(*sock, type, OK);
if(blocked)
ssend(*sock, "\"top_ads\":{");
else
ssend(*sock, "\"top_domains\":{");
// // First send header with unspecified content-length outside of the for-loop
// sendAPIResponse(*sock, type, OK);
//
// if(blocked)
// ssend(*sock, "\"top_ads\":{");
// else
// ssend(*sock, "\"top_domains\":{");
}
int skip = 0; bool first = true;
@@ -316,7 +316,7 @@ void getTopDomains(char *client_message, int *sock, char type)
if(blocked && showblocked && domains[j].blockedcount > 0)
{
if(type == SOCKET)
if(type == TELNET)
{
if(audit && domains[j].wildcard)
ssend(*sock,"%i %i %s wildcard\n",i,domains[j].blockedcount,domains[j].domain);
@@ -325,32 +325,32 @@ void getTopDomains(char *client_message, int *sock, char type)
}
else
{
if(!first) ssend(*sock,",");
first = false;
ssend(*sock,"\"%s\":%i", domains[j].domain, domains[j].blockedcount);
// if(!first) ssend(*sock,",");
// first = false;
// ssend(*sock,"\"%s\":%i", domains[j].domain, domains[j].blockedcount);
}
}
else if(!blocked && showpermitted && (domains[j].count - domains[j].blockedcount) > 0)
{
if(type == SOCKET)
if(type == TELNET)
{
ssend(*sock,"%i %i %s\n",i,(domains[j].count - domains[j].blockedcount),domains[j].domain);
}
else
{
if(!first) ssend(*sock,",");
first = false;
ssend(*sock,"\"%s\":%i", domains[j].domain, (domains[j].count - domains[j].blockedcount));
// if(!first) ssend(*sock,",");
// first = false;
// ssend(*sock,"\"%s\":%i", domains[j].domain, (domains[j].count - domains[j].blockedcount));
}
}
}
if(type != SOCKET)
if(type != TELNET)
{
if(blocked)
ssend(*sock,"},\"ads_blocked_today\":%i", counters.blocked);
else
ssend(*sock,"},\"dns_queries_today\":%i", (counters.queries - counters.invalidqueries));
// if(blocked)
// ssend(*sock,"},\"ads_blocked_today\":%i", counters.blocked);
// else
// ssend(*sock,"},\"dns_queries_today\":%i", (counters.queries - counters.invalidqueries));
}
if(excludedomains != NULL)
@@ -370,9 +370,9 @@ void getTopClients(char *client_message, int *sock, char type)
int i, temparray[counters.clients][2], count=10, num;
// Match both top-domains and top-ads
// SOCKET: >top-clients (15)
// TELNET: >top-clients (15)
// API: /stats/top_clients?limit=15
if(type == SOCKET)
if(type == TELNET)
{
if(sscanf(client_message, "%*[^(](%i)", &num) > 0)
{
@@ -397,7 +397,7 @@ void getTopClients(char *client_message, int *sock, char type)
// This option can be combined with existing options,
// i.e. both >top-clients withzero" and ">top-clients withzero (123)" are valid
bool includezeroclients = false;
if(type == SOCKET) {
if(type == TELNET) {
if(command(client_message, " withzero")) {
includezeroclients = true;
}
@@ -425,11 +425,11 @@ void getTopClients(char *client_message, int *sock, char type)
logg("Excluding %i clients from being displayed", setupVarsElements);
}
if(type != SOCKET)
if(type != TELNET)
{
// First send header with unspecified content-length outside of the for-loop
sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"top_clients\":{");
// // First send header with unspecified content-length outside of the for-loop
// sendAPIResponse(*sock, type, OK);
// ssend(*sock, "\"top_clients\":{");
}
int skip = 0; bool first = true;
@@ -454,24 +454,24 @@ void getTopClients(char *client_message, int *sock, char type)
// - "withzero" option is set, and/or
// - the client made at least one query within the most recent 24 hours
if(includezeroclients || clients[j].count > 0) {
if(type == SOCKET)
if(type == TELNET)
{
ssend(*sock,"%i %i %s %s\n",i,clients[j].count,clients[j].ip,clients[j].name);
}
else
{
if(!first) ssend(*sock,",");
first = false;
if(strlen(clients[j].name) > 0)
ssend(*sock,"\"%s|%s\":%i", clients[j].name, clients[j].ip, clients[j].count);
else
ssend(*sock,"\"%s\":%i", clients[j].ip, clients[j].count);
// if(!first) ssend(*sock,",");
// first = false;
// if(strlen(clients[j].name) > 0)
// ssend(*sock,"\"%s|%s\":%i", clients[j].name, clients[j].ip, clients[j].count);
// else
// ssend(*sock,"\"%s\":%i", clients[j].ip, clients[j].count);
}
}
}
if(type != SOCKET)
ssend(*sock,"},\"dns_queries_today\":%i", (counters.queries - counters.invalidqueries));
// if(type != TELNET)
// ssend(*sock,"},\"dns_queries_today\":%i", (counters.queries - counters.invalidqueries));
if(excludeclients != NULL)
clearSetupVarsArray();
@@ -486,7 +486,7 @@ void getForwardDestinations(char *client_message, int *sock, char type)
bool allocated = false, first = true, sort = true;
int i, temparray[counters.forwarded+1][2], forwardedsum = 0, totalqueries = 0;
if(type == SOCKET && command(client_message, "unsorted"))
if(type == TELNET && command(client_message, "unsorted"))
sort = false;
else if(strstr(client_message, "unsorted"))
sort = false;
@@ -516,11 +516,11 @@ void getForwardDestinations(char *client_message, int *sock, char type)
totalqueries = counters.forwardedqueries + counters.cached + counters.blocked;
// Send HTTP headers with unknown content length
sendAPIResponse(*sock, type, OK);
// sendAPIResponse(*sock, type, OK);
// Send initial JSON output
if(type != SOCKET)
ssend(*sock, "\"forward_destinations\":{");
// if(type != TELNET)
// ssend(*sock, "\"forward_destinations\":{");
// Loop over available forward destinations
for(i=0; i < min(counters.forwarded+1, 10); i++)
@@ -584,19 +584,19 @@ void getForwardDestinations(char *client_message, int *sock, char type)
// Send data if count > 0
if(percentage > 0.0)
{
if(type == SOCKET)
if(type == TELNET)
{
ssend(*sock, "%i %.2f %s %s\n", i, percentage, ip, name);
}
else
{
if(!first) ssend(*sock, ",");
first = false;
if(strlen(name) > 0)
ssend(*sock, "\"%s|%s\":%.2f", name, ip, percentage);
else
ssend(*sock, "\"%s\":%.2f", ip, percentage);
// if(!first) ssend(*sock, ",");
// first = false;
//
// if(strlen(name) > 0)
// ssend(*sock, "\"%s|%s\":%.2f", name, ip, percentage);
// else
// ssend(*sock, "\"%s\":%.2f", ip, percentage);
}
}
@@ -608,8 +608,8 @@ void getForwardDestinations(char *client_message, int *sock, char type)
}
}
if(type != SOCKET)
ssend(*sock, "}");
// if(type != TELNET)
// ssend(*sock, "}");
if(debugclients)
logg("Sent forward destination data to client, ID: %i", *sock);
@@ -627,11 +627,11 @@ void getQueryTypes(int *sock, char type)
percentageIPv6 = 1e2*counters.IPv6/total;
}
if(type == SOCKET)
if(type == TELNET)
ssend(*sock,"A (IPv4): %.2f\nAAAA (IPv6): %.2f\n", percentageIPv4, percentageIPv6);
else {
sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"query_types\":{\"A (IPv4)\":%.2f,\"AAAA (IPv6)\":%.2f}", percentageIPv4, percentageIPv6);
// sendAPIResponse(*sock, type, OK);
// ssend(*sock, "\"query_types\":{\"A (IPv4)\":%.2f,\"AAAA (IPv6)\":%.2f}", percentageIPv4, percentageIPv6);
}
if(debugclients)
@@ -655,7 +655,7 @@ void getAllQueries(char *client_message, int *sock, char type)
char *clientname = NULL;
bool filterclientname = false;
if(type == SOCKET)
if(type == TELNET)
{
// Time filtering?
if(command(client_message, ">getallqueries-time"))
@@ -724,7 +724,7 @@ void getAllQueries(char *client_message, int *sock, char type)
int ibeg = 0, num;
// Test for integer that specifies number of entries to be shown
if(type == SOCKET)
if(type == TELNET)
{
if(sscanf(client_message, "%*[^(](%i)", &num) > 0)
{
@@ -794,11 +794,11 @@ void getAllQueries(char *client_message, int *sock, char type)
logg("Privacy mode enabled");
}
if(type != SOCKET)
{
sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"history\":[");
}
// if(type != TELNET)
// {
// sendAPIResponse(*sock, type, OK);
// ssend(*sock, "\"history\":[");
// }
int i; bool first = true;
for(i=ibeg; i < counters.queries; i++)
@@ -840,7 +840,7 @@ void getAllQueries(char *client_message, int *sock, char type)
continue;
}
if(type == SOCKET)
if(type == TELNET)
{
if(!privacymode)
{
@@ -854,24 +854,24 @@ void getAllQueries(char *client_message, int *sock, char type)
}
else
{
// {"data":[["1497351662","IPv4","clients4.google.com","10.8.0.2",2,1],
if(!first) ssend(*sock, ",");
first = false;
if(!privacymode)
{
if(strlen(clients[queries[i].clientID].name) > 0)
ssend(*sock,"[%i,\"%s\",\"%s\",\"%s\",%i,%i]",queries[i].timestamp,qtype,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status,domains[queries[i].domainID].dnssec);
else
ssend(*sock,"[%i,\"%s\",\"%s\",\"%s\",%i,%i]",queries[i].timestamp,qtype,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status,domains[queries[i].domainID].dnssec);
}
else
ssend(*sock,"[%i,\"%s\",\"%s\",\"hidden\",%i,%i]",queries[i].timestamp,qtype,domains[queries[i].domainID].domain,queries[i].status,domains[queries[i].domainID].dnssec);
// // {"data":[["1497351662","IPv4","clients4.google.com","10.8.0.2",2,1],
// if(!first) ssend(*sock, ",");
// first = false;
//
// if(!privacymode)
// {
// if(strlen(clients[queries[i].clientID].name) > 0)
// ssend(*sock,"[%i,\"%s\",\"%s\",\"%s\",%i,%i]",queries[i].timestamp,qtype,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status,domains[queries[i].domainID].dnssec);
// else
// ssend(*sock,"[%i,\"%s\",\"%s\",\"%s\",%i,%i]",queries[i].timestamp,qtype,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status,domains[queries[i].domainID].dnssec);
// }
// else
// ssend(*sock,"[%i,\"%s\",\"%s\",\"hidden\",%i,%i]",queries[i].timestamp,qtype,domains[queries[i].domainID].domain,queries[i].status,domains[queries[i].domainID].dnssec);
}
}
if(type != SOCKET)
ssend(*sock, "]");
// if(type != TELNET)
// ssend(*sock, "]");
// Free allocated memory
if(filterclientname)
@@ -893,7 +893,7 @@ void getRecentBlocked(char *client_message, int *sock, char type)
return;
// Test for integer that specifies number of entries to be shown
if(type == SOCKET)
if(type == TELNET)
{
if(sscanf(client_message, "%*[^(](%i)", &num) > 0)
{
@@ -916,11 +916,11 @@ void getRecentBlocked(char *client_message, int *sock, char type)
}
}
if(type != SOCKET)
{
sendAPIResponse(*sock, type, OK);
ssend(*sock, "\"recent_blocked\":[");
}
// if(type != TELNET)
// {
// sendAPIResponse(*sock, type, OK);
// ssend(*sock, "\"recent_blocked\":[");
// }
// Find most recent query with either status 1 (blocked)
// or status 4 (wildcard blocked)
@@ -934,15 +934,15 @@ void getRecentBlocked(char *client_message, int *sock, char type)
if(queries[i].status == 1 || queries[i].status == 4)
{
found++;
if(type == SOCKET)
if(type == TELNET)
{
ssend(*sock,"%s\n", domains[queries[i].domainID].domain);
}
else
{
if(!first) ssend(*sock, ",");
first = false;
ssend(*sock, "\"%s\"", domains[queries[i].domainID].domain);
// if(!first) ssend(*sock, ",");
// first = false;
// ssend(*sock, "\"%s\"", domains[queries[i].domainID].domain);
}
}
@@ -950,11 +950,11 @@ void getRecentBlocked(char *client_message, int *sock, char type)
break;
}
if(type != SOCKET)
ssend(*sock, "]");
// if(type != TELNET)
// ssend(*sock, "]");
}
// only available via SOCKET
// only available via TELNET
void getMemoryUsage(int *sock, char type)
{
unsigned long int structbytes = sizeof(countersStruct) + sizeof(ConfigStruct) + counters.queries_MAX*sizeof(queriesDataStruct) + counters.forwarded_MAX*sizeof(forwardedDataStruct) + counters.clients_MAX*sizeof(clientsDataStruct) + counters.domains_MAX*sizeof(domainsDataStruct) + counters.overTime_MAX*sizeof(overTimeDataStruct) + (counters.wildcarddomains)*sizeof(*wildcarddomains);
@@ -994,11 +994,11 @@ void getForwardDestinationsOverTime(int *sock, char type)
}
}
if(type != SOCKET)
{
sendAPIResponse(*sock, type, OK);
ssend(*sock,"\"over_time\":{");
}
// if(type != TELNET)
// {
// sendAPIResponse(*sock, type, OK);
// ssend(*sock,"\"over_time\":{");
// }
if(sendit > -1)
{
@@ -1008,15 +1008,15 @@ void getForwardDestinationsOverTime(int *sock, char type)
double percentage;
validate_access("overTime", i, true, __LINE__, __FUNCTION__, __FILE__);
if(type == SOCKET)
if(type == TELNET)
{
ssend(*sock, "%i", overTime[i].timestamp);
}
else
{
if(!first) ssend(*sock, ",");
first = false;
ssend(*sock, "\"%i\":[", overTime[i].timestamp);
// if(!first) ssend(*sock, ",");
// first = false;
// ssend(*sock, "\"%i\":[", overTime[i].timestamp);
}
int j, forwardedsum = 0;
@@ -1067,7 +1067,7 @@ void getForwardDestinationsOverTime(int *sock, char type)
else
percentage = 0.0;
if(type == SOCKET)
if(type == TELNET)
ssend(*sock, " %.2f", percentage);
else
ssend(*sock, "%.2f,", percentage);
@@ -1080,19 +1080,19 @@ void getForwardDestinationsOverTime(int *sock, char type)
else
percentage = 0.0;
if(type == SOCKET)
if(type == TELNET)
ssend(*sock, " %.2f\n", percentage);
else
ssend(*sock, "%.2f]", percentage);
}
}
if(type != SOCKET)
{
ssend(*sock,"},");
// Manually set API -> Don't send header a second time
getForwardDestinations(">forward-dest unsorted", sock, API);
}
// if(type != TELNET)
// {
// ssend(*sock,"},");
// // Manually set API -> Don't send header a second time
// getForwardDestinations(">forward-dest unsorted", sock, SOCKET);
// }
if(debugclients)
logg("Sent overTime forwarded data to client, ID: %i", *sock);
@@ -1120,11 +1120,11 @@ void getQueryTypesOverTime(int *sock, char type)
}
}
if(type != SOCKET)
{
sendAPIResponse(*sock, type, OK);
ssend(*sock,"\"query_types\":{");
}
// if(type != TELNET)
// {
// sendAPIResponse(*sock, type, OK);
// ssend(*sock,"\"query_types\":{");
// }
if(sendit > -1)
{
@@ -1141,18 +1141,18 @@ void getQueryTypesOverTime(int *sock, char type)
percentageIPv6 = 1e2*overTime[i].querytypedata[1] / sum;
}
if(type == SOCKET)
if(type == TELNET)
ssend(*sock, "%i %.2f %.2f\n", overTime[i].timestamp, percentageIPv4, percentageIPv6);
else {
if(!first) ssend(*sock, ",");
first = false;
ssend(*sock, "\"%i\":[%.2f,%.2f]", overTime[i].timestamp, percentageIPv4, percentageIPv6);
// if(!first) ssend(*sock, ",");
// first = false;
// ssend(*sock, "\"%i\":[%.2f,%.2f]", overTime[i].timestamp, percentageIPv4, percentageIPv6);
}
}
}
if(type != SOCKET)
ssend(*sock,"}");
// if(type != TELNET)
// ssend(*sock,"}");
if(debugclients)
logg("Sent overTime query types data to client, ID: %i", *sock);
-9
View File
@@ -89,14 +89,6 @@ int main (int argc, char* argv[]) {
}
sleepms(100);
// Start API thread
pthread_t api_listenthread;
if(pthread_create( &api_listenthread, &attr, api_listening_thread, NULL ) != 0)
{
logg("Unable to open API listening thread. Exiting...");
killed = 1;
}
while(!killed)
{
sleepms(100);
@@ -176,7 +168,6 @@ int main (int argc, char* argv[]) {
pthread_cancel(socket_listenthread);
close_telnet_socket();
close_unix_socket();
close_api_socket();
removepid();
logg("########## FTL terminated! ##########");
return 1;
+1 -155
View File
@@ -11,13 +11,12 @@
#include "FTL.h"
#include "api.h"
void process_socket_request(char *client_message, int *sock)
void process_request(char *client_message, int *sock, char type)
{
char EOT[2];
EOT[0] = 0x04;
EOT[1] = 0x00;
bool processed = false;
char type = SOCKET;
if(command(client_message, ">stats"))
{
@@ -149,159 +148,6 @@ void process_socket_request(char *client_message, int *sock)
}
}
void process_api_request(char *client_message, char *full_message, int *sock, bool header)
{
char type;
if(header)
type = APIH;
else
type = API;
char *data = getPayload(full_message);
long session;
char authResult = authenticate(full_message, data, &session, *sock);
if(authResult == AUTH_UNAUTHORIZED && !matchesEndpoint(client_message, "GET /stats/summary")
&& !matchesEndpoint(client_message, "GET /stats/overTime/graph")
&& !matchesEndpoint(client_message, "GET /dns/status")) {
sendAPIResponse(*sock, type, UNAUTHORIZED);
ssend(*sock, "\"status\":\"unauthorized\"}");
return;
}
if(authResult == AUTH_NEW) {
sendAPIResponseWithCookie(*sock, type, OK, &session);
ssend(*sock, "\"status\":\"authorized\",\"session\":%ld}", session);
return;
}
if(matchesEndpoint(client_message, "GET /stats/summary"))
{
getStats(sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/overTime/graph"))
{
getOverTime(sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/top_domains") || matchesEndpoint(client_message, "GET /stats/top_ads"))
{
getTopDomains(client_message, sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/top_clients"))
{
getTopClients(client_message, sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/forward_dest") || matchesEndpoint(client_message, "GET /stats/forward_destinations"))
{
getForwardDestinations(client_message, sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/dashboard"))
{
getStats(sock, type);
type = API;
ssend(*sock, ",");
getOverTime(sock, type);
ssend(*sock, ",");
getTopDomains(client_message, sock, type);
ssend(*sock, ",");
getTopClients(client_message, sock, type);
ssend(*sock, ",");
getForwardDestinations(client_message, sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/query_types"))
{
getQueryTypes(sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/history"))
{
getAllQueries(client_message, sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/recent_blocked"))
{
getRecentBlocked(client_message, sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/overTime/forward_dest"))
{
getForwardDestinationsOverTime(sock, type);
}
else if(matchesEndpoint(client_message, "GET /stats/overTime/query_types"))
{
getQueryTypesOverTime(sock, type);
}
else if(matchesEndpoint(client_message, "GET /dns/whitelist"))
{
getList(sock, type, WHITELIST);
}
else if(matchesEndpoint(client_message, "POST /dns/whitelist"))
{
addList(sock, type, WHITELIST, data);
}
else if(matchesRegex("DELETE \\/dns\\/whitelist\\/[^\\/]*$", client_message))
{
removeList(sock, type, WHITELIST, client_message);
}
else if(matchesEndpoint(client_message, "GET /dns/blacklist"))
{
getList(sock, type, BLACKLIST);
}
else if(matchesEndpoint(client_message, "POST /dns/blacklist"))
{
addList(sock, type, BLACKLIST, data);
}
else if(matchesRegex("DELETE \\/dns\\/blacklist\\/[^\\/]*$", client_message))
{
removeList(sock, type, BLACKLIST, client_message);
}
else if(matchesEndpoint(client_message, "GET /dns/wildlist"))
{
getList(sock, type, WILDLIST);
}
else if(matchesEndpoint(client_message, "POST /dns/wildlist"))
{
addList(sock, type, WILDLIST, data);
}
else if(matchesRegex("DELETE \\/dns\\/wildlist\\/[^\\/]*$", client_message))
{
removeList(sock, type, WILDLIST, client_message);
}
else if(matchesEndpoint(client_message, "GET /dns/status"))
{
getPiholeStatus(sock, type);
}
else if(header)
{
sendAPIResponse(*sock, type, NOT_FOUND);
ssend(*sock, "\"status\":\"not_found\"");
}
ssend(*sock, "}");
}
bool command(char *client_message, const char* cmd) {
return strstr(client_message, cmd) != NULL;
}
bool matchesEndpoint(char *client_message, const char *cmd) {
char *get_params_start = strstr(client_message, "?");
bool result;
// Check if there are GET parameters to ignore
if(get_params_start != NULL) {
char without_get_params[256];
// Check to make sure we don't overflow the buffer
if(strlen(cmd)+1 > sizeof(without_get_params) / sizeof(char))
return false;
size_t msg_len = get_params_start - client_message;
strncpy(without_get_params, client_message, msg_len);
without_get_params[msg_len] = 0;
result = strcmp(without_get_params, cmd) == 0;
}
else
result = strcmp(client_message, cmd) == 0;
return result;
}
+1 -4
View File
@@ -40,15 +40,12 @@ void memory_check(int which);
void close_telnet_socket(void);
void close_unix_socket(void);
void close_api_socket(void);
void seom(int sock);
void ssend(int sock, const char *format, ...);
void *telnet_listening_thread(void *args);
void *socket_listening_thread(void *args);
void *api_listening_thread(void *args);
void process_socket_request(char *client_message, int *sock);
void process_api_request(char *client_message, char *full_message, int *sock, bool header);
void process_request(char *client_message, int *sock, char type);
bool command(char *client_message, const char* cmd);
bool matchesEndpoint(char *client_message, const char *cmd);
+9 -183
View File
@@ -21,7 +21,7 @@
#define BACKLOG 5
// File descriptors
int telnetfd, socketfd, apifd;
int telnetfd, socketfd;
void saveport(int port)
{
@@ -62,7 +62,7 @@ void bind_to_telnet_port(char type, int *socketdescriptor)
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
if(config.socket_listenlocal && type == SOCKET)
if(config.socket_listenlocal)
serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else
serv_addr.sin_addr.s_addr = INADDR_ANY;
@@ -77,12 +77,9 @@ void bind_to_telnet_port(char type, int *socketdescriptor)
switch(type)
{
case SOCKET:
case TELNET:
port_init = 4711;
break;
case API:
port_init = 4747;
break;
default:
logg("Incompatible socket type %i", (int)type);
exit(EXIT_FAILURE);
@@ -110,7 +107,7 @@ void bind_to_telnet_port(char type, int *socketdescriptor)
exit(EXIT_FAILURE);
}
if(type == SOCKET)
if(type == TELNET)
saveport(port);
// The listen system call allows the process to listen on the socket for connections
@@ -119,18 +116,8 @@ void bind_to_telnet_port(char type, int *socketdescriptor)
logg("Error on listening");
exit(EXIT_FAILURE);
}
switch(type)
{
case SOCKET:
logg("Listening on port %i for incoming socket connections", port);
break;
case API:
logg("Listening on port %i for incoming API connections", port);
break;
default:
/* That cannot happen */
break;
}
logg("Listening on port %i for incoming telnet connections", port);
}
@@ -243,11 +230,6 @@ void close_unix_socket(void)
close(socketfd);
}
void close_api_socket(void)
{
close(apifd);
}
void *telnet_connection_handler_thread(void *socket_desc)
{
//Get the socket descriptor
@@ -276,7 +258,7 @@ void *telnet_connection_handler_thread(void *socket_desc)
// Requests should not be processed/answered when data is about to change
enable_thread_lock(threadname);
process_socket_request(message, &sock);
process_request(message, &sock, TELNET);
free(message);
// Release thread lock
@@ -334,7 +316,7 @@ void *socket_connection_handler_thread(void *socket_desc)
// Requests should not be processed/answered when data is about to change
enable_thread_lock(threadname);
process_socket_request(message, &sock);
process_request(message, &sock, SOCKET);
free(message);
// Release thread lock
@@ -381,7 +363,7 @@ void *telnet_listening_thread(void *args)
prctl(PR_SET_NAME,"telnet listener",0,0,0);
// Initialize sockets only after initial log parsing in listenting_thread
bind_to_telnet_port(SOCKET, &telnetfd);
bind_to_telnet_port(TELNET, &telnetfd);
// Listen as long as FTL is not killed
while(!killed)
@@ -443,159 +425,3 @@ void *socket_listening_thread(void *args)
}
return 0;
}
void *api_connection_handler_thread(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
// Store copy only for displaying the debug messages
int sockID = sock;
char client_message[SOCKETBUFFERLEN] = "";
// Set thread name
char threadname[16];
sprintf(threadname,"api-%i",sockID);
prctl(PR_SET_NAME,threadname,0,0,0);
//Receive from client
if(recv(sock, client_message, SOCKETBUFFERLEN-1, 0) > 0)
{
char *message = calloc(strlen(client_message)+1,sizeof(char));
strcpy(message, client_message);
// Clear client message receive buffer
memset(client_message, 0, sizeof client_message);
if(debug)
logg("Received API request: \n%s", message);
if(strncmp(message, "GET ", 4) == 0 || strncmp(message, "POST ", 5) == 0 || strncmp(message, "DELETE ", 7) == 0)
{
// HTTP requests can be simple or full.
// A simple request contains one line only, and looks like this:
// GET /index.html
// A full request can contain more than one line and may look like this:
// GET /index.html HTTP/1.1
// User-Agent: Wget/1.16 (linux-gnueabihf)
// Accept: */*
// Host: 127.0.0.1:4747
// Connection: Keep-Alive
bool header = false;
// Extract requested URL including arguments
const char *p2;
if(strstr(message, "HTTP/") != NULL)
{
// Output HTTP response headers only if we have a full request
header = true;
// End of request = "HTTP/"
p2 = strstr(message, " HTTP/");
}
else
{
// End of requst = end of first line
p2 = strstr(message, "\n");
}
if(p2 != NULL)
{
size_t len = p2 - message;
char *request = calloc(len+1, sizeof(char));
strncpy(request, message, len);
request[len] = '\0';
// Are we asked for a favicon?
if(strstr(request, "/favicon.ico") != NULL)
ssend(sock, "HTTP/1.0 404 Not Found\nServer: FTL\n\n");
else
{
enable_thread_lock(threadname);
process_api_request(request, message, &sock, header);
disable_thread_lock(threadname);
}
// Free allocated memory
free(request);
}
else
{
logg("API received malformated request: \"%s\"", message);
}
}
else if(strncmp(message, "OPTIONS ", 8) == 0)
{
// OPTIONS request: CORS preflight
ssend(sock, "HTTP/1.0 200 OK\nServer: FTL\nAccess-Control-Allow-Origin: *\n"
"Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS\n"
"Access-Control-Allow-Headers: Content-Type\n\n");
}
else if(strncmp(message, "HEAD ", 5) == 0)
{
// HEAD request: We do not send any content at all
ssend(sock, "HTTP/1.0 200 OK\nServer: FTL\n\n");
}
else
{
if(debug)
logg("API received something strange");
}
// Close connection to show that we reached the end of the transmission
close(sock);
sock = 0;
// Free allocated memory
free(message);
}
//Free the socket pointer
if(sock != 0)
close(sock);
free(socket_desc);
if(clientip[sock] != NULL) {
free(clientip[sock]);
clientip[sock] = NULL;
}
return 0;
}
void *api_listening_thread(void *args)
{
int *newsock;
// We will use the attributes object later to start all threads in detached mode
pthread_attr_t attr;
// Initialize thread attributes object with default attribute values
pthread_attr_init(&attr);
// When a detached thread terminates, its resources are automatically released back to
// the system without the need for another thread to join with the terminated thread
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// Set thread name
prctl(PR_SET_NAME,"API listener",0,0,0);
// Initialize sockets only after initial log parsing in listening_thread
bind_to_telnet_port(API, &apifd);
// Listen as long as FTL is not killed
while(!killed)
{
// Look for new clients that want to connect
int csck = listener(apifd);
if(csck < 0) continue;
// Allocate memory used to transport client socket ID to client listening thread
newsock = calloc(1,sizeof(int));
*newsock = csck;
pthread_t api_connection_thread;
// Create a new thread
if(pthread_create( &api_connection_thread, &attr, api_connection_handler_thread, (void*) newsock ) != 0)
{
// Log the error code description
logg("WARNING: Unable to open client API thread, error: %s", strerror(errno));
}
}
return 0;
}
-10
View File
@@ -9,7 +9,6 @@
* Please see LICENSE file for your rights under this license. */
#include "FTL.h"
#include "api.h"
FTLFileNamesStruct FTLfiles = {
"/etc/pihole/pihole-FTL.conf",
@@ -120,15 +119,6 @@ void memory_check(int which)
exit(EXIT_FAILURE);
}
break;
case AUTHDATA:
// Always called when we need one more entry, like wildcard
logg_struct_resize("authdata", authLength+1, 1);
authData = realloc(authData, (authLength+1) * sizeof(AuthData));
if(authData == NULL) {
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
default:
/* That cannot happen */
break;
+1 -1
View File
@@ -60,7 +60,7 @@ git submodule add https://github.com/ztombol/bats-support test/libs/bats-support
# Block until FTL is ready, retry once per second for 45 seconds
n=0
until [ $n -ge 45 ]; do
(nc -vv -z -w 30 127.0.0.1 4711 && nc -vv -z -w 30 127.0.0.1 4747) && break
nc -vv -z -w 30 127.0.0.1 4711 && break
n=$[$n+1]
echo "..."
tail -n2 pihole-FTL.log
+11 -57
View File
@@ -183,52 +183,6 @@ load 'libs/bats-support/load'
[[ "${lines[@]}" == *"INSERT INTO \"ftl\" VALUES(0,1);"* ]]
}
@test "HTTP server: FTL responding correctly to HEAD request" {
run bash -c "curl --head -s 127.0.0.1:4747"
echo "output: ${lines[@]}"
echo "curl exit code: ${status}"
[[ ${lines[0]} == "HTTP/1.0 200 OK" ]]
[[ ${lines[1]} == "Server: FTL" ]]
[[ ${lines[2]} == "" ]]
[[ "${status}" -eq 0 ]]
}
@test "HTTP server: FTL responding correctly to GET request" {
run bash -c "curl -s 127.0.0.1:4747"
echo "output: ${lines[@]}"
echo "curl exit code: ${status}"
[[ "${status}" -eq 0 ]]
}
@test "API: Correct answer to summary request (including header check)" {
run bash -c "curl -si 127.0.0.1:4747/stats/summary"
echo "output: ${lines[@]}"
echo "curl exit code: ${status}"
[[ ${lines[0]} == "HTTP/1.0 200 OK" ]]
[[ ${lines[1]} == "Server: FTL" ]]
[[ ${lines[2]} == "Cache-Control: no-cache" ]]
[[ ${lines[3]} == "Access-Control-Allow-Origin: *" ]]
[[ ${lines[4]} == "Content-Type: application/json" ]]
[[ ${lines[5]} == "{\"domains_being_blocked\":-1,\"dns_queries_today\":7,\"ads_blocked_today\":2,\"ads_percentage_today\":28.5714,\"unique_domains\":6,\"queries_forwarded\":3,\"queries_cached\":2,\"clients_ever_seen\":3,\"unique_clients\":3,\"status\":\"unknown\"}" ]]
[[ "${status}" -eq 0 ]]
}
#@test "API: Correct answer to top_domains request" {
# run bash -c "curl -s 127.0.0.1:4747/stats/top_domains"
# echo "output: ${lines[@]}"
# echo "curl exit code: ${status}"
# [[ ${lines[0]} == "{\"top_domains\":{\"play.google.com\":2,\"example.com\":1,\"checkip.dyndns.org\":1,\"raspberrypi\":1},\"dns_queries_today\":7}" ]]
# [[ "${status}" -eq 0 ]]
#}
#@test "API: Correct answer to top_ads request" {
# run bash -c "curl -s 127.0.0.1:4747/stats/top_ads"
# echo "output: ${lines[@]}"
# echo "curl exit code: ${status}"
# [[ ${lines[0]} == "{\"top_ads\":{\"addomain.com\":1,\"blacklisted.com\":1},\"ads_blocked_today\":2}" ]]
# [[ "${status}" -eq 0 ]]
#}
@test "Arguments check: Invalid option" {
run bash -c './pihole-FTL abc'
echo "output: ${lines[@]}"
@@ -247,17 +201,17 @@ load 'libs/bats-support/load'
echo "output: ${lines[@]}"
[[ ${lines[0]} == "Socket created" ]]
[[ ${lines[1]} == "Connection established" ]]
[[ ${lines[2]} == "domains_being_blocked -1" ]]
[[ ${lines[3]} == "dns_queries_today 7" ]]
[[ ${lines[4]} == "ads_blocked_today 2" ]]
[[ ${lines[5]} == "ads_percentage_today 28.571428" ]]
[[ ${lines[6]} == "unique_domains 6" ]]
[[ ${lines[7]} == "queries_forwarded 3" ]]
[[ ${lines[8]} == "queries_cached 2" ]]
[[ ${lines[9]} == "clients_ever_seen 3" ]]
[[ ${lines[10]} == "unique_clients 3" ]]
[[ ${lines[11]} == "status unknown" ]]
[[ ${lines[12]} == "---EOM---" ]]
# [[ ${lines[2]} == "domains_being_blocked -1" ]]
# [[ ${lines[3]} == "dns_queries_today 7" ]]
# [[ ${lines[4]} == "ads_blocked_today 2" ]]
# [[ ${lines[5]} == "ads_percentage_today 28.571428" ]]
# [[ ${lines[6]} == "unique_domains 6" ]]
# [[ ${lines[7]} == "queries_forwarded 3" ]]
# [[ ${lines[8]} == "queries_cached 2" ]]
# [[ ${lines[9]} == "clients_ever_seen 3" ]]
# [[ ${lines[10]} == "unique_clients 3" ]]
# [[ ${lines[11]} == "status unknown" ]]
[[ ${lines[2]} == "---EOM---" ]]
}
@test "Final part of the tests: Killing pihole-FTL process" {