Skip to content

Commit e5a5aa8

Browse files
committed
Provide regex ID for API
Signed-off-by: DL6ER <[email protected]>
1 parent e085728 commit e5a5aa8

File tree

7 files changed

+75
-39
lines changed

7 files changed

+75
-39
lines changed

src/api/docs/content/specs/queries.yaml

+4-8
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,10 @@ components:
208208
time:
209209
type: number
210210
description: Time until the response was received (ms, negative if N/A)
211-
ttl:
212-
type: integer
213-
description: Query's Time-To-Live (TTL) value (`-1` if N/A)
214211
regex_id:
215212
type: integer
216-
description: ID of blocking regex (`-1` if N/A)
213+
description: ID of blocking regex (`NULL` if N/A)
214+
nullable: true
217215
upstream:
218216
type: string
219217
description: IP or name + port of upstream server
@@ -231,8 +229,7 @@ components:
231229
reply:
232230
type: "IP"
233231
time: 19
234-
ttl: -1
235-
regex_id: -1
232+
regex_id: NULL
236233
upstream: "localhost#5353"
237234
dbid: 112421354
238235
- time: 1581907871.583821
@@ -247,8 +244,7 @@ components:
247244
reply:
248245
type: "IP"
249246
time: 12.3
250-
ttl: 7
251-
regex_id: -1
247+
regex_id: NULL
252248
upstream: "localhost#5353"
253249
dbid: 112421355
254250
cursor:

src/api/queries.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ int api_queries_suggestions(struct ftl_conn *api)
174174
JSON_SEND_OBJECT(json);
175175
}
176176

177-
#define QUERYSTR "SELECT q.id,timestamp,q.type,status,d.domain,f.forward,additional_info,reply_type,reply_time,dnssec,c.ip,c.name,a.content" // ttl, regex_id
177+
#define QUERYSTR "SELECT q.id,timestamp,q.type,status,d.domain,f.forward,additional_info,reply_type,reply_time,dnssec,c.ip,c.name,a.content,regex_id"
178178
// JOIN: Only return rows where there is a match in BOTH tables
179179
// LEFT JOIN: Return all rows from the left table, and the matched rows from the right table
180180
#define JOINSTR "JOIN client_by_id c ON q.client = c.id JOIN domain_by_id d ON q.domain = d.id LEFT JOIN forward_by_id f ON q.forward = f.id LEFT JOIN addinfo_by_id a ON a.id = q.additional_info"
@@ -666,8 +666,11 @@ int api_queries(struct ftl_conn *api)
666666
JSON_ADD_NULL_TO_OBJECT(client, "name");
667667
JSON_ADD_ITEM_TO_OBJECT(item, "client", client);
668668

669-
JSON_ADD_NUMBER_TO_OBJECT(item, "ttl", 0); // sqlite3_column_int(read_stmt, 12));
670-
JSON_ADD_NUMBER_TO_OBJECT(item, "regex_id", 0); // sqlite3_column_int(read_stmt, 13));
669+
// Add regex_id if it exists
670+
if(sqlite3_column_type(read_stmt, 13) == SQLITE_INTEGER)
671+
JSON_ADD_NUMBER_TO_OBJECT(item, "regex_id", sqlite3_column_int(read_stmt, 13));
672+
else
673+
JSON_ADD_NULL_TO_OBJECT(item, "regex_id");
671674

672675
const unsigned char *cname = NULL;
673676
switch(query.status)

src/database/common.c

+15
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,21 @@ void db_init(void)
471471
dbversion = db_get_int(db, DB_VERSION);
472472
}
473473

474+
// Update to version 13 if lower
475+
if(dbversion < 13)
476+
{
477+
// Update to version 13: Add additional column for regex ID
478+
log_info("Updating long-term database to version 13");
479+
if(!add_query_storage_column_regex_id(db))
480+
{
481+
log_info("Additional records not generated, database not available");
482+
dbclose(&db);
483+
return;
484+
}
485+
// Get updated version
486+
dbversion = db_get_int(db, DB_VERSION);
487+
}
488+
474489
lock_shm();
475490
import_aliasclients(db);
476491
unlock_shm();

src/database/query-table.c

