/* bencode.h — bencode parser/encoder for .torrent, tracker, and DHT messages. * * The parser is zero-copy: strings are slices into the caller's buffer, never * duplicated. Every parsed value also records its exact raw byte span, which is * what lets us compute an info-hash over the *original* encoding of the `info` * dict without re-serializing (re-serialization would risk a non-canonical * byte sequence and a wrong hash). Container children live in an arena owned by * the document, so the whole tree frees in one shot. * * Hardened for hostile input (it parses bytes straight off the wire): explicit * depth and node-count limits, strict integer/string syntax, no unbounded * recursion blow-up. This is a primary fuzz target. */ #ifndef NAUT_BENCODE_H #define NAUT_BENCODE_H #include "naut/common.h" typedef enum { NAUT_BC_INT, NAUT_BC_STR, NAUT_BC_LIST, NAUT_BC_DICT } naut_bc_type; typedef struct naut_bc naut_bc; typedef struct { const uint8_t *kp; size_t kn; /* key slice (bencode dict keys are strings) */ const naut_bc *val; } naut_bc_pair; struct naut_bc { naut_bc_type type; union { int64_t i; struct { const uint8_t *p; size_t n; } str; struct { const naut_bc *items; size_t count; } list; struct { const naut_bc_pair *pairs; size_t count; } dict; } v; const uint8_t *raw; /* exact encoding span of this value... */ size_t raw_len; /* ...used for info-hash over the original bytes */ }; typedef struct naut_bc_doc naut_bc_doc; /* Parse the entire buffer as one bencode value. Rejects trailing garbage. * On success *out owns the tree (free with naut_bc_free). */ naut_err naut_bc_parse(const uint8_t *data, size_t len, naut_bc_doc **out); /* Parse one value from the start of a larger buffer. `consumed` receives the * encoded value length; trailing bytes remain owned by the caller. */ naut_err naut_bc_parse_prefix(const uint8_t *data, size_t len, naut_bc_doc **out, size_t *consumed); const naut_bc *naut_bc_root(const naut_bc_doc *doc); void naut_bc_free(naut_bc_doc *doc); /* Accessors (return NULL / defaults on type mismatch). */ const naut_bc *naut_bc_dict_get(const naut_bc *d, const char *key); const naut_bc *naut_bc_list_at(const naut_bc *l, size_t i); bool naut_bc_get_int(const naut_bc *v, int64_t *out); bool naut_bc_get_str(const naut_bc *v, const uint8_t **p, size_t *n); /* true if a STR value equals the given C string exactly */ bool naut_bc_str_eq(const naut_bc *v, const char *s); /* --- encoder (DHT/tracker/.torrent writing): append to a growable buffer --- */ typedef struct { uint8_t *buf; size_t len, cap; naut_err err; } naut_bc_writer; void naut_bc_w_init(naut_bc_writer *w); void naut_bc_w_free(naut_bc_writer *w); void naut_bc_w_int(naut_bc_writer *w, int64_t v); void naut_bc_w_bytes(naut_bc_writer *w, const void *p, size_t n); void naut_bc_w_cstr(naut_bc_writer *w, const char *s); void naut_bc_w_list_begin(naut_bc_writer *w); void naut_bc_w_dict_begin(naut_bc_writer *w); void naut_bc_w_end(naut_bc_writer *w); /* closes the current list/dict */ #endif /* NAUT_BENCODE_H */