-
-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use MessagePack for the Unix socket API #75
Changes from 106 commits
941dfb2
38c706d
3b99d82
03fc5be
e159b56
19c54b0
35a1882
a4fc933
d7d57a8
f84b461
0ef2256
b2688bf
1d29630
7617293
5f59aff
e20fe2a
b15f537
1481176
824b9e9
4643f97
2b439cf
776bf43
7af31af
0e7f484
249b9e9
ea0a7cc
9cff885
f2f9601
48d355b
b5c500f
2179f5d
b868c56
2aa2ff1
9d891d5
70e3b5d
38ea0a7
942250e
30a3f7e
59fe873
5df3233
ecc2ef3
446a1b9
cce43dc
1905f9c
0e3f8b5
7cef472
364ad81
c8f349d
cb9d1cd
a06ecba
693e69b
6cab551
c29ce3b
3f330dd
f8072a0
ec47c81
17a7823
9893ef6
5df0395
0dfb855
f566fd3
bbb3df2
cfea5cf
542e26c
5693b72
e0f462e
08391f4
52d3364
7c88707
ccbf0ee
32c2a41
c9de13b
0a6f5a5
345ac16
4762b8a
f64251e
551351b
ebe0631
9b98101
9ec7bd8
2f8e540
3a5752d
a743931
87dc82c
1893aa5
06be1c4
729d5d4
fb574f7
4842c16
834a959
e5c4d19
e2f2f0d
3331c42
604ad7e
3573f54
894bd39
1f5ca04
4e90a6e
2212e23
5005f28
ae81270
cd2fd11
f15b9ed
636183b
c9e40a4
6050aa5
8adb3d3
f62f9f0
3d78cc3
595ab25
620bb44
97f6ac5
c0048e9
e527985
439227a
b5c9c6e
616b10a
203cc94
f0793be
e54b391
c0022a9
adfcacc
c6369dd
4eaf794
4386138
348a2ee
7d3dfb6
e07786e
05f8604
00f8877
33dd350
3f1ffaf
555a0cb
55e18ea
81200a2
89ea996
7d0f680
0814339
779a824
bd63981
2671a6f
64a1408
f90f6c8
dde1602
1482742
43716b4
da7c354
30ae391
4ed20a4
37360bb
f02c4e8
b9780dc
7d87722
3158f17
cf2aff7
071f924
1983d3d
700a21b
353e0cb
0013edb
31c422e
9b8b232
c88af99
d3d7098
cf0cdfe
7c57b86
1fd7ade
232507a
0aee819
df3b049
996689f
9f5ae62
590f1f9
173efff
76aff45
ad99f97
4e8027b
be5815f
9007af7
42bf9a4
b6b7b57
9bc0562
5341b18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ | |
#include <time.h> | ||
#include <sys/time.h> | ||
#include <sys/socket.h> | ||
#include <regex.h> | ||
// struct sockaddr_in | ||
#include <netinet/in.h> | ||
// char* inet_ntoa(struct in_addr in) | ||
|
@@ -66,6 +67,9 @@ | |
// Default -60 (one minute before a full hour) | ||
#define GCdelay (-60) | ||
|
||
// How many client connection do we accept at once? | ||
#define MAXCONNS 20 | ||
|
||
// Static structs | ||
typedef struct { | ||
const char* conf; | ||
|
@@ -82,6 +86,7 @@ typedef struct { | |
const char* whitelist; | ||
const char* blacklist; | ||
const char* setupVars; | ||
const char* dnsmasqconf; | ||
const char* wildcards; | ||
const char* auditlist; | ||
const char* dnsmasqconfig; | ||
|
@@ -186,8 +191,9 @@ typedef struct { | |
int querytypedata; | ||
} memoryStruct; | ||
|
||
enum { QUERIES, FORWARDED, CLIENTS, DOMAINS, OVERTIME, WILDCARD }; | ||
enum { SOCKET }; | ||
enum { QUERIES, FORWARDED, CLIENTS, DOMAINS, OVERTIME, WILDCARD, AUTHDATA }; | ||
enum { SOCKET, API, APIH }; | ||
enum { WHITELIST, BLACKLIST, WILDLIST }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might not be needed as well. |
||
|
||
logFileNamesStruct files; | ||
FTLFileNamesStruct FTLfiles; | ||
|
@@ -231,3 +237,4 @@ long int lastdbindex; | |
bool travis; | ||
bool DBdeleteoldqueries; | ||
bool rereadgravity; | ||
char * clientip[MAXCONNS]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might even want to get rid of all of this as we aren't implementing an authentication directly in |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
/* Pi-hole: A black hole for Internet advertisements | ||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net) | ||
* Network-wide ad blocking via your own hardware. | ||
* | ||
* FTL Engine | ||
* General API commands | ||
* | ||
* 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 "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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks dangerous. Doesn't this read |
||
// 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; | ||
int result; | ||
|
||
result = regcomp(®ex, regex_expression, REG_EXTENDED); | ||
|
||
if(result != 0) { | ||
logg("Failed to compile regex"); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
result = regexec(®ex, input, 0, NULL, 0); | ||
regfree(®ex); | ||
|
||
return result == 0; | ||
} | ||
|
||
bool isValidDomain(char *domain) { | ||
char *valid_chars_regex = "^((-|_)*[a-z0-9]((-|_)*[a-z0-9])*(-|_)*)(\\.(-|_)*([a-z0-9]((-|_)*[a-z0-9])*))*$"; | ||
char *total_length_regex = "^.{1,253}$"; | ||
char *label_length_regex = "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$"; | ||
|
||
return matchesRegex(valid_chars_regex, domain) && | ||
matchesRegex(total_length_regex, domain) && | ||
matchesRegex(label_length_regex, domain); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* Pi-hole: A black hole for Internet advertisements | ||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net) | ||
* Network-wide ad blocking via your own hardware. | ||
* | ||
* FTL Engine | ||
* API commands and structures | ||
* | ||
* This file is copyright under the latest version of the EUPL. | ||
* Please see LICENSE file for your rights under this license. */ | ||
|
||
// Endpoints under /stats/ | ||
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); | ||
|
||
// Endpoints under /dns/ | ||
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still use any subroutine from the regex.h header?