Ejemplo n.º 1
0
/**
 * 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);
}
Ejemplo n.º 2
0
/**
 * Put large value data into the .dat and fill in the supplied .pag buffer
 * with the block numbers where the value is stored and other size information.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param blen		length of big value in the page
 * @param val		start of value data
 * @param vlen		length of value
 *
 * @return TRUE if value was written successfully in the .dat file.
 */
gboolean
bigval_put(DBM *db, char *bval, size_t blen, const char *val, size_t vlen)
{
	g_assert(bigval_length(vlen) == blen);

	if (!big_file_alloc(db, bigval_blocks(bval), bigblocks(vlen)))
		return FALSE;

	/*
	 * Write the value header:
	 *
	 * value size
	 */

	poke_be32(bval, (guint32) vlen);

	/*
	 * And now the indirection block numbers of the value, pointing in .dat.
	 */

	if (0 != big_store(db, bigval_blocks(bval), val, vlen)) {
		big_file_free(db, bigval_blocks(bval), bigblocks(vlen));
		return FALSE;
	}

	return TRUE;
}
Ejemplo n.º 3
0
/**
 * Put large key data into the .dat and fill in the supplied .pag buffer
 * with the block numbers where the key is stored and other size information.
 *
 * @param db		the sdbm database
 * @param bkey		start of big key in the page
 * @param blen		length of big key in the page
 * @param key		start of key data
 * @param klen		length of key
 *
 * @return TRUE if key was written successfully in the .dat file.
 */
gboolean
bigkey_put(DBM *db, char *bkey, size_t blen, const char *key, size_t klen)
{
	g_assert(bigkey_length(klen) == blen);

	if (!big_file_alloc(db, bigkey_blocks(bkey), bigblocks(klen)))
		return FALSE;

	/*
	 * Write the key header:
	 *
	 * key size
	 * first BIG_KEYSAVED bytes of key
	 * last BIG_KEYSAVED bytes of key
	 */

	poke_be32(bkey, (guint32) klen);
	memcpy(bigkey_head(bkey), key, BIG_KEYSAVED);
	memcpy(bigkey_tail(bkey), key + (klen - BIG_KEYSAVED), BIG_KEYSAVED);

	/*
	 * And now the indirection block numbers of the key, pointing in .dat.
	 */

	if (0 != big_store(db, bigkey_blocks(bkey), key, klen)) {
		big_file_free(db, bigkey_blocks(bkey), bigblocks(klen));
		return FALSE;
	}

	return TRUE;
}
Ejemplo n.º 4
0
/**
 * 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);
}
Ejemplo n.º 5
0
/**
 * Tries to convert the host address "from" to the network type "to_net"
 * and stores the converted address in "*to". If conversion is not possible,
 * FALSE is returned and "*to" is set to zero_host_addr.
 *
 * @param from The address to convert.
 * @param to Will hold the converted address.
 * @param to_net The network type to convert the address to.
 * 
 * @return TRUE if the address could be converted, FALSE otherwise.
 */
bool
host_addr_convert(const host_addr_t from, host_addr_t *to,
	enum net_type to_net)
{
	if (from.net == to_net) {
		*to = from;
		return TRUE;
	}

	switch (to_net) {
	case NET_TYPE_IPV4:
		switch (from.net) {
		case NET_TYPE_IPV6:
			if (host_addr_can_convert(from, NET_TYPE_IPV4)) {
				*to = host_addr_peek_ipv4(&from.addr.ipv6[12]);
				return TRUE;
			}
			break;
		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			break;
		}
		break;

	case NET_TYPE_IPV6:
		switch (from.net) {
		case NET_TYPE_IPV4:
			to->net = to_net;
			memset(to->addr.ipv6, 0, 10);
			to->addr.ipv6[10] = 0xff;
			to->addr.ipv6[11] = 0xff;
			poke_be32(&to->addr.ipv6[12], host_addr_ipv4(from));
			return TRUE;
		case NET_TYPE_NONE:
			break;
		}
		break;

	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		break;
	}

	*to = zero_host_addr;
	return FALSE;
}
Ejemplo n.º 6
0
/**
 * Replace value data in-place.
 *
 * @param db		the sdbm database
 * @param bval		start of big value in the page
 * @param data		the new value
 * @param len		length of data
 *
 * @return 0 if OK, -1 on error with errno set.
 */
