コード例 #1
0
/**
 * Initializations.
 */
void G_COLD
uhc_init(void)
{
	uint i;

	g_return_if_fail(NULL == uhc_list);
	uhc_list = hash_list_new(uhc_hash, uhc_equal);

	for (i = 0; i < N_ITEMS(boot_hosts); i++) {
		const char *host, *ep, *uhc;
		uint16 port;

		uhc = boot_hosts[i].uhc;

		/* Some consistency checks */
		uhc_get_host_port(uhc, &host, &port);
		g_assert(NULL != host);
		g_assert(0 != port);

		ep = is_strprefix(uhc, host);
		g_assert(NULL != ep);
		g_assert(':' == ep[0]);

		uhc_list_append(uhc);
	}

	hash_list_shuffle(uhc_list);
}
コード例 #2
0
ファイル: magnet.c プロジェクト: MrJoe/gtk-gnutella
static struct magnet_source *
magnet_parse_push_source(const char *uri, const char **error_str)
{
	struct magnet_source *ms;
	const char *p, *endptr;
	struct guid guid;

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

	p = is_strprefix(uri, "push://");
	g_return_val_if_fail(p, NULL);

	endptr = strchr(p, ':');		/* First push-proxy host */
	if (NULL == endptr || GUID_HEX_SIZE != (endptr - p))
		endptr = strchr(p, '/');	/* No push-proxy host */

	if (
		NULL == endptr ||
		GUID_HEX_SIZE != (endptr - p) ||
		!hex_to_guid(p, &guid)
	) {
		*error_str = "Bad GUID in push source";
		return NULL;
	}

	ms = magnet_parse_proxy_location(endptr, error_str);
	if (ms) {
		ms->guid = atom_guid_get(&guid);
	}
	return ms;
}
コード例 #3
0
ファイル: magnet.c プロジェクト: MrJoe/gtk-gnutella
static struct magnet_source *
magnet_parse_path(const char *path, const char **error_str)
{
	static const struct magnet_source zero_ms;
	struct magnet_source ms;
	const char *p, *endptr;

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

	ms = zero_ms;
	p = path;

	if ('/' != *p) {
		*error_str = "Expected path starting with '/'";
		/* Skip this parameter */
		return NULL;
	}
	g_assert(*p == '/');

	endptr = is_strprefix(p, "/uri-res/N2R?");
	if (endptr) {
		struct sha1 sha1;
		
		p = endptr;
		if (!urn_get_sha1(p, &sha1)) {
			*error_str = "Bad SHA1 in MAGNET URI";
			return NULL;
		}
		ms.sha1 = atom_sha1_get(&sha1);
	} else {
		ms.path = atom_str_get(p);
	}

	return wcopy(&ms, sizeof ms);
}
コード例 #4
0
ファイル: getgateway.c プロジェクト: MrJoe/gtk-gnutella
/**
 * Default implementation to get the default gateway by parsing the
 * output of the "netstat -rn" command.
 *
 * @param addrp		where gateway address is to be written
 *
 * @return 0 on success, -1 on failure with errno set.
 */
static G_GNUC_COLD int
parse_netstat(host_addr_t *addrp)
#ifdef HAS_POPEN
{
	FILE *f = NULL;
	char tmp[80];
	uint32 gate = 0;

	/*
	 * This implementation should be a safe default on UNIX platforms, but
	 * it is inefficient and as such can only constitute a fallback.
	 */

	if (-1 != access("/bin/netstat", X_OK)) {
		f = popen("/bin/netstat -rn", "r");
	} else if (-1 != access("/usr/bin/netstat", X_OK)) {
		f = popen("/usr/bin/netstat -rn", "r");
	}

	if (NULL == f) {
		errno = ENOENT;		/* netstat not found */
		return -1;
	}

	/*
	 * Typical netstat -rn output:
	 *
	 * Destination        Gateway            Flags .....
	 * 0.0.0.0            192.168.0.200      UG
	 * default            192.168.0.200      UG
	 *
	 * Some systems like linux display "0.0.0.0", but traditional UNIX
	 * output is "default" for the default route.
	 */

	while (fgets(tmp, sizeof tmp, f)) {
		char *p;
		uint32 ip;

		p = is_strprefix(tmp, "default");
		if (NULL == p)
			p = is_strprefix(tmp, "0.0.0.0");

		if (NULL == p || !is_ascii_space(*p))
			continue;

		ip = string_to_ip(p);
		if (ip != 0) {
			gate = ip;
			break;
		}
	}

	pclose(f);

	if (0 == gate) {
		errno = ENETUNREACH;
		return -1;
	}

	*addrp = host_addr_get_ipv4(gate);
	return 0;
}
コード例 #5
0
/**
 * Loads the whitelist into memory.
 */
