v1.2.1 - Handle NDKs pings of kind 99999

This commit is contained in:
Your Name
2026-02-03 13:19:33 -04:00
parent 18a7deec54
commit 086d2af56c
3 changed files with 66 additions and 10 deletions

View File

@@ -13,8 +13,8 @@
// Using CRELAY_ prefix to avoid conflicts with nostr_core_lib VERSION macros // Using CRELAY_ prefix to avoid conflicts with nostr_core_lib VERSION macros
#define CRELAY_VERSION_MAJOR 1 #define CRELAY_VERSION_MAJOR 1
#define CRELAY_VERSION_MINOR 2 #define CRELAY_VERSION_MINOR 2
#define CRELAY_VERSION_PATCH 0 #define CRELAY_VERSION_PATCH 1
#define CRELAY_VERSION "v1.2.0" #define CRELAY_VERSION "v1.2.1"
// Relay metadata (authoritative source for NIP-11 information) // Relay metadata (authoritative source for NIP-11 information)
#define RELAY_NAME "C-Relay" #define RELAY_NAME "C-Relay"

View File

@@ -1456,6 +1456,10 @@ int validate_search_term(const char* search_term, char* error_message, size_t er
/** /**
* Validate all filter values in a filter object * Validate all filter values in a filter object
* Returns:
* 1 = valid
* 0 = invalid (malformed, should count toward rate limit)
* -1 = invalid but benign (e.g., kind 99999 from NDK ping, should not count toward rate limit)
*/ */
int validate_filter_values(cJSON* filter_json, char* error_message, size_t error_size) { int validate_filter_values(cJSON* filter_json, char* error_message, size_t error_size) {
if (!filter_json || !cJSON_IsObject(filter_json)) { if (!filter_json || !cJSON_IsObject(filter_json)) {
@@ -1463,6 +1467,8 @@ int validate_filter_values(cJSON* filter_json, char* error_message, size_t error
return 0; return 0;
} }
int has_kind_99999 = 0; // Track if we encounter kind 99999 (NDK ping)
// Validate kinds array // Validate kinds array
cJSON* kinds = cJSON_GetObjectItem(filter_json, "kinds"); cJSON* kinds = cJSON_GetObjectItem(filter_json, "kinds");
if (kinds) { if (kinds) {
@@ -1485,11 +1491,25 @@ int validate_filter_values(cJSON* filter_json, char* error_message, size_t error
} }
int kind_val = (int)cJSON_GetNumberValue(kind_item); int kind_val = (int)cJSON_GetNumberValue(kind_item);
// Special case: kind 99999 is used by NDK for ping/connectivity checks
// We reject it but don't count it as a malformed request
if (kind_val == 99999) {
has_kind_99999 = 1;
snprintf(error_message, error_size, "kinds[%d]: invalid event kind %d (used by NDK for ping)", i, kind_val);
continue; // Continue checking other kinds
}
if (kind_val < 0 || kind_val > 65535) { // Reasonable range for event kinds if (kind_val < 0 || kind_val > 65535) { // Reasonable range for event kinds
snprintf(error_message, error_size, "kinds[%d]: invalid event kind %d", i, kind_val); snprintf(error_message, error_size, "kinds[%d]: invalid event kind %d", i, kind_val);
return 0; return 0;
} }
} }
// If we only found kind 99999 and no other validation errors, return -1 (benign error)
if (has_kind_99999) {
return -1;
}
} }
// Validate authors array // Validate authors array

View File