+40-19
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,38 @@ bool add_query_storage_columns(sqlite3 *db)
698698
return true;
699699
}
700700

701+
bool add_query_storage_column_regex_id(sqlite3 *db)
702+
{
703+
// Start transaction of database update
704+
SQL_bool(db, "BEGIN TRANSACTION");
705+
706+
// Add additional column to the query_storage table
707+
SQL_bool(db, "ALTER TABLE query_storage ADD COLUMN regex_id INTEGER");
708+
709+
// Update VIEW queries
710+
SQL_bool(db, "DROP VIEW queries");
711+
SQL_bool(db, "CREATE VIEW queries AS "
712+
"SELECT id, timestamp, type, status, "
713+
"CASE typeof(domain) WHEN 'integer' THEN (SELECT domain FROM domain_by_id d WHERE d.id = q.domain) ELSE domain END domain,"
714+
"CASE typeof(client) WHEN 'integer' THEN (SELECT ip FROM client_by_id c WHERE c.id = q.client) ELSE client END client,"
715+
"CASE typeof(forward) WHEN 'integer' THEN (SELECT forward FROM forward_by_id f WHERE f.id = q.forward) ELSE forward END forward,"
716+
"CASE typeof(additional_info) WHEN 'integer' THEN (SELECT content FROM addinfo_by_id a WHERE a.id = q.additional_info) ELSE additional_info END additional_info, "
717+
"reply_type, reply_time, dnssec, regex_id "
718+
"FROM query_storage q");
719+
720+
// Update database version to 13
721+
if(!db_set_FTL_property(db, DB_VERSION, 13))
722+
{
723+
log_err("add_query_storage_columns2(): Failed to update database version!");
724+
return false;
725+
}
726+
727+
// Finish transaction
728+
SQL_bool(db, "COMMIT");
729+
730+
return true;
731+
}
732+
701733
bool optimize_queries_table(sqlite3 *db)
702734
{
703735
// Start transaction of database update
@@ -1193,7 +1225,8 @@ bool queries_to_database(void)
11931225
"(SELECT id FROM addinfo_by_id WHERE type = ?9 AND content = ?10),"
11941226
"?11," \
11951227
"?12," \
1196-
"?13)", -1, SQLITE_PREPARE_PERSISTENT, &query_stmt, NULL);
1228+
"?13," \
1229+
"?14)", -1, SQLITE_PREPARE_PERSISTENT, &query_stmt, NULL);
11971230
if( rc != SQLITE_OK )
11981231
{
11991232
log_err("queries_to_database(query_storage) - SQL error step: %s", sqlite3_errstr(rc));
@@ -1397,6 +1430,7 @@ bool queries_to_database(void)
13971430
{
13981431
sqlite3_bind_int(query_stmt, 9, ADDINFO_REGEX_ID);
13991432
sqlite3_bind_int(query_stmt, 10, cache->domainlist_id);
1433+
sqlite3_bind_int(query_stmt, 14, cache->domainlist_id);
14001434

14011435
// Execute prepared addinfo statement and check if successful
14021436
sqlite3_bind_int(addinfo_stmt, 1, ADDINFO_REGEX_ID);
@@ -1411,13 +1445,17 @@ bool queries_to_database(void)
14111445
}
14121446
}
14131447
else
1448+
{
14141449
sqlite3_bind_null(query_stmt, 9);
1450+
sqlite3_bind_null(query_stmt, 14);
1451+
}
14151452
}
14161453
else
14171454
{
14181455
// Nothing to add here
14191456
sqlite3_bind_null(query_stmt, 9);
14201457
sqlite3_bind_null(query_stmt, 10);
1458+
sqlite3_bind_null(query_stmt, 14);
14211459
}
14221460

14231461
// REPLY_TYPE
@@ -1434,25 +1472,8 @@ bool queries_to_database(void)
14341472
// DNSSEC
14351473
sqlite3_bind_int(query_stmt, 13, query->dnssec);
14361474

