/**
 * 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;
}
Exemple #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;
}
Exemple #3
0
static void
handle_vmsg_port(const struct gnutella_header *header,
  const char *data, size_t size)
{
  const char *base = &data[8];
  const size_t len = size - 8;
  (void) header;
  if (len == 2) {
    printf("Port: %u\n", peek_le16(base));
  } else {
    handle_extension(base, len);
  }
}
Exemple #4
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);
    }
  }
}
Exemple #5
0
static void
handle_vmsg_addr_port(const struct gnutella_header *header,
  const char *data, size_t size)
{
  const char *base = &data[8];
  const size_t len = size - 8;
  (void) header;
  if (len == 6) {
    printf("Address: %s\n", net_addr_port_to_string(
            net_addr_peek_ipv4(&base[0]), peek_le16(&base[4])));
  } else {
    handle_extension(base, len);
  }
}
Exemple #6
0
/**
 * Extract the IP and port number from the GUID of queries marked for OOB
 * query hit delivery.
 *
 * Bytes 0 to 3 of the guid are the 4 octet bytes of the IP address.
 * Bytes 13 and 14 are the little endian representation of the port.
 */
void
guid_oob_get_addr_port(const guid_t *guid, host_addr_t *addr, uint16 *port)
{
	if (addr) {
		/*
		 * IPv6-Ready: this is always 4 bytes, even if the final address is
		 * an IPv6 one because the GGEP "6" key will supply us the IPv6
		 * address should the IPv4 one be 127.0.0.0.
		 */
		*addr = host_addr_peek_ipv4(&guid->v[0]);
	}
	if (port) {
		*port = peek_le16(&guid->v[13]);
	}
}
Exemple #7
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);
    }
  }
}
/**
 * Deserialization convenience for IP:port.
 *
 * The supplied buffer must hold either 6 or 18 more bytes of data, depending
 * on the address type we want to deserialize.
 */
void
host_ip_port_peek(const void *p, enum net_type nt,
	host_addr_t *addr, uint16 *port)
{
	const void *q = p;

	if (NET_TYPE_IPV4 == nt) {
		*addr = host_addr_peek_ipv4(q);
		q = const_ptr_add_offset(q, 4);
	} else if (NET_TYPE_IPV6 == nt) {
		*addr = host_addr_peek_ipv6(q);
		q = const_ptr_add_offset(q, 16);
	} else {
		/* Can only deserialize IPv4:port or IPv6:port */
		g_assert_not_reached();
	}
	*port = peek_le16(q);
}
Exemple #9
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);
}
Exemple #10
0
/**
 * Extract the UDP IP:port from a /Q2/UDP and populate the search request info
 * if we have a valid address.
 */
static void
g2_node_extract_udp(const g2_tree_t *t, search_request_info_t *sri,
	const gnutella_node_t *n)
{
	const char *p;
	size_t paylen;

	p = g2_tree_node_payload(t, &paylen);

	/*
	 * Only handle if we have an IP:port entry.
	 * We only handle IPv4 because G2 does not support IPv6.
	 *
	 * We don't care about the presence of the query key because as G2 leaf,
	 * we only process /Q2 coming from our TCP-connected hubs, and they
	 * are in charge of validating it.  Now hubs may forward us /Q2 coming
	 * from neighbouring hubs and those won't have a query key, hence we
	 * need to handle payloads with no trailing 32-bit QK.
	 */

	if (6 == paylen || 10 == paylen) {	/* IPv4 + port (+ QK usually) */
		host_addr_t addr = host_addr_peek_ipv4(p);
		uint16 port = peek_le16(&p[4]);

		if (host_is_valid(addr, port)) {
			sri->addr = addr;
			sri->port = port;

			/*
			 * If the address is that of the node sending us the query,
			 * and it is not a UDP node, then we can deliver the hit
			 * back via the TCP connection we have, so no need to use OOB.
			 */

			if (n->port == port && host_addr_equiv(addr, n->gnet_addr))
				sri->oob = NODE_IS_UDP(n);
			else
				sri->oob = TRUE;
		}
	}
}
Exemple #11
0
/**
 * Parse the payload of given node to extract a node address + port.
 *
 * @param t		the tree node whose payload we wish to parse
 * @param addr	where to write the address part
 * @param port	where to write the port part
 *
 * @return TRUE if OK, FALSE if we could not extract anything.
 */
bool
g2_node_parse_address(const g2_tree_t *t, host_addr_t *addr, uint16 *port)
{
	const char *payload;
	size_t paylen;

	payload = g2_tree_node_payload(t, &paylen);

	/*
	 * Only handle if we have an IP:port entry.
	 * We only handle IPv4 because G2 does not support IPv6.
	 */

	if (6 == paylen) {		/* IPv4 + port */
		*addr = host_addr_peek_ipv4(payload);
		*port = peek_le16(&payload[4]);
		return TRUE;
	}

	return FALSE;		/* Unrecognized payload length */
}
Exemple #12
0
/**
 * Tree message iterator to handle "CH" nodes and extract their IP:port.
 */
static void
g2_node_extract_ch(void *data, void *udata)
{
	const g2_tree_t *t = data;

	(void) udata;

	if (0 == strcmp("CH", g2_tree_name(t))) {
		const char *payload;
		size_t paylen;

		payload = g2_tree_node_payload(t, &paylen);

		if (10 == paylen) {		/* IPv4:port + 32-bit timestamp */
			host_addr_t addr = host_addr_peek_ipv4(payload);
			uint16 port = peek_le16(&payload[4]);

			if (host_is_valid(addr, port) && !hostiles_is_bad(addr))
				guess_add_hub(addr, port);
		}
	}
}
Exemple #13
0
static void 
handle_peer_array(const char *data, size_t size)
{
  size_t pos;
  
  if (0 == size) {
    printf(" <No payload>");
    return;
  }
  if (0 != (size % 6)) {
    printf(" <Invalid length (%lu); not a multiple of 6>",
        (unsigned long) size);
    return;
  }
  for (pos = 0; pos < size; pos += 6) {
    if (pos > 0) {
      printf(",");
    }
    printf(" %s",
        net_addr_port_to_string(net_addr_peek_ipv4(&data[pos]),
          peek_le16(&data[pos + 4])));
  }
}
Exemple #14
0
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);
    }
  }
}
Exemple #15
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");
}