static const char * dump_header_addr_to_string(const struct dump_header *dh) { in_port_t port = peek_be16(dh->port); if (DH_F_IPV4 & dh->flags) { return net_addr_port_to_string(net_addr_peek_ipv4(&dh->addr[0]), port); } else if (DH_F_IPV6 & dh->flags) { return net_addr_port_to_string(net_addr_peek_ipv6(&dh->addr[0]), port); } else { return "<unknown>"; } }
/** * Decode major/minor and release information from the specified two * contiguous GUID bytes. * * @param guid is the GUID considered * @param start is the offset of the markup (2 or 4) in the GUID * @param majp is filled with the major version if it's a GTKG markup * @param minp is filled with the minor version if it's a GTKG markup * @param relp is filled with the release status if it's a GTKG markup * * @return whether we recognized a GTKG markup. */ static bool guid_extract_gtkg_info(const guid_t *guid, size_t start, uint8 *majp, uint8 *minp, bool *relp) { uint8 major; uint8 minor; bool release; uint16 mark; uint16 xmark; uint8 product_major; g_assert(start < GUID_RAW_SIZE - 1); major = peek_u8(&guid->v[start]) & 0x0f; minor = peek_u8(&guid->v[start + 1]) & 0x7f; release = booleanize(0 == (peek_u8(&guid->v[start + 1]) & 0x80)); mark = guid_gtkg_encode_version(major, minor, release); xmark = peek_be16(&guid->v[start]); if (mark != xmark) return FALSE; /* * Even if by extraordinary the above check matches, make sure we're * not distant from more than one major version. Since GTKG versions * expire every year, and I don't foresee more than one major version * release per year, this strengthens the positive check. */ product_major = product_get_major(); if (major != product_major) { int8 delta = product_major - major; if (delta < -1 || delta > 1) return FALSE; } /* * We've validated the GUID: the HEC is correct and the version is * consistently encoded, judging by the highest 4 bits of guid.v[4]. */ if (majp) *majp = major; if (minp) *minp = minor; if (relp) *relp = release; return TRUE; }
/** * Parse ``size'' bytes starting at ``data'' and fill-in the information * about the next record in ``header''. * * @return the length of the record successfully parsed, 0 on error (since * the minimal amount of bytes for an empty record would be DIME_HEADER_SIZE). */ static size_t dime_parse_record_header(const char *data, size_t size, struct dime_record *header) { const char * const data0 = data; size_t n; g_assert(data); g_assert(header); n = DIME_HEADER_SIZE; if (size < n) { goto failure; } header->version = peek_u8(&data[0]) >> 3; if (DIME_VERSION != header->version) { g_warning("dime_parse_record_header(): Cannot parse dime version %u, " "only version %u is supported", header->version, DIME_VERSION); goto failure; } header->flags = peek_u8(&data[0]) & (DIME_F_MB | DIME_F_ME | DIME_F_CF); header->type_t = peek_u8(&data[1]) >> 4; header->resrvd = peek_u8(&data[1]) & 0x0F; header->options_length = peek_be16(&data[2]); header->id_length = peek_be16(&data[4]); header->type_length = peek_be16(&data[6]); header->data_length = peek_be32(&data[8]); size -= n; data += n; header->options = data; n = dime_ceil(header->options_length); if (size < n) { dime_log_truncated_record("options", header, header->options_length, size); goto failure; } size -= n; data += n; header->id = data; n = dime_ceil(header->id_length); if (size < n) { dime_log_truncated_record("ID", header, header->id_length, size); goto failure; } size -= n; data += n; header->type = data; n = dime_ceil(header->type_length); if (size < n) { dime_log_truncated_record("type", header, header->type_length, size); goto failure; } size -= n; data += n; header->data = data; n = dime_ceil(header->data_length); if (size < n) { dime_log_truncated_record("data", header, header->data_length, size); goto failure; } size -= n; data += n; return data - data0; failure: return 0; }
/** * Validate a base64-encoded version token `tokenb64' of `len' bytes. * The `ip' is given only for clock update operations. * * @returns error code, or TOK_OK if token is valid. */ tok_error_t tok_version_valid( const char *version, const char *tokenb64, int len, host_addr_t addr) { time_t now = tm_time(); time_t stamp; uint32 crc; const struct tokkey *tk; const struct tokkey *rtk; const struct tokkey *latest; uint idx; const char *key; SHA1Context ctx; char lvldigest[1024]; char token[TOKEN_VERSION_SIZE]; struct sha1 digest; version_t rver; char *end; int toklen; int lvllen; int lvlsize; uint i; end = strchr(tokenb64, ';'); /* After 25/02/2003 */ toklen = end ? (end - tokenb64) : len; /* * Verify token. */ if (toklen != TOKEN_BASE64_SIZE) return TOK_BAD_LENGTH; if (!base64_decode_into(tokenb64, toklen, token, TOKEN_VERSION_SIZE)) return TOK_BAD_ENCODING; stamp = (time_t) peek_be32(&token); /* * Use that stamp, whose precision is TOKEN_LIFE, to update our * clock skew if necessary. */ clock_update(stamp, TOKEN_LIFE, addr); if (ABS(stamp - clock_loc2gmt(now)) > TOKEN_CLOCK_SKEW) return TOK_BAD_STAMP; if (!version_fill(version, &rver)) /* Remote version */ return TOK_BAD_VERSION; tk = find_tokkey_version(&rver, stamp); /* The keys they used */ if (tk == NULL) return TOK_BAD_KEYS; idx = (uchar) token[6] & 0x1f; /* 5 bits for the index */ if (idx >= tk->count) return TOK_BAD_INDEX; key = tk->keys[idx]; SHA1Reset(&ctx); SHA1Input(&ctx, key, strlen(key)); SHA1Input(&ctx, token, 7); SHA1Input(&ctx, version, strlen(version)); SHA1Result(&ctx, &digest); if (0 != memcmp(&token[7], digest.data, SHA1_RAW_SIZE)) return TOK_INVALID; if (version_build_cmp(&rver, &tk->ver) < 0) return TOK_OLD_VERSION; if (end == NULL) return TOK_MISSING_LEVEL; latest = find_latest(&rver); if (latest == NULL) /* Unknown in our key set */ return TOK_OLD_VERSION; /* * Verify build. * * Build numbers were emitted when we switched to SVN on 2006-08-26 * and stopped being a monotonous increasing function when we switched * to git on 2011-09-11. */ if ( rver.timestamp >= 1156543200 && /* 2006-08-26 */ rver.timestamp < GIT_SWITCH /* 2011-09-11 */ ) { if (0 == rver.build) return TOK_MISSING_BUILD; if (rver.build < latest->ver.build) return TOK_WRONG_BUILD; } /* * Verify level. */ lvllen = len - toklen - 2; /* Forget about "; " */ end += 2; /* Skip "; " */ if (UNSIGNED(lvllen) >= sizeof(lvldigest) || lvllen <= 0) return TOK_BAD_LEVEL_LENGTH; if (lvllen & 0x3) return TOK_BAD_LEVEL_LENGTH; lvllen = base64_decode_into(end, lvllen, lvldigest, sizeof(lvldigest)); if (lvllen == 0 || (lvllen & 0x1)) return TOK_BAD_LEVEL_ENCODING; g_assert(lvllen >= 2); g_assert((lvllen & 0x1) == 0); /* * Only check the highest keys we can check. */ lvllen /= 2; /* # of keys held remotely */ lvlsize = G_N_ELEMENTS(token_keys) - (tk - token_keys); lvlsize = MIN(lvllen, lvlsize); g_assert(lvlsize >= 1); rtk = tk + (lvlsize - 1); /* Keys at that level */ crc = crc32_update(0, token, TOKEN_VERSION_SIZE); crc = tok_crc(crc, rtk); lvlsize--; /* Move to 0-based offset */ if (peek_be16(&lvldigest[2*lvlsize]) != crc) return TOK_INVALID_LEVEL; for (i = 0; i < G_N_ELEMENTS(token_keys); i++) { rtk = &token_keys[i]; if (rtk->ver.timestamp > rver.timestamp) { rtk--; /* `rtk' could not exist remotely */ break; } } if (lvlsize < rtk - tk) return TOK_SHORT_LEVEL; return TOK_OK; }
static void handle_query(const struct gnutella_header *header, const char * const data, const size_t size) { const char *end; if (size < 2) { printf("Too short: %s\n", escape_buffer(data, size)); } else { uint16_t flags; int swapped = 0; flags = peek_be16(data); if (!(flags & QUERY_F_MARK)) { uint16_t mask = QUERY_F_MARK | QUERY_F_GGEP_H | QUERY_F_LEAF_GUIDED; uint16_t reversed; /* Try to decode endian swapped flags as emitted by RAZA */ reversed = peek_le16(data); if ((reversed & mask) == mask) { swapped = 1; flags = reversed; } } if (flags & QUERY_F_MARK) { int is_firewalled = flags & QUERY_F_FIREWALLED; int want_xml = flags & QUERY_F_WANT_XML; int leaf_guided = flags & QUERY_F_LEAF_GUIDED; int ggep_h = flags & QUERY_F_GGEP_H; int is_oob = flags & QUERY_F_OOB; int rudp_supp = flags & QUERY_F_RUDP; int bit8 = flags & QUERY_F_BIT8; printf("Flags: %s%s%s%s%s%s%s%s\n" , is_firewalled ? "firewalled " : "" , want_xml ? "XML " : "" , leaf_guided ? "leaf-guided " : "" , ggep_h ? "GGEP/H " : "" , is_oob ? "OOB " : "" , rudp_supp ? "RUDP " : "" , bit8 ? "bit8 " : "" , swapped ? "[SWAPPED]" : "" ); if (is_oob) { printf("OOB address: %s\n", net_addr_port_to_string(net_addr_peek_ipv4(&header->guid.data[0]), peek_le16(&header->guid.data[13])) ); } } else { printf("Flags: 0x%04X\n", flags); } end = memchr(&data[2], '\0', size - 2); if (end) { end++; } else { end = &data[size]; } printf("Query: \"%s\"\n", escape_buffer(&data[2], (end - &data[2]) - 1)); if (&data[size] != end) { size_t ext_len; ext_len = &data[size] - end; if ('\0' == data[size - 1]) { ext_len--; } handle_extension(end, ext_len); } } }
static inline bool host_addr_is_6to4(const host_addr_t ha) { return host_addr_is_ipv6(ha) && 0x2002 == peek_be16(&ha.addr.ipv6[0]); }