@@ -975,11 +975,15 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate filters before processing // Validate filters before processing
char filter_error[512] = {0}; char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) { int validation_result = validate_filter_array(filters, filter_error, sizeof(filter_error));
if (validation_result <= 0) {
DEBUG_TRACE("REQ rejected: filter validation failed - %s", filter_error); DEBUG_TRACE("REQ rejected: filter validation failed - %s", filter_error);
send_notice_message(wsi, pss, filter_error); send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("REQ rejected: invalid filters"); DEBUG_WARN("REQ rejected: invalid filters");
// Only record as malformed if it's a true error (0), not benign error (-1)
if (validation_result == 0) {
record_malformed_request(pss); record_malformed_request(pss);
}
cJSON_Delete(filters); cJSON_Delete(filters);
cJSON_Delete(json); cJSON_Delete(json);
// Note: complete_message points to reassembly_buffer, which is managed separately // Note: complete_message points to reassembly_buffer, which is managed separately
@@ -1060,10 +1064,14 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate filters before processing // Validate filters before processing
char filter_error[512] = {0}; char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) { int validation_result = validate_filter_array(filters, filter_error, sizeof(filter_error));
if (validation_result <= 0) {
send_notice_message(wsi, pss, filter_error); send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("COUNT rejected: invalid filters"); DEBUG_WARN("COUNT rejected: invalid filters");
// Only record as malformed if it's a true error (0), not benign error (-1)
if (validation_result == 0) {
record_malformed_request(pss); record_malformed_request(pss);
}
cJSON_Delete(filters); cJSON_Delete(filters);
cJSON_Delete(json); cJSON_Delete(json);
// Note: complete_message points to reassembly_buffer, which is managed separately // Note: complete_message points to reassembly_buffer, which is managed separately
@@ -1673,11 +1681,15 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate filters before processing // Validate filters before processing
char filter_error[512] = {0}; char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) { int validation_result = validate_filter_array(filters, filter_error, sizeof(filter_error));
if (validation_result <= 0) {
DEBUG_TRACE("REQ rejected: filter validation failed - %s", filter_error); DEBUG_TRACE("REQ rejected: filter validation failed - %s", filter_error);
send_notice_message(wsi, pss, filter_error); send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("REQ rejected: invalid filters"); DEBUG_WARN("REQ rejected: invalid filters");
// Only record as malformed if it's a true error (0), not benign error (-1)
if (validation_result == 0) {
record_malformed_request(pss); record_malformed_request(pss);
}
cJSON_Delete(filters); cJSON_Delete(filters);
cJSON_Delete(json); cJSON_Delete(json);
free(message); free(message);
@@ -1756,10 +1768,14 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Validate filters before processing // Validate filters before processing
char filter_error[512] = {0}; char filter_error[512] = {0};
if (!validate_filter_array(filters, filter_error, sizeof(filter_error))) { int validation_result = validate_filter_array(filters, filter_error, sizeof(filter_error));
if (validation_result <= 0) {
send_notice_message(wsi, pss, filter_error); send_notice_message(wsi, pss, filter_error);
DEBUG_WARN("COUNT rejected: invalid filters"); DEBUG_WARN("COUNT rejected: invalid filters");
// Only record as malformed if it's a true error (0), not benign error (-1)
if (validation_result == 0) {
record_malformed_request(pss); record_malformed_request(pss);
}
cJSON_Delete(filters); cJSON_Delete(filters);
cJSON_Delete(json); cJSON_Delete(json);
free(message); free(message);
@@ -2871,6 +2887,10 @@ int is_valid_hex_string(const char* str, size_t expected_len) {
/** /**
* Validate a filter array for REQ and COUNT messages * Validate a filter array for REQ and COUNT messages
* Returns:
* 1 = valid
* 0 = invalid (malformed, should count toward rate limit)
* -1 = invalid but benign (e.g., kind 99999 from NDK ping, should not count toward rate limit)
*/ */
int validate_filter_array(cJSON* filters, char* error_message, size_t error_size) { int validate_filter_array(cJSON* filters, char* error_message, size_t error_size) {
if (!filters || !cJSON_IsArray(filters)) { if (!filters || !cJSON_IsArray(filters)) {
@@ -2884,6 +2904,8 @@ int validate_filter_array(cJSON* filters, char* error_message, size_t error_size
return 0; return 0;
} }
int has_kind_99999 = 0; // Track if we encounter kind 99999 (NDK ping)
// Validate each filter object // Validate each filter object
for (int i = 0; i < filter_count; i++) { for (int i = 0; i < filter_count; i++) {
cJSON* filter = cJSON_GetArrayItem(filters, i); cJSON* filter = cJSON_GetArrayItem(filters, i);
@@ -2964,6 +2986,15 @@ int validate_filter_array(cJSON* filters, char* error_message, size_t error_size
return 0; return 0;
} }
int kind_val = (int)cJSON_GetNumberValue(kind); int kind_val = (int)cJSON_GetNumberValue(kind);
// Special case: kind 99999 is used by NDK (Nostr Development Kit) for ping/connectivity checks
// We reject it but don't count it as a malformed request to avoid rate limiting NDK clients
if (kind_val == 99999) {
has_kind_99999 = 1;
snprintf(error_message, error_size, "error: invalid kind value %d (NDK ping)", kind_val);
continue; // Continue checking other kinds
}
if (kind_val < 0 || kind_val > MAX_KIND_VALUE) { if (kind_val < 0 || kind_val > MAX_KIND_VALUE) {
snprintf(error_message, error_size, "error: invalid kind value %d", kind_val); snprintf(error_message, error_size, "error: invalid kind value %d", kind_val);
return 0; return 0;
@@ -3041,5 +3072,10 @@ int validate_filter_array(cJSON* filters, char* error_message, size_t error_size
} }
} }
// If we found kind 99999 (NDK ping), return -1 to indicate benign error
if (has_kind_99999) {
return -1;
}
return 1; // All filters valid return 1; // All filters valid
} }