Merge branch 'development-v6' into tweak/limit_history_clients

This commit is contained in:
DL6ER 2024-01-13 10:32:56 +01:00
commit 58637597bf
No known key found for this signature in database
GPG Key ID: 00135ACBD90B28DD
30 changed files with 336 additions and 123 deletions

View File

@ -336,14 +336,18 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
return 0;
}
static void delete_session(const int user_id)
static bool delete_session(const int user_id)
{
// Skip if nothing to be done here
if(user_id < 0 || user_id >= max_sessions)
return;
return false;
const bool was_valid = auth_data[user_id].used;
// Zero out this session (also sets valid to false == 0)
memset(&auth_data[user_id], 0, sizeof(auth_data[user_id]));
return was_valid;
}
void delete_all_sessions(void)
@ -354,24 +358,6 @@ void delete_all_sessions(void)
static int send_api_auth_status(struct ftl_conn *api, const int user_id, const time_t now)
{
if(user_id == API_AUTH_LOCALHOST)
{
log_debug(DEBUG_API, "API Auth status: OK (localhost does not need auth)");
cJSON *json = JSON_NEW_OBJECT();
get_session_object(api, json, user_id, now);
JSON_SEND_OBJECT(json);
}
if(user_id == API_AUTH_EMPTYPASS)
{
log_debug(DEBUG_API, "API Auth status: OK (empty password)");
cJSON *json = JSON_NEW_OBJECT();
get_session_object(api, json, user_id, now);
JSON_SEND_OBJECT(json);
}
if(user_id > API_AUTH_UNAUTHORIZED && (api->method == HTTP_GET || api->method == HTTP_POST))
{
log_debug(DEBUG_API, "API Auth status: OK");
@ -388,17 +374,45 @@ static int send_api_auth_status(struct ftl_conn *api, const int user_id, const t
get_session_object(api, json, user_id, now);
JSON_SEND_OBJECT(json);
}
else if(user_id > API_AUTH_UNAUTHORIZED && api->method == HTTP_DELETE)
else if(api->method == HTTP_DELETE)
{
log_debug(DEBUG_API, "API Auth status: Logout, asking to delete cookie");
if(user_id > API_AUTH_UNAUTHORIZED)
{
log_debug(DEBUG_API, "API Auth status: Logout, asking to delete cookie");
// Revoke client authentication. This slot can be used by a new client afterwards.
delete_session(user_id);
strncpy(pi_hole_extra_headers, FTL_DELETE_COOKIE, sizeof(pi_hole_extra_headers));
// Revoke client authentication. This slot can be used by a new client afterwards.
const int code = delete_session(user_id) ? 204 : 404;
// Send empty reply with appropriate HTTP status code
send_http_code(api, "application/json; charset=utf-8", code, "");
return code;
}
else
{
log_debug(DEBUG_API, "API Auth status: Logout, but not authenticated");
cJSON *json = JSON_NEW_OBJECT();
get_session_object(api, json, user_id, now);
JSON_SEND_OBJECT_CODE(json, 401); // 401 Unauthorized
}
}
else if(user_id == API_AUTH_LOCALHOST)
{
log_debug(DEBUG_API, "API Auth status: OK (localhost does not need auth)");
strncpy(pi_hole_extra_headers, FTL_DELETE_COOKIE, sizeof(pi_hole_extra_headers));
cJSON *json = JSON_NEW_OBJECT();
get_session_object(api, json, user_id, now);
JSON_SEND_OBJECT_CODE(json, 410); // 410 Gone
JSON_SEND_OBJECT(json);
}
else if(user_id == API_AUTH_EMPTYPASS)
{
log_debug(DEBUG_API, "API Auth status: OK (empty password)");
cJSON *json = JSON_NEW_OBJECT();
get_session_object(api, json, user_id, now);
JSON_SEND_OBJECT(json);
}
else
{
@ -563,7 +577,7 @@ int api_auth(struct ftl_conn *api)
{
// Expired slow, mark as unused
if(auth_data[i].used &&
auth_data[i].valid_until < now)
auth_data[i].valid_until < now)
{
log_debug(DEBUG_API, "API: Session of client %u (%s) expired, freeing...",
i, auth_data[i].remote_addr);
@ -634,6 +648,11 @@ int api_auth(struct ftl_conn *api)
"Rate-limiting login attempts",
NULL);
}
else if(result == NO_PASSWORD_SET)
{
// No password set
log_debug(DEBUG_API, "API: Trying to auth with password but none set: '%s'", password);
}
else
{
log_debug(DEBUG_API, "API: Password incorrect: '%s'", password);
@ -667,9 +686,9 @@ int api_auth_session_delete(struct ftl_conn *api)
return send_json_error(api, 400, "bad_request", "Session ID not in use", NULL);
// Delete session
delete_session(uid);
const int code = delete_session(uid) ? 204 : 404;
// Send empty reply with code 204 No Content
send_http_code(api, "application/json; charset=utf-8", 204, "");
return 204;
// Send empty reply with appropriate HTTP status code
send_http_code(api, "application/json; charset=utf-8", code, "");
return code;
}

View File

@ -294,7 +294,7 @@ static const char *getJSONvalue(struct conf_item *conf_item, cJSON *elem, struct
}
if(!set_and_check_password(conf_item, elem->valuestring))
return "Failed to create password hash (verification failed), password remains unchanged";
return "password hash verification failed";
break;
}
@ -904,7 +904,7 @@ static int api_config_put_delete(struct ftl_conn *api)
key, true);
}
// Check if this entry does already exist in the array
// Check if this entry exists in the array
int idx = 0;
for(; idx < cJSON_GetArraySize(new_item->v.json); idx++)
{
@ -938,13 +938,12 @@ static int api_config_put_delete(struct ftl_conn *api)
if(found)
{
// Remove item from array
found = true;
cJSON_DeleteItemFromArray(new_item->v.json, idx);
}
else
{
// Item not found
message = "Item not found";
hint = "Can only delete existing items";
break;
}
}
@ -964,13 +963,16 @@ static int api_config_put_delete(struct ftl_conn *api)
// Release allocated memory
free_config_path(requested_path);
// Error 404 if not found
if(!found || message != NULL)
// Error 404 if config element not found
if(!found)
{
cJSON *json = JSON_NEW_OBJECT();
JSON_SEND_OBJECT_CODE(json, 404);
}
// Error 400 if unique item already present
if(message != NULL)
{
// For any other error, a more specific message will have been added
// above
if(!message)
message = "No item specified";
return send_json_error(api, 400,
"bad_request",
message,

View File

@ -85,16 +85,18 @@ int api_dhcp_leases_DELETE(struct ftl_conn *api)
// Send empty reply with code 204 No Content
return send_json_error(api,
400,
"bad_request",
"bad_request",
"The provided IPv4 address is invalid",
api->item);
api->item);
}
// Delete lease
log_debug(DEBUG_API, "Deleting DHCP lease for address %s", api->item);
FTL_unlink_DHCP_lease(api->item);
const bool found = FTL_unlink_DHCP_lease(api->item);
// Send empty reply with code 204 No Content
// Send empty reply with codes:
// - 204 No Content (if a lease was deleted)
// - 404 Not Found (if no lease was found)
cJSON *json = JSON_NEW_OBJECT();
JSON_SEND_OBJECT_CODE(json, 204);
JSON_SEND_OBJECT_CODE(json, found ? 204 : 404);
}

