15
15
#include "../config.h"
16
16
// logg()
17
17
#include "../log.h"
18
- // match_regex()
19
- #include "../regex_r.h"
20
18
// getstr()
21
19
#include "../shmem.h"
22
20
// SQLite3 prepared statement vectors
23
21
#include "../vector.h"
24
22
// log_subnet_warning()
23
+ // logg_inaccessible_adlist
25
24
#include "message-table.h"
26
25
// getMACfromIP()
27
26
#include "network-table.h"
@@ -210,11 +209,11 @@ bool gravityDB_reopen(void)
210
209
return gravityDB_open ();
211
210
}
212
211
213
- static char * get_client_querystr (const char * table , const char * groups )
212
+ static char * get_client_querystr (const char * table , const char * column , const char * groups )
214
213
{
215
214
// Build query string with group filtering
216
215
char * querystr = NULL ;
217
- if (asprintf (& querystr , "SELECT EXISTS(SELECT domain from %s WHERE domain = ? AND group_id IN (%s));" , table , groups ) < 1 )
216
+ if (asprintf (& querystr , "SELECT %s from %s WHERE domain = ? AND group_id IN (%s);" , column , table , groups ) < 1 )
218
217
{
219
218
logg ("get_client_querystr(%s, %s) - asprintf() error" , table , groups );
220
219
return NULL ;
@@ -858,19 +857,14 @@ bool gravityDB_prepare_client_statements(clientsData *client)
858
857
return false;
859
858
860
859
// Prepare whitelist statement
861
- // We use SELECT EXISTS() as this is known to efficiently use the index
862
- // We are only interested in whether the domain exists or not in the
863
- // list but don't case about duplicates or similar. SELECT EXISTS(...)
864
- // returns true as soon as it sees the first row from the query inside
865
- // of EXISTS().
866
860
if (config .debug & DEBUG_DATABASE )
867
861
logg ("gravityDB_open(): Preparing vw_whitelist statement for client %s" , clientip );
868
- querystr = get_client_querystr ("vw_whitelist" , getstr (client -> groupspos ));
862
+ querystr = get_client_querystr ("vw_whitelist" , "id" , getstr (client -> groupspos ));
869
863
sqlite3_stmt * stmt = NULL ;
870
864
int rc = sqlite3_prepare_v3 (gravity_db , querystr , -1 , SQLITE_PREPARE_PERSISTENT , & stmt , NULL );
871
865
if ( rc != SQLITE_OK )
872
866
{
873
- logg ("gravityDB_open(\"SELECT EXISTS (... vw_whitelist ...)\") - SQL error prepare: %s" , sqlite3_errstr (rc ));
867
+ logg ("gravityDB_open(\"SELECT(... vw_whitelist ...)\") - SQL error prepare: %s" , sqlite3_errstr (rc ));
874
868
gravityDB_close ();
875
869
return false;
876
870
}
@@ -880,11 +874,11 @@ bool gravityDB_prepare_client_statements(clientsData *client)
880
874
// Prepare gravity statement
881
875
if (config .debug & DEBUG_DATABASE )
882
876
logg ("gravityDB_open(): Preparing vw_gravity statement for client %s" , clientip );
883
- querystr = get_client_querystr ("vw_gravity" , getstr (client -> groupspos ));
877
+ querystr = get_client_querystr ("vw_gravity" , "domain" , getstr (client -> groupspos ));
884
878
rc = sqlite3_prepare_v3 (gravity_db , querystr , -1 , SQLITE_PREPARE_PERSISTENT , & stmt , NULL );
885
879
if ( rc != SQLITE_OK )
886
880
{
887
- logg ("gravityDB_open(\"SELECT EXISTS (... vw_gravity ...)\") - SQL error prepare: %s" , sqlite3_errstr (rc ));
881
+ logg ("gravityDB_open(\"SELECT(... vw_gravity ...)\") - SQL error prepare: %s" , sqlite3_errstr (rc ));
888
882
gravityDB_close ();
889
883
return false;
890
884
}
@@ -894,11 +888,11 @@ bool gravityDB_prepare_client_statements(clientsData *client)
894
888
// Prepare blacklist statement
895
889
if (config .debug & DEBUG_DATABASE )
896
890
logg ("gravityDB_open(): Preparing vw_blacklist statement for client %s" , clientip );
897
- querystr = get_client_querystr ("vw_blacklist" , getstr (client -> groupspos ));
891
+ querystr = get_client_querystr ("vw_blacklist" , "id" , getstr (client -> groupspos ));
898
892
rc = sqlite3_prepare_v3 (gravity_db , querystr , -1 , SQLITE_PREPARE_PERSISTENT , & stmt , NULL );
899
893
if ( rc != SQLITE_OK )
900
894
{
901
- logg ("gravityDB_open(\"SELECT EXISTS (... vw_blacklist ...)\") - SQL error prepare: %s" , sqlite3_errstr (rc ));
895
+ logg ("gravityDB_open(\"SELECT(... vw_blacklist ...)\") - SQL error prepare: %s" , sqlite3_errstr (rc ));
902
896
gravityDB_close ();
903
897
return false;
904
898
}
@@ -1146,7 +1140,7 @@ int gravityDB_count(const enum gravity_tables list)
1146
1140
return result ;
1147
1141
}
1148
1142
1149
- static enum db_result domain_in_list (const char * domain , sqlite3_stmt * stmt , const char * listname )
1143
+ static enum db_result domain_in_list (const char * domain , sqlite3_stmt * stmt , const char * listname , int * domain_id )
1150
1144
{
1151
1145
// Do not try to bind text to statement when database is not available
1152
1146
if (!gravityDB_opened && !gravityDB_open ())
@@ -1180,19 +1174,21 @@ static enum db_result domain_in_list(const char *domain, sqlite3_stmt *stmt, con
1180
1174
sqlite3_clear_bindings (stmt );
1181
1175
return LIST_NOT_AVAILABLE ;
1182
1176
}
1183
- else if (rc != SQLITE_ROW )
1177
+ else if (rc != SQLITE_ROW && rc != SQLITE_DONE )
1184
1178
{
1185
- // Any return code that is neither SQLITE_BUSY not SQLITE_ROW
1186
- // is a real error we should log
1179
+ // Any return code that is neither SQLITE_BUSY nor SQLITE_ROW or
1180
+ // SQLITE_DONE is an error we should log
1187
1181
logg ("domain_in_list(\"%s\", %p, %s): Failed to perform step: %s" ,
1188
1182
domain , stmt , listname , sqlite3_errstr (rc ));
1189
1183
sqlite3_reset (stmt );
1190
1184
sqlite3_clear_bindings (stmt );
1191
1185
return LIST_NOT_AVAILABLE ;
1192
1186
}
1193
1187
1194
- // Get result of query "SELECT EXISTS(...)"
1195
- const int result = sqlite3_column_int (stmt , 0 );
1188
+ // Get result of query (if available)
1189
+ const int result = (rc == SQLITE_ROW ) ? sqlite3_column_int (stmt , 0 ) : -1 ;
1190
+ if (domain_id != NULL )
1191
+ * domain_id = result ;
1196
1192
1197
1193
if (config .debug & DEBUG_DATABASE )
1198
1194
logg ("domain_in_list(\"%s\", %p, %s): %d" , domain , stmt , listname , result );
@@ -1209,8 +1205,7 @@ static enum db_result domain_in_list(const char *domain, sqlite3_stmt *stmt, con
1209
1205
sqlite3_clear_bindings (stmt );
1210
1206
1211
1207
// Return if domain was found in current table
1212
- // SELECT EXISTS(...) either returns 0 (false) or 1 (true).
1213
- return (result == 1 ) ? FOUND : NOT_FOUND ;
1208
+ return (rc == SQLITE_ROW ) ? FOUND : NOT_FOUND ;
1214
1209
}
1215
1210
1216
1211
void gravityDB_reload_groups (clientsData * client )
@@ -1268,17 +1263,7 @@ enum db_result in_whitelist(const char *domain, DNSCacheData *dns_cache, clients
1268
1263
// We have to check both the exact whitelist (using a prepared database statement)
1269
1264
// as well the compiled regex whitelist filters to check if the current domain is
1270
1265
// whitelisted.
1271
- enum db_result on_whitelist = domain_in_list (domain , stmt , "whitelist" );
1272
-
1273
- // For performance reasons, the regex evaluations is executed only if the
1274
- // exact whitelist lookup does not deliver a positive match. This is an
1275
- // optimization as the database lookup will most likely hit (a) more domains
1276
- // and (b) will be faster (given a sufficiently large number of regex
1277
- // whitelisting filters).
1278
- if (on_whitelist == NOT_FOUND )
1279
- on_whitelist = match_regex (domain , dns_cache , client -> id , REGEX_WHITELIST , false) != -1 ;
1280
-
1281
- return on_whitelist ;
1266
+ return domain_in_list (domain , stmt , "whitelist" , & dns_cache -> domainlist_id );
1282
1267
}
1283
1268
1284
1269
enum db_result in_gravity (const char * domain , clientsData * client )
@@ -1306,10 +1291,10 @@ enum db_result in_gravity(const char *domain, clientsData *client)
1306
1291
if (stmt == NULL )
1307
1292
stmt = gravity_stmt -> get (gravity_stmt , client -> id );
1308
1293
1309
- return domain_in_list (domain , stmt , "gravity" );
1294
+ return domain_in_list (domain , stmt , "gravity" , NULL );
1310
1295
}
1311
1296
1312
- enum db_result in_blacklist (const char * domain , clientsData * client )
1297
+ enum db_result in_blacklist (const char * domain , DNSCacheData * dns_cache , clientsData * client )
1313
1298
{
1314
1299
// If list statement is not ready and cannot be initialized (e.g. no
1315
1300
// access to the database), we return false to prevent an FTL crash
@@ -1334,7 +1319,7 @@ enum db_result in_blacklist(const char *domain, clientsData *client)
1334
1319
if (stmt == NULL )
1335
1320
stmt = blacklist_stmt -> get (blacklist_stmt , client -> id );
1336
1321
1337
- return domain_in_list (domain , stmt , "blacklist" );
1322
+ return domain_in_list (domain , stmt , "blacklist" , & dns_cache -> domainlist_id );
1338
1323
}
1339
1324
1340
1325
bool in_auditlist (const char * domain )
@@ -1345,7 +1330,7 @@ bool in_auditlist(const char *domain)
1345
1330
return false;
1346
1331
1347
1332
// We check the domain_audit table for the given domain
1348
- return domain_in_list (domain , auditlist_stmt , "auditlist" ) == FOUND ;
1333
+ return domain_in_list (domain , auditlist_stmt , "auditlist" , NULL ) == FOUND ;
1349
1334
}
1350
1335
1351
1336
bool gravityDB_get_regex_client_groups (clientsData * client , const unsigned int numregex , const regexData * regex ,
@@ -1407,3 +1392,43 @@ bool gravityDB_get_regex_client_groups(clientsData* client, const unsigned int n
1407
1392
1408
1393
return true;
1409
1394
}
1395
+
1396
+ void check_inaccessible_adlists (void )
1397
+ {
1398
+
1399
+ // check if any adlist was inaccessible in the last gravity run
1400
+ // if so, gravity stored `status` in the adlist table with
1401
+ // "3": List unavailable, Pi-hole used a local copy
1402
+ // "4": List unavailable, there is no local copy available
1403
+
1404
+ // Do not proceed when database is not available
1405
+ if (!gravityDB_opened && !gravityDB_open ())
1406
+ {
1407
+ logg ("check_inaccessible_adlists(): Gravity database not available" );
1408
+ return ;
1409
+ }
1410
+
1411
+ const char * querystr = "SELECT id, address FROM adlist WHERE status IN (3,4) AND enabled=1" ;
1412
+
1413
+ // Prepare query
1414
+ sqlite3_stmt * query_stmt ;
1415
+ int rc = sqlite3_prepare_v2 (gravity_db , querystr , -1 , & query_stmt , NULL );
1416
+ if (rc != SQLITE_OK ){
1417
+ logg ("check_inaccessible_adlists(): %s - SQL error prepare: %s" , querystr , sqlite3_errstr (rc ));
1418
+ gravityDB_close ();
1419
+ return ;
1420
+ }
1421
+
1422
+ // Perform query
1423
+ while ((rc = sqlite3_step (query_stmt )) == SQLITE_ROW )
1424
+ {
1425
+ int id = sqlite3_column_int (query_stmt , 0 );
1426
+ const char * address = (const char * )sqlite3_column_text (query_stmt , 1 );
1427
+
1428
+ // log to the message table
1429
+ logg_inaccessible_adlist (id , address );
1430
+ }
1431
+
1432
+ // Finalize statement
1433
+ sqlite3_finalize (query_stmt );
1434
+ }
0 commit comments