Exemple #1
0
/**
 * Build a PUSH request.
 *
 * @param guid	the GUID of the remote servent we're trying to reach
 *
 * @return a /PUSH message, or NULL if the listening address or port
 * are invalid.
 */
pmsg_t *
g2_build_push(const guid_t *guid)
{
	g2_tree_t *t, *c;
	pmsg_t *mb;
	char payload[18];
	size_t plen;
	host_addr_t addr = listen_addr_primary();
	uint16 port = socket_listen_port();

	if (0 == port || !is_host_addr(addr))
		return NULL;

	host_ip_port_poke(payload, addr, port, &plen);

	t = g2_tree_alloc(G2_NAME(PUSH), payload, plen);
	g2_build_add_tls(t);

	/*
	 * The /?/TO child is a generic GUID-based addressing scheme.
	 *
	 * To ensure it is the first child of the packet, we add it last since
	 * our children are pre-pended to the list of existing ones.
	 */

	c = g2_tree_alloc("TO", guid, GUID_RAW_SIZE);
	g2_tree_add_child(t, c);

	mb = g2_build_ctrl_pmsg(t);
	g2_tree_free_null(&t);

	return mb;
}
Exemple #2
0
/**
 * Parse "port:IP" string to retrieve the host address and port.
 *
 * @param str		the string to parse
 * @param endptr	if not NULL, it will point the first character after
 * 					the parsed elements.
 * @param port_ptr	where the parsed port is written
 * @param addr_ptr	where the parsed address is written
 *
 * @return TRUE if we parsed the string correctly, FALSE if it did not
 * look like a valid "port:IP" string.
 */
bool
string_to_port_host_addr(const char *str, const char **endptr,
	uint16 *port_ptr, host_addr_t *addr_ptr)
{
	const char *ep;
	host_addr_t addr;
	bool ret;
	uint16 port;
	int error;

	port = parse_uint16(str, &ep, 10, &error);
	if (!error && ':' == *ep) {
		ret = string_to_host_or_addr(ep, &ep, &addr);
		ret = ret && is_host_addr(addr);
	} else {
		addr = zero_host_addr;
		ret = FALSE;
	}

	if (addr_ptr)
		*addr_ptr = addr;
	if (port_ptr)
		*port_ptr = port;
	if (endptr)
		*endptr = ep;

	return ret;
}
Exemple #3
0
/**
 * Check whether host can be reached from the Internet.
 * We rule out IPs of private networks, plus some other invalid combinations.
 */
bool
host_addr_is_routable(const host_addr_t addr)
{
	host_addr_t ha;

	if (!is_host_addr(addr) || is_private_addr(addr))
		return FALSE;

	if (!host_addr_convert(addr, &ha, NET_TYPE_IPV4))
		ha = addr;

	switch (host_addr_net(ha)) {
	case NET_TYPE_IPV4:
		return ipv4_addr_is_routable(host_addr_ipv4(ha));

	case NET_TYPE_IPV6:
		return 	!host_addr_matches(ha, ipv6_unspecified, 8) &&
				!host_addr_matches(ha, ipv6_multicast, 8) &&
				!host_addr_matches(ha, ipv6_site_local, 10) &&
				!host_addr_matches(ha, ipv6_link_local, 10) &&
				!(
						host_addr_is_tunneled(ha) &&
						!ipv4_addr_is_routable(host_addr_tunnel_client_ipv4(ha))
				);

	case NET_TYPE_LOCAL:
	case NET_TYPE_NONE:
		return FALSE;
	}

	g_assert_not_reached();
	return FALSE;
}
Exemple #4
0
/**
 * Parse "IP:port" string to retrieve the host address and port.
 *
 * @param str		the string to parse
 * @param endptr	if not NULL, it will point the first character after
 * 					the parsed elements.
 * @param addr_ptr	where the parsed address is written
 * @param port_ptr	where the parsed port is written
 *
 * @return TRUE if we parsed the string correctly, FALSE if it did not
 * look like a valid "IP:port" string.
 */
bool
string_to_host_addr_port(const char *str, const char **endptr,
	host_addr_t *addr_ptr, uint16 *port_ptr)
{
	const char *ep;
	host_addr_t addr;
	bool ret;
	uint16 port;

	ret = string_to_host_or_addr(str, &ep, &addr);
	if (ret && ':' == *ep && is_host_addr(addr)) {
		int error;

		ep++;
		port = parse_uint16(ep, &ep, 10, &error);
		ret = 0 == error && 0 != port;
	} else {
		ret = FALSE;
		port = 0;
	}

	if (addr_ptr)
		*addr_ptr = addr;
	if (port_ptr)
		*port_ptr = port;
	if (endptr)
		*endptr = ep;

	return ret;
}
/**
 * Request asynchronous DNS resolution for item, prior to inserting to
 * the whitelist or updating the existing host address (when revalidating).
 */
