Example #1
0
/**
 * Mark blocks in the supplied vector as allocated in the checking bitmap.
 *
 * @param db		the sdbm database
 * @param bvec		vector where allocated block numbers are stored
 * @param bcnt		amount of blocks in vector
 */
static void
big_file_mark_used(DBM *db, const void *bvec, int bcnt)
{
	DBMBIG *dbg = db->big;
	const void *q;
	int n;

	if (!big_check_start(db))
		return;

	for (q = bvec, n = bcnt; n > 0; n--) {
		size_t bno = peek_be32(q);
		bit_field_t *map;
		long bmap;
		size_t bit;

		bmap = bno / BIG_BITCOUNT;			/* Bitmap handling this block */
		bit = bno & (BIG_BITCOUNT - 1);		/* Index within bitmap */
		q = const_ptr_add_offset(q, sizeof(guint32));

		/*
		 * It's because of this sanity check that we don't want to consider
		 * the bitcheck field as a huge continuous map.  Also doing that would
		 * violate the encapsulation: we're not supposed to know how bits are
		 * allocated in the field.
		 */

		if (bmap >= dbg->bitmaps)
			continue;

		map = ptr_add_offset(dbg->bitcheck, bmap * BIG_BLKSIZE);
		bit_field_set(map, bit);
	}
}
Example #2
0
/**
 * Handle reception of a /LNI
 */
static void
g2_node_handle_lni(gnutella_node_t *n, const g2_tree_t *t)
{
	g2_tree_t *c;

	/*
	 * Handle the children of /LNI.
	 */

	G2_TREE_CHILD_FOREACH(t, c) {
		enum g2_lni_child ct = TOKENIZE(g2_tree_name(c), g2_lni_children);
		const char *payload;
		size_t paylen;

		switch (ct) {
		case G2_LNI_GU:			/* the node's GUID */
			payload = g2_tree_node_payload(c, &paylen);
			if (GUID_RAW_SIZE == paylen)
				node_set_guid(n, (guid_t *) payload, TRUE);
			break;

		case G2_LNI_NA:			/* the node's address, with listening port */
			{
				host_addr_t addr;
				uint16 port;

				if (g2_node_parse_address(c, &addr, &port)) {
					if (host_address_is_usable(addr))
						n->gnet_addr = addr;
					n->gnet_port = port;
				}
			}
			break;

		case G2_LNI_LS:			/* library statistics */
			payload = g2_tree_node_payload(c, &paylen);
			if (paylen >= 8) {
				uint32 files = peek_le32(payload);
				uint32 kbytes = peek_le32(&payload[4]);

				n->gnet_files_count = files;
				n->gnet_kbytes_count = kbytes;
				n->flags |= NODE_F_SHARED_INFO;
			}
			break;

		case G2_LNI_V:			/* vendor code */
			payload = g2_tree_node_payload(c, &paylen);
			if (paylen >= 4)
				n->vcode.u32 = peek_be32(payload);
			break;

		case G2_LNI_UP:			/* uptime */
			payload = g2_tree_node_payload(c, &paylen);
			if (paylen <= 4)
				n->up_date = tm_time() - vlint_decode(payload, paylen);
			break;
		}
	}
}
Example #3
0
/**
 * Check whether the Gnutella host vector already contains the address:port.
 *
 * @return TRUE if the host vector already contains it.
 */