1437-
/* // TTL
1438-
sqlite3_bind_int(query_stmt, 14, query->ttl);
1475+
// REGEX_ID (already set above)
14391476

1440-
// REGEX_ID
1441-
if(query->status == QUERY_REGEX)
1442-
{
1443-
// Restore regex ID if applicable
1444-
const int cacheID = findCacheID(query->domainID, query->clientID, query->type);
1445-
DNSCacheData *cache = getDNSCache(cacheID, true);
1446-
if(cache != NULL)
1447-
sqlite3_bind_int(query_stmt, 15, cache->deny_regex_id);
1448-
else
1449-
sqlite3_bind_null(query_stmt, 15);
1450-
}
1451-
else
1452-
{
1453-
sqlite3_bind_null(query_stmt, 15);
1454-
}
1455-
*/
14561477
// Step and check if successful
14571478
rc = sqlite3_step(query_stmt);
14581479
sqlite3_clear_bindings(query_stmt);

src/database/query-table.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"client TEXT NOT NULL, " \
2424
"forward TEXT );"
2525

26-
#define CREATE_QUERY_STORAGE_TABLE_V12 "CREATE TABLE query_storage ( id INTEGER PRIMARY KEY AUTOINCREMENT, " \
26+
#define CREATE_QUERY_STORAGE_TABLE_V13 "CREATE TABLE query_storage ( id INTEGER PRIMARY KEY AUTOINCREMENT, " \
2727
"timestamp INTEGER NOT NULL, " \
2828
"type INTEGER NOT NULL, " \
2929
"status INTEGER NOT NULL, " \
@@ -33,9 +33,10 @@
3333
"additional_info INTEGER, " \
3434
"reply_type INTEGER, " \
3535
"reply_time REAL, " \
36-
"dnssec INTEGER );"
36+
"dnssec INTEGER, " \
37+
"regex_id INTEGER );"
3738

38-
#define CREATE_QUERIES_VIEW_V12 "CREATE VIEW queries AS " \
39+
#define CREATE_QUERIES_VIEW_V13 "CREATE VIEW queries AS " \
3940
"SELECT id, timestamp, type, status, " \
4041
"CASE typeof(domain) " \
4142
"WHEN 'integer' THEN (SELECT domain FROM domain_by_id d WHERE d.id = q.domain) ELSE domain END domain," \
@@ -45,7 +46,7 @@
4546
"WHEN 'integer' THEN (SELECT forward FROM forward_by_id f WHERE f.id = q.forward) ELSE forward END forward," \
4647
"CASE typeof(additional_info) "\
4748
"WHEN 'integer' THEN (SELECT content FROM addinfo_by_id a WHERE a.id = q.additional_info) ELSE additional_info END additional_info, " \
48-
"reply_type, reply_time, dnssec FROM query_storage q"
49+
"reply_type, reply_time, dnssec, regex_id FROM query_storage q"
4950

5051
// Version 1
5152
#define CREATE_QUERIES_TIMESTAMP_INDEX "CREATE INDEX idx_queries_timestamp ON queries (timestamp);"
@@ -76,12 +77,12 @@
7677

