Пример #1
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;
		}
	}
}
Пример #2
0
static char *
thex_upload_uuid(const struct tth *tth)
{
	static char buf[64];
	const char *data;

	data = tth->data;
	str_bprintf(buf, sizeof buf,
		"uuid:%08x-%04x-%04x-%04x-%08x%04x",
		peek_le32(&data[0]), peek_le16(&data[4]), peek_le16(&data[6]),
		peek_le16(&data[8]), peek_le32(&data[10]), peek_le16(&data[14]));
	return buf;
}
Пример #3
0
static void
handle_pong(const char * const data, const size_t size)
{
  if (size < 14) {
    printf("Too short:  %s\n", escape_buffer(data, size));
  } else {
    printf("Source: %s\n",
      net_addr_port_to_string(net_addr_peek_ipv4(&data[2]), peek_le16(data)));
    printf("Files:  %lu\n", (unsigned long) peek_le32(&data[6]));
    printf("Volume: %lu KiB\n", (unsigned long) peek_le32(&data[10]));

    if (size > 14) {
      handle_extension(&data[14], size - 14);
    }
  }
}
Пример #4
0
/**
 * Encrypt a block with the supplied key.
 *
 * @param res	where result is stored
 * @param key	the encryption key
 * @param value	the value to encrypt
 */
static void G_HOT
t_encrypt(tea_block_t *res, const tea_key_t *key, const tea_block_t *value)
{
	uint32 v0, v1, sum = 0;
	int i;
    uint32 delta = TEA_CONSTANT;
	uint32 k0, k1, k2, k3;			/* cache key */

	v0 = peek_le32(&value->v[0]);
	v1 = peek_le32(&value->v[4]);
	k0 = peek_le32(&key->v[0]);
	k1 = peek_le32(&key->v[4]);
	k2 = peek_le32(&key->v[8]);
	k3 = peek_le32(&key->v[12]);

#define TEA_ROUND_ESTEP											\
	sum += delta;												\
	v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);		\
	v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);

    for (i = 0; i < TEA_ROUNDS / 4; i++) {
		TEA_ROUND_ESTEP;
		TEA_ROUND_ESTEP;
		TEA_ROUND_ESTEP;
		TEA_ROUND_ESTEP;
    }

	poke_le32(&res->v[0], v0);
	poke_le32(&res->v[4], v1);
}
Пример #5
0
g2_node_extract_size_request(const g2_tree_t *t, uint64 *min, uint64 *max)
{
	const char *p;
	size_t paylen;

	/*
	 * The payload can be 2 32-bit or 2 64-bit values.
	 */

	p = g2_tree_node_payload(t, &paylen);

	if (8 == paylen) {
		*min = (uint64) peek_le32(p);
		*max = (uint64) peek_le32(&p[4]);
		return TRUE;
	} else if (16 == paylen) {
		*min = peek_le64(p);
		*max = peek_le64(&p[8]);
		return TRUE;
	}

	return FALSE;
}
Пример #6
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);
}
Пример #7
0
/**
 * Squeeze buffer to a 32-bit value.
 * Buffer length must be a multiple of 4.
 */
uint32
tea_squeeze(void *buf, size_t len)
{
	char *p;
	size_t remain;
	uint32 result = 0;

	g_assert(0 == (len & 0x03));		/* multiple of 4 bytes */

	for (remain = len, p = buf; remain >= 4; remain -= 4, p += 4) {
		uint32 val;

		val = peek_le32(p);
		result ^= val;
	}

	g_assert(0 == remain);

	return result;
}
Пример #8
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");
}
Пример #9
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;
}