|
@@ -585,28 +585,40 @@ static int check_signature_token(const char *digest,
|
|
|
#define DUMP_AREA(a,name) STMT_NIL
|
|
|
#endif
|
|
|
|
|
|
-
|
|
|
-static time_t last_desc_dumped = 0;
|
|
|
+
|
|
|
+
|
|
|
|
|
|
static smartlist_t *descs_dumped = NULL;
|
|
|
|
|
|
static size_t len_descs_dumped = 0;
|
|
|
|
|
|
+
|
|
|
+ * One entry in the list of dumped descriptors; filename dumped to, length
|
|
|
+ * and SHA-256.
|
|
|
+ */
|
|
|
+
|
|
|
typedef struct {
|
|
|
char *filename;
|
|
|
size_t len;
|
|
|
- time_t timestamp;
|
|
|
+ uint8_t digest_sha256[DIGEST256_LEN];
|
|
|
} dumped_desc_t;
|
|
|
|
|
|
|
|
|
* the FIFO, and clean up the oldest entries to the extent they exceed the
|
|
|
- * configured cap. */
|
|
|
+ * configured cap. If any old entries with a matching hash existed, they
|
|
|
+ * just got overwritten right before this was called and we should adjust
|
|
|
+ * the total size counter without deleting them.
|
|
|
+ */
|
|
|
static void
|
|
|
-dump_desc_fifo_add_and_clean(char *filename, size_t len, time_t now)
|
|
|
+dump_desc_fifo_add_and_clean(char *filename, const uint8_t *digest_sha256,
|
|
|
+ size_t len)
|
|
|
{
|
|
|
dumped_desc_t *ent = NULL, *tmp;
|
|
|
size_t max_len;
|
|
|
|
|
|
+ tor_assert(filename != NULL);
|
|
|
+ tor_assert(digest_sha256 != NULL);
|
|
|
+
|
|
|
if (descs_dumped == NULL) {
|
|
|
|
|
|
tor_assert(len_descs_dumped == 0);
|
|
@@ -618,43 +630,45 @@ dump_desc_fifo_add_and_clean(char *filename, size_t len, time_t now)
|
|
|
ent = tor_malloc_zero(sizeof(*ent));
|
|
|
ent->filename = filename;
|
|
|
ent->len = len;
|
|
|
- ent->timestamp = now;
|
|
|
+ memcpy(ent->digest_sha256, digest_sha256, DIGEST256_LEN);
|
|
|
|
|
|
|
|
|
- if (get_options()->DetailedLogForUnparseableDescriptors > 0) {
|
|
|
- max_len = get_options()->DetailedLogForUnparseableDescriptors;
|
|
|
-
|
|
|
- while (len_descs_dumped + len > max_len &&
|
|
|
- smartlist_len(descs_dumped) > 0) {
|
|
|
-
|
|
|
- tmp = (dumped_desc_t *)(smartlist_get(descs_dumped, 0));
|
|
|
+ max_len = get_options()->MaxUnparseableDescSizeToLog;
|
|
|
+
|
|
|
+ while (len_descs_dumped + len > max_len &&
|
|
|
+ smartlist_len(descs_dumped) > 0) {
|
|
|
+
|
|
|
+ tmp = (dumped_desc_t *)(smartlist_get(descs_dumped, 0));
|
|
|
+
|
|
|
+
|
|
|
+ * Check if it matches the filename we just added, so we don't delete
|
|
|
+ * something we just emitted if we get repeated identical descriptors.
|
|
|
+ */
|
|
|
+ if (strcmp(tmp->filename, filename) != 0) {
|
|
|
+
|
|
|
+ unlink(tmp->filename);
|
|
|
+ tor_assert(len_descs_dumped >= tmp->len);
|
|
|
+ len_descs_dumped -= tmp->len;
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "Deleting old unparseable descriptor dump %s due to "
|
|
|
+ "space limits",
|
|
|
+ tmp->filename);
|
|
|
+ } else {
|
|
|
|
|
|
- * Check if it matches the filename we just added, so we don't
|
|
|
- * delete something we just emitted if we get repeated identical
|
|
|
- * descriptors.
|
|
|
+ * Don't delete, but do adjust the counter since we will bump it
|
|
|
+ * later
|
|
|
*/
|
|
|
- if (strcmp(tmp->filename, filename) != 0) {
|
|
|
-
|
|
|
- unlink(tmp->filename);
|
|
|
- tor_assert(len_descs_dumped >= tmp->len);
|
|
|
- len_descs_dumped -= tmp->len;
|
|
|
- log_info(LD_DIR, "Deleting old unparseable descriptor dump %s due to "
|
|
|
- "space limits", tmp->filename);
|
|
|
- } else {
|
|
|
-
|
|
|
- * Don't delete, but do adjust the counter since we will bump it
|
|
|
- * later
|
|
|
- */
|
|
|
- tor_assert(len_descs_dumped >= tmp->len);
|
|
|
- len_descs_dumped -= tmp->len;
|
|
|
- log_info(LD_DIR, "Replacing old descriptor dump %s with new identical"
|
|
|
- " one", tmp->filename);
|
|
|
- }
|
|
|
-
|
|
|
- smartlist_del_keeporder(descs_dumped, 0);
|
|
|
- tor_free(tmp->filename);
|
|
|
- tor_free(tmp);
|
|
|
+ tor_assert(len_descs_dumped >= tmp->len);
|
|
|
+ len_descs_dumped -= tmp->len;
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "Replacing old descriptor dump %s with new identical one",
|
|
|
+ tmp->filename);
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ smartlist_del_keeporder(descs_dumped, 0);
|
|
|
+ tor_free(tmp->filename);
|
|
|
+ tor_free(tmp);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -662,6 +676,43 @@ dump_desc_fifo_add_and_clean(char *filename, size_t len, time_t now)
|
|
|
len_descs_dumped += len;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * head of the queue if so. Return 1 if one existed and 0 otherwise.
|
|
|
+ */
|
|
|
+static int
|
|
|
+dump_desc_fifo_bump_hash(const uint8_t *digest_sha256)
|
|
|
+{
|
|
|
+ dumped_desc_t *match = NULL;
|
|
|
+
|
|
|
+ tor_assert(digest_sha256);
|
|
|
+
|
|
|
+ if (descs_dumped) {
|
|
|
+
|
|
|
+ SMARTLIST_FOREACH_BEGIN(descs_dumped, dumped_desc_t *, ent) {
|
|
|
+ if (ent &&
|
|
|
+ memcmp(ent->digest_sha256, digest_sha256, DIGEST256_LEN) == 0) {
|
|
|
+
|
|
|
+ * Save a pointer to the match and remove it from its current
|
|
|
+ * position.
|
|
|
+ */
|
|
|
+ match = ent;
|
|
|
+ SMARTLIST_DEL_CURRENT_KEEPORDER(descs_dumped, ent);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } SMARTLIST_FOREACH_END(ent);
|
|
|
+
|
|
|
+ if (match) {
|
|
|
+
|
|
|
+ smartlist_add(descs_dumped, match);
|
|
|
+
|
|
|
+
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
*/
|
|
|
static void
|
|
@@ -688,28 +739,14 @@ dump_desc_fifo_cleanup(void)
|
|
|
static void
|
|
|
dump_desc(const char *desc, const char *type)
|
|
|
{
|
|
|
- time_t now = time(NULL);
|
|
|
tor_assert(desc);
|
|
|
tor_assert(type);
|
|
|
-
|
|
|
- int dumping_this_one;
|
|
|
-
|
|
|
- * Are we including the hash in the filename and using the
|
|
|
- * FIFO mechanism?
|
|
|
- */
|
|
|
- int dumping_by_hash;
|
|
|
-
|
|
|
- int emit_prefix;
|
|
|
size_t len;
|
|
|
|
|
|
uint8_t digest_sha256[DIGEST256_LEN];
|
|
|
char digest_sha256_hex[HEX_DIGEST256_LEN+1];
|
|
|
|
|
|
char *debugfile, *debugfile_base;
|
|
|
-
|
|
|
- size_t filelen;
|
|
|
-
|
|
|
- char *content;
|
|
|
|
|
|
|
|
|
len = strlen(desc);
|
|
@@ -724,76 +761,46 @@ dump_desc(const char *desc, const char *type)
|
|
|
base16_encode(digest_sha256_hex, sizeof(digest_sha256_hex),
|
|
|
(const char *)digest_sha256, sizeof(digest_sha256));
|
|
|
|
|
|
- if (get_options()->DetailedLogForUnparseableDescriptors > 0) {
|
|
|
-
|
|
|
- dumping_by_hash = 1;
|
|
|
- dumping_this_one = 1;
|
|
|
-
|
|
|
- * Detailed logging mechanism will mention type and hash in the main log;
|
|
|
- * don't clutter up the files with anything but the exact dump.
|
|
|
- */
|
|
|
- emit_prefix = 0;
|
|
|
- tor_asprintf(&debugfile_base, "unparseable-desc.%s", digest_sha256_hex);
|
|
|
- debugfile = get_datadir_fname(debugfile_base);
|
|
|
- } else if (!last_desc_dumped || last_desc_dumped + 60 < now) {
|
|
|
-
|
|
|
- dumping_by_hash = 0;
|
|
|
- dumping_this_one = 1;
|
|
|
- emit_prefix = 1;
|
|
|
- debugfile_base = tor_strdup("unparseable-desc");
|
|
|
- debugfile = get_datadir_fname(debugfile_base);
|
|
|
- } else {
|
|
|
-
|
|
|
- dumping_by_hash = 0;
|
|
|
- dumping_this_one = 0;
|
|
|
- emit_prefix = 1;
|
|
|
- debugfile_base = NULL;
|
|
|
- debugfile = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (dumping_this_one) {
|
|
|
- if (emit_prefix) filelen = 50 + strlen(type) + len;
|
|
|
- else filelen = len;
|
|
|
-
|
|
|
-
|
|
|
- if (emit_prefix) {
|
|
|
- content = tor_malloc_zero(filelen);
|
|
|
- tor_snprintf(content, filelen, "Unable to parse descriptor of type "
|
|
|
- "%s:\n%s", type, desc);
|
|
|
- } else {
|
|
|
- content = tor_strdup(desc);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- write_str_to_file(debugfile, content, 1);
|
|
|
- log_info(LD_DIR,
|
|
|
- "Unable to parse descriptor of type %s with hash %s and length "
|
|
|
- "%lu. See file %s in data directory for details.",
|
|
|
- type, digest_sha256_hex, (unsigned long)len, debugfile_base);
|
|
|
-
|
|
|
-
|
|
|
- tor_free(content);
|
|
|
-
|
|
|
- last_desc_dumped = now;
|
|
|
-
|
|
|
-
|
|
|
- if (dumping_by_hash) {
|
|
|
- dump_desc_fifo_add_and_clean(debugfile, filelen, now);
|
|
|
+
|
|
|
+ * We mention type and hash in the main log; don't clutter up the files
|
|
|
+ * with anything but the exact dump.
|
|
|
+ */
|
|
|
+ tor_asprintf(&debugfile_base, "unparseable-desc.%s", digest_sha256_hex);
|
|
|
+ debugfile = get_datadir_fname(debugfile_base);
|
|
|
+
|
|
|
+ if (len <= get_options()->MaxUnparseableDescSizeToLog) {
|
|
|
+ if (!dump_desc_fifo_bump_hash(digest_sha256)) {
|
|
|
+
|
|
|
+ write_str_to_file(debugfile, desc, 1);
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "Unable to parse descriptor of type %s with hash %s and "
|
|
|
+ "length %lu. See file %s in data directory for details.",
|
|
|
+ type, digest_sha256_hex, (unsigned long)len, debugfile_base);
|
|
|
+
|
|
|
+ dump_desc_fifo_add_and_clean(debugfile, digest_sha256, len);
|
|
|
|
|
|
debugfile = NULL;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ log_info(LD_DIR,
|
|
|
+ "Unable to parse descriptor of type %s with hash %s and "
|
|
|
+ "length %lu. Descriptor not dumped because one with that hash "
|
|
|
+ "has already been dumped.",
|
|
|
+ type, digest_sha256_hex, (unsigned long)len);
|
|
|
+
|
|
|
}
|
|
|
} else {
|
|
|
|
|
|
log_info(LD_DIR,
|
|
|
"Unable to parse descriptor of type %s with hash %s and length "
|
|
|
- "%lu. Descriptor not dumped since we just dumped one %u seconds "
|
|
|
- "ago.",
|
|
|
- type, digest_sha256_hex, (unsigned long)len,
|
|
|
- (unsigned int)(now - last_desc_dumped));
|
|
|
+ "%lu. Descriptor not dumped because it exceeds maximum log size "
|
|
|
+ "all by itself.",
|
|
|
+ type, digest_sha256_hex, (unsigned long)len);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- if (debugfile_base != NULL) tor_free(debugfile_base);
|
|
|
- if (debugfile != NULL) tor_free(debugfile);
|
|
|
+ tor_free(debugfile_base);
|
|
|
+ tor_free(debugfile);
|
|
|
|
|
|
err:
|
|
|
return;
|