bool
gnet_host_vec_contains(gnet_host_vec_t *vec, host_addr_t addr, uint16 port)
{
	size_t i;

	g_return_val_if_fail(vec, FALSE);

	switch (host_addr_net(addr)) {
	case NET_TYPE_IPV4:
		for (i = 0; i < vec->n_ipv4; i++) {
			char *dest = cast_to_pointer(&vec->hvec_v4[i]);
			uint32 ip = peek_be32(&dest[0]);
			uint16 pt = peek_le16(&dest[4]);

			if (pt == port && host_addr_ipv4(addr) == ip)
				return TRUE;
		}
		break;
	case NET_TYPE_IPV6:
		for (i = 0; i < vec->n_ipv6; i++) {
			char *dest = cast_to_pointer(&vec->hvec_v6[i]);
			uint16 pt = peek_le16(&dest[16]);

			if (pt == port && 0 == memcmp(dest, host_addr_ipv6(&addr), 16))
				return TRUE;
		}
		break;
	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		break;
	}

	return FALSE;
}
Example #4
0
static void
handle_push(const char *data, size_t size)
{
  if (size < 26) {
    fprintf(stderr, "handle_push(): Too small\n");
    return;
  }
  printf("ServentID: %08lx-%08lx-%08lx-%08lx\n",
      (unsigned long) peek_be32(&data[0]),
      (unsigned long) peek_be32(&data[4]),
      (unsigned long) peek_be32(&data[8]),
      (unsigned long) peek_be32(&data[12]));
  printf("Index: %lu\n", (unsigned long) peek_le32(&data[16]));
  printf("Target: %s\n",
      net_addr_port_to_string(net_addr_peek_ipv4(&data[20]),
        peek_le16(&data[24])));

  handle_extension(&data[26], size - 26);
}
Example #5
0
/**
 * Make sure vector of block numbers is ordered and points to allocated data,
 * but was not already flagged as being used by another key / value.
 *
 * @param what		string describing what is being tested (key or value)
 * @param db		the sdbm database
 * @param bvec		vector where allocated block numbers are stored
 * @param bcnt		amount of blocks in vector
 *
 * @return TRUE on success.
 */
static gboolean
big_file_check(const char *what, DBM *db, const void *bvec, int bcnt)
{
	size_t prev_bno = 0;		/* 0 is invalid: it's the first bitmap */
	const void *q;
	int n;

	if (!big_check_start(db))
		return TRUE;			/* Cannot validate, assume it's OK */

	for (q = bvec, n = bcnt; n > 0; n--) {
		size_t bno = peek_be32(q);
		bit_field_t *map;
		long bmap;
		size_t bit;

		if (!big_block_is_allocated(db, bno)) {
			g_warning("sdbm: \"%s\": "
				"%s from .pag refers to unallocated block %lu in .dat",
				sdbm_name(db), what, (unsigned long) bno);
			return FALSE;
		}
		if (prev_bno != 0 && bno <= prev_bno) {
			g_warning("sdbm: \"%s\": "
				"%s from .pag lists unordered block list (corrupted file?)",
				sdbm_name(db), what);
			return FALSE;
		}
		q = const_ptr_add_offset(q, sizeof(guint32));
		prev_bno = bno;

		/*
		 * Make sure block is not used by someone else.
		 *
		 * Because we mark blocks as used in big keys and values only after
		 * we validated both the key and the value for a given pair, we cannot
		 * detect shared blocks between the key and value of a pair.
		 */

		bmap = bno / BIG_BITCOUNT;			/* Bitmap handling this block */
		bit = bno & (BIG_BITCOUNT - 1);		/* Index within bitmap */

		g_assert(bmap < db->big->bitmaps);

		map = ptr_add_offset(db->big->bitcheck, bmap * BIG_BLKSIZE);
		if (bit_field_get(map, bit)) {
			g_warning("sdbm: \"%s\": "
				"%s from .pag refers to already seen block %lu in .dat",
				sdbm_name(db), what, (unsigned long) bno);
			return FALSE;
		}
	}

	return TRUE;
}
Example #6
0
static void
handle_vmsg_time_sync_reply(const struct gnutella_header *header,
    const char *data, size_t size)
{
  if (size < 17) {
    printf("Too short:  %s\n", escape_buffer(data, size));
  } else {
    bool used_ntp = data[8] & 0x1;
    char buf[32], *p;

    printf("NTP: %s\n", used_ntp ? "yes" : "no");

    p = print_iso8601_date(buf, sizeof buf, peek_be32(&header->guid.data[0]));
    *p = '\0';
    printf("T1: %s (%lu us)\n",
      buf, (unsigned long) peek_be32(&header->guid.data[4]));

    p = print_iso8601_date(buf, sizeof buf, peek_be32(&data[9]));
    *p = '\0';
    printf("T2: %s (%lu us)\n",
      buf, (unsigned long) peek_be32(&data[13]));

    p = print_iso8601_date(buf, sizeof buf, peek_be32(&header->guid.data[8]));
    *p = '\0';
    printf("T3: %s (%lu us)\n",
      buf, (unsigned long) peek_be32(&header->guid.data[12]));

    if (size > 17) {
      handle_extension(&data[17], size - 17);
    }
  }
}
Example #7
0
/**
 * Minimal pseudo-random number generation, combining a simple PRNG with
 * past-collected entropy.
 *
 * @return a 31-bit random number.
 */