View File

@ -118,21 +118,27 @@ components:
- Authentication
operationId: "delete_groups"
description: |
A logout attempt without a valid session will result in a `401 Unauthorized` error.
This endpoint can be used to delete the current session. It will
invalidate the session token and the CSRF token. The session can be
extended before its expiration by performing any authenticated action.
By default, the session lasts for 5 minutes. It can be invalidated by
either logging out or deleting the session. Additionally, the session
becomes invalid when the password is altered or a new application
password is created.
A session that was not created due to a login cannot be deleted (e.g., empty API password).
You can also delete a session by its ID using the `DELETE /auth/session/{id}` endpoint.
Note that you cannot delete the current session if you have not
authenticated (e.g., no password has been set on your Pi-hole).
responses:
'200':
description: OK (session not deletable)
'204':
description: No Content (deleted)
'404':
description: Not Found (no session active)
content:
application/json:
schema:
allOf:
- $ref: 'auth.yaml#/components/schemas/session'
- $ref: 'common.yaml#/components/schemas/took'
examples:
no_login_required:
$ref: 'auth.yaml#/components/examples/no_login_required'
$ref: 'common.yaml#/components/schemas/took'
'401':
description: Unauthorized
content:
@ -141,17 +147,6 @@ components:
allOf:
- $ref: 'common.yaml#/components/errors/unauthorized'
- $ref: 'common.yaml#/components/schemas/took'
'410':
description: Gone
content:
application/json:
schema:
allOf:
- $ref: 'auth.yaml#/components/schemas/session'
- $ref: 'common.yaml#/components/schemas/took'
examples:
login_failed:
$ref: 'auth.yaml#/components/examples/login_failed'
session_list:
get:
summary: List of all current sessions
@ -213,6 +208,12 @@ components:
responses:
'204':
description: No Content (deleted)
'404':
description: Not Found (session not found)
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad Request
content:

