示例#1
0
文件: ip.c 项目: Epictetus/postgres
/*
 * Enumerate the system's network interface addresses and call the callback
 * for each one.  Returns 0 if successful, -1 if trouble.
 *
 * This version is our fallback if there's no known way to get the
 * interface addresses.  Just return the standard loopback addresses.
 */
int
pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
{
	struct sockaddr_in addr;
	struct sockaddr_storage mask;

#ifdef HAVE_IPV6
	struct sockaddr_in6 addr6;
#endif

	/* addr 127.0.0.1/8 */
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = ntohl(0x7f000001);
	memset(&mask, 0, sizeof(mask));
	pg_sockaddr_cidr_mask(&mask, "8", AF_INET);
	run_ifaddr_callback(callback, cb_data,
						(struct sockaddr *) & addr,
						(struct sockaddr *) & mask);

#ifdef HAVE_IPV6
	/* addr ::1/128 */
	memset(&addr6, 0, sizeof(addr6));
	addr6.sin6_family = AF_INET6;
	addr6.sin6_addr.s6_addr[15] = 1;
	memset(&mask, 0, sizeof(mask));
	pg_sockaddr_cidr_mask(&mask, "128", AF_INET6);
	run_ifaddr_callback(callback, cb_data,
						(struct sockaddr *) & addr6,
						(struct sockaddr *) & mask);
#endif

	return 0;
}
示例#2
0
文件: ip.c 项目: Epictetus/postgres
/*
 * Run the callback function for the addr/mask, after making sure the
 * mask is sane for the addr.
 */
static void
run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data,
					struct sockaddr * addr, struct sockaddr * mask)
{
	struct sockaddr_storage fullmask;

	if (!addr)
		return;

	/* Check that the mask is valid */
	if (mask)
	{
		if (mask->sa_family != addr->sa_family)
		{
			mask = NULL;
		}
		else if (mask->sa_family == AF_INET)
		{
			if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY)
				mask = NULL;
		}
#ifdef HAVE_IPV6
		else if (mask->sa_family == AF_INET6)
		{
			if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr))
				mask = NULL;
		}
#endif
	}

	/* If mask is invalid, generate our own fully-set mask */
	if (!mask)
	{
		pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family);
		mask = (struct sockaddr *) & fullmask;
	}

	(*callback) (addr, mask, cb_data);
}
static bool
load_rule(int line, const char * dbname, const char * user,
		  const char * ip, const char * mask, int limit)
{
	rule_t * rule;

	/* error if the segment is already full (no space for another rule) */
	if (rules->n_rules == MAX_RULES)
		elog(ERROR, "too many connection limit rules (max: %d)", MAX_RULES);

	/* get space for the next rule */
	rule = &(rules->rules[rules->n_rules]);
	memset(rule, 0, sizeof(rule_t));

	/* reset the rule (no fields) */
	rule->fields = 0;
	rule->limit = limit;
	rule->line = line;

	/* dbname entered */
	if (strcmp("all", dbname) != 0)
	{
		strcpy(rule->database, dbname);
		rule->fields |= CHECK_DBNAME;
	}

	/* username entered */
	if (strcmp("all", user) != 0)
	{
		strcpy(rule->user, user);
		rule->fields |= CHECK_USER;
	}

	/* load the IP (see parse_hba_line in hba.c) */
	if (strcmp("all", ip) != 0)
	{

		int		ret;
		char   *ipcopy ;

		/* IP address parsing */
		struct	addrinfo hints;
		struct	addrinfo * gai_result;

		/* process the IP address (without the mask), or a hostname */

		ipcopy = pstrdup(ip);

		if (strchr(ipcopy, '/'))
			*strchr(ipcopy, '/') = '\0';

		hints.ai_flags = AI_NUMERICHOST;
		hints.ai_family = PF_UNSPEC;
		hints.ai_socktype = 0;
		hints.ai_protocol = 0;
		hints.ai_addrlen = 0;
		hints.ai_canonname = NULL;
		hints.ai_addr = NULL;
		hints.ai_next = NULL;

		/* try to parse the IP address */
		ret = pg_getaddrinfo_all(ipcopy, NULL, &hints, &gai_result);
		if (ret == 0 && gai_result)
		{
			memcpy(&(rule->ip), gai_result->ai_addr, gai_result->ai_addrlen);
			rule->fields |= CHECK_IP;
		}
		else if (ret == EAI_NONAME)
		{
			strcpy(rule->hostname, ipcopy);
			rule->fields |= CHECK_HOST;
		}
		else
		{
			elog(WARNING,
				 "invalid IP address \"%s\": %s", ipcopy, gai_strerror(ret));
			pfree(ipcopy);
			return false;
		}

		pfree(ipcopy);

		if (gai_result)
			pg_freeaddrinfo_all(hints.ai_family, gai_result);

		/* Get the netmask */
		if (strchr(ip, '/'))
		{
			if (strlen(rule->hostname) != 0)
			{
				elog(WARNING,
					 "specifying both host name and CIDR mask is invalid: \"%s\"", ip);
				return false;
			}
			else if (pg_sockaddr_cidr_mask(&(rule->mask), strchr(ip, '/') + 1, rule->ip.ss_family) < 0)
			{
				elog(WARNING,
					 "invalid CIDR mask in address \"%s\"", ip);
				return false;
			}
		}
		else if (strlen(rule->hostname) == 0)
		{
			if (mask == NULL)
			{
				elog(WARNING,
					 "no mask specified for rule %d", rules->n_rules);
				return false;
			}

			ret = pg_getaddrinfo_all(mask, NULL, &hints, &gai_result);
			if (ret || !gai_result)
			{
				elog(WARNING,
					 "invalid IP mask \"%s\": %s",
					 mask, gai_strerror(ret));

				if (gai_result)
					pg_freeaddrinfo_all(hints.ai_family, gai_result);

				return false;
			}

			memcpy(&rule->mask, gai_result->ai_addr, gai_result->ai_addrlen);
			pg_freeaddrinfo_all(hints.ai_family, gai_result);

			if (rule->ip.ss_family != rule->mask.ss_family)
			{
				elog(WARNING,
					 "IP address and mask do not match");
				return false;
			}
		}
	} /* IP address parsing */

	/* successfully parsed - at least one field needs to be set (increment) */
	if (rule->fields == 0)
	{
		elog(WARNING, "rule on line %d is invalid - no value set", line);
		return false;
	} else
		rules->n_rules += 1;

	return true;

}