static void
whitelist_dns_resolve(struct whitelist *item, bool revalidate)
{
	struct whitelist_dns *ctx;
	char *host;

	g_assert(item != NULL);
	g_assert(revalidate || !is_host_addr(item->addr));
	g_assert(item->host != NULL);

	/*
	 * Since resolution is normally going to happen asynchronously, we must
	 * keep track of the generation at which the resolution was requested.
	 */

	WALLOC(ctx);
	ctx->item = item;
	ctx->generation = whitelist_generation;
	ctx->revalidate = revalidate;

	host = item->host->name;

	if (adns_resolve(host, settings_dns_net(), whitelist_dns_cb, ctx)) {
		/* Asynchronous resolution */
		if (GNET_PROPERTY(whitelist_debug) > 1)
			log_whitelist_item(item, "asynchronously resolving");
	} else {
		/* Synchronous resolution, whitelist_dns_cb() already called */
	}
}
/**
 * Log whitelist item.
 */
static void
log_whitelist_item(const struct whitelist *item, const char *what)
{
	const char *host;
	uint8 bits;

	if (item->host != NULL) {
		host = 0 == item->port ? item->host->name :
			host_port_to_string(item->host->name, ipv4_unspecified, item->port);
	} else {
		host = 0 == item->port ? host_addr_to_string(item->addr) :
			host_addr_port_to_string(item->addr, item->port);
	}

	if (is_host_addr(item->addr)) {
		bits = item->bits == addr_default_mask(item->addr) ? 0 : item->bits;
	} else {
		bits = 0;
	}

	g_debug("WLIST %s %s%s%s%s", what,
		item->use_tls ? "tls:" : "", host,
		bits == 0 ? "" : "/",
		bits == 0 ? "" : uint32_to_string(bits));
}
Exemple #7
0
/**
 * Dispose of the value from the `used' table.
 */
static void
val_free(struct used_val *v)
{
	g_assert(v);
	g_assert(is_host_addr(v->addr));

	cq_cancel(&v->cq_ev);
	WFREE(v);
}
Exemple #8
0
static inline size_t
count_addrs(const host_addr_t *addrs, size_t m)
{
	size_t n;

	for (n = 0; n < m; n++) {
		if (!is_host_addr(addrs[n]))
			break;
	}
	return n;
}
Exemple #9
0
/**
 * Called from callout queue when it's time to destroy the record.
 */
static void
val_destroy(cqueue_t *unused_cq, void *obj)
{
	struct used_val *v = obj;

	(void) unused_cq;
	g_assert(v);
	g_assert(is_host_addr(v->addr));

	hevset_remove(used, &v->addr);
	v->cq_ev = NULL;
	val_free(v);
}
Exemple #10
0
/**
 * Create a value for the `used' table.
 */
static struct used_val *
val_create(const host_addr_t addr, int precision)
{
	struct used_val *v;

	g_assert(is_host_addr(addr));

	WALLOC(v);
	v->addr = addr;
	v->precision = precision;
	v->cq_ev = cq_main_insert(REUSE_DELAY * 1000, val_destroy, v);

	return v;
}
Exemple #11
0
static const char *
magnet_parse_host_port(const char *hostport,
	host_addr_t *addr, uint16 *port, const char **host, const char **host_end,
	const char **error_str)
{
	const char *p;
	const char *endptr;

	clear_error_str(&error_str);
	g_return_val_if_fail(hostport, NULL);

	p = hostport;

	if (!string_to_host_or_addr(p, &endptr, addr)) {
		*error_str = "Expected host part";
		return NULL;
	}

	if (is_host_addr(*addr)) {
		if (host)     *host = NULL;
		if (host_end) *host_end = NULL;
	} else {
		if (host)     *host = p;
		if (host_end) *host_end = endptr;
	}
	p += endptr - p;

	if (':' == *p) {
		const char *ep2;
		int error;
		uint16 u;

		p++;
		u = parse_uint16(p, &ep2, 10, &error);
		if (error) {
			*error_str = "TCP port is out of range";
			/* Skip this parameter */
			return NULL;
		}

		*port = u;
		p += ep2 - p;
	} else {
		*port = 80;
	}

	return p;
}
Exemple #12
0
static GSList *
resolve_hostname(const char *host, enum net_type net)
#ifdef HAS_GETADDRINFO
{
	static const struct addrinfo zero_hints;
	struct addrinfo hints, *ai, *ai0 = NULL;
	hset_t *hs;
	GSList *sl_addr;
	int error;

	g_assert(host);
	
	hints = zero_hints;
	hints.ai_family = net_type_to_pf(net);

	error = getaddrinfo(host, NULL, &hints, &ai0);
	if (error) {
		g_message("getaddrinfo() failed for \"%s\": %s",
				host, gai_strerror(error));
		return NULL;
	}

	sl_addr = NULL;
	hs = hset_create_any(host_addr_hash_func, NULL, host_addr_eq_func);
	for (ai = ai0; ai; ai = ai->ai_next) {
		host_addr_t addr;

		if (!ai->ai_addr)
			continue;

		addr = addrinfo_to_addr(ai);

		if (is_host_addr(addr) && !hset_contains(hs, &addr)) {
			host_addr_t *addr_copy;

			addr_copy = wcopy(&addr, sizeof addr);
			sl_addr = g_slist_prepend(sl_addr, addr_copy);
			hset_insert(hs, addr_copy);
		}
	}
	hset_free_null(&hs);

	if (ai0)
		freeaddrinfo(ai0);

	return g_slist_reverse(sl_addr);
}
/**
 * Add (address-resolved) item to the whitelist.
 */
