/** * 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); }
/** * 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; }
/** * Retrieve value associated with an IP address, i.e. that of the range * containing it. * * @param db the IP range database * @param ha the IP address to lookup * * @return The data associated with the IP address or 0 if not found. */ uint16 iprange_get_addr(const struct iprange_db *idb, const host_addr_t ha) { host_addr_t to; if ( host_addr_convert(ha, &to, NET_TYPE_IPV4) || host_addr_tunnel_client(ha, &to) ) { return iprange_get(idb, host_addr_ipv4(to)); } else if (host_addr_is_ipv6(ha)) { return iprange_get6(idb, host_addr_ipv6(&ha)); } return 0; }
/** * Prints the host address ``ha'' to ``dst''. The string written to ``dst'' * is always NUL-terminated unless ``size'' is zero. If ``size'' is too small, * the string will be truncated. * * @param dst the destination buffer; may be NULL iff ``size'' is zero. * @param ha the host address. * @param size the size of ``dst'' in bytes. * * @return The length of the resulting string assuming ``size'' is sufficient. */ size_t host_addr_to_string_buf(const host_addr_t ha, char *dst, size_t size) { switch (host_addr_net(ha)) { case NET_TYPE_IPV4: return ipv4_to_string_buf(host_addr_ipv4(ha), dst, size); case NET_TYPE_IPV6: return ipv6_to_string_buf(host_addr_ipv6(&ha), dst, size); case NET_TYPE_LOCAL: return g_strlcpy(dst, "<local>", size); case NET_TYPE_NONE: return g_strlcpy(dst, "<none>", size); } g_assert_not_reached(); return 0; }
/** * Write an IPv4 or IPv6 address. */ void pmsg_write_ipv4_or_ipv6_addr(pmsg_t *mb, host_addr_t addr) { g_assert(pmsg_is_writable(mb)); /* Not shared, or would corrupt data */ g_assert(pmsg_available(mb) >= 17); switch (host_addr_net(addr)) { case NET_TYPE_IPV4: pmsg_write_u8(mb, 4); pmsg_write_be32(mb, host_addr_ipv4(addr)); break; case NET_TYPE_IPV6: pmsg_write_u8(mb, 16); pmsg_write(mb, host_addr_ipv6(&addr), 16); break; case NET_TYPE_LOCAL: case NET_TYPE_NONE: g_error("unexpected address in pmsg_write_ipv4_or_ipv6_addr(): %s", host_addr_to_string(addr)); } }
/** * 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; } }
/** * 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; }
/** * 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)); }
/** * 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; }