7778
#ifdef QUERY_TABLE_PRIVATE
7879
const char *table_creation[] = {
79-
CREATE_QUERY_STORAGE_TABLE_V12,
80+
CREATE_QUERY_STORAGE_TABLE_V13,
8081
CREATE_DOMAINS_BY_ID,
8182
CREATE_CLIENTS_BY_ID,
8283
CREATE_FORWARD_BY_ID,
8384
CREATE_ADDINFO_BY_ID,
84-
CREATE_QUERIES_VIEW_V12,
85+
CREATE_QUERIES_VIEW_V13,
8586
};
8687
const char *index_creation[] = {
8788
CREATE_QUERY_STORAGE_ID_INDEX,
@@ -123,5 +124,6 @@ bool queries_to_database(void);
123124
bool optimize_queries_table(sqlite3 *db);
124125
bool create_addinfo_table(sqlite3 *db);
125126
bool add_query_storage_columns(sqlite3 *db);
127+
bool add_query_storage_column_regex_id(sqlite3 *db);
126128

127129
#endif //QUERY_TABLE_PRIVATE_H

src/datastructure.h

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ typedef struct {
3333
int id; // the ID is a (signed) int in dnsmasq, so no need for a long int here
3434
int CNAME_domainID; // only valid if query has a CNAME blocking status
3535
int ede;
36-
unsigned int ttl;
3736
double response;
3837
double timestamp;
3938
int64_t db;

test/test_suite.bats

+2-2
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@
440440
@test "pihole-FTL.db schema is as expected" {
441441
run bash -c './pihole-FTL sqlite3 /etc/pihole/pihole-FTL.db .dump'
442442
printf "%s\n" "${lines[@]}"
443-
[[ "${lines[@]}" == *"CREATE TABLE IF NOT EXISTS \"query_storage\" (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL, domain INTEGER NOT NULL, client INTEGER NOT NULL, forward INTEGER, additional_info INTEGER, reply_type INTEGER, reply_time REAL, dnssec INTEGER);"* ]]
443+
[[ "${lines[@]}" == *"CREATE TABLE IF NOT EXISTS \"query_storage\" (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, type INTEGER NOT NULL, status INTEGER NOT NULL, domain INTEGER NOT NULL, client INTEGER NOT NULL, forward INTEGER, additional_info INTEGER, reply_type INTEGER, reply_time REAL, dnssec INTEGER, regex_id INTEGER);"* ]]
444444
[[ "${lines[@]}" == *"CREATE INDEX idx_queries_timestamps ON \"query_storage\" (timestamp);"* ]]
445445
[[ "${lines[@]}" == *"CREATE TABLE ftl (id INTEGER PRIMARY KEY NOT NULL, value BLOB NOT NULL);"* ]]
446446
[[ "${lines[@]}" == *"CREATE TABLE counters (id INTEGER PRIMARY KEY NOT NULL, value INTEGER NOT NULL);"* ]]
@@ -449,7 +449,7 @@
449449
[[ "${lines[@]}" == *"CREATE TABLE aliasclient (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, comment TEXT);"* ]]
450450
[[ "${lines[@]}" == *"INSERT INTO ftl VALUES(0,12);"* ]] # Expecting FTL database version 12
451451
# vvv This has been added in version 10 vvv
452-
[[ "${lines[@]}" == *"CREATE VIEW queries AS SELECT id, timestamp, type, status, CASE typeof(domain) WHEN 'integer' THEN (SELECT domain FROM domain_by_id d WHERE d.id = q.domain) ELSE domain END domain,CASE typeof(client) WHEN 'integer' THEN (SELECT ip FROM client_by_id c WHERE c.id = q.client) ELSE client END client,CASE typeof(forward) WHEN 'integer' THEN (SELECT forward FROM forward_by_id f WHERE f.id = q.forward) ELSE forward END forward,CASE typeof(additional_info) WHEN 'integer' THEN (SELECT content FROM addinfo_by_id a WHERE a.id = q.additional_info) ELSE additional_info END additional_info, reply_type, reply_time, dnssec FROM query_storage q;"* ]]
452+
[[ "${lines[@]}" == *"CREATE VIEW queries AS SELECT id, timestamp, type, status, CASE typeof(domain) WHEN 'integer' THEN (SELECT domain FROM domain_by_id d WHERE d.id = q.domain) ELSE domain END domain,CASE typeof(client) WHEN 'integer' THEN (SELECT ip FROM client_by_id c WHERE c.id = q.client) ELSE client END client,CASE typeof(forward) WHEN 'integer' THEN (SELECT forward FROM forward_by_id f WHERE f.id = q.forward) ELSE forward END forward,CASE typeof(additional_info) WHEN 'integer' THEN (SELECT content FROM addinfo_by_id a WHERE a.id = q.additional_info) ELSE additional_info END additional_info, reply_type, reply_time, dnssec, regex_id FROM query_storage q;"* ]]
453453
[[ "${lines[@]}" == *"CREATE TABLE domain_by_id (id INTEGER PRIMARY KEY, domain TEXT NOT NULL);"* ]]
454454
[[ "${lines[@]}" == *"CREATE TABLE client_by_id (id INTEGER PRIMARY KEY, ip TEXT NOT NULL, name TEXT);"* ]]
455455
[[ "${lines[@]}" == *"CREATE TABLE forward_by_id (id INTEGER PRIMARY KEY, forward TEXT NOT NULL);"* ]]

0 commit comments

Comments
 (0)