static void G_COLD
whitelist_retrieve(void)
{
	char line[1024];
	FILE *f;
	filestat_t st;
	unsigned linenum = 0;
	file_path_t fp[1];

	whitelist_generation++;

	file_path_set(fp, settings_config_dir(), whitelist_file);
	f = file_config_open_read_norename("Host Whitelist", fp, N_ITEMS(fp));
	if (!f)
		return;

	if (fstat(fileno(f), &st)) {
		g_warning("%s(): fstat() failed: %m", G_STRFUNC);
		fclose(f);
		return;
	}

    while (fgets(line, sizeof line, f)) {
		pslist_t *sl_addr, *sl;
		const char *endptr, *start;
		host_addr_t addr;
    	uint16 port;
		uint8 bits;
		bool item_ok;
		bool use_tls;
		char *hname;

        linenum++;

		if (!file_line_chomp_tail(line, sizeof line, NULL)) {
			g_warning("%s(): line %u too long, aborting", G_STRFUNC, linenum);
			break;
		}

        if (file_line_is_skipable(line))
			continue;

		sl_addr = NULL;
		addr = zero_host_addr;
		endptr = NULL;
		hname = NULL;

		endptr = is_strprefix(line, "tls:");
		if (endptr) {
			use_tls = TRUE;
			start = endptr;
		} else {
			use_tls = FALSE;
			start = line;
		}

		port = 0;
		if (string_to_host_addr_port(start, &endptr, &addr, &port)) {
       		sl_addr = name_to_host_addr(host_addr_to_string(addr),
							settings_dns_net());
		} else if (string_to_host_or_addr(start, &endptr, &addr)) {
			uchar c = *endptr;

			switch (c) {
			case '\0':
			case ':':
			case '/':
				break;
			default:
				if (!is_ascii_space(c))
					endptr = NULL;
			}

			if (!endptr) {
				g_warning("%s(): line %d: "
					"expected a hostname or IP address \"%s\"",
					G_STRFUNC, linenum, line);
				continue;
			}

			/* Terminate the string for name_to_host_addr() */
			hname = h_strndup(start, endptr - start);
		} else {
            g_warning("%s(): line %d: expected hostname or IP address \"%s\"",
				G_STRFUNC, linenum, line);
			continue;
		}

       	g_assert(sl_addr != NULL || hname != NULL);
		g_assert(NULL != endptr);
		bits = 0;
		item_ok = TRUE;

		/*
		 * When an explicit address is given (no hostname) and with no
		 * port, one can suffix the address with bits to indicate a CIDR
		 * range of whitelisted addresses.
		 */

		if (0 == port) {
			/* Ignore trailing items separated by a space */
			while ('\0' != *endptr && !is_ascii_space(*endptr)) {
				uchar c = *endptr++;

				if (':' == c) {
					int error;
					uint32 v;

					if (0 != port) {
						g_warning("%s(): line %d: multiple colons after host",
							G_STRFUNC, linenum);
						item_ok = FALSE;
						break;
					}

					v = parse_uint32(endptr, &endptr, 10, &error);
					port = (error || v > 0xffff) ? 0 : v;
					if (0 == port) {
						g_warning("%s(): line %d: "
							"invalid port value after host",
							G_STRFUNC, linenum);
						item_ok = FALSE;
						break;
					}
				} else if ('/' == c) {
					const char *ep;
					uint32 mask;

					if (0 != bits) {
						g_warning("%s(): line %d: "
							"multiple slashes after host", G_STRFUNC, linenum);
						item_ok = FALSE;
						break;
					}

					if (string_to_ip_strict(endptr, &mask, &ep)) {
						if (!host_addr_is_ipv4(addr)) {
							g_warning("%s(): line %d: "
								"IPv4 netmask after non-IPv4 address",
								G_STRFUNC, linenum);
							item_ok = FALSE;
							break;
						}
						endptr = ep;

						if (0 == (bits = netmask_to_cidr(mask))) {
							g_warning("%s(): line %d: "
								"IPv4 netmask after non-IPv4 address",
								G_STRFUNC, linenum);
							item_ok = FALSE;
							break;
						}

					} else {
						int error;
						uint32 v;

						v = parse_uint32(endptr, &endptr, 10, &error);
						if (
							error ||
							0 == v ||
							(v > 32 && host_addr_is_ipv4(addr)) ||
							(v > 128 && host_addr_is_ipv6(addr))
						) {
							g_warning("%s(): line %d: "
								"invalid numeric netmask after host",
								G_STRFUNC, linenum);
							item_ok = FALSE;
							break;
						}
						bits = v;
					}
				} else {
					g_warning("%s(): line %d: "
						"unexpected character after host", G_STRFUNC, linenum);
					item_ok = FALSE;
					break;
				}
			}
		}

		if (item_ok) {
			struct whitelist *item;
			if (hname) {
				item = whitelist_hostname_create(use_tls, hname, port);
				whitelist_dns_resolve(item, FALSE);
			} else {
				PSLIST_FOREACH(sl_addr, sl) {
					host_addr_t *aptr = sl->data;
					g_assert(aptr != NULL);
					item = whitelist_addr_create(use_tls, *aptr, port, bits);
					whitelist_add(item);
				}
			}
		} else {
コード例 #6
0
ファイル: gwc.c プロジェクト: gtk-gnutella/gtk-gnutella
/**
 * Called from gwc_parse_dispatch_lines() for each complete line of output.
 *
 * @return FALSE to stop processing of any remaining data.
 */
static bool
gwc_host_line(struct gwc_parse_context *ctx, const char *buf, size_t len)
{
    int c;

    if (GNET_PROPERTY(bootstrap_debug) > 3)
        g_message("BOOT GWC host line (%lu bytes): %s", (ulong) len, buf);

    if (is_strprefix(buf, "ERROR")) {
        g_warning("GWC cache \"%s\" returned %s",
                  http_async_url(ctx->handle), buf);
        http_async_cancel(ctx->handle);
        return FALSE;
    }

    if (len <= 2)
        return TRUE;		/* Skip this line silently */

    /*
     * A line starting with "H|" is a host, with "U|" a GWC URL.
     * Letters are case-insensitive.
     */

    if (buf[1] != '|')
        goto malformed;

    c = ascii_toupper(buf[0]);

    if ('H' == c) {
        host_addr_t addr;
        uint16 port;

        if (string_to_host_addr_port(&buf[2], NULL, &addr, &port)) {
            ctx->processed++;
            hcache_add_caught(HOST_G2HUB, addr, port, "GWC");
            if (GNET_PROPERTY(bootstrap_debug) > 1) {
                g_message("BOOT (G2) collected %s from GWC %s",
                          host_addr_port_to_string(addr, port),
                          http_async_url(ctx->handle));
            }
        }
        return TRUE;
    } else if ('U' == c) {
        char *end = strchr(&buf[2], '|');
        char *url;

        if (NULL == end)
            goto malformed;

        ctx->processed++;
        url = h_strndup(&buf[2], ptr_diff(end, &buf[2]));
        gwc_add(url);
        hfree(url);
        return TRUE;
    } else if ('I' == c) {
        return TRUE;		/* Ignore information line */
    }

    /*
     * If we come here, we did not recognize the line properly.
     */

    if (GNET_PROPERTY(bootstrap_debug) > 2) {
        g_warning("GWC ignoring unknown line \"%s\" from %s",
                  buf, http_async_url(ctx->handle));
    }

    return TRUE;

malformed:
    if (GNET_PROPERTY(bootstrap_debug)) {
        g_warning("GWC ignoring malformed line \"%s\" from %s",
                  buf, http_async_url(ctx->handle));
    }

    return TRUE;
}
コード例 #7
0
ファイル: version.c プロジェクト: Eppo791906066/gtk-gnutella
/**
 * Parse gtk-gnutella's version number in User-Agent/Server string `str'
 * and extract relevant information into `ver'.
 *
 * @param str	the version string to be parsed
 * @param ver	the structure filled with parsed information
 * @param end	filled with a pointer to the first unparsed character
 *
 * @returns TRUE if we parsed a gtk-gnutella version correctly, FALSE if we
 * were not facing a gtk-gnutella version, or if we did not recognize it.
 */
static bool
version_parse(const char *str, version_t *ver, const char **end)
{
	const char *v;
	int error;

	/*
	 * Modern version numbers are formatted like this:
	 *
	 *    gtk-gnutella/0.85 (04/04/2002; X11; FreeBSD 4.6-STABLE i386)
	 *    gtk-gnutella/0.90u (24/06/2002; X11; Linux 2.4.18-pre7 i686)
	 *    gtk-gnutella/0.90b (24/06/2002; X11; Linux 2.4.18-2emi i686)
	 *    gtk-gnutella/0.90b2 (24/06/2002; X11; Linux 2.4.18-2emi i686)
	 *
	 * The letter after the version number is either 'u' for unstable, 'a'
	 * for alpha, 'b' for beta, or nothing for a stable release.  It can be
	 * followed by digits when present.
	 *
	 * In prevision for future possible extensions, we also parse
	 *
	 *    gtk-gnutella/0.90.1b2 (24/06/2002; X11; Linux 2.4.18-2emi i686)
	 *
	 * where the third number is the "patchlevel".
	 *
	 * Starting 2006-08-26, the user-agent string includes the SVN revision
	 * at the time of the build.  To be compatible with the servents out
	 * there, the version is included as an optional tag following the date.
	 *
	 *    gtk-gnutella/0.85 (04/04/2002; r3404; X11; FreeBSD 4.6-STABLE i386)
	 *
	 * However, we also start parsing the new format that we shall use when
	 * all current GTKG out there have expired:
	 *
	 *    gtk-gnutella/0.85-3404 (04/04/2002; X11; FreeBSD 4.6-STABLE i386)
	 *    gtk-gnutella/0.90b2-3404 (04/04/2002; X11; FreeBSD 4.6-STABLE i386)
	 *
	 * where the '-3404' introduces the build number.
	 *
	 * Since switching to git (2011-09-11), the SVN build is no longer present
	 * but rather the output of "git describe" is used to show any difference
	 * with the latest release tag.
	 *
	 * A release would be described as:
	 *
	 *    gtk-gnutella/0.97.1 (2011-09-11; GTK1; Linux i686)
	 *
	 * but any change on top of that would be seen as:
	 *
	 *    gtk-gnutella/0.97.1-24-g844b7 (2011-09-11; GTK1; Linux i686)
	 *
	 * to indicate that 24 commits were made after the release, and the commit
	 * ID is 844b7... (only enough hexadecimal digits are output to make the
	 * string unique at the time it was generated.
	 *
	 * If furthermore a build is done from a dirty git repository, the string
	 * "-dirty" is appended after the commit ID:
	 *
	 *    gtk-gnutella/0.97.1-24-g844b7-dirty (2011-09-11; GTK1; Linux i686)
	 */

	if (NULL == (v = is_strprefix(str, GTA_PRODUCT_NAME "/")))
		return FALSE;

	/*
	 * Parse "major.minor", followed by optional ".patchlevel".
	 */

	ver->major = parse_uint32(v, &v, 10, &error);
	if (error)
		return FALSE;

	if (*v++ != '.')
		return FALSE;

	ver->minor = parse_uint32(v, &v, 10, &error);
	if (error)
		return FALSE;

	if ('.' == *v) {
		v++;
		ver->patchlevel = parse_uint32(v, &v, 10, &error);
		if (error)
			return FALSE;
	} else
		ver->patchlevel = 0;

	/*
	 * Parse optional tag letter "x" followed by optional "taglevel".
	 */

	if (is_ascii_alpha(*v)) {
		ver->tag = *v++;
		if (is_ascii_digit(*v)) {
			ver->taglevel = parse_uint32(v, &v, 10, &error);
			if (error)
				return FALSE;
		} else
			ver->taglevel = 0;
	} else {
		ver->tag = '\0';
		ver->taglevel = 0;
	}

	/*
	 * Parse optional "-build" (legacy SVN) or "-change-bxxxxxxxx" (git
	 * version scheme) to be able to sort identical versions with distinct
	 * changes applied to them.
	 */

	if ('-' == *v) {
		v++;
		if (!is_strprefix(v, "dirty")) {
			ver->build = parse_uint32(v, &v, 10, &error);
			if (error)
				return FALSE;
		}
	} else
		ver->build = 0;

	if (end != NULL)
		*end = v;

	if (GNET_PROPERTY(version_debug) > 1)
		version_dump(str, ver, "#");

	return TRUE;
}
コード例 #8
0
ファイル: version.c プロジェクト: Eppo791906066/gtk-gnutella
/**
 * Parse extended build information (git's commit string + dirtyness)
 * from a version string, starting at the first byte after the build number.
 *
 * A typical extended build information would look like:
 *
 *		-g5c02b-dirty
 *
 * The hexadecimal string after "-g" points to the leading git commit ID.
 * The "-dirty" indication is present when the binary was built with
 * uncommitted changes.
 *
 * @returns TRUE if we parsed the extended build information properly, FALSE
 * if we were not facing a proper extension.
 */
static bool
version_ext_parse(const char *str, version_ext_t *vext)
{
	const char *v;
	const char *e;
	size_t commit_len;
	char commit[SHA1_BASE16_SIZE + 1];

	v = is_strprefix(str, "-g");
	if (NULL == v) {
		/*
		 * There may not be any git tag, but there may be a dirty indication.
		 */

		e = is_strprefix(str, "dirty");
		if (e != NULL) {
			vext->dirty = TRUE;
			return TRUE;
		} else if (' ' == *str || '\0' == *str) {
			return TRUE;
		}
		return FALSE;
	}

	/*
	 * Compute the length of the hexadecimal string, up to the next '-' or
	 * the next ' ' or the end of the string.
	 */

	e = strchr(v, ' ');
	if (e != NULL) {
		const char *d;
		d = strchr(v, '-');
		if (NULL == d || d > e) {
			commit_len = e - v;		/* '-' before ' ' or no '-' at all */
		} else {
			commit_len = d - v;		/* '-' after ' ' */
			e = d;
		}
	} else {
		e = strchr(v, '-');
		if (e != NULL) {
			commit_len = e - v;
		} else {
			commit_len = strlen(v);
		}
	}

	if (commit_len > SHA1_BASE16_SIZE)
		return FALSE;

	vext->commit_len = commit_len;

	memset(commit, '0', sizeof commit - 1);
	commit[SHA1_BASE16_SIZE] = '\0';
	memcpy(commit, v, commit_len);

	ZERO(&vext->commit);
	(void) base16_decode(vext->commit.data, sizeof vext->commit,
		commit, SHA1_BASE16_SIZE);

	if (e != NULL && is_strprefix(e, "-dirty")) {
		vext->dirty = TRUE;
	} else {
		vext->dirty = FALSE;
	}

	return TRUE;
}