/** * 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; }
/** * 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; }
/** * 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; }
/** * 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)); }
/** * 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); }
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; }
/** * 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); }
/** * 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; }
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; }
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); }
/** * @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); } } }