diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | libnetdata/avl/avl.h | 5 | ||||
-rw-r--r-- | libnetdata/dictionary/dictionary.c | 4 | ||||
-rw-r--r-- | libnetdata/dictionary/dictionary.h | 1 | ||||
-rw-r--r-- | libnetdata/socket/socket.h | 12 | ||||
-rw-r--r-- | libnetdata/string/string.c | 226 | ||||
-rw-r--r-- | registry/registry.c | 135 | ||||
-rw-r--r-- | registry/registry_db.c | 241 | ||||
-rw-r--r-- | registry/registry_init.c | 167 | ||||
-rw-r--r-- | registry/registry_internals.c | 50 | ||||
-rw-r--r-- | registry/registry_internals.h | 30 | ||||
-rw-r--r-- | registry/registry_log.c | 6 | ||||
-rw-r--r-- | registry/registry_machine.c | 64 | ||||
-rw-r--r-- | registry/registry_machine.h | 15 | ||||
-rw-r--r-- | registry/registry_person.c | 142 | ||||
-rw-r--r-- | registry/registry_person.h | 30 | ||||
-rw-r--r-- | registry/registry_url.c | 88 | ||||
-rw-r--r-- | registry/registry_url.h | 35 | ||||
-rw-r--r-- | web/api/web_api.c | 31 | ||||
-rw-r--r-- | web/api/web_api.h | 5 | ||||
-rw-r--r-- | web/api/web_api_v1.c | 23 | ||||
-rw-r--r-- | web/api/web_api_v2.c | 151 |
23 files changed, 868 insertions, 597 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 866cb5d8ba..0ae2cd3e6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -700,8 +700,6 @@ set(REGISTRY_PLUGIN_FILES registry/registry_machine.h registry/registry_person.c registry/registry_person.h - registry/registry_url.c - registry/registry_url.h ) set(STATSD_PLUGIN_FILES diff --git a/Makefile.am b/Makefile.am index 26e345bbf4..5998a7bea0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -661,8 +661,6 @@ REGISTRY_PLUGIN_FILES = \ registry/registry_machine.h \ registry/registry_person.c \ registry/registry_person.h \ - registry/registry_url.c \ - registry/registry_url.h \ $(NULL) STATSD_PLUGIN_FILES = \ diff --git a/libnetdata/avl/avl.h b/libnetdata/avl/avl.h index 49dea3cbae..595d6ec6c0 100644 --- a/libnetdata/avl/avl.h +++ b/libnetdata/avl/avl.h @@ -24,6 +24,11 @@ typedef struct avl_element { signed char avl_balance; /* Balance factor. */ } avl_t; +typedef struct __attribute__((packed)) avl_element_packed { + struct avl_element *avl_link[2]; /* Subtrees. */ + signed char avl_balance; /* Balance factor. */ +} avl_t_packed; + /* An AVL tree */ typedef struct avl_tree_type { avl_t *root; diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c index f18a7f87f9..bb76e6f6f1 100644 --- a/libnetdata/dictionary/dictionary.c +++ b/libnetdata/dictionary/dictionary.c @@ -369,10 +369,6 @@ size_t dictionary_referenced_items(DICTIONARY *dict) { return referenced_items; } -long int dictionary_stats_for_registry(DICTIONARY *dict) { - if(unlikely(!dict)) return 0; - return (dict->stats->memory.index + dict->stats->memory.dict); -} void dictionary_version_increment(DICTIONARY *dict) { __atomic_fetch_add(&dict->version, 1, __ATOMIC_RELAXED); } diff --git a/libnetdata/dictionary/dictionary.h b/libnetdata/dictionary/dictionary.h index fccdbf506b..eea14d3fae 100644 --- a/libnetdata/dictionary/dictionary.h +++ b/libnetdata/dictionary/dictionary.h @@ -310,7 +310,6 @@ void dictionary_foreach_unlock(DICTFE *dfe); size_t dictionary_version(DICTIONARY *dict); size_t dictionary_entries(DICTIONARY *dict); size_t dictionary_referenced_items(DICTIONARY *dict); -long int dictionary_stats_for_registry(DICTIONARY *dict); // for all cases that the caller does not provide a stats structure, this is where they are accumulated. extern struct dictionary_stats dictionary_stats_category_other; diff --git a/libnetdata/socket/socket.h b/libnetdata/socket/socket.h index 0e29711e04..3a5b7b4a20 100644 --- a/libnetdata/socket/socket.h +++ b/libnetdata/socket/socket.h @@ -11,7 +11,7 @@ typedef enum web_client_acl { WEB_CLIENT_ACL_NONE = (0), - WEB_CLIENT_ACL_NOCHECK = (0), + WEB_CLIENT_ACL_NOCHECK = (0), // Don't check anything - this should work on all channels WEB_CLIENT_ACL_DASHBOARD = (1 << 0), WEB_CLIENT_ACL_REGISTRY = (1 << 1), WEB_CLIENT_ACL_BADGE = (1 << 2), @@ -23,9 +23,17 @@ typedef enum web_client_acl { WEB_CLIENT_ACL_SSL_DEFAULT = (1 << 8), WEB_CLIENT_ACL_ACLK = (1 << 9), WEB_CLIENT_ACL_WEBRTC = (1 << 10), + WEB_CLIENT_ACL_BEARER_OPTIONAL = (1 << 11), // allow unprotected access if bearer is not enabled in netdata + WEB_CLIENT_ACL_BEARER_REQUIRED = (1 << 12), // allow access only if a valid bearer is used } WEB_CLIENT_ACL; -#define WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC (WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_WEBRTC) +#define WEB_CLIENT_ACL_DASHBOARD_ACLK_WEBRTC (WEB_CLIENT_ACL_DASHBOARD | WEB_CLIENT_ACL_ACLK | WEB_CLIENT_ACL_WEBRTC | WEB_CLIENT_ACL_BEARER_OPTIONAL) + +#ifdef NETDATA_DEV_MODE +#define ACL_DEV_OPEN_ACCESS WEB_CLIENT_ACL_DASHBOARD +#else +#define ACL_DEV_OPEN_ACCESS 0 +#endif #define WEB_CLIENT_ACL_ALL 0xFFFF diff --git a/libnetdata/string/string.c b/libnetdata/string/string.c index 159f8a6a84..373d0c24c5 100644 --- a/libnetdata/string/string.c +++ b/libnetdata/string/string.c @@ -8,6 +8,11 @@ typedef int32_t REFCOUNT; // ---------------------------------------------------------------------------- // STRING implementation - dedup all STRING +#define STRING_PARTITION_SHIFTS (0) +#define STRING_PARTITIONS (256 >> STRING_PARTITION_SHIFTS) +#define string_partition_str(str) ((uint8_t)((str)[0]) >> STRING_PARTITION_SHIFTS) +#define string_partition(string) (string_partition_str((string)->str)) + struct netdata_string { uint32_t length; // the string length including the terminating '\0' @@ -18,20 +23,22 @@ struct netdata_string { const char str[]; // the string itself, is appended to this structure }; -static struct string_hashtable { - Pvoid_t JudyHSArray; // the Judy array - hashtable - netdata_rwlock_t rwlock; // the R/W lock to protect the Judy array +static struct string_partition { + RW_SPINLOCK spinlock; // the R/W spinlock to protect the Judy array - long int entries; // the number of entries in the index - long int active_references; // the number of active references alive - long int memory; // the memory used, without the JudyHS index + Pvoid_t JudyHSArray; // the Judy array - hashtable - size_t inserts; // the number of successful inserts to the index - size_t deletes; // the number of successful deleted from the index size_t searches; // the number of successful searches in the index size_t duplications; // when a string is referenced size_t releases; // when a string is unreferenced + size_t inserts; // the number of successful inserts to the index + size_t deletes; // the number of successful deleted from the index + + long int entries; // the number of entries in the index + long int active_references; // the number of active references alive + long int memory; // the memory used, without the JudyHS index + #ifdef NETDATA_INTERNAL_CHECKS // internal statistics size_t found_deleted_on_search; @@ -41,50 +48,45 @@ static struct string_hashtable { size_t spins; #endif -} string_base = { - .JudyHSArray = NULL, - .rwlock = NETDATA_RWLOCK_INITIALIZER, -}; +} string_base[STRING_PARTITIONS] = { 0 }; #ifdef NETDATA_INTERNAL_CHECKS -#define string_internal_stats_add(var, val) __atomic_add_fetch(&string_base.var, val, __ATOMIC_RELAXED) +#define string_internal_stats_add(partition, var, val) __atomic_add_fetch(&string_base[partition].var, val, __ATOMIC_RELAXED) #else -#define string_internal_stats_add(var, val) do {;} while(0) +#define string_internal_stats_add(partition, var, val) do {;} while(0) #endif -#define string_stats_atomic_increment(var) __atomic_add_fetch(&string_base.var, 1, __ATOMIC_RELAXED) -#define string_stats_atomic_decrement(var) __atomic_sub_fetch(&string_base.var, 1, __ATOMIC_RELAXED) +#define string_stats_atomic_increment(partition, var) __atomic_add_fetch(&string_base[partition].var, 1, __ATOMIC_RELAXED) +#define string_stats_atomic_decrement(partition, var) __atomic_sub_fetch(&string_base[partition].var, 1, __ATOMIC_RELAXED) void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_t *entries, size_t *references, size_t *memory, size_t *duplications, size_t *releases) { - if(inserts) - *inserts = string_base.inserts; - - if(deletes) - *deletes = string_base.deletes; - - if(searches) - *searches = string_base.searches; - - if(entries) - *entries = (size_t)string_base.entries; - - if(references) - *references = (size_t)string_base.active_references; - - if(memory) - *memory = (size_t)string_base.memory; - - if(duplications) - *duplications = string_base.duplications; - - if(releases) - *releases = string_base.releases; + if (inserts) *inserts = 0; + if (deletes) *deletes = 0; + if (searches) *searches = 0; + if (entries) *entries = 0; + if (references) *references = 0; + if (memory) *memory = 0; + if (duplications) *duplications = 0; + if (releases) *releases = 0; + + for(size_t i = 0; i < STRING_PARTITIONS ;i++) { + if (inserts) *inserts += string_base[i].inserts; + if (deletes) *deletes += string_base[i].deletes; + if (searches) *searches += string_base[i].searches; + if (entries) *entries += (size_t) string_base[i].entries; + if (references) *references += (size_t) string_base[i].active_references; + if (memory) *memory += (size_t) string_base[i].memory; + if (duplications) *duplications += string_base[i].duplications; + if (releases) *releases += string_base[i].releases; + } } #define string_entry_acquire(se) __atomic_add_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST); #define string_entry_release(se) __atomic_sub_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST); static inline bool string_entry_check_and_acquire(STRING *se) { + uint8_t partition = string_partition(se); + REFCOUNT expected, desired, count = 0; expected = __atomic_load_n(&se->refcount, __ATOMIC_SEQ_CST); @@ -96,7 +98,7 @@ static inline bool string_entry_check_and_acquire(STRING *se) { // We cannot use this. // The reference counter reached value zero, // so another thread is deleting this. - string_internal_stats_add(spins, count - 1); + string_internal_stats_add(partition, spins, count - 1); return false; } @@ -104,11 +106,11 @@ static inline bool string_entry_check_and_acquire(STRING *se) { } while(!__atomic_compare_exchange_n(&se->refcount, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); - string_internal_stats_add(spins, count - 1); + string_internal_stats_add(partition, spins, count - 1); // statistics // string_base.active_references is altered at the in string_strdupz() and string_freez() - string_stats_atomic_increment(duplications); + string_stats_atomic_increment(partition, duplications); return true; } @@ -123,9 +125,11 @@ STRING *string_dup(STRING *string) { string_entry_acquire(string); + uint8_t partition = string_partition(string); + // statistics - string_stats_atomic_increment(active_references); - string_stats_atomic_increment(duplications); + string_stats_atomic_increment(partition, active_references); + string_stats_atomic_increment(partition, duplications); return string; } @@ -134,26 +138,28 @@ STRING *string_dup(STRING *string) { static inline STRING *string_index_search(const char *str, size_t length) { STRING *string; + uint8_t partition = string_partition_str(str); + // Find the string in the index // With a read-lock so that multiple readers can use the index concurrently. - netdata_rwlock_rdlock(&string_base.rwlock); + rw_spinlock_read_lock(&string_base[partition].spinlock); Pvoid_t *Rc; - Rc = JudyHSGet(string_base.JudyHSArray, (void *)str, length); + Rc = JudyHSGet(string_base[partition].JudyHSArray, (void *)str, length - 1); if(likely(Rc)) { // found in the hash table string = *Rc; if(string_entry_check_and_acquire(string)) { // we can use this entry - string_internal_stats_add(found_available_on_search, 1); + string_internal_stats_add(partition, found_available_on_search, 1); } else { // this entry is about to be deleted by another thread // do not touch it, let it go... string = NULL; - string_internal_stats_add(found_deleted_on_search, 1); + string_internal_stats_add(partition, found_deleted_on_search, 1); } } else { @@ -161,8 +167,8 @@ static inline STRING *string_index_search(const char *str, size_t length) { string = NULL; } - string_stats_atomic_increment(searches); - netdata_rwlock_unlock(&string_base.rwlock); + string_stats_atomic_increment(partition, searches); + rw_spinlock_read_unlock(&string_base[partition].spinlock); return string; } @@ -175,12 +181,14 @@ static inline STRING *string_index_search(const char *str, size_t length) { static inline STRING *string_index_insert(const char *str, size_t length) { STRING *string; - netdata_rwlock_wrlock(&string_base.rwlock); + uint8_t partition = string_partition_str(str); + + rw_spinlock_write_lock(&string_base[partition].spinlock); STRING **ptr; { JError_t J_Error; - Pvoid_t *Rc = JudyHSIns(&string_base.JudyHSArray, (void *)str, length, &J_Error); + Pvoid_t *Rc = JudyHSIns(&string_base[partition].JudyHSArray, (void *)str, length - 1, &J_Error); if (unlikely(Rc == PJERR)) { fatal( "STRING: Cannot insert entry with name '%s' to JudyHS, JU_ERRNO_* == %u, ID == %d", @@ -199,9 +207,9 @@ static inline STRING *string_index_insert(const char *str, size_t length) { string->length = length; string->refcount = 1; *ptr = string; - string_base.inserts++; - string_base.entries++; - string_base.memory += (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(length)); + string_base[partition].inserts++; + string_base[partition].entries++; + string_base[partition].memory += (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(length)); } else { // the item is already in the index @@ -209,25 +217,27 @@ static inline STRING *string_index_insert(const char *str, size_t length) { if(string_entry_check_and_acquire(string)) { // we can use this entry - string_internal_stats_add(found_available_on_insert, 1); + string_internal_stats_add(partition, found_available_on_insert, 1); } else { // this entry is about to be deleted by another thread // do not touch it, let it go... string = NULL; - string_internal_stats_add(found_deleted_on_insert, 1); + string_internal_stats_add(partition, found_deleted_on_insert, 1); } - string_stats_atomic_increment(searches); + string_stats_atomic_increment(partition, searches); } - netdata_rwlock_unlock(&string_base.rwlock); + rw_spinlock_write_unlock(&string_base[partition].spinlock); return string; } // delete an entry from the index static inline void string_index_delete(STRING *string) { - netdata_rwlock_wrlock(&string_base.rwlock); + uint8_t partition = string_partition(string); + + rw_spinlock_write_lock(&string_base[partition].spinlock); #ifdef NETDATA_INTERNAL_CHECKS if(unlikely(__atomic_load_n(&string->refcount, __ATOMIC_SEQ_CST) != 0)) @@ -236,9 +246,9 @@ static inline void string_index_delete(STRING *string) { bool deleted = false; - if (likely(string_base.JudyHSArray)) { + if (likely(string_base[partition].JudyHSArray)) { JError_t J_Error; - int ret = JudyHSDel(&string_base.JudyHSArray, (void *)string->str, string->length, &J_Error); + int ret = JudyHSDel(&string_base[partition].JudyHSArray, (void *)string->str, string->length - 1, &J_Error); if (unlikely(ret == JERR)) { netdata_log_error( "STRING: Cannot delete entry with name '%s' from JudyHS, JU_ERRNO_* == %u, ID == %d", @@ -253,18 +263,20 @@ static inline void string_index_delete(STRING *string) { netdata_log_error("STRING: tried to delete '%s' that is not in the index. Ignoring it.", string->str); else { size_t mem_size = sizeof(STRING) + string->length; - string_base.deletes++; - string_base.entries--; - string_base.memory -= (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(string->length)); + string_base[partition].deletes++; + string_base[partition].entries--; + string_base[partition].memory -= (long)(mem_size + JUDYHS_INDEX_SIZE_ESTIMATE(string->length)); freez(string); } - netdata_rwlock_unlock(&string_base.rwlock); + rw_spinlock_write_unlock(&string_base[partition].spinlock); } STRING *string_strdupz(const char *str) { if(unlikely(!str || !*str)) return NULL; + uint8_t partition = string_partition_str(str); + size_t length = strlen(str) + 1; STRING *string = string_index_search(str, length); @@ -277,7 +289,7 @@ STRING *string_strdupz(const char *str) { } // statistics - string_stats_atomic_increment(active_references); + string_stats_atomic_increment(partition, active_references); return string; } @@ -285,6 +297,7 @@ STRING *string_strdupz(const char *str) { void string_freez(STRING *string) { if(unlikely(!string)) return; + uint8_t partition = string_partition(string); REFCOUNT refcount = string_entry_release(string); #ifdef NETDATA_INTERNAL_CHECKS @@ -296,8 +309,8 @@ void string_freez(STRING *string) { string_index_delete(string); // statistics - string_stats_atomic_decrement(active_references); - string_stats_atomic_increment(releases); + string_stats_atomic_decrement(partition, active_references); + string_stats_atomic_increment(partition, releases); } inline size_t string_strlen(STRING *string) { @@ -405,6 +418,54 @@ static void string_unittest_free_char_pp(char **pp, size_t entries) { freez(pp); } +static long unittest_string_entries(void) { + long entries = 0; + for(size_t p = 0; p < STRING_PARTITIONS ;p++) + entries += string_base[p].entries; + + return entries; +} + +#ifdef NETDATA_INTERNAL_CHECKS + +static size_t unittest_string_found_deleted_on_search(void) { + size_t entries = 0; + for(size_t p = 0; p < STRING_PARTITIONS ;p++) + entries += string_base[p].found_deleted_on_search; + + return entries; +} +static size_t unittest_string_found_available_on_search(void) { + size_t entries = 0; + for(size_t p = 0; p < STRING_PARTITIONS ;p++) + entries += string_base[p].found_available_on_search; + + return entries; +} +static size_t unittest_string_found_deleted_on_insert(void) { + size_t entries = 0; + for(size_t p = 0; p < STRING_PARTITIONS ;p++) + entries += string_base[p].found_deleted_on_insert; + + return entries; +} +static size_t unittest_string_found_available_on_insert(void) { + size_t entries = 0; + for(size_t p = 0; p < STRING_PARTITIONS ;p++) + entries += string_base[p].found_available_on_insert; + + return entries; +} +static size_t unittest_string_spins(void) { + size_t entries = 0; + for(size_t p = 0; p < STRING_PARTITIONS ;p++) + entries += string_base[p].spins; + + return entries; +} + +#endif // NETDATA_INTERNAL_CHECKS + int string_unittest(size_t entries) { size_t errors = 0; @@ -413,7 +474,7 @@ int string_unittest(size_t entries) { // check string { - long int string_entries_starting = string_base.entries; + long entries_starting = unittest_string_entries(); fprintf(stderr, "\nChecking strings...\n"); @@ -496,9 +557,10 @@ int string_unittest(size_t entries) { freez(strings); - if(string_base.entries != string_entries_starting + 2) { + if(unittest_string_entries() != entries_starting + 2) { errors++; - fprintf(stderr, "ERROR: strings dictionary should have %ld items but it has %ld\n", string_entries_starting + 2, string_base.entries); + fprintf(stderr, "ERROR: strings dictionary should have %ld items but it has %ld\n", + entries_starting + 2, unittest_string_entries()); } else fprintf(stderr, "OK: strings dictionary has 2 items\n"); @@ -551,11 +613,11 @@ int string_unittest(size_t entries) { }; #ifdef NETDATA_INTERNAL_CHECKS - size_t ofound_deleted_on_search = string_base.found_deleted_on_search, - ofound_available_on_search = string_base.found_available_on_search, - ofound_deleted_on_insert = string_base.found_deleted_on_insert, - ofound_available_on_insert = string_base.found_available_on_insert, - ospins = string_base.spins; + size_t ofound_deleted_on_search = unittest_string_found_deleted_on_search(), + ofound_available_on_search = unittest_string_found_available_on_search(), + ofound_deleted_on_insert = unittest_string_found_deleted_on_insert(), + ofound_available_on_insert = unittest_string_found_available_on_insert(), + ospins = unittest_string_spins(); #endif size_t oinserts, odeletes, osearches, oentries, oreferences, omemory, oduplications, oreleases; @@ -592,11 +654,11 @@ int string_unittest(size_t entries) { inserts - oinserts, deletes - odeletes, searches - osearches, sentries - oentries, references - oreferences, memory - omemory, duplications - oduplications, releases - oreleases); #ifdef NETDATA_INTERNAL_CHECKS - size_t found_deleted_on_search = string_base.found_deleted_on_search, - found_available_on_search = string_base.found_available_on_search, - found_deleted_on_insert = string_base.found_deleted_on_insert, - found_available_on_insert = string_base.found_available_on_insert, - spins = string_base.spins; + size_t found_deleted_on_search = unittest_string_found_deleted_on_search(), + found_available_on_search = unittest_string_found_available_on_search(), + found_deleted_on_insert = unittest_string_found_deleted_on_insert(), + found_available_on_insert = unittest_string_found_available_on_insert(), + spins = unittest_string_spins(); fprintf(stderr, "on insert: %zu ok + %zu deleted\non search: %zu ok + %zu deleted\nspins: %zu\n", found_available_on_insert - ofound_available_on_insert, diff --git a/registry/registry.c b/registry/registry.c index f8de470eb8..04edb95c0d 100644 --- a/registry/registry.c +++ b/registry/registry.c @@ -8,6 +8,10 @@ #define REGISTRY_STATUS_FAILED "failed" #define REGISTRY_STATUS_DISABLED "disabled" +bool registry_is_valid_url(const char *url) { + return url && (*url == 'h' || *url == '*'); +} + // ---------------------------------------------------------------------------- // REGISTRY concurrency locking @@ -23,19 +27,19 @@ static inline void registry_unlock(void) { // COOKIES static void registry_set_cookie(struct web_client *w, const char *guid) { - char edate[100]; + char e_date[100]; time_t et = now_realtime_sec() + registry.persons_expiration; - struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf); - strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm); + struct tm e_tm_buf, *etm = gmtime_r(&et, &e_tm_buf); + strftime(e_date, sizeof(e_date), "%a, %d %b %Y %H:%M:%S %Z", etm); - buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s\r\n", guid, edate); + buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s\r\n", guid, e_date); if(registry.enable_cookies_samesite_secure) - buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; SameSite=None; Secure\r\n", guid, edate); + buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; SameSite=None; Secure\r\n", guid, e_date); if(registry.registry_domain && *registry.registry_domain) { - buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s\r\n", guid, edate, registry.registry_domain); + buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s\r\n", guid, e_date, registry.registry_domain); if(registry.enable_cookies_samesite_secure) - buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s; SameSite=None; Secure\r\n", guid, edate, registry.registry_domain); + buffer_sprintf(w->response.header, "Set-Cookie: " NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s; Domain=%s; SameSite=None; Secure\r\n", guid, e_date, registry.registry_domain); } w->response.has_cookies = true; @@ -84,37 +88,41 @@ struct registry_json_walk_person_urls_callback { int count; }; +static STRING *asterisks = NULL; + // callback for rendering PERSON_URLs -static int registry_json_person_url_callback(void *entry, void *data) { - REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry; - struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data; +static int registry_json_person_url_callback(REGISTRY_PERSON_URL *pu, struct registry_json_walk_person_urls_callback *c) { + if(unlikely(!asterisks)) + asterisks = string_strdupz("***"); + struct web_client *w = c->w; - if (!strcmp(pu->url->url,"***")) return 0; + if (pu->url == asterisks) return 0; buffer_json_add_array_item_array(w->response.data); buffer_json_add_array_item_string(w->response.data, pu->machine->guid); - buffer_json_add_array_item_string(w->response.data, pu->url->url); + buffer_json_add_array_item_string(w->response.data, string2str(pu->url)); buffer_json_add_array_item_uint64(w->response.data, pu->last_t * (uint64_t) 1000); buffer_json_add_array_item_uint64(w->response.data, pu->usages); - buffer_json_add_array_item_string(w->response.data, pu->machine_name); + buffer_json_add_array_item_string(w->response.data, string2str(pu->machine_name)); buffer_json_array_close(w->response.data); return 1; } // callback for rendering MACHINE_URLs -static int registry_json_machine_url_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) { - REGISTRY_MACHINE_URL *mu = (REGISTRY_MACHINE_URL *)entry; - struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data; +static int registry_json_machine_url_callback(REGISTRY_MACHINE_URL *mu, struct registry_json_walk_person_urls_callback *c) { + if(unlikely(!asterisks)) + asterisks = string_strdupz("***"); + struct web_client *w = c->w; REGISTRY_MACHINE *m = c->m; - if (!strcmp(mu->url->url,"***")) return 0; + if (mu->url == asterisks) return 0; buffer_json_add_array_item_array(w->response.data); buffer_json_add_array_item_string(w->response.data, m->guid); - buffer_json_add_array_item_string(w->response.data, mu->url->url); + buffer_json_add_array_item_string(w->response.data, string2str(mu->url)); buffer_json_add_array_item_uint64(w->response.data, mu->last_t * (uint64_t) 1000); buffer_json_add_array_item_uint64(w->response.data, mu->usages); buffer_json_array_close(w->response.data); @@ -130,9 +138,7 @@ struct registry_person_url_callback_verify_machine_exists_data { int count; }; -static inline int registry_person_url_callback_verify_machine_exists(void *entry, void *data) { - struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data; - REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry; +static inline int registry_person_url_callback_verify_machine_exists(REGISTRY_PERSON_URL *pu, struct registry_person_url_callback_verify_machine_exists_data *d) { REGISTRY_MACHINE *m = d->m; if(pu->machine == m) @@ -161,34 +167,54 @@ int registry_request_hello_json(RRDHOST *host, struct web_client *w) { buffer_json_member_add_string(w->response.data, "cloud_base_url", registry.cloud_base_url); buffer_json_member_add_boolean(w->response.data, "anonymous_statistics", netdata_anonymous_statistics_enabled); + buffer_json_member_add_array(w->response.data, "nodes"); + RRDHOST *h; + dfe_start_read(rrdhost_root_index, h) { + buffer_json_add_array_item_object(w->response.data); + buffer_json_member_add_string(w->response.data, "machine_guid", h->machine_guid); + buffer_json_member_add_string(w->response.data, "hostname", rrdhost_registry_hostname(h)); + buffer_json_object_close(w->response.data); + } + dfe_done(h); + buffer_json_array_close(w->response.data); + registry_json_footer(w); return HTTP_RESP_OK; } // ---------------------------------------------------------------------------- -//public ACCESS request - -#define REGISTRY_VERIFY_COOKIES_GUID "give-me-back-this-cookie-now--please" +// public ACCESS request // the main method for registering an access int registry_request_access_json(RRDHOST *host, struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) { if(unlikely(!registry.enabled)) return registry_json_disabled(host, w, "access"); + if(!registry_is_valid_url(url)) { + buffer_flush(w->response.data); + buffer_strcat(w->response.data, "Invalid URL given in the request"); + return HTTP_RESP_BAD_REQUEST; + } + // ------------------------------------------------------------------------ - // verify the browser supports cookies + // verify the browser supports cookies or the bearer if(registry.verify_cookies_redirects > 0 && !person_guid[0]) { + registry_request_access(REGISTRY_VERIFY_COOKIES_GUID, machine_guid, url, name, when); + buffer_flush(w->response.data); registry_set_cookie(w, REGISTRY_VERIFY_COOKIES_GUID); w->response.data->content_type = CT_APPLICATION_JSON; registry_json_header(host, w, "access", REGISTRY_STATUS_REDIRECT); + buffer_json_member_add_string(w->response.data, "person_guid", REGISTRY_VERIFY_COOKIES_GUID); buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce); registry_json_footer(w); return HTTP_RESP_OK; } - if(unlikely(person_guid[0] && !strcmp(person_guid, REGISTRY_VERIFY_COOKIES_GUID))) + if(unlikely(person_guid[0] && is_dummy_person(person_guid))) + // it passed the check - they gave us a different person_guid + // empty the dummy one, so that we will generate a new person_guid person_guid[0] = '\0'; // ------------------------------------------------------------------------ @@ |