Merge branch 'development-v6' into tweak/domain_array

This commit is contained in:
DL6ER
2023-10-13 20:12:03 +02:00
26 changed files with 236 additions and 110 deletions
+1
View File
@@ -7,5 +7,6 @@ patch -p1 < patch/civetweb/0001-Always-Kepler-syntax-for-Lua-server-pages.patch
patch -p1 < patch/civetweb/0001-Add-FTL-URI-rewriting-changes-to-CivetWeb.patch
patch -p1 < patch/civetweb/0001-Add-mbedTLS-debug-logging-hook.patch
patch -p1 < patch/civetweb/0001-Register-CSRF-token-in-conn-request_info.patch
patch -p1 < patch/civetweb/0001-Do-not-try-to-guess-server-hostname-in-Civetweb-when.patch
echo "ALL PATCHES APPLIED OKAY"
@@ -0,0 +1,29 @@
From e41d902b5b01896360e1235aebabd3eb352158aa Mon Sep 17 00:00:00 2001
From: DL6ER <dl6er@dl6er.de>
Date: Sun, 8 Oct 2023 14:31:20 +0200
Subject: [PATCH] Do not try to guess server hostname in Civetweb when
redirecting directory URIs to end with a slash
Signed-off-by: DL6ER <dl6er@dl6er.de>
---
src/webserver/civetweb/civetweb.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/webserver/civetweb/civetweb.c b/src/webserver/civetweb/civetweb.c
index f44b17ba..3df8eab9 100644
--- a/src/webserver/civetweb/civetweb.c
+++ b/src/webserver/civetweb/civetweb.c
@@ -15306,7 +15306,9 @@ handle_request(struct mg_connection *conn)
if (!new_path) {
mg_send_http_error(conn, 500, "out or memory");
} else {
- mg_get_request_link(conn, new_path, buflen - 1);
+ /* Pi-hole modification */
+ //mg_get_request_link(conn, new_path, buflen - 1);
+ strcpy(new_path, ri->local_uri_raw);
strcat(new_path, "/");
if (ri->query_string) {
/* Append ? and query string */
--
2.34.1
+1
View File
@@ -44,6 +44,7 @@ static struct {
{ "/api/groups", "/{name}", api_list, { false, true, 0 }, true, HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_DELETE },
{ "/api/lists", "/{list}", api_list, { false, true, 0 }, true, HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_DELETE },
{ "/api/info/client", "", api_info_client, { false, true, 0 }, false, HTTP_GET },
{ "/api/info/login", "", api_info_login, { false, true, 0 }, false, HTTP_GET },
{ "/api/info/system", "", api_info_system, { false, true, 0 }, true, HTTP_GET },
{ "/api/info/database", "", api_info_database, { false, true, 0 }, true, HTTP_GET },
{ "/api/info/sensors", "", api_info_sensors, { false, true, 0 }, true, HTTP_GET },
+1
View File
@@ -60,6 +60,7 @@ int api_info_version(struct ftl_conn *api);
int api_info_messages_count(struct ftl_conn *api);
int api_info_messages(struct ftl_conn *api);
int api_info_metrics(struct ftl_conn *api);
int api_info_login(struct ftl_conn *api);
// Config methods
int api_config(struct ftl_conn *api);
-4
View File
@@ -302,7 +302,6 @@ static int get_all_sessions(struct ftl_conn *api, cJSON *json)
static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_id, const time_t now)
{
cJSON *session = JSON_NEW_OBJECT();
const bool dns = get_blockingstatus() != DNS_FAILED;
// Authentication not needed
if(user_id == API_AUTH_LOCALHOST || user_id == API_AUTH_EMPTYPASS)
@@ -312,7 +311,6 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
JSON_ADD_NULL_TO_OBJECT(session, "sid");
JSON_ADD_NUMBER_TO_OBJECT(session, "validity", -1);
JSON_ADD_ITEM_TO_OBJECT(json, "session", session);
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
return 0;
}
@@ -325,7 +323,6 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
JSON_REF_STR_IN_OBJECT(session, "csrf", auth_data[user_id].csrf);
JSON_ADD_NUMBER_TO_OBJECT(session, "validity", auth_data[user_id].valid_until - now);
JSON_ADD_ITEM_TO_OBJECT(json, "session", session);
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
return 0;
}
@@ -335,7 +332,6 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
JSON_ADD_NULL_TO_OBJECT(session, "sid");
JSON_ADD_NUMBER_TO_OBJECT(session, "validity", -1);
JSON_ADD_ITEM_TO_OBJECT(json, "session", session);
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
return 0;
}
+1 -19
View File
@@ -26,8 +26,6 @@ components:
$ref: 'auth.yaml#/components/examples/no_login_required'
login_required:
$ref: 'auth.yaml#/components/examples/login_required'
dns_failure:
$ref: 'auth.yaml#/components/examples/dns_failure'
post:
summary: Submit password for login
tags:
@@ -157,6 +155,7 @@ components:
tags:
- Authentication
operationId: "get_auth_totp"
security: []
description: Suggest new TOTP credentials for two-factor authentication (2FA)
responses:
'200':
@@ -245,9 +244,6 @@ components:
validity:
type: integer
description: Remaining lifetime of this session unless refreshed (seconds)
dns:
type: boolean
description: Whether the DNS server is up and running. False only in failed state
password:
type: object
@@ -371,7 +367,6 @@ components:
sid: null
csrf: null
validity: 300
dns: true
no_login_required:
summary: No login required for this client
value:
@@ -381,7 +376,6 @@ components:
sid: null
csrf: null
validity: -1
dns: true
login_required:
summary: Login required
value:
@@ -391,7 +385,6 @@ components:
sid: null
csrf: null
validity: -1
dns: true
login_failed:
summary: Login failed
value:
@@ -401,17 +394,6 @@ components:
sid: null
csrf: null
validity: -1
dns: true
dns_failure:
summary: DNS server failure
value:
session:
valid: false
totp: false
sid: null
csrf: null
validity: -1
dns: false
errors:
no_payload:
summary: Bad request (no valid JSON payload)
+28
View File
@@ -6,6 +6,7 @@ components:
summary: Get information about requesting client
tags:
- "FTL information"
security: []
operationId: "get_client"
description: |
The property `timer` may contain additional details concerning a temporary en-/disabling.
@@ -278,6 +279,24 @@ components:
allOf:
- $ref: 'common.yaml#/components/errors/unauthorized'
- $ref: 'common.yaml#/components/schemas/took'
login:
get:
summary: Login page related information
tags:
- "FTL information"
operationId: "get_logininfo"
security: []
description: |
This API hook returns information used on the login page to possibly display messages/warnings.
responses:
'200':
description: OK
content:
application/json:
schema:
allOf:
- $ref: 'info.yaml#/components/schemas/login'
- $ref: 'common.yaml#/components/schemas/took'
schemas:
client:
@@ -1068,6 +1087,15 @@ components:
type: integer
description: Number of items
example: 42
login:
type: object
properties:
https_port:
type: integer
description: HTTPS port of the Pi-hole webserver (0 if disabled)
dns:
type: boolean
description: Whether the DNS server is up and running. False only in failed state
examples:
errors:
messages:
+3
View File
@@ -190,6 +190,9 @@ paths:
/info/metrics:
$ref: 'info.yaml#/components/paths/metrics'
/info/login:
$ref: 'info.yaml#/components/paths/login'
/logs/dnsmasq:
$ref: 'logs.yaml#/components/paths/logs/dnsmasq'
+1
View File
@@ -15,6 +15,7 @@ int api_docs(struct ftl_conn *api)
// Handle resource request by redirecting to "/"
if(strcmp(api->request->request_uri, "/api/docs") == 0)
{
log_debug(DEBUG_API, "Redirecting /api/docs --301--> /api/docs/");
mg_send_http_redirect(api->conn, "/api/docs/", 301);
}
+15
View File
@@ -49,6 +49,9 @@
#include <limits.h>
#include "metrics.h"
// get_https_port()
#include "webserver/webserver.h"
// DIR
#include <dirent.h>
@@ -1032,3 +1035,15 @@ int api_info_metrics(struct ftl_conn *api)
JSON_ADD_ITEM_TO_OBJECT(json2, "metrics", json);
JSON_SEND_OBJECT(json2);
}
int api_info_login(struct ftl_conn *api)
{
cJSON *json = JSON_NEW_OBJECT();
const bool dns = get_blockingstatus() != DNS_FAILED;
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
JSON_ADD_NUMBER_TO_OBJECT(json, "https_port", get_https_port());
JSON_SEND_OBJECT(json);
}
+8 -6
View File
@@ -311,18 +311,20 @@ void parse_args(int argc, char* argv[])
if(argc > 1 && strcmp(argv[1], "--gen-x509") == 0)
{
if(argc != 3 && argc != 4)
if(argc < 3 || argc > 5)
{
printf("Usage: %s --gen-x509 <output file> [rsa]\n", argv[0]);
printf("Example: %s --gen-x509 /etc/pihole/tls.pem\n", argv[0]);
printf(" or: %s --gen-x509 /etc/pihole/tls.pem rsa\n", argv[0]);
printf("Usage: %s --gen-x509 <output file> [<domain>] [rsa]\n", argv[0]);
printf("Example: %s --gen-x509 /etc/pihole/tls.pem\n", argv[0]);
printf(" with domain: %s --gen-x509 /etc/pihole/tls.pem pi.hole\n", argv[0]);
printf(" RSA with domain: %s --gen-x509 /etc/pihole/tls.pem nanopi.lan rsa\n", argv[0]);
exit(EXIT_FAILURE);
}
// Enable stdout printing
cli_mode = true;
log_ctrl(false, true);
const bool rsa = argc == 4 && strcasecmp(argv[3], "rsa") == 0;
exit(generate_certificate(argv[2], rsa) ? EXIT_SUCCESS : EXIT_FAILURE);
const char *domain = argc > 3 ? argv[3] : "pi.hole";
const bool rsa = argc > 4 && strcasecmp(argv[4], "rsa") == 0;
exit(generate_certificate(argv[2], rsa, domain) ? EXIT_SUCCESS : EXIT_FAILURE);
}
// If the first argument is "gravity" (e.g., /usr/bin/pihole-FTL gravity),
+2 -1
View File
@@ -509,7 +509,8 @@ void initConfig(struct config *conf)
{ "LOCAL", "Allow only local requests. This setting accepts DNS queries only from hosts whose address is on a local subnet, i.e., a subnet for which an interface exists on the server. It is intended to be set as a default on installation, to allow unconfigured installations to be useful but also safe from being used for DNS amplification attacks if (accidentally) running public." },
{ "SINGLE", "Permit all origins, accept only on the specified interface. Respond only to queries arriving on the specified interface. The loopback (lo) interface is automatically added to the list of interfaces to use when this option is used. Make sure your Pi-hole is properly firewalled!" },
{ "BIND", "By default, FTL binds the wildcard address. If this is not what you want, you can use this option as it forces FTL to really bind only the interfaces it is listening on. Note that this may result in issues when the interface may go down (cable unplugged, etc.). About the only time when this is useful is when running another nameserver on the same port on the same machine. This may also happen if you run a virtualization API such as libvirt. When this option is used, IP alias interface labels (e.g. enp2s0:0) are checked rather than interface names." },
{ "ALL", "Permit all origins, accept on all interfaces. Make sure your Pi-hole is properly firewalled! This truly allows any traffic to be replied to and is a dangerous thing to do as your Pi-hole could become an open resolver. You should always ask yourself if the first option doesn't work for you as well." }
{ "ALL", "Permit all origins, accept on all interfaces. Make sure your Pi-hole is properly firewalled! This truly allows any traffic to be replied to and is a dangerous thing to do as your Pi-hole could become an open resolver. You should always ask yourself if the first option doesn't work for you as well." },
{ "NONE", "Do not add any configuration concerning the listening mode to the dnsmasq configuration file. This is useful if you want to manually configure the listening mode in auxiliary configuration files. This option is really meant for advanced users only, support for this option may be limited." }
};
CONFIG_ADD_ENUM_OPTIONS(conf->dns.listeningMode.a, listeningMode);
}
+3
View File
@@ -360,6 +360,9 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_
fprintf(pihole_conf, "interface=%s\n", interface);
fputs("bind-interfaces\n", pihole_conf);
break;
case LISTEN_NONE:
fputs("# No interface configuration applied, make sure to cover this yourself\n", pihole_conf);
break;
}
fputs("\n", pihole_conf);
+7 -2
View File
@@ -2207,9 +2207,14 @@ bool gravityDB_readTableGetRow(const enum gravity_list_type listtype, tablerow *
// Convert to string
if(listtype == GRAVITY_DOMAINLIST_ALLOW_EXACT ||
listtype == GRAVITY_DOMAINLIST_DENY_EXACT ||
listtype == GRAVITY_DOMAINLIST_ALLOW_REGEX ||
listtype == GRAVITY_DOMAINLIST_DENY_REGEX)
listtype == GRAVITY_DOMAINLIST_ALLOW_ALL ||
listtype == GRAVITY_DOMAINLIST_DENY_EXACT ||
listtype == GRAVITY_DOMAINLIST_DENY_REGEX ||
listtype == GRAVITY_DOMAINLIST_DENY_ALL ||
listtype == GRAVITY_DOMAINLIST_ALL_EXACT ||
listtype == GRAVITY_DOMAINLIST_ALL_REGEX ||
listtype == GRAVITY_DOMAINLIST_ALL_ALL)
{
switch(row->type_int)
{
+1 -1
View File
@@ -1262,7 +1262,7 @@ static void shellDtostr(
char z[400];
if( n<1 ) n = 1;
if( n>350 ) n = 350;
sprintf(z, "%#+.*e", n, r);
snprintf(z, sizeof(z)-1, "%#+.*e", n, r);
sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
}
+26 -19
View File
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.43.1. By combining all the individual C code files into this
** version 3.43.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
** d3a40c05c49e1a49264912b1a05bc2143ac.
** 310099cce5a487035fa535dd3002c59ac7f.
*/
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
@@ -459,9 +459,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.43.1"
#define SQLITE_VERSION_NUMBER 3043001
#define SQLITE_SOURCE_ID "2023-09-11 12:01:27 2d3a40c05c49e1a49264912b1a05bc2143ac0e7c3df588276ce80a4cbc9bd1b0"
#define SQLITE_VERSION "3.43.2"
#define SQLITE_VERSION_NUMBER 3043002
#define SQLITE_SOURCE_ID "2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -35185,29 +35185,29 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou
double rr[2];
rr[0] = r;
rr[1] = 0.0;
if( rr[0]>1.84e+19 ){
while( rr[0]>1.84e+119 ){
if( rr[0]>9.223372036854774784e+18 ){
while( rr[0]>9.223372036854774784e+118 ){
exp += 100;
dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
}
while( rr[0]>1.84e+29 ){
while( rr[0]>9.223372036854774784e+28 ){
exp += 10;
dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
}
while( rr[0]>1.84e+19 ){
while( rr[0]>9.223372036854774784e+18 ){
exp += 1;
dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
}else{
while( rr[0]<1.84e-82 ){
while( rr[0]<9.223372036854774784e-83 ){
exp -= 100;
dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
}
while( rr[0]<1.84e+08 ){
while( rr[0]<9.223372036854774784e+07 ){
exp -= 10;
dekkerMul2(rr, 1.0e+10, 0.0);
}
while( rr[0]<1.84e+18 ){
while( rr[0]<9.22337203685477478e+17 ){
exp -= 1;
dekkerMul2(rr, 1.0e+01, 0.0);
}
@@ -77024,6 +77024,7 @@ static int rebuildPage(
int k; /* Current slot in pCArray->apEnd[] */
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
assert( nCell>0 );
assert( i<iEnd );
j = get2byte(&aData[hdr+5]);
if( NEVER(j>(u32)usableSize) ){ j = 0; }
@@ -77330,6 +77331,7 @@ static int editPage(
return SQLITE_OK;
editpage_fail:
/* Unable to edit this page. Rebuild it from scratch instead. */
if( nNew<1 ) return SQLITE_CORRUPT_BKPT;
populateCellCache(pCArray, iNew, nNew);
return rebuildPage(pCArray, iNew, nNew, pPg);
}
@@ -100833,8 +100835,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
/* Set the value of register r[1] in the SQL statement to integer iRow.
** This is done directly as a performance optimization
*/
v->aMem[1].flags = MEM_Int;
v->aMem[1].u.i = iRow;
sqlite3VdbeMemSetInt64(&v->aMem[1], iRow);
/* If the statement has been run before (and is paused at the OP_ResultRow)
** then back it up to the point where it does the OP_NotExists. This could
@@ -204134,6 +204135,7 @@ static void jsonReplaceFunc(
}
pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
if( pParse==0 ) return;
pParse->nJPRef++;
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
pParse->useMod = 1;
@@ -204146,6 +204148,7 @@ static void jsonReplaceFunc(
jsonReturnJson(pParse, pParse->aNode, ctx, 1);
replace_err:
jsonDebugPrintParse(pParse);
jsonParseFree(pParse);
}
@@ -204180,6 +204183,7 @@ static void jsonSetFunc(
}
pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
if( pParse==0 ) return;
pParse->nJPRef++;
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
bApnd = 0;
@@ -204196,9 +204200,8 @@ static void jsonSetFunc(
}
jsonDebugPrintParse(pParse);
jsonReturnJson(pParse, pParse->aNode, ctx, 1);
jsonSetDone:
/* no cleanup required */;
jsonParseFree(pParse);
}
/*
@@ -239687,7 +239690,6 @@ static void fts5DoSecureDelete(
int iIdx = 0;
int iStart = 0;
int iKeyOff = 0;
int iPrevKeyOff = 0;
int iDelKeyOff = 0; /* Offset of deleted key, if any */
nIdx = nPg-iPgIdx;
@@ -244249,6 +244251,9 @@ static int fts5FilterMethod(
pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
}
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
if( rc!=SQLITE_OK ) goto filter_out;
if( pTab->pSortCsr ){
/* If pSortCsr is non-NULL, then this call is being made as part of
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
@@ -244271,7 +244276,9 @@ static int fts5FilterMethod(
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
}else if( pCsr->pExpr ){
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
if( rc==SQLITE_OK ){
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
}
if( rc==SQLITE_OK ){
if( bOrderByRank ){
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
@@ -245752,7 +245759,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2023-09-11 12:01:27 2d3a40c05c49e1a49264912b1a05bc2143ac0e7c3df588276ce80a4cbc9bd1b0", -1, SQLITE_TRANSIENT);
sqlite3_result_text(pCtx, "fts5: 2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790", -1, SQLITE_TRANSIENT);
}
/*
+3 -3
View File
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.43.1"
#define SQLITE_VERSION_NUMBER 3043001
#define SQLITE_SOURCE_ID "2023-09-11 12:01:27 2d3a40c05c49e1a49264912b1a05bc2143ac0e7c3df588276ce80a4cbc9bd1b0"
#define SQLITE_VERSION "3.43.2"
#define SQLITE_VERSION_NUMBER 3043002
#define SQLITE_SOURCE_ID "2023-10-10 12:14:04 4310099cce5a487035fa535dd3002c59ac7f1d1bec68d7cf317fd3e769484790"
/*
** CAPI3REF: Run-Time Library Version Numbers
+4
View File
@@ -1051,6 +1051,8 @@ const char * __attribute__ ((const)) get_listeningMode_str(const enum listening_
return "SINGLE";
case LISTEN_BIND:
return "BIND";
case LISTEN_NONE:
return "NONE";
}
return NULL;
}
@@ -1065,6 +1067,8 @@ int __attribute__ ((pure)) get_listeningMode_val(const char *listeningMode)
return LISTEN_SINGLE;
else if(strcasecmp(listeningMode, "BIND") == 0)
return LISTEN_BIND;
else if(strcasecmp(listeningMode, "NONE") == 0)
return LISTEN_NONE;
// Invalid value
return -1;
+2 -1
View File
@@ -288,7 +288,8 @@ enum listening_mode {
LISTEN_LOCAL,
LISTEN_ALL,
LISTEN_SINGLE,
LISTEN_BIND
LISTEN_BIND,
LISTEN_NONE
} __attribute__ ((packed));
enum fifo_logs {
+3 -1
View File
@@ -15306,7 +15306,9 @@ handle_request(struct mg_connection *conn)
if (!new_path) {
mg_send_http_error(conn, 500, "out or memory");
} else {
mg_get_request_link(conn, new_path, buflen - 1);
/* Pi-hole modification */
//mg_get_request_link(conn, new_path, buflen - 1);
strcpy(new_path, ri->local_uri_raw);
strcat(new_path, "/");
if (ri->query_string) {
/* Append ? and query string */
+78 -49
View File
@@ -86,6 +86,8 @@ static int redirect_root_handler(struct mg_connection *conn, void *input)
// 308 Permanent Redirect from http://pi.hole -> http://pi.hole/admin
if(strcmp(uri, "/") == 0)
{
log_debug(DEBUG_API, "Redirecting / --308--> %s",
config.webserver.paths.webhome.v.s);
mg_send_http_redirect(conn, config.webserver.paths.webhome.v.s, 308);
return 1;
}
@@ -100,52 +102,23 @@ static int redirect_lp_handler(struct mg_connection *conn, void *input)
// Get requested URI
const struct mg_request_info *request = mg_get_request_info(conn);
const char *uri = request->local_uri_raw;
const size_t uri_len = strlen(uri);
const char *query_string = request->query_string;
const size_t query_len = query_string != NULL ? strlen(query_string) : 0;
// Remove the ".lp" from the URI
char *pos = strstr(uri, ".lp");
char *new_uri = calloc(strlen(uri) + query_len, sizeof(char));
// Copy everything from before the ".lp" to the new URI
strncpy(new_uri, uri, pos - uri);
// We allocate uri_len + query_len - 1 bytes, which is enough for the
// new URI. The calculation is as follows:
// 1. We are saving three bytes by skipping ".lp" at the end of the URI
// 2. We are adding one byte for the trailing '\0'
// 3. We are adding query_len bytes for the query string (if present)
// 4. We are adding one byte for the '?' between URI and query string
// (if present)
// Total bytes required: uri_len - 3 + query_len + 1 + 1
char *new_uri = calloc(uri_len + query_len - 1, sizeof(char));
// Append query string to the new URI if present
if(query_len > 0)
{
strcat(new_uri, "?");
strcat(new_uri, query_string);
}
// Send a 301 redirect to the new URI
log_debug(DEBUG_API, "Redirecting %s?%s ==301==> %s",
uri, query_string, new_uri);
mg_send_http_redirect(conn, new_uri, 301);
free(new_uri);
return 1;
}
static int redirect_slash_handler(struct mg_connection *conn, void *input)
{
// Get requested URI
const struct mg_request_info *request = mg_get_request_info(conn);
const char *uri = request->local_uri_raw;
const char *query_string = request->query_string;
const size_t query_len = query_string != NULL ? strlen(query_string) : 0;
// Do not redirect if the new URI is the webhome
if(strcmp(uri, config.webserver.paths.webhome.v.s) == 0)
{
log_debug(DEBUG_API, "Not redirecting %s?%s",
uri, query_string);
// Handle as a normal request
return request_handler(conn, input);
}
// Remove the trailing slash from the URI
char *new_uri = strdup(uri);
new_uri[strlen(new_uri) - 1] = '\0';
// Copy everything from before the ".lp" to the new URI to effectively
// remove it
strncpy(new_uri, uri, uri_len - 3);
// Append query string to the new URI if present
if(query_len > 0)
@@ -204,6 +177,52 @@ void FTL_mbed_debug(void *user_param, int level, const char *file, int line, con
log_web("mbedTLS(%s:%d, %d): %.*s", file, line, level, (int)len, message);
}
#define MAXPORTS 8
static struct serverports
{
bool is_secure;
unsigned char protocol; // 1 = IPv4, 2 = IPv4+IPv6, 3 = IPv6
in_port_t port;
} server_ports[MAXPORTS] = { 0 };
static in_port_t https_port = 0;
static void get_server_ports(void)
{
if(ctx == NULL)
return;
// Loop over all listening ports
struct mg_server_port mgports[MAXPORTS] = { 0 };
if(mg_get_server_ports(ctx, MAXPORTS, mgports) > 0)
{
// Loop over all ports
for(unsigned int i = 0; i < MAXPORTS; i++)
{
// Stop if no more ports are configured
if(mgports[i].protocol == 0)
break;
// Store port information
server_ports[i].port = mgports[i].port;
server_ports[i].is_secure = mgports[i].is_ssl;
server_ports[i].protocol = mgports[i].protocol;
// Store HTTPS port if not already set
if(mgports[i].is_ssl && https_port == 0)
https_port = mgports[i].port;
// Print port information
log_debug(DEBUG_API, "Listening on port %d (HTTP%s, IPv%s)",
mgports[i].port, mgports[i].is_ssl ? "S" : "",
mgports[i].protocol == 1 ? "4" : (mgports[i].protocol == 3 ? "6" : "4+6"));
}
}
}
in_port_t __attribute__((pure)) get_https_port(void)
{
return https_port;
}
void http_init(void)
{
log_web("Initializing HTTP server on port %s", config.webserver.port.v.s);
@@ -277,17 +296,27 @@ void http_init(void)
strlen(config.webserver.tls.cert.v.s) > 0)
{
// Try to generate certificate if not present
if(!file_readable(config.webserver.tls.cert.v.s) &&
!generate_certificate(config.webserver.tls.cert.v.s, false))
if(!file_readable(config.webserver.tls.cert.v.s))
{
log_err("Generation of SSL/TLS certificate %s failed!",
config.webserver.tls.cert.v.s);
if(generate_certificate(config.webserver.tls.cert.v.s, false, config.webserver.domain.v.s))
{
log_info("Created SSL/TLS certificate for %s at %s",
config.webserver.domain.v.s, config.webserver.tls.cert.v.s);
}
else
{
log_err("Generation of SSL/TLS certificate %s failed!",
config.webserver.tls.cert.v.s);
}
}
if(file_readable(config.webserver.tls.cert.v.s))
{
options[++next_option] = "ssl_certificate";
options[++next_option] = config.webserver.tls.cert.v.s;
log_info("Using SSL/TLS certificate file %s",
config.webserver.tls.cert.v.s);
}
else
{
@@ -330,14 +359,14 @@ void http_init(void)
// Register **.lp -> ** redirect handler
mg_set_request_handler(ctx, "**.lp$", redirect_lp_handler, NULL);
// Register **/ -> ** redirect handler
mg_set_request_handler(ctx, "**/$", redirect_slash_handler, NULL);
// Register handler for the rest
mg_set_request_handler(ctx, "**", request_handler, NULL);
// Prepare prerequisites for Lua
allocate_lua();
// Get server ports
get_server_ports();
}
static char *append_to_path(char *path, const char *append)
+2
View File
@@ -13,4 +13,6 @@
void http_init(void);
void http_terminate(void);
in_port_t get_https_port(void) __attribute__((pure));
#endif // WEBSERVER_H
+10 -2
View File
@@ -78,7 +78,7 @@ static int generate_private_key_ec(mbedtls_pk_context *key,
return 0;
}
bool generate_certificate(const char* certfile, bool rsa)
bool generate_certificate(const char* certfile, bool rsa, const char *domain)
{
int ret;
mbedtls_x509write_cert crt;
@@ -153,13 +153,21 @@ bool generate_certificate(const char* certfile, bool rsa)
mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
mbedtls_x509write_crt_set_subject_key(&crt, &key);
mbedtls_x509write_crt_set_issuer_key(&crt, &key);
mbedtls_x509write_crt_set_subject_name(&crt, "CN=pi.hole");
mbedtls_x509write_crt_set_issuer_name(&crt, "CN=pi.hole");
mbedtls_x509write_crt_set_validity(&crt, "20010101000000", "20301231235959");
mbedtls_x509write_crt_set_basic_constraints(&crt, 0, -1);
mbedtls_x509write_crt_set_subject_key_identifier(&crt);
mbedtls_x509write_crt_set_authority_key_identifier(&crt);
// Set subject name depending on the (optionally) specified domain
{
char *subject_name = calloc(strlen(domain) + 4, sizeof(char));
strcpy(subject_name, "CN=");
strcat(subject_name, domain);
mbedtls_x509write_crt_set_subject_name(&crt, subject_name);
free(subject_name);
}
// Export certificate in PEM format
if((ret = mbedtls_x509write_crt_pem(&crt, cert_buffer, sizeof(cert_buffer),
mbedtls_ctr_drbg_random, &ctr_drbg)) != 0)
+1 -1
View File
@@ -13,6 +13,6 @@
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
bool generate_certificate(const char* certfile, bool rsa);
bool generate_certificate(const char* certfile, bool rsa, const char *domain);
#endif // X509_H
+5
View File
@@ -159,6 +159,11 @@
# properly firewalled! This truly allows any traffic to be replied to and is a
# dangerous thing to do as your Pi-hole could become an open resolver. You
# should always ask yourself if the first option doesn't work for you as well.
# - "NONE"
# Do not add any configuration concerning the listening mode to the dnsmasq
# configuration file. This is useful if you want to manually configure the
# listening mode in auxiliary configuration files. This option is really meant
# for advanced users only, support for this option may be limited.
listeningMode = "LOCAL"
# Log DNS queries and replies to pihole.log
+1 -1
View File
@@ -1266,7 +1266,7 @@
@test "API authorization (without password): No login required" {
run bash -c 'curl -s 127.0.0.1/api/auth'
printf "%s\n" "${lines[@]}"
[[ ${lines[0]} == '{"session":{"valid":true,"totp":false,"sid":null,"validity":-1},"dns":true,"took":'*'}' ]]
[[ ${lines[0]} == '{"session":{"valid":true,"totp":false,"sid":null,"validity":-1},"took":'*'}' ]]
}
@test "API authorization: Setting password" {