View File

@ -95,6 +95,12 @@ components:
responses:
'204':
description: Item deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
@ -233,6 +239,12 @@ components:
responses:
'204':
description: Items deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:

View File

@ -121,7 +121,7 @@ components:
examples:
invalid_path_depth:
$ref: 'config.yaml#/components/examples/errors/bad_request/invalid_path_depth'
item_not_found:
item_already_present:
$ref: 'config.yaml#/components/examples/errors/bad_request/item_already_present'
'401':
description: Unauthorized
@ -144,6 +144,12 @@ components:
responses:
'204':
description: Item deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
@ -155,8 +161,8 @@ components:
examples:
invalid_path_depth:
$ref: 'config.yaml#/components/examples/errors/bad_request/invalid_path_depth'
item_not_found:
$ref: 'config.yaml#/components/examples/errors/bad_request/item_not_found'
item_already_present:
$ref: 'config.yaml#/components/examples/errors/bad_request/item_already_present'
'401':
description: Unauthorized
content:
@ -795,13 +801,6 @@ components:
key: "bad_request"
message: "Invalid path depth"
hint: "Use, e.g., DELETE /config/dnsmasq/upstreams/127.0.0.1 to remove \"127.0.0.1\" from config.dns.upstreams"
item_not_found:
summary: Item to be deleted does not exist
value:
error:
key: "bad_request"
message: "Item not found"
hint: "Can only delete existing items"
item_already_present:
summary: Item to be added exists already
value:

View File

@ -40,6 +40,12 @@ components:
responses:
'204':
description: Item deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:

View File

@ -128,6 +128,12 @@ components:
responses:
'204':
description: Item deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
@ -251,6 +257,12 @@ components:
responses:
'204':
description: Items deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:

View File

@ -63,6 +63,9 @@ components:
- $ref: 'groups.yaml#/components/schemas/groups/get' # identical to GET
- $ref: 'groups.yaml#/components/schemas/lists_processed'
- $ref: 'common.yaml#/components/schemas/took'
headers:
Location:
$ref: 'common.yaml#/components/headers/Location'
'400':
description: Bad request
content:
@ -94,6 +97,12 @@ components:
responses:
'204':
description: Item deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
@ -193,18 +202,14 @@ components:
- "item": "test1"
- "item": "test2"
responses:
'201':
description: Created item
'204':
description: Items deleted
'404':
description: Item not found
content:
application/json:
schema:
allOf:
- $ref: 'groups.yaml#/components/schemas/groups/get' # identical to GET
- $ref: 'groups.yaml#/components/schemas/lists_processed'
- $ref: 'common.yaml#/components/schemas/took'
headers:
Location:
$ref: 'common.yaml#/components/headers/Location'
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:

View File

@ -218,10 +218,16 @@ components:
parameters:
- $ref: 'info.yaml#/components/parameters/message_id'
description: |
*Note:* There will be no content on success. You may specify multiple IDs to delete multiple messages at once (comma-separated in the path like `1,2,3`)
You may specify multiple IDs to delete multiple messages at once (comma-separated in the path like `1,2,3`)
responses:
'204':
description: Item deleted
'404':
description: Not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
@ -235,6 +241,14 @@ components:
$ref: 'info.yaml#/components/examples/errors/messages/uri_error'
bad_request:
$ref: 'info.yaml#/components/examples/errors/messages/bad_request'
'401':
description: Unauthorized
content:
application/json:
schema:
allOf:
- $ref: 'common.yaml#/components/errors/unauthorized'
- $ref: 'common.yaml#/components/schemas/took'
messages_count:
get:
summary: Get count of Pi-hole diagnosis messages

View File

@ -93,6 +93,12 @@ components:
responses:
'204':
description: Item deleted
'404':
description: Item not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
@ -189,18 +195,14 @@ components:
schema:
$ref: 'lists.yaml#/components/schemas/lists/post'
responses:
'201':
description: Created item
'204':
description: Items deleted
'404':
description: Item not found
content:
application/json:
schema:
allOf:
- $ref: 'lists.yaml#/components/schemas/lists/get'
- $ref: 'lists.yaml#/components/schemas/lists_processed'
- $ref: 'common.yaml#/components/schemas/took'
headers:
Location:
$ref: 'common.yaml#/components/headers/Location'
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:

View File

@ -93,6 +93,20 @@ components:
responses:
'204':
description: No Content (deleted)
'404':
description: Not found
content:
application/json:
schema:
$ref: 'common.yaml#/components/schemas/took'
'400':
description: Bad request
content:
application/json:
schema:
allOf:
- $ref: 'common.yaml#/components/errors/bad_request'
- $ref: 'common.yaml#/components/schemas/took'
'401':
description: Unauthorized
content:

View File

@ -940,15 +940,18 @@ static int api_info_messages_DELETE(struct ftl_conn *api)
}
// Delete message with this ID from the database
delete_message(ids);
int deleted = 0;
delete_message(ids, &deleted);
// Free memory
free(id);
cJSON_free(ids);
// Send empty reply with code 204 No Content
// Send empty reply with codes:
// - 204 No Content (if any items were deleted)
// - 404 Not Found (if no items were deleted)
cJSON *json = JSON_NEW_OBJECT();
JSON_SEND_OBJECT_CODE(json, 204);
JSON_SEND_OBJECT_CODE(json, deleted > 0 ? 204 : 404);
}
int api_info_messages(struct ftl_conn *api)

View File