static int
entropy_rand31(void)
{
	int result;
	static size_t offset;

	result = rand31();

	/*
	 * Combine with previously generated entropy to create even better
	 * randomness.  That previous entropy is refreshed each time a new
	 * entropy collection cycle is initiated.  We simply loop over the
	 * five 32-bit words, interpreted in a big-endian way.
	 */

	result += peek_be32(ptr_add_offset(&entropy_previous, offset));
	offset = (offset + 4) % sizeof entropy_previous;

	return result & RAND31_MASK;
}
Example #8
0
/**
 * Free allocated blocks from the .dat file.
 *
 * @param db		the sdbm database
 * @param bvec		vector where allocated block numbers are stored
 * @param bcnt		amount of blocks in vector to free
 */
static void
big_file_free(DBM *db, const void *bvec, int bcnt)
{
	size_t bno;
	const void *q;
	int n;

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

	/*
	 * If database is not volatile, sync the bitmap to make sure the freed
	 * blocks are reusable even if we crash later.
	 */

	if (!db->is_volatile)
		big_sync(db);
}
Example #9
0
static void
handle_vmsg_priv(const struct gnutella_header *header,
    const char *data, size_t size)
{
  if (size < 8) {
    printf("Too short:  %s\n", escape_buffer(data, size));
  } else {
    char vendor[32], *p;
    size_t vendor_size = sizeof vendor;
    struct vmsg_head vh;
    unsigned i;

    p = append_escaped_chars(vendor, &vendor_size, data, 4);
    *p = '\0';

    vh.vendor = peek_be32(&data[0]);
    vh.selector = peek_le16(&data[4]);
    vh.version = peek_le16(&data[6]);
    printf("%s/%uv%u", vendor, vh.selector, vh.version);

    for (i = 0; i < ARRAY_LEN(vmsg_table); i++) {
      if (
        vmsg_table[i].vendor == vh.vendor &&
        vmsg_table[i].selector == vh.selector &&
        vmsg_table[i].version == vh.version
      ) {
        printf(" %s\n", vmsg_table[i].name);
        vmsg_table[i].handler(header, data, size);
        break;
      }
    }

    if (ARRAY_LEN(vmsg_table) == i) {
      printf("\n");
      handle_extension(&data[8], size - 8);
    }
  }
}
Example #10
0
static inline uint32
host_addr_6to4_client_ipv4(const host_addr_t ha)
{
	return peek_be32(&ha.addr.ipv6[2]);	/* 2002:AABBCCDD::/48 */
}
Example #11
0
/**
 * 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;
}
Example #12
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;
}
Example #13
0
static void
handle_qhit(const char *data, size_t size)
{
  const struct gnutella_qhit_header *header;
  const struct gnutella_guid *guid;
  const struct gnutella_qhit_item *item;
  size_t guid_offset = size - sizeof *guid;
  unsigned hits;
  size_t pos;
  
  RUNTIME_ASSERT(size <= GNUTELLA_MAX_PAYLOAD);
  
  if (size < sizeof *header) {
    fprintf(stderr, "handle_qhit(): Too little payload for header.\n");
    return;
  }
  header = cast_to_const_void_ptr(data);
  
  hits = (unsigned char) header->hits;
  printf("Hits: %u\n", hits);
  printf("Address: %s\n",
    net_addr_port_to_string(net_addr_peek_ipv4(cast_to_const_char_ptr(header->addr)),
      peek_le16(header->port)));
  printf("Speed: %lu\n", (unsigned long) peek_le32(header->speed));

  if (size < sizeof *header + sizeof *guid) {
    fprintf(stderr, "handle_qhit(): Insufficient payload for query hit.\n");
    return;
  }
  if (size >= sizeof *header + sizeof *guid) {
    
    guid = cast_to_const_void_ptr(&data[guid_offset]);
    printf("Servent ID: %08lx-%08lx-%08lx-%08lx\n",
        (unsigned long) peek_be32(&guid->data[0]),
        (unsigned long) peek_be32(&guid->data[4]),
        (unsigned long) peek_be32(&guid->data[8]),
        (unsigned long) peek_be32(&guid->data[12]));
  }
  printf("----\n");

  pos = sizeof *header;
  for (/* NOTHING */; hits > 0; hits--) {
    const char *nul_ptr;
   
    if (pos >= guid_offset || guid_offset - pos < sizeof *item + 2)
      break;

    item = cast_to_const_void_ptr(&data[pos]);
    printf("Index: %lu\n", (unsigned long) peek_le32(item->index));
    printf("Size:  %lu\n", (unsigned long) peek_le32(item->size));

    pos += sizeof *item; 

    nul_ptr = memchr(&data[pos], 0, guid_offset - pos);
    if (!nul_ptr) {
      fprintf(stderr, "handle_qhit(): Non-terminated filename.\n");
      return;
    } else {
      size_t len;

      len = (nul_ptr - &data[pos]);
      if (len > (((size_t) -1) / 4 - 1)) {
        fprintf(stderr, "handle_qhit(): Filename is too long.\n");
        /* Ignore */
      } else {
        const char *p;
        size_t avail;
        
        printf("Filename: ");

        avail = len;
        p = &data[pos];
        while (avail > 0) {
          uint32_t cp;
          cp = utf8_decode(p, avail);
          if ((uint32_t) -1 != cp) {
            uint8_t u_len, i;

            u_len = utf8_first_byte_length_hint((unsigned char) *p);
            RUNTIME_ASSERT(u_len > 0);
            RUNTIME_ASSERT(avail >= u_len);
            avail -= u_len;

            if (cp >= 0x20 && cp != 0x7f) {
              for (i = 0; i < u_len; i++) {
                putchar((unsigned char) p[i]);
              }
            } else {
              char ch = cp & 0xff;
              printf("%s", escape_buffer(&ch, 1)); 
            }
            
            p += u_len;
          } else {
            if (verbosity > 0) {
              fprintf(stderr, "handle_qhit(): Invalid UTF-8.\n");
            }
            break;
          }
        }
      }
      printf("\n");

      pos += len;
    }

    RUNTIME_ASSERT(nul_ptr);
    RUNTIME_ASSERT(&data[pos] == nul_ptr);
    RUNTIME_ASSERT('\0' == *nul_ptr);

    pos++;
    RUNTIME_ASSERT(pos <= guid_offset);

    nul_ptr = memchr(&data[pos], 0, guid_offset - pos);
    if (!nul_ptr) {
      fprintf(stderr, "handle_qhit(): Non-terminated extension block.\n");
      return;
    } else if (nul_ptr != &data[pos]) {
      size_t len = nul_ptr - &data[pos];
      
      printf("Extension size:  %lu\n", (unsigned long) len);
     
      handle_extension(&data[pos], len);
      pos += len;
    }

    RUNTIME_ASSERT(nul_ptr);
    RUNTIME_ASSERT(&data[pos] == nul_ptr);
    RUNTIME_ASSERT('\0' == *nul_ptr);

    pos++;
    RUNTIME_ASSERT(pos <= guid_offset);

    printf("------\n");
  }

  if (hits > 0) {
    fprintf(stderr, "handle_qhit(): Expected %u more hits.\n", hits);
  }

  if (pos < guid_offset) {
      static const unsigned vendor_id_len = 4;
      
      printf("Extended QHD size:  %lu\n", (unsigned long) guid_offset - pos);
      if (guid_offset - pos >= vendor_id_len) {

        printf("Vendor ID: %s\n", escape_buffer(&data[pos], vendor_id_len));

        pos += vendor_id_len;
        if (pos < guid_offset) {
          uint8_t open_data_size = data[pos];
          bool has_ggep = false;
          
          printf("Open data size:  %u\n", open_data_size);
          pos++;

          if (open_data_size > guid_offset - pos) {
            printf("Open data size is too large.\n");
            return;
          }

          if (open_data_size >= 2) {
            uint8_t mask = data[pos];
            uint8_t value = data[pos + 1];
          
            printf("mask:  0x%02x\n", mask);
            printf("value: 0x%02x\n", value);
            
            if (0x20 & mask) {
              has_ggep = 0x20 & value;
              printf("Has GGEP: %s\n", has_ggep ? "yes" : "no");
            }
            if (0x10 & mask) {
              printf("Has speed: %s\n", (0x10 & value) ? "yes" : "no");
            }
            if (0x08 & mask) {
              printf("Has uploaded: %s\n", (0x08 & value) ? "yes" : "no");
            }
            if (0x04 & mask) {
              printf("Busy: %s\n", (0x04 & value) ? "yes" : "no");
            }
            /* mask and value are swapped */
            if (0x01 & value) {
              printf("Must push: %s\n", (0x01 & mask) ? "yes" : "no");
            }
          }

          pos += open_data_size;

          if (pos < guid_offset) {
            size_t priv_data_size = guid_offset - pos;
            static const char id_deflate[] = "{deflate}";
            const char *priv_data, *x;
            
            priv_data = &data[pos];
            priv_data_size = guid_offset - pos;
            
            printf("Private data area size:  %lu\n",
              (unsigned long) priv_data_size);

            handle_extension(priv_data, priv_data_size);

            x = compat_memmem(priv_data, priv_data_size,
                    id_deflate, STATIC_STRLEN(id_deflate));
            if (x) {
              char buf[64 * 1024];
              const char *src;
              size_t n, src_len;

              src = &x[STATIC_STRLEN(id_deflate)];
              src_len = priv_data_size - STATIC_STRLEN(id_deflate);
              n = buffer_inflate(buf, sizeof buf, src, src_len);
              if ((size_t) -1 != n) {
                printf("Inflated:  %s\n", escape_buffer(buf, n));
              }
            }

            pos += priv_data_size;
          }

          RUNTIME_ASSERT(pos == guid_offset);
        }
      }
  }
  
  printf("----\n");
}
Example #14
0
int
main(int argc, char *argv[])
{
  const char *filename;
  bool skip_hs = false;
  bool with_dump_headers = false;
  int fd, c;

  setvbuf(stdout, NULL, _IOLBF, 0);
  
  while (-1 != (c = getopt(argc, argv, "DHh"))) {
    switch (c) {
    case 'h':
      usage(EXIT_SUCCESS);
      break;

    case 'H':
      skip_hs = true;
      break;
     
    case 'D':
      with_dump_headers = true;
      break;
     
    default:
      fprintf(stderr, "Unsupported option: -- %c\n", c);
      usage(EXIT_FAILURE);
    }
  }
  argc -= optind;
  argv += optind;

  if (argc > 1) {
    fprintf(stderr,
      "Error: "
      "Specify exactly one filename or none to read from the standard input."
      "\n");
    usage(EXIT_FAILURE);
  }

  filename = argv[0];
  if (filename) {
    fd = open(filename, O_RDONLY, 0);
    if (fd < 0) {
      fprintf(stderr, "open(\"%s\", O_RDONLY, 0) failed: %s\n",
        filename, strerror(errno));
      exit(EXIT_FAILURE);
    }
  } else {
    fd = STDIN_FILENO;
  }

  /* Discard the handshake */
  if (skip_hs) {
    if (0 != skip_handshake(fd)) {
      fprintf(stderr, "Failed to skip handshake\n");
      exit(EXIT_FAILURE);
    }
    printf("Skipped handshake\n");
  }
 
  for (;;) {
    struct gnutella_header header;
    static char *payload;
    size_t ret;
    uint32_t payload_size;
    
    STATIC_ASSERT(23 == sizeof header);

    if (!payload) {
      payload = malloc(GNUTELLA_MAX_PAYLOAD);
      if (!payload) {
        fprintf(stderr, "malloc(%lu) failed: %s",
            (unsigned long) GNUTELLA_MAX_PAYLOAD, strerror(errno));
        return -1;
      }
    }

    if (with_dump_headers) {
      struct dump_header dh;
      safe_read(fd, &dh, sizeof dh);

      if (dh.flags & DH_F_TO) {
        struct dump_header dh_from;
        safe_read(fd, &dh_from, sizeof dh_from);
        print_dump_from_header(&dh_from);
        print_dump_to_header(&dh);
      } else {
        print_dump_from_header(&dh);
      }
    }

    ret = fill_buffer_from_fd(fd, &header, sizeof header);
    switch (ret) {
    case 0:
      fprintf(stderr, "Error: Unexpected end of file.\n");
      exit(EXIT_FAILURE);
    case (size_t) -1:
      fprintf(stderr, "Error: Could not fill packet buffer: %s\n",
          strerror(errno));
      exit(EXIT_FAILURE);
    case 1:
      break;
    default:
      RUNTIME_ASSERT(0);
    }

    payload_size = peek_le32(header.size);

    if (payload_size > GNUTELLA_MAX_PAYLOAD) {
      fprintf(stderr, "Error: Message is too large.\n");
      return -1;
    }

    if (payload_size > 0) {
      ret = fill_buffer_from_fd(fd, payload, payload_size);
      switch (ret) {
        case 0:
        case (size_t) -1:
          exit(EXIT_FAILURE);
        case 1:
          break;
        default:
          RUNTIME_ASSERT(0);
      }
    }

    printf("GUID: %08lx-%08lx-%08lx-%08lx\n",
        (unsigned long) peek_be32(&header.guid.data[0]),
        (unsigned long) peek_be32(&header.guid.data[4]),
        (unsigned long) peek_be32(&header.guid.data[8]),
        (unsigned long) peek_be32(&header.guid.data[12]));

    if (header.type != GPT_DHT) {
      printf("Type: %s\n", packet_type_to_string(header.type));
      printf("TTL : %u\n", (unsigned char) header.ttl);
      printf("Hops: %u\n", (unsigned char) header.hops);
      printf("Size: %lu\n", (unsigned long) payload_size);
    } else {
      printf("Type: %s\n", kademlia_type_to_string(header.type));
      printf("V   : %u.%u\n",
          (unsigned char) header.ttl, (unsigned char) header.hops);
      printf("Size: %lu\n", (unsigned long) payload_size + 23 - 61);
    }

    printf("--\n");
   
    switch ((enum gnutella_packet_type) header.type) {
    case GPT_PING:      handle_ping(payload, payload_size); break;
    case GPT_PONG:      handle_pong(payload, payload_size); break;
    case GPT_QRP:       handle_qrp(payload, payload_size); break;
    case GPT_VMSG_PRIV: handle_vmsg_priv(&header, payload, payload_size); break;
    case GPT_VMSG_STD:  handle_vmsg_std(payload, payload_size); break;
    case GPT_PUSH:      handle_push(payload, payload_size); break;
    case GPT_RUDP:      handle_rudp(payload, payload_size); break;
    case GPT_DHT:       handle_dht(payload, payload_size); break;
    case GPT_QUERY:     handle_query(&header, payload, payload_size); break;
    case GPT_QHIT:      handle_qhit(payload, payload_size); break;
    case GPT_HSEP:      handle_hsep(payload, payload_size); break;
    }
    printf("==========\n");

  }

  return 0;
}
Example #15
0
static inline bool
host_addr_is_teredo(const host_addr_t ha)
{
	return host_addr_is_ipv6(ha) && 0x20010000UL == peek_be32(&ha.addr.ipv6[0]);
}
Example #16
0
/**
 * Store big value in the .dat file, writing to the supplied block numbers.
 *
 * @param db		the sdbm database
 * @param bvec		start of block vector, containing block numbers
 * @param data		start of data to write
 * @param len		length of data to write
 *
 * @return -1 on error with errno set, 0 if OK.
 */