int
big_replace(DBM *db, char *bval, const char *data, size_t len)
{
	size_t old_len = big_length(bval);

	g_assert(size_is_non_negative(len));
	g_assert(bigblocks(old_len) == bigblocks(len));
	g_assert(len <= MAX_INT_VAL(guint32));

	/*
	 * Write data on the same blocks as before, since we know it will fit.
	 */

	poke_be32(bval, (guint32) len);		/* First 4 bytes: real data length */

	return big_store(db, bigval_blocks(bval), data, len);
}
Ejemplo n.º 7
0
/**
 * Generate GUID for a query with OOB results delivery.
 * If `initial' is false, this is a requery.
 *
 * Bytes 0 to 3 if the GUID are the 4 octet bytes of the IP address.
 * Bytes 13 and 14 are the little endian representation of the port.
 * Byte 15 holds an HEC with bit 0 indicating a requery.
 */
void
guid_query_oob_muid(struct guid *muid, const host_addr_t addr, uint16 port,
	bool initial)
{
	uint32 ip;

	g_assert(host_addr_is_ipv4(addr));

	guid_random_fill(muid);

	ip = host_addr_ipv4(addr);
	poke_be32(&muid->v[0], ip);
	poke_le16(&muid->v[13], port);

	guid_flag_oob_gtkg(muid);		/* Mark as being from GTKG */

	if (initial)
		muid->v[15] &= ~GUID_REQUERY;
	else
		muid->v[15] |= GUID_REQUERY;
}
Ejemplo n.º 8
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);
}
Ejemplo n.º 9
0
/**
 * Add new host (identified by address and port) to the Gnutella host vector.
 */
void
gnet_host_vec_add(gnet_host_vec_t *vec, host_addr_t addr, uint16 port)
{
	g_return_if_fail(vec);

	switch (host_addr_net(addr)) {
	case NET_TYPE_IPV4:
		if (vec->n_ipv4 < 255) {
			size_t size, old_size;
			char *dest;

			old_size = vec->n_ipv4 * sizeof vec->hvec_v4[0];
			size = old_size + sizeof vec->hvec_v4[0];
			vec->hvec_v4 = wrealloc(vec->hvec_v4, old_size, size);

			dest = cast_to_pointer(&vec->hvec_v4[vec->n_ipv4++]);
			poke_be32(&dest[0], host_addr_ipv4(addr));
			poke_le16(&dest[4], port);
		}
		break;
	case NET_TYPE_IPV6:
		if (vec->n_ipv6 < 255) {
			size_t size, old_size;
			char *dest;

			old_size = vec->n_ipv6 * sizeof vec->hvec_v6[0];
			size = old_size + sizeof vec->hvec_v6[0];
			vec->hvec_v6 = wrealloc(vec->hvec_v6, old_size, size);

			dest = cast_to_pointer(&vec->hvec_v6[vec->n_ipv6++]);
			dest = mempcpy(dest, host_addr_ipv6(&addr), 16);
			poke_le16(dest, port);
		}
		break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		break;
	}
}
Ejemplo n.º 10
0
/**
 * Serialization convenience for IP:port.
 *
 * Write the IP:port (IP as big-endian, port as little-endian) into the
 * supplied buffer, whose length MUST be 18 bytes at least.
 *
 * If len is non-NULL, it is written with the length of the serialized data.
 *
 * @return pointer following serialization data.
 */