@ -705,7 +705,8 @@ static int api_list_remove(struct ftl_conn *api,
}
// From here on, we can assume the JSON payload is valid
if(gravityDB_delFromTable(listtype, array, &sql_msg))
unsigned int deleted = 0u;
if(gravityDB_delFromTable(listtype, array, &deleted, &sql_msg))
{
// Inform the resolver that it needs to reload gravity
set_event(RELOAD_GRAVITY);
@ -714,9 +715,11 @@ static int api_list_remove(struct ftl_conn *api,
if(allocated_json)
cJSON_free(array);
// Send empty reply with code 204 No Content
// Send empty reply with codes:
// - 204 No Content (if any items were deleted)
// - 404 Not Found (if no items were deleted)
cJSON *json = JSON_NEW_OBJECT();
JSON_SEND_OBJECT_CODE(json, 204);
JSON_SEND_OBJECT_CODE(json, deleted > 0u ? 204 : 404);
}
else
{

View File

@ -440,7 +440,8 @@ static int api_network_devices_DELETE(struct ftl_conn *api)
// Delete row from network table by ID
const char *sql_msg = NULL;
if(!networkTable_deleteDevice(db, device_id, &sql_msg))
int deleted = 0;
if(!networkTable_deleteDevice(db, device_id, &deleted, &sql_msg))
{
// Add SQL message (may be NULL = not available)
return send_json_error(api, 500,
@ -452,9 +453,11 @@ static int api_network_devices_DELETE(struct ftl_conn *api)
// Close database
dbclose(&db);
// Send empty reply with code 204 No Content
// Send empty reply with codes:
// - 204 No Content (if any items were deleted)
// - 404 Not Found (if no items were deleted)
cJSON *json = JSON_NEW_OBJECT();
JSON_SEND_OBJECT_CODE(json, 204);
JSON_SEND_OBJECT_CODE(json, deleted > 0 ? 204 : 404);
}
int api_network_devices(struct ftl_conn *api)

View File

@ -160,8 +160,9 @@ static bool readStringValue(struct conf_item *conf_item, const char *value, stru
// Get password hash as allocated string (an empty string is hashed to an empty string)
char *pwhash = strlen(value) > 0 ? create_password(value) : strdup("");
// Verify that the password hash is valid
if(verify_password(value, pwhash, false) != PASSWORD_CORRECT)
// Verify that the password hash is either valid or empty
const enum password_result status = verify_password(value, pwhash, false);
if(status != PASSWORD_CORRECT && status != NO_PASSWORD_SET)
{
log_err("Failed to create password hash (verification failed), password remains unchanged");
free(pwhash);

View File

@ -328,6 +328,7 @@ enum password_result verify_login(const char *password)
log_debug(DEBUG_API, "App password correct");
return APPPASSWORD_CORRECT;
}
// Return result
return pw;
}
@ -336,7 +337,7 @@ enum password_result verify_password(const char *password, const char *pwhash, c
{
// No password set
if(pwhash == NULL || pwhash[0] == '\0')
return PASSWORD_CORRECT;
return NO_PASSWORD_SET;
// No password supplied
if(password == NULL || password[0] == '\0')
@ -606,8 +607,9 @@ bool set_and_check_password(struct conf_item *conf_item, const char *password)
// Get password hash as allocated string (an empty string is hashed to an empty string)
char *pwhash = strlen(password) > 0 ? create_password(password) : strdup("");
// Verify that the password hash is valid
if(verify_password(password, pwhash, false) != PASSWORD_CORRECT)
// Verify that the password hash is valid or that no password is set
const enum password_result status = verify_password(password, pwhash, false);
if(status != PASSWORD_CORRECT && status != NO_PASSWORD_SET)
{
free(pwhash);
log_warn("Failed to create password hash (verification failed), password remains unchanged");

View File

@ -26,6 +26,7 @@ enum password_result {
PASSWORD_INCORRECT = 0,
PASSWORD_CORRECT = 1,
APPPASSWORD_CORRECT = 2,
NO_PASSWORD_SET = 3,
PASSWORD_RATE_LIMITED = -1
} __attribute__((packed));

View File

@ -1792,8 +1792,9 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row,
return okay;
}
bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON* array, const char **message)
bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON* array, unsigned int *deleted, const char **message)
{
// Return early if database is not available
if(gravity_db == NULL)
{
*message = "Database not available";
@ -2004,6 +2005,9 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON*
break;
}
// Add number of deleted rows
*deleted += sqlite3_changes(gravity_db);
}
// Drop temporary table

View File

@ -69,7 +69,7 @@ bool gravityDB_readTableGetRow(const enum gravity_list_type listtype, tablerow *
void gravityDB_readTableFinalize(void);
bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row,
const char **message, const enum http_method method);
bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON* array, const char **message);
bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON* array, unsigned int *deleted, const char **message);
bool gravityDB_edit_groups(const enum gravity_list_type listtype, cJSON *groups,
const tablerow *row, const char **message);

View File

@ -378,7 +378,7 @@ end_of_add_message: // Close database connection
return rowid;
}
bool delete_message(cJSON *ids)
bool delete_message(cJSON *ids, int *deleted)
{
// Return early if database is known to be broken
if(FTLDBerror())
@ -413,6 +413,10 @@ bool delete_message(cJSON *ids)
log_err("SQL error (%i): %s", sqlite3_errcode(db), sqlite3_errmsg(db));
return false;
}
// Add to deleted count
*deleted += sqlite3_changes(db);
sqlite3_reset(res);
sqlite3_clear_bindings(res);
}

