/** * Fill dump header with node address information. */ static void dump_header_set(struct dump_header *dh, const struct gnutella_node *node) { ZERO(dh); dh->data[0] = NODE_IS_UDP(node) ? DH_F_UDP : DH_F_TCP; switch (host_addr_net(node->addr)) { case NET_TYPE_IPV4: { guint32 ip; dh->data[0] |= DH_F_IPV4; ip = host_addr_ipv4(node->addr); poke_be32(&dh->data[1], ip); } break; case NET_TYPE_IPV6: dh->data[0] |= DH_F_IPV6; memcpy(&dh->data[1], host_addr_ipv6(&node->addr), 16); break; case NET_TYPE_LOCAL: case NET_TYPE_NONE: break; } poke_be16(&dh->data[17], node->port); }
/** * Generate new token for given version string. */ static char * tok_generate(time_t now, const char *version) { char token[TOKEN_BASE64_SIZE + 1]; char digest[TOKEN_VERSION_SIZE]; char lvldigest[LEVEL_SIZE]; char lvlbase64[LEVEL_BASE64_SIZE + 1]; const struct tokkey *tk; uint32 crc32; uint idx; const char *key; SHA1Context ctx; struct sha1 sha1; int lvlsize; int i; /* * Compute token. */ key = random_key(now, &idx, &tk); now = clock_loc2gmt(now); /* As close to GMT as possible */ poke_be32(&digest[0], now); random_bytes(&digest[4], 3); digest[6] &= 0xe0U; /* Upper 3 bits only */ digest[6] |= idx & 0xffU; /* Has 5 bits for the index */ SHA1Reset(&ctx); SHA1Input(&ctx, key, strlen(key)); SHA1Input(&ctx, digest, 7); SHA1Input(&ctx, version, strlen(version)); SHA1Result(&ctx, &sha1); memcpy(&digest[7], sha1.data, SHA1_RAW_SIZE); /* * Compute level. */ lvlsize = G_N_ELEMENTS(token_keys) - (tk - token_keys); crc32 = crc32_update(0, digest, TOKEN_VERSION_SIZE); for (i = 0; i < lvlsize; i++) { poke_be16(&lvldigest[i*2], tok_crc(crc32, tk)); tk++; } /* * Encode into base64. */ base64_encode_into(digest, TOKEN_VERSION_SIZE, token, TOKEN_BASE64_SIZE); token[TOKEN_BASE64_SIZE] = '\0'; ZERO(&lvlbase64); base64_encode_into(lvldigest, 2 * lvlsize, lvlbase64, LEVEL_BASE64_SIZE); return g_strconcat(token, "; ", lvlbase64, (void *) 0); }
/** * Create a dime record header. */ static void dime_fill_record_header(const struct dime_record *record, char *data, size_t size, guint flags) { unsigned char value; g_assert(record); g_assert(data); g_assert(size >= DIME_HEADER_SIZE); value = DIME_VERSION << 3; value |= (DIME_F_MB & flags); value |= (DIME_F_ME & flags); value |= (DIME_F_CF & flags); poke_u8(&data[0], value); poke_u8(&data[1], (record->type_t << 4) | record->resrvd); poke_be16(&data[2], record->options_length); poke_be16(&data[4], record->id_length); poke_be16(&data[6], record->type_length); poke_be32(&data[8], record->data_length); }
/** * Create a security token from host address and port using specified key. * * Optionally, extra contextual data may be given (i.e. the token is not * only based on the address and port) to make the token more unique to * a specific context. * * @param stg the security token generator * @param n key index to use * @param tok where security token is written * @param addr address of the host for which we're generating a token * @param port port of the host for which we're generating a token * @param data optional contextual data * @param len length of contextual data */ static void sectoken_generate_n(sectoken_gen_t *stg, size_t n, sectoken_t *tok, host_addr_t addr, uint16 port, const void *data, size_t len) { char block[8]; char enc[8]; char *p = block; sectoken_gen_check(stg); g_assert(tok != NULL); g_assert(size_is_non_negative(n)); g_assert(n < stg->keycnt); g_assert((NULL != data) == (len != 0)); switch (host_addr_net(addr)) { case NET_TYPE_IPV4: p = poke_be32(p, host_addr_ipv4(addr)); break; case NET_TYPE_IPV6: { uint val; val = binary_hash(host_addr_ipv6(&addr), 16); p = poke_be32(p, val); } break; case NET_TYPE_LOCAL: case NET_TYPE_NONE: g_error("unexpected address for security token generation: %s", host_addr_to_string(addr)); } p = poke_be16(p, port); p = poke_be16(p, 0); /* Filler */ g_assert(p == &block[8]); STATIC_ASSERT(sizeof(tok->v) == sizeof(uint32)); STATIC_ASSERT(sizeof(block) == sizeof(enc)); tea_encrypt(&stg->keys[n], enc, block, sizeof block); /* * If they gave contextual data, encrypt them by block of 8 bytes, * filling the last partial block with zeroes if needed. */ if (data != NULL) { const void *q = data; size_t remain = len; char denc[8]; STATIC_ASSERT(sizeof(denc) == sizeof(enc)); while (remain != 0) { size_t fill = MIN(remain, 8U); unsigned i; if (fill != 8U) ZERO(&block); memcpy(block, q, fill); remain -= fill; q = const_ptr_add_offset(q, fill); /* * Encrypt block of contextual data (possibly filled with trailing * zeroes) and merge back the result into the main encryption * output with XOR. */ tea_encrypt(&stg->keys[n], denc, block, sizeof block); for (i = 0; i < sizeof denc; i++) enc[i] ^= denc[i]; } } poke_be32(tok->v, tea_squeeze(enc, sizeof enc)); }
/** * Flag a MUID for OOB queries as being from GTKG, by patching `guid' in place. * * Bytes 4/5 become the GTKG version mark. * Byte 15 becomes the HEC of the leading 15 bytes. */ static void guid_flag_oob_gtkg(struct guid *muid) { poke_be16(&muid->v[4], gtkg_version_mark); muid->v[15] = guid_hec_oob(muid); /* guid_hec() skips leading byte */ }
/** * Flag a GUID/MUID as being from GTKG, by patching `guid' in place. * * Bytes 2/3 become the GTKG version mark. * Byte 0 becomes the HEC of the remaining 15 bytes. */ static void guid_flag_gtkg(struct guid *guid) { poke_be16(&guid->v[2], gtkg_version_mark); guid->v[0] = guid_hec(guid); }