static int
big_store(DBM *db, const void *bvec, const void *data, size_t len)
{
	DBMBIG *dbg = db->big;
	int bcnt = bigbcnt(len);
	int n;
	const void *p;
	const char *q;
	size_t remain;

	g_return_val_if_fail(NULL == dbg->bitcheck, -1);

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

	/*
	 * Look at the amount of consecutive block numbers we have to be able
	 * to write into them via a single system call.
	 */

	n = bcnt;
	p = bvec;
	q = data;
	remain = len;

	while (n > 0) {
		size_t towrite = MIN(remain, BIG_BLKSIZE);
		guint32 bno = peek_be32(p);
		guint32 prev_bno = bno;

		p = const_ptr_add_offset(p, sizeof(guint32));
		n--;
		remain = size_saturate_sub(remain, towrite);

		while (n > 0) {
			guint32 next_bno = peek_be32(p);
			size_t amount;

			if (next_bno <= prev_bno)	/* Block numbers are sorted */
				goto corrupted_page;

			if (next_bno - prev_bno != 1)
				break;						/*  Not consecutive */

			prev_bno = next_bno;
			p = const_ptr_add_offset(p, sizeof(guint32));
			amount = MIN(remain, BIG_BLKSIZE);
			towrite += amount;
			n--;
			remain = size_saturate_sub(remain, amount);
		}

		dbg->bigwrite++;
		if (-1 == compat_pwrite(dbg->fd, q, towrite, OFF_DAT(bno))) {
			g_warning("sdbm: \"%s\": "
				"could not write %lu bytes starting at data block #%u: %s",
				sdbm_name(db), (unsigned long) towrite, bno, g_strerror(errno));

			ioerr(db, TRUE);
			return -1;
		}

		q += towrite;
		dbg->bigwrite_blk += bigblocks(towrite);
		g_assert(ptr_diff(q, data) <= len);
	}

	g_assert(ptr_diff(q, data) == len);

	return 0;

corrupted_page:
	g_warning("sdbm: \"%s\": corrupted page: %d big data block%s not sorted",
		sdbm_name(db), bcnt, 1 == bcnt ? "" : "s");

	ioerr(db, FALSE);
	errno = EFAULT;		/* Data corrupted somehow (.pag file) */
	return -1;
}
Example #17
0
/**
 * Fetch data block from the .dat file, reading from the supplied block numbers.
 *
 * @param db		the sdbm database
 * @param bvec		start of block vector, containing block numbers
 * @param len		length of the data to be read
 *
 * @return -1 on error with errno set, 0 if OK.  Read data is left in the
 * scratch buffer.
 */