void *
host_ip_port_poke(void *p, const host_addr_t addr, uint16 port, size_t *len)
{
	void *q = p;

	switch (host_addr_net(addr)) {
	case NET_TYPE_IPV4:
		q = poke_be32(q, host_addr_ipv4(addr));
		break;
	case NET_TYPE_IPV6:
		q = mempcpy(q, host_addr_ipv6(&addr), sizeof addr.addr.ipv6);
		break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		g_assert_not_reached();
	}

	q = poke_le16(q, port);

	if (len != NULL)
		*len = ptr_diff(q, p);

	return q;
}
Ejemplo n.º 11
0
void
utf8_regression_1(void)
{
  uint32_t i;
  unsigned valid = 0;

  for (i = 0; i < 0xffffffffUL; i++) {
    static char data[5];
    static char hit[0x10FFFFU + 1];
    uint32_t d;

    if (0 == (i % (((uint32_t) -1) / 100))) {
      printf("i=%u\n", i / (((uint32_t) -1) / 100));
    }

    poke_be32(data, i);
    d = utf8_decode(data, 4);
    if ((uint32_t) -1 == d)
      continue;

    if (d > 0x10ffffU || utf32_is_non_character(d) || utf32_is_surrogate(d)) {
      printf("data: %02x %02x %02x %02x\n",
          (unsigned char) data[0],
          (unsigned char) data[1],
          (unsigned char) data[2],
          (unsigned char) data[3]);
      printf("d: U+%lx\n", (unsigned long) d);
      printf("i: %lu\n", (unsigned long) i);
      RUNTIME_ASSERT(d <= 0x10ffffU);
      RUNTIME_ASSERT(!utf32_is_non_character(d));
      RUNTIME_ASSERT(!utf32_is_surrogate(d));
    }

    if (!hit[d]) {
      hit[d] = 1;
      valid++;
    }

    {
      unsigned n;
      char buf[4];

      n = utf8_encode(d, buf);
      RUNTIME_ASSERT(n > 0);
      RUNTIME_ASSERT(n <= 4);
      RUNTIME_ASSERT(n == utf8_first_byte_length_hint(data[0]));

      if (0 != memcmp(data, buf, n)) {
        printf("buf:  %02x %02x %02x %02x\n",
            (unsigned char) buf[0],
            (unsigned char) buf[1],
            (unsigned char) buf[2],
            (unsigned char) buf[3]);
        printf("data: %02x %02x %02x %02x\n",
            (unsigned char) data[0],
            (unsigned char) data[1],
            (unsigned char) data[2],
            (unsigned char) data[3]);
        printf("d: U+%lx\n", (unsigned long) i);
        printf("i: %lu\n", (unsigned long) i);
        printf("n: %u\n", n);
        RUNTIME_ASSERT(0);
      }
    }
  }
  printf("valid=%u\n", valid);

  printf("PASSED\n");
}
Ejemplo n.º 12
0
/**
 * Allocate blocks (consecutive if possible) from the .dat file.
 * Block numbers are written back in the specified vector, in sequence.
 *
 * Blocks are always allocated with increasing block numbers, i.e. the list
 * of block numbers returned is guaranteed to be sorted.  This will help
 * upper layers to quickly determine whether all the blocks are contiguous
 * for instance.
 *
 * The file is extended as necessary to be able to allocate the blocks but
 * this is only done when there are no more free blocks available.
 *
 * @param db		the sdbm database
 * @param bvec		vector where allocated block numbers will be stored
 * @param bcnt		amount of blocks in vector (amount to allocate)
 *
 * @return TRUE if we were able to allocate all the requested blocks.
 */