View File

@ -16,7 +16,7 @@
int count_messages(const bool filter_dnsmasq_warnings);
bool format_messages(cJSON *array);
bool create_message_table(sqlite3 *db);
bool delete_message(cJSON *ids);
bool delete_message(cJSON *ids, int *deleted);
bool flush_message_table(void);
void logg_regex_warning(const char *type, const char *warning, const int dbindex, const char *regex);
void logg_subnet_warning(const char *ip, const int matching_count, const char *matching_ids,

View File

@ -2425,7 +2425,7 @@ void networkTable_readIPsFinalize(sqlite3_stmt *read_stmt)
sqlite3_finalize(read_stmt);
}
bool networkTable_deleteDevice(sqlite3 *db, const int id, const char **message)
bool networkTable_deleteDevice(sqlite3 *db, const int id, int *deleted, const char **message)
{
// First step: Delete all associated IPs of this device
// Prepare SQLite statement
@ -2462,6 +2462,9 @@ bool networkTable_deleteDevice(sqlite3 *db, const int id, const char **message)
return false;
}
// Check if we deleted any rows
*deleted += sqlite3_changes(db);
// Finalize statement
sqlite3_finalize(stmt);
@ -2498,6 +2501,9 @@ bool networkTable_deleteDevice(sqlite3 *db, const int id, const char **message)
return false;
}
// Check if we deleted any rows
*deleted += sqlite3_changes(db);
// Finalize statement
sqlite3_finalize(stmt);

View File