static void
whitelist_add(struct whitelist *item)
{
	g_assert(item != NULL);
	g_assert(is_host_addr(item->addr));

	/*
	 * If TLS-usage was configured, re-add to the TLS cache so that
	 * connections to that host will use TLS.
	 */

	if (item->use_tls && item->port != 0)
		tls_cache_insert(item->addr, item->port);

	if (GNET_PROPERTY(whitelist_debug))
		log_whitelist_item(item, "adding");

	sl_whitelist = pslist_prepend(sl_whitelist, item);
}
Exemple #14
0
/**
 * @return A pointer to a static buffer holding the host address as string.
 */
const gchar * 
uploads_gui_host_string(const gnet_upload_info_t *u)
{
	static gchar buf[1024];
	const gchar *peer;

	if (u->gnet_port && is_host_addr(u->gnet_addr)) {
		peer = host_addr_port_to_string(u->gnet_addr, u->gnet_port);
	} else {
		peer = NULL;
	}

	concat_strings(buf, sizeof buf,
		host_addr_to_string(u->addr),
		u->encrypted ? " (E) " : " ",
		peer ? " <" : "",
		peer ? peer : "",
		peer ? ">"  : "",
		(void *) 0);

	return buf;
}
/**
 * Try to connect to the list of nodes given by in following form:
 *
 * list = <node> | <node>, 1*<node>
 * port = 1..65535
 * hostname = 1*[a-zA-Z0-9.-]
 * node = hostname [":" <port>]
 *       | <IPv4 address>[":" <port>]
 *		 | <IPv6 address>
 *		 | "[" <IPv6 address> "]:" <port>
 * peer = ["tls:"]["g2:"]<node>
 *
 * If the port is omitted, the default port (GTA_PORT: 6346) is used.
 * The case-insensitive prefix "tls:" requests a TLS (encrypted) connection.
 */
void
nodes_gui_common_connect_by_name(const gchar *line)
{
	const gchar *q;

    g_assert(line);

	q = line;
	while ('\0' != *q) {
		const gchar *endptr, *hostname;
		size_t hostname_len;
		host_addr_t addr;
		guint32 flags;
    	guint16 port;
		bool g2;

		q = skip_ascii_spaces(q);
		if (',' == *q) {
			q++;
			continue;
		}

		addr = zero_host_addr;
		port = GTA_PORT;
		flags = SOCK_F_FORCE;
		endptr = NULL;
		hostname = NULL;
		hostname_len = 0;

		endptr = is_strcaseprefix(q, "tls:");
		if (endptr) {
			flags |= SOCK_F_TLS;
			q = endptr;
		}

		endptr = is_strcaseprefix(q, "g2:");
		if (endptr) {
			g2 = TRUE;
			q = endptr;
		} else {
			g2 = FALSE;
		}

		if (!string_to_host_or_addr(q, &endptr, &addr)) {
			g_message("expected hostname or IP address");
			break;
		}

		if (!is_host_addr(addr)) {
			hostname = q;
			hostname_len = endptr - q;
		}

		q = endptr;

		if (':' == *q) {
			gint error;

			port = parse_uint16(&q[1], &endptr, 10, &error);
			if (error || 0 == port) {
				g_message("cannot parse port");
				break;
			}

			q = skip_ascii_spaces(endptr);
		} else {
			q = skip_ascii_spaces(endptr);
			if ('\0' != *q && ',' != *q) {
				g_message("expected \",\" or \":\"");
				break;
			}
		}

		if (!hostname) {
			if (g2) {
				guc_node_g2_add(addr, port, flags);
			} else {
				guc_node_add(addr, port, flags);
			}
		} else {
			struct add_node_context *ctx;
			gchar *p;

			if ('\0' == hostname[hostname_len])	{
				p = NULL;
			} else {
				size_t n = 1 + hostname_len;

				g_assert(n > hostname_len);
				p = halloc(n);
				g_strlcpy(p, hostname, n);
				hostname = p;
			}

			WALLOC(ctx);
			ctx->port = port;
			ctx->flags = flags;
			ctx->g2 = g2;
			guc_adns_resolve(hostname, add_node_helper, ctx);

			HFREE_NULL(p);
		}
	}
}