static gboolean
big_file_alloc(DBM *db, void *bvec, int bcnt)
{
	DBMBIG *dbg = db->big;
	size_t first;
	int n;
	void *q;
	int bmap = 0;		/* Initial bitmap from which we allocate */

	g_assert(bcnt > 0);
	g_return_val_if_fail(NULL == dbg->bitcheck, FALSE);

	if (-1 == dbg->fd && -1 == big_open(dbg))
		return FALSE;

	/*
	 * First try to allocate all the blocks sequentially.
	 */

retry:

	first = big_falloc_seq(db, bmap, bcnt);
	if (first != 0) {
		while (bcnt-- > 0) {
			bvec = poke_be32(bvec, first++);
		}
		goto success;
	}

	/*
	 * There are no "bcnt" consecutive free blocks in the file.
	 *
	 * Before extending the file, we're going to fill the holes as much
	 * as possible.
	 */

	for (first = 0, q = bvec, n = bcnt; n > 0; n--) {
		first = big_falloc(db, first + 1);
		if (0 == first)
			break;
		q = poke_be32(q, first);
	}

	if (0 == n)
		goto success;		/* Found the requested "bcnt" free blocks */

	/*
	 * Free the incompletely allocated blocks: since we're about to extend
	 * the file, we'll use consecutive blocks from the new chunk governed
	 * by the added empty bitmap.
	 */

	for (q = bvec, n = bcnt - n; n > 0; n--) {
		first = peek_be32(q);
		big_ffree(db, first);
		q = ptr_add_offset(q, sizeof(guint32));
	}

	/*
	 * Extend the file by allocating another bitmap.
	 */

	g_assert(0 == bmap);		/* Never retried yet */

	if (dbg->bitbuf_dirty && !flush_bitbuf(db))
		return FALSE;

	memset(dbg->bitbuf, 0, BIG_BLKSIZE);
	bit_field_set(dbg->bitbuf, 0);	/* First page is the bitmap itself */
	dbg->bitbno = dbg->bitmaps * BIG_BITCOUNT;
	dbg->bitmaps++;

	/*
	 * Now retry starting to allocate blocks from the newly added bitmap.
	 *
	 * This will likely succeed if we're trying to allocate less than 8 MiB
	 * worth of data (with 1 KiB blocks).
	 */

	bmap = dbg->bitmaps - 1;
	goto retry;

success:
	/*
	 * We successfully allocated blocks from the bitmap.
	 *
	 * If the database is not volatile, we need to flush the bitmap to disk
	 * immediately in case of a crash, to avoid reusing these parts of the file.
	 */

	if (!db->is_volatile && dbg->bitbuf_dirty && !flush_bitbuf(db)) {
		/* Cannot flush -> cannot allocate the blocks: free them */
		for (q = bvec, n = bcnt; n > 0; n--) {
			first = peek_be32(q);
			big_ffree(db, first);
			q = ptr_add_offset(q, sizeof(guint32));
		}
		return FALSE;
	}

	return TRUE;		/* Succeeded */
}
Ejemplo n.º 13
0
/**
 * 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));
}
Ejemplo n.º 14
0
/**
 * Create a new Gnutella host vector out of a sequence of gnet_host_t items.
 */
static gnet_host_vec_t *
gnet_host_vec_from_sequence(sequence_t *s)
{
	sequence_iter_t *iter;
	gnet_host_vec_t *vec;
	uint n_ipv6 = 0, n_ipv4 = 0, hcnt;

	if (sequence_is_empty(s))
		return NULL;

	hcnt = 0;
	iter = sequence_forward_iterator(s);
	while (sequence_iter_has_next(iter)) {
		const gnet_host_t *host = sequence_iter_next(iter);

		switch (gnet_host_get_net(host)) {
		case NET_TYPE_IPV4:
			n_ipv4++;
			hcnt++;
			break;
		case NET_TYPE_IPV6:
			n_ipv6++;
			hcnt++;
			break;
		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			break;
		}
	}
	sequence_iterator_release(&iter);
	if (0 == hcnt)
		return NULL;

	vec = gnet_host_vec_alloc();
	vec->n_ipv4 = MIN(n_ipv4, 255);
	vec->n_ipv6 = MIN(n_ipv6, 255);

	if (vec->n_ipv4 > 0)
		WALLOC_ARRAY(vec->hvec_v4, vec->n_ipv4);
	if (vec->n_ipv6 > 0)
		WALLOC_ARRAY(vec->hvec_v6, vec->n_ipv6);

	n_ipv4 = 0;
	n_ipv6 = 0;

	iter = sequence_forward_iterator(s);
	while (sequence_iter_has_next(iter)) {
		const gnet_host_t *host = sequence_iter_next(iter);
		host_addr_t addr = gnet_host_get_addr(host);
		uint16 port = gnet_host_get_port(host);

		switch (gnet_host_get_net(host)) {
		case NET_TYPE_IPV4:
			if (n_ipv4 < vec->n_ipv4) {
				char *dest = cast_to_pointer(&vec->hvec_v4[n_ipv4++]);
				poke_be32(&dest[0], host_addr_ipv4(addr));
				poke_le16(&dest[4], port);
			}
			break;
		case NET_TYPE_IPV6:
			if (n_ipv6 < vec->n_ipv6) {
				char *dest = cast_to_pointer(&vec->hvec_v6[n_ipv6++]);
				dest = mempcpy(dest, host_addr_ipv6(&addr), 16);
				poke_le16(dest, port);
			}
			break;
		case NET_TYPE_LOCAL:
		case NET_TYPE_NONE:
			break;
		}
	}
	sequence_iterator_release(&iter);
	return vec;
}