static int
big_fetch(DBM *db, const void *bvec, size_t len)
{
	int bcnt = bigbcnt(len);
	DBMBIG *dbg = db->big;
	int n;
	const void *p;
	char *q;
	size_t remain;
	guint32 prev_bno;

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

	if (dbg->scratch_len < len)
		big_scratch_grow(dbg, len);

	/*
	 * Read consecutive blocks in one single system call.
	 */

	n = bcnt;
	p = bvec;
	q = dbg->scratch;
	remain = len;

	while (n > 0) {
		size_t toread = MIN(remain, BIG_BLKSIZE);
		guint32 bno = peek_be32(p);
		
		prev_bno = bno;
		if (!big_block_is_allocated(db, prev_bno))
			goto corrupted_database;
		p = const_ptr_add_offset(p, sizeof(guint32));
		n--;
		remain = size_saturate_sub(remain, toread);

		while (n > 0) {
			guint32 next_bno = peek_be32(p);
			size_t amount;

			if (next_bno <= prev_bno)	/* Block numbers are sorted */
				goto corrupted_page;

			if (next_bno - prev_bno != 1)
				break;						/*  Not consecutive */

			prev_bno = next_bno;
			if (!big_block_is_allocated(db, prev_bno))
				goto corrupted_database;
			p = const_ptr_add_offset(p, sizeof(guint32));
			amount = MIN(remain, BIG_BLKSIZE);
			toread += amount;
			n--;
			remain = size_saturate_sub(remain, amount);
		}

		dbg->bigread++;
		if (-1 == compat_pread(dbg->fd, q, toread, OFF_DAT(bno))) {
			g_warning("sdbm: \"%s\": "
				"could not read %lu bytes starting at data block #%u: %s",
				sdbm_name(db), (unsigned long) toread, bno, g_strerror(errno));

			ioerr(db, FALSE);
			return -1;
		}

		q += toread;
		dbg->bigread_blk += bigblocks(toread);
		g_assert(UNSIGNED(q - dbg->scratch) <= dbg->scratch_len);
	}

	g_assert(UNSIGNED(q - dbg->scratch) == len);

	return 0;

corrupted_database:
	g_warning("sdbm: \"%s\": cannot read unallocated data block #%u",
		sdbm_name(db), prev_bno);
	goto fault;

corrupted_page:
	g_warning("sdbm: \"%s\": corrupted page: %d big data block%s not sorted",
		sdbm_name(db), bcnt, 1 == bcnt ? "" : "s");

	/* FALL THROUGH */

fault:
	ioerr(db, FALSE);
	errno = EFAULT;		/* Data corrupted somehow (.pag or .dat file) */
	return -1;
}
Example #18
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 */
}