@ -52,6 +52,6 @@ bool networkTable_readIPs(sqlite3 *db, sqlite3_stmt **read_stmt, const int id, c
bool networkTable_readIPsGetRecord(sqlite3_stmt *read_stmt, network_addresses_record *network_addresses, const char **message);
void networkTable_readIPsFinalize(sqlite3_stmt *read_stmt);
bool networkTable_deleteDevice(sqlite3 *db, const int id, const char **message);
bool networkTable_deleteDevice(sqlite3 *db, const int id, int *deleted, const char **message);
#endif //NETWORKTABLE_H

View File

@ -94,7 +94,7 @@ int main_dnsmasq (int argc, char **argv)
sigaction(SIGUSR1, &sigact, NULL);
sigaction(SIGUSR2, &sigact, NULL);
sigaction(SIGHUP, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGUSR6, &sigact, NULL); // Pi-hole modification
sigaction(SIGALRM, &sigact, NULL);
sigaction(SIGCHLD, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
@ -1330,7 +1330,7 @@ static void sig_handler(int sig)
event = EVENT_CHILD;
else if (sig == SIGALRM)
event = EVENT_ALARM;
else if (sig == SIGTERM)
else if (sig == SIGUSR6) // Pi-hole modified
event = EVENT_TERM;
else if (sig == SIGUSR1)
event = EVENT_DUMP;

View File

@ -3263,6 +3263,7 @@ bool FTL_unlink_DHCP_lease(const char *ipaddr)
#endif
else
{
// Invalid IP address or no lease found
return false;
}

View File

@ -311,11 +311,94 @@ static void SIGRT_handler(int signum, siginfo_t *si, void *unused)
// Parse neighbor cache
set_event(PARSE_NEIGHBOR_CACHE);
}
// else if(rtsig == 6)
// {
// // Signal internally used to signal dnsmasq it has to stop
// }
// Restore errno before returning back to previous context
errno = _errno;
}
static void SIGTERM_handler(int signum, siginfo_t *si, void *unused)
{
// Ignore SIGTERM outside of the main process (TCP forks)
if(mpid != getpid())
return;
// Get PID and UID of the process that sent the terminating signal
const pid_t kill_pid = si->si_pid;
const uid_t kill_uid = si->si_uid;
// Get name of the process that sent the terminating signal
char kill_name[256] = { 0 };
char kill_exe [256] = { 0 };
snprintf(kill_exe, sizeof(kill_exe), "/proc/%ld/cmdline", (long int)kill_pid);
FILE *fp = fopen(kill_exe, "r");
if(fp != NULL)
{
// Successfully opened file
size_t read = 0;
// Read line from file
if((read = fread(kill_name, sizeof(char), sizeof(kill_name), fp)) > 0)
{
// Successfully read line
// cmdline contains the command-line arguments as a set
// of strings separated by null bytes ('\0'), with a
// further null byte after the last string. Hence, we
// need to replace all null bytes with spaces for
// displaying it below
for(unsigned int i = 0; i < min((size_t)read, sizeof(kill_name)); i++)
{
if(kill_name[i] == '\0')
kill_name[i] = ' ';
}
// Remove any trailing spaces
for(unsigned int i = read - 1; i > 0; i--)
{
if(kill_name[i] == ' ')
kill_name[i] = '\0';
else
break;
}
}
else
{
// Failed to read line
strcpy(kill_name, "N/A");
}
}
else
{
// Failed to open file
strcpy(kill_name, "N/A");
}
// Get username of the process that sent the terminating signal
char kill_user[256] = { 0 };
struct passwd *pwd = getpwuid(kill_uid);
if(pwd != NULL)
{
// Successfully obtained username
strncpy(kill_user, pwd->pw_name, sizeof(kill_user));
}
else
{
// Failed to obtain username
strcpy(kill_user, "N/A");
}
// Log who sent the signal
log_info("Asked to terminate by \"%s\" (PID %ld, user %s UID %ld)",
kill_name, (long int)kill_pid,
kill_user, (long int)kill_uid);
// Terminate dnsmasq to stop DNS service
raise(SIGUSR6);
}
// Register ordinary signals handler
void handle_signals(void)
{
@ -337,6 +420,13 @@ void handle_signals(void)
}
}
// Also catch SIGTERM
struct sigaction SIGaction = { 0 };
SIGaction.sa_flags = SA_SIGINFO;
sigemptyset(&SIGaction.sa_mask);
SIGaction.sa_sigaction = &SIGTERM_handler;
sigaction(SIGTERM, &SIGaction, NULL);
// Log start time of FTL
FTLstarttime = time(NULL);
}
@ -351,8 +441,12 @@ void handle_realtime_signals(void)
// Catch all real-time signals
for(int signum = SIGRTMIN; signum <= SIGRTMAX; signum++)
{
struct sigaction SIGACTION;
memset(&SIGACTION, 0, sizeof(struct sigaction));
if(signum == SIGUSR6)
// Skip SIGUSR6 as it is used internally to signify
// dnsmasq to stop
continue;
struct sigaction SIGACTION = { 0 };
SIGACTION.sa_flags = SA_SIGINFO;
sigemptyset(&SIGACTION.sa_mask);
SIGACTION.sa_sigaction = &SIGRT_handler;

View File

@ -12,6 +12,8 @@
#include "enums.h"
#define SIGUSR6 (SIGRTMIN + 6)
// defined in dnsmasq/dnsmasq.h
extern volatile char FTL_terminate;

View File

@ -542,8 +542,6 @@ end_of_parseList:
// Print newline
puts("");
}
// Print final newline
puts("");
}
// Free memory

View File

@ -200,7 +200,10 @@
})
#define JSON_SEND_OBJECT_CODE(object, code)({ \
cJSON_AddNumberToObject(object, "took", double_time() - api->now);\
if((code) != 204) \
{ \
cJSON_AddNumberToObject(object, "took", double_time() - api->now); \
} \
char *json_string = json_formatter(object); \
if(json_string == NULL) \
{ \