Blame addrfunc.c

Packit 61cb5a
/*
Packit 61cb5a
 * Copyright (c) 2010-2011, Red Hat, Inc.
Packit 61cb5a
 *
Packit 61cb5a
 * Permission to use, copy, modify, and/or distribute this software for any
Packit 61cb5a
 * purpose with or without fee is hereby granted, provided that the above
Packit 61cb5a
 * copyright notice and this permission notice appear in all copies.
Packit 61cb5a
 *
Packit 61cb5a
 * THE SOFTWARE IS PROVIDED "AS IS" AND RED HAT, INC. DISCLAIMS ALL WARRANTIES
Packit 61cb5a
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit 61cb5a
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RED HAT, INC. BE LIABLE
Packit 61cb5a
 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit 61cb5a
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
Packit 61cb5a
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
Packit 61cb5a
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit 61cb5a
 */
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Author: Jan Friesse <jfriesse@redhat.com>
Packit 61cb5a
 */
Packit 61cb5a
Packit 61cb5a
#include <sys/types.h>
Packit 61cb5a
Packit 61cb5a
#include <sys/socket.h>
Packit 61cb5a
Packit 61cb5a
#include <net/if.h>
Packit 61cb5a
#include <netinet/in.h>
Packit 61cb5a
#include <arpa/inet.h>
Packit 61cb5a
Packit 61cb5a
#include <err.h>
Packit 61cb5a
#include <stdio.h>
Packit 61cb5a
#include <stdlib.h>
Packit 61cb5a
#include <string.h>
Packit 61cb5a
#include <stdarg.h>
Packit 61cb5a
Packit 61cb5a
#include "addrfunc.h"
Packit 61cb5a
#include "logging.h"
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Compares two addrinfo structures. Family, socktype, protocol and sockaddr are
Packit 61cb5a
 * compared. This one don't goes to deep, so compares really only one struct not
Packit 61cb5a
 * list of them.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_eq(const struct addrinfo *a1, const struct addrinfo *a2)
Packit 61cb5a
{
Packit 61cb5a
Packit 61cb5a
	return ((a1->ai_family == a2->ai_family) &&
Packit 61cb5a
	    (a1->ai_socktype == a2->ai_socktype) &&
Packit 61cb5a
	    (a1->ai_protocol == a2->ai_protocol) &&
Packit 61cb5a
	    af_sockaddr_eq(a1->ai_addr, a2->ai_addr));
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Deep compare of two addrinfo structures. Internally calls addrinfo_eq
Packit 61cb5a
 * function to compare one struct. It returns 1, if at least one addr from a1
Packit 61cb5a
 * matches with at least on addr from a2.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_deep_eq(const struct addrinfo *a1, const struct addrinfo *a2)
Packit 61cb5a
{
Packit 61cb5a
	const struct addrinfo *a1_i, *a2_i;
Packit 61cb5a
Packit 61cb5a
	for (a1_i = a1; a1_i != NULL; a1_i = a1_i->ai_next) {
Packit 61cb5a
		for (a2_i = a2; a2_i != NULL; a2_i = a2_i->ai_next) {
Packit 61cb5a
			if (af_ai_eq(a1_i, a2_i)) {
Packit 61cb5a
				return (1);
Packit 61cb5a
			}
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (0);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Find out if ai is duplicate of items in ai_list. ai_list is first addrinfo item (returned by
Packit 61cb5a
 * getaddrinfo) and list is traversed up to ai item.
Packit 61cb5a
 * Function return 0 if ai is not duplicate of items in ai_list, otherwise 1
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_is_dup(const struct addrinfo *ai_list, const struct addrinfo *ai)
Packit 61cb5a
{
Packit 61cb5a
	const struct addrinfo *ai_i;
Packit 61cb5a
	int res;
Packit 61cb5a
Packit 61cb5a
	res = 0;
Packit 61cb5a
Packit 61cb5a
	for (ai_i = ai_list; res == 0 && ai_i != ai && ai_i != NULL; ai_i = ai_i->ai_next) {
Packit 61cb5a
		if (af_ai_eq(ai_i, ai)) {
Packit 61cb5a
			res = 1;
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (res);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Test if given list of addrinfo ai is loopback address or not. Returns > 0 if
Packit 61cb5a
 * addrinfo list ai is loopback, otherwise 0. This one goes to deep.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_deep_is_loopback(const struct addrinfo *a1)
Packit 61cb5a
{
Packit 61cb5a
	const struct addrinfo *a1_i;
Packit 61cb5a
Packit 61cb5a
	for (a1_i = a1; a1_i != NULL; a1_i = a1_i->ai_next) {
Packit 61cb5a
		if (af_ai_is_loopback(a1_i)) {
Packit 61cb5a
			return (1);
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (0);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/* Deeply test what IP versions are supported on given ai_addr. Can return 4 (only ipv4 is
Packit 61cb5a
 * supported), 6 (only ipv6 is supported), 0 (both ipv4 and ipv6 are supported) and -1 (nether ipv4
Packit 61cb5a
 * or ipv6 are supported)
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_deep_supported_ipv(const struct addrinfo *ai_addr)
Packit 61cb5a
{
Packit 61cb5a
	const struct addrinfo *ai_iter;
Packit 61cb5a
	int ip4, ip6;
Packit 61cb5a
Packit 61cb5a
	ip4 = 0;
Packit 61cb5a
	ip6 = 0;
Packit 61cb5a
Packit 61cb5a
	for (ai_iter = ai_addr; ai_iter != NULL; ai_iter = ai_iter->ai_next) {
Packit 61cb5a
		switch (af_ai_supported_ipv(ai_iter)) {
Packit 61cb5a
		case 4:
Packit 61cb5a
			ip4 = 1;
Packit 61cb5a
			break;
Packit 61cb5a
		case 6:
Packit 61cb5a
			ip6 = 1;
Packit 61cb5a
			break;
Packit 61cb5a
		case 0:
Packit 61cb5a
			DEBUG_PRINTF("internal program error.");
Packit 61cb5a
			err(1, "Internal program error");
Packit 61cb5a
			break;
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (ip4 && ip6)
Packit 61cb5a
		return (0);
Packit 61cb5a
	if (ip6)
Packit 61cb5a
		return (6);
Packit 61cb5a
	if (ip4)
Packit 61cb5a
		return (4);
Packit 61cb5a
Packit 61cb5a
	return (-1);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Test if given addrinfo ai is loopback address or not. Returns > 0 if
Packit 61cb5a
 * addrinfo ai is loopback, otherwise 0. This one don't goes to deep,
Packit 61cb5a
 * so compares really only one struct not list of them.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_is_loopback(const struct addrinfo *ai)
Packit 61cb5a
{
Packit 61cb5a
	int res;
Packit 61cb5a
Packit 61cb5a
	switch (ai->ai_family) {
Packit 61cb5a
	case PF_INET:
Packit 61cb5a
		res = ntohl(((struct sockaddr_in *)(ai->ai_addr))->sin_addr.s_addr) >> 24 == 0x7f;
Packit 61cb5a
		break;
Packit 61cb5a
	case PF_INET6:
Packit 61cb5a
		res = IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr);
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Unknown ai family %d", ai->ai_family);
Packit 61cb5a
		errx(1, "Unknown ai family %d", ai->ai_family);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (res);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Free content of ai_list. List must have sas field active (not ai field)
Packit 61cb5a
 */
Packit 61cb5a
void
Packit 61cb5a
af_ai_list_free(struct ai_list *ai_list)
Packit 61cb5a
{
Packit 61cb5a
	struct ai_item *ai_item;
Packit 61cb5a
	struct ai_item *ai_item_next;
Packit 61cb5a
Packit 61cb5a
	ai_item = TAILQ_FIRST(ai_list);
Packit 61cb5a
Packit 61cb5a
	while (ai_item != NULL) {
Packit 61cb5a
		ai_item_next = TAILQ_NEXT(ai_item, entries);
Packit 61cb5a
Packit 61cb5a
		free(ai_item->host_name);
Packit 61cb5a
		free(ai_item);
Packit 61cb5a
Packit 61cb5a
		ai_item = ai_item_next;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	TAILQ_INIT(ai_list);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/* Return supported ip version. This function doesn't go deeply to structure. It can return 4 (ipv4
Packit 61cb5a
 * is supported), 6 (ipv6 is supported) or 0 (nether ipv4 or ipv6 are supported).
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_ai_supported_ipv(const struct addrinfo *ai_addr)
Packit 61cb5a
{
Packit 61cb5a
	int ipv;
Packit 61cb5a
Packit 61cb5a
	ipv = 0;
Packit 61cb5a
Packit 61cb5a
	switch (ai_addr->ai_family) {
Packit 61cb5a
	case PF_INET:
Packit 61cb5a
		ipv = 4;
Packit 61cb5a
		break;
Packit 61cb5a
	case PF_INET6:
Packit 61cb5a
		ipv = 6;
Packit 61cb5a
		break;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (ipv);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Make result address from two addresses a1 and a2. addr_source is primary source of address (for
Packit 61cb5a
 * ipv6 also scope, ...) and can be 1 or 2. port_source address is for copy of port number. Result
Packit 61cb5a
 * is stored in res.
Packit 61cb5a
 * Function can return -1 on fail (addr_source or port_number is not 1 or 2), otherwise 0.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_copy_addr(const struct sockaddr_storage *a1, const struct sockaddr_storage *a2, int addr_source,
Packit 61cb5a
    int port_source, struct sockaddr_storage *res)
Packit 61cb5a
{
Packit 61cb5a
	const struct sockaddr_storage *sas;
Packit 61cb5a
Packit 61cb5a
	if (addr_source != 1 && addr_source != 2) {
Packit 61cb5a
		return (-1);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (port_source != 1 && port_source != 2) {
Packit 61cb5a
		return (-1);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	sas = (addr_source == 1 ? a1 : a2);
Packit 61cb5a
	memcpy(res, sas, sizeof(struct sockaddr_storage));
Packit 61cb5a
Packit 61cb5a
	if (addr_source == port_source) {
Packit 61cb5a
		return (0);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	sas = (port_source == 1 ? a1 : a2);
Packit 61cb5a
Packit 61cb5a
	switch (sas->ss_family) {
Packit 61cb5a
	case AF_INET:
Packit 61cb5a
		((struct sockaddr_in *)res)->sin_port = ((struct sockaddr_in *)sas)->sin_port;
Packit 61cb5a
		break;
Packit 61cb5a
	case AF_INET6:
Packit 61cb5a
		((struct sockaddr_in6 *)res)->sin6_port = ((struct sockaddr_in6 *)sas)->sin6_port;
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Unknown sas family %d", sas->ss_family);
Packit 61cb5a
		errx(1, "Unknown sas family %d", sas->ss_family);
Packit 61cb5a
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (0);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Copy informations stored in sockaddr sa to sockaddr_storage sas.
Packit 61cb5a
 */
Packit 61cb5a
void
Packit 61cb5a
af_copy_sa_to_sas(struct sockaddr_storage *sas, const struct sockaddr *sa)
Packit 61cb5a
{
Packit 61cb5a
Packit 61cb5a
	memset(sas, 0, sizeof(*sa));
Packit 61cb5a
	memcpy(sas, sa, af_sa_len(sa));
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Fill in sockaddr sa pointer with in addr any for specified sa_family with specified port. port
Packit 61cb5a
 * must be in local byte order.
Packit 61cb5a
 */
Packit 61cb5a
void
Packit 61cb5a
af_create_any_addr(struct sockaddr *sa, int sa_family, uint16_t port)
Packit 61cb5a
{
Packit 61cb5a
	struct sockaddr_in sa_in;
Packit 61cb5a
	struct sockaddr_in6 sa_in6;
Packit 61cb5a
Packit 61cb5a
	switch (sa_family) {
Packit 61cb5a
	case PF_INET:
Packit 61cb5a
		memset(&sa_in, 0, sizeof(sa_in));
Packit 61cb5a
		sa_in.sin_family = sa_family;
Packit 61cb5a
		sa_in.sin_port = htons(port);
Packit 61cb5a
		sa_in.sin_addr.s_addr = INADDR_ANY;
Packit 61cb5a
		memcpy(sa, &sa_in, sizeof(sa_in));
Packit 61cb5a
		break;
Packit 61cb5a
	case PF_INET6:
Packit 61cb5a
		memset(&sa_in6, 0, sizeof(sa_in6));
Packit 61cb5a
		sa_in6.sin6_family = sa_family;
Packit 61cb5a
		sa_in6.sin6_port = htons(port);
Packit 61cb5a
		sa_in6.sin6_addr = in6addr_any;
Packit 61cb5a
		memcpy(sa, &sa_in6, sizeof(sa_in6));
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Unknown ai family %d", sa_family);
Packit 61cb5a
		errx(1, "Unknown ai family %d", sa_family);
Packit 61cb5a
	}
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Tries to find local address in ai_list with given ip_ver. if_flags may be set to bit mask with
Packit 61cb5a
 * IFF_MULTICAST and/or IFF_BROADCAST and only network interface with that flags will be accepted.
Packit 61cb5a
 * Returns 0 on success, otherwise -1.
Packit 61cb5a
 * It also changes ifa_list (result of getaddrs), ifa_local (local addr) and ai_item (addrinfo item
Packit 61cb5a
 * which matches ifa_local).
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_find_local_ai(const struct ai_list *ai_list, int *ip_ver, struct ifaddrs **ifa_list,
Packit 61cb5a
    struct ifaddrs **ifa_local, struct ai_item **ai_item, unsigned int if_flags)
Packit 61cb5a
{
Packit 61cb5a
	struct addrinfo *ai_i;
Packit 61cb5a
	struct ai_item *aip;
Packit 61cb5a
	struct ifaddrs *ifa, *ifa_i;
Packit 61cb5a
	char sa_str[LOGGING_SA_TO_STR_LEN];
Packit 61cb5a
	char sa_str2[LOGGING_SA_TO_STR_LEN];
Packit 61cb5a
	int ipv4_fallback;
Packit 61cb5a
	int res;
Packit 61cb5a
Packit 61cb5a
	*ifa_local = NULL;
Packit 61cb5a
	ipv4_fallback = 0;
Packit 61cb5a
Packit 61cb5a
	if (getifaddrs(&ifa) == -1) {
Packit 61cb5a
		err(1, "getifaddrs");
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	TAILQ_FOREACH(aip, ai_list, entries) {
Packit 61cb5a
		for (ai_i = aip->ai; ai_i != NULL; ai_i = ai_i->ai_next) {
Packit 61cb5a
			if (af_ai_is_dup(aip->ai, ai_i)) {
Packit 61cb5a
				logging_sa_to_str(ai_i->ai_addr, sa_str, sizeof(sa_str));
Packit 61cb5a
				DEBUG2_PRINTF("Found duplicate addr %s", sa_str);
Packit 61cb5a
				continue ;
Packit 61cb5a
			}
Packit 61cb5a
Packit 61cb5a
			for (ifa_i = ifa; ifa_i != NULL; ifa_i = ifa_i->ifa_next) {
Packit 61cb5a
				if (ifa_i->ifa_addr == NULL ||
Packit 61cb5a
				    (ifa_i->ifa_addr->sa_family != AF_INET &&
Packit 61cb5a
				    ifa_i->ifa_addr->sa_family != AF_INET6)) {
Packit 61cb5a
					continue ;
Packit 61cb5a
				}
Packit 61cb5a
Packit 61cb5a
				logging_sa_to_str(ifa_i->ifa_addr, sa_str, sizeof(sa_str));
Packit 61cb5a
				logging_sa_to_str(ai_i->ai_addr, sa_str2, sizeof(sa_str2));
Packit 61cb5a
				DEBUG2_PRINTF("Comparing %s(%s) with %s", sa_str, ifa_i->ifa_name,
Packit 61cb5a
				    sa_str2);
Packit 61cb5a
Packit 61cb5a
				if (af_sockaddr_eq(ifa_i->ifa_addr, ai_i->ai_addr)) {
Packit 61cb5a
					res = af_is_supported_local_ifa(ifa_i, *ip_ver, if_flags);
Packit 61cb5a
Packit 61cb5a
					if (res == 1 || res == 2) {
Packit 61cb5a
						if (*ifa_local != NULL && ipv4_fallback == 0)
Packit 61cb5a
							goto multiple_match_error;
Packit 61cb5a
Packit 61cb5a
						*ifa_list = ifa;
Packit 61cb5a
						*ifa_local = ifa_i;
Packit 61cb5a
						*ai_item = aip;
Packit 61cb5a
Packit 61cb5a
						if (*ip_ver == 0) {
Packit 61cb5a
							/*
Packit 61cb5a
							 * Device supports ipv6
Packit 61cb5a
							 */
Packit 61cb5a
							*ip_ver = 6;
Packit 61cb5a
							DEBUG2_PRINTF("Supports ipv6");
Packit 61cb5a
						}
Packit 61cb5a
Packit 61cb5a
						if (res == 2) {
Packit 61cb5a
							/*
Packit 61cb5a
							 * Set this item as ipv4 fallback
Packit 61cb5a
							 */
Packit 61cb5a
							ipv4_fallback++;
Packit 61cb5a
							DEBUG2_PRINTF("Supports ipv4 - fallback");
Packit 61cb5a
						}
Packit 61cb5a
					}
Packit 61cb5a
				}
Packit 61cb5a
			}
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (*ip_ver == 0 && *ifa_local != NULL) {
Packit 61cb5a
		if (ipv4_fallback > 1)
Packit 61cb5a
			goto multiple_match_error;
Packit 61cb5a
Packit 61cb5a
		*ip_ver = 4;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (*ifa_local != NULL) {
Packit 61cb5a
		return (0);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	DEBUG_PRINTF("Can't find local addr");
Packit 61cb5a
	return (-1);
Packit 61cb5a
Packit 61cb5a
multiple_match_error:
Packit 61cb5a
	errx(1, "Multiple local interfaces match parameters.");
Packit 61cb5a
	return (-1);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Convert host_name and port with ip ver (4 or 6) to addrinfo.
Packit 61cb5a
 * Wrapper on getaddrinfo
Packit 61cb5a
 */
Packit 61cb5a
struct addrinfo *
Packit 61cb5a
af_host_to_ai(const char *host_name, const char *port, int ip_ver)
Packit 61cb5a
{
Packit 61cb5a
	struct addrinfo ai_hints, *ai_res0, *ai_i;
Packit 61cb5a
	int error;
Packit 61cb5a
	char ai_s[LOGGING_SA_TO_STR_LEN];
Packit 61cb5a
Packit 61cb5a
	memset(&ai_hints, 0, sizeof(ai_hints));
Packit 61cb5a
	switch (ip_ver) {
Packit 61cb5a
	case 0:
Packit 61cb5a
		ai_hints.ai_family = PF_UNSPEC;
Packit 61cb5a
		break;
Packit 61cb5a
	case 4:
Packit 61cb5a
		ai_hints.ai_family = PF_INET;
Packit 61cb5a
		break;
Packit 61cb5a
	case 6:
Packit 61cb5a
		ai_hints.ai_family = PF_INET6;
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		errx(1, "Unknown PF Family");
Packit 61cb5a
		/* NOTREACHED */
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	ai_hints.ai_socktype = SOCK_DGRAM;
Packit 61cb5a
	ai_hints.ai_protocol = IPPROTO_UDP;
Packit 61cb5a
	ai_hints.ai_flags = AI_PASSIVE;
Packit 61cb5a
Packit 61cb5a
	DEBUG_PRINTF("getaddrinfo for \"%s\" port %s ip_ver %d", host_name,
Packit 61cb5a
	    port, ip_ver);
Packit 61cb5a
	error = getaddrinfo(host_name, port, &ai_hints, &ai_res0);
Packit 61cb5a
	if (error != 0) {
Packit 61cb5a
		errx(1, "Can't get addr info for %s: %s", host_name, gai_strerror(error));
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (logging_get_verbose() >= LOGGING_LEVEL_DEBUG2) {
Packit 61cb5a
		for (ai_i = ai_res0; ai_i != NULL; ai_i = ai_i->ai_next) {
Packit 61cb5a
			logging_ai_to_str(ai_i, ai_s, sizeof(ai_s));
Packit 61cb5a
			DEBUG2_PRINTF("%s", ai_s);
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (ai_res0);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Test if addrinfo a1 is included in ai_list list. Return 1 if a1 is included, otherwise 0.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_is_ai_in_list(const struct addrinfo *a1, const struct ai_list *ai_list)
Packit 61cb5a
{
Packit 61cb5a
	struct ai_item *aip;
Packit 61cb5a
Packit 61cb5a
	TAILQ_FOREACH(aip, ai_list, entries) {
Packit 61cb5a
		if (af_ai_deep_eq(a1, aip->ai))
Packit 61cb5a
			return (1);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (0);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Test if addr is multicast address.
Packit 61cb5a
 * Return 0 if address is not multicast addres, otherwise != 0.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_is_sa_mcast(const struct sockaddr *addr)
Packit 61cb5a
{
Packit 61cb5a
Packit 61cb5a
	switch (addr->sa_family) {
Packit 61cb5a
	case AF_INET:
Packit 61cb5a
		return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr));
Packit 61cb5a
		break;
Packit 61cb5a
	case AF_INET6:
Packit 61cb5a
		return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr);
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Unknown sockaddr family");
Packit 61cb5a
                errx(1, "Unknown sockaddr family");
Packit 61cb5a
		break;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (0);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Test if ifa is supported device.
Packit 61cb5a
 * Such device must:
Packit 61cb5a
 * - not be loopback
Packit 61cb5a
 * - be up
Packit 61cb5a
 * - support for if_flags (multicast/broadcast)
Packit 61cb5a
 * - support given ip_ver
Packit 61cb5a
 * if_flags may be set to bit mask with IFF_MULTICAST and/or IFF_BROADCAST.
Packit 61cb5a
 * Function returns 0, if device doesn't fulfill requirements. 1, if device supports all
Packit 61cb5a
 * requirements and 2, if device support requirements and ip_ver is set to 0 but device supports
Packit 61cb5a
 * ipv4.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_is_supported_local_ifa(const struct ifaddrs *ifa, int ip_ver, unsigned int if_flags)
Packit 61cb5a
{
Packit 61cb5a
	char ai_s[LOGGING_SA_TO_STR_LEN];
Packit 61cb5a
Packit 61cb5a
	logging_sa_to_str(ifa->ifa_addr, ai_s, sizeof(ai_s));
Packit 61cb5a
Packit 61cb5a
	if (ifa->ifa_flags & IFF_LOOPBACK) {
Packit 61cb5a
		DEBUG2_PRINTF("%s with addr %s is loopback", ifa->ifa_name, ai_s);
Packit 61cb5a
Packit 61cb5a
		return (0);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (!(ifa->ifa_flags & IFF_UP)) {
Packit 61cb5a
		DEBUG2_PRINTF("%s with addr %s is not up", ifa->ifa_name, ai_s);
Packit 61cb5a
Packit 61cb5a
		return (0);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (if_flags & IFF_MULTICAST) {
Packit 61cb5a
		if (!(ifa->ifa_flags & IFF_MULTICAST)) {
Packit 61cb5a
			DEBUG2_PRINTF("%s with addr %s doesn't support mcast", ifa->ifa_name, ai_s);
Packit 61cb5a
Packit 61cb5a
			return (0);
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (if_flags & IFF_BROADCAST) {
Packit 61cb5a
		if (!(ifa->ifa_flags & IFF_BROADCAST)) {
Packit 61cb5a
			DEBUG2_PRINTF("%s with addr %s doesn't support broadcast", ifa->ifa_name,
Packit 61cb5a
			    ai_s);
Packit 61cb5a
Packit 61cb5a
			return (0);
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	if (ip_ver != 0 && af_sa_supported_ipv(ifa->ifa_addr) != ip_ver) {
Packit 61cb5a
		DEBUG2_PRINTF("%s doesn't support requested ipv%d", ai_s, ip_ver);
Packit 61cb5a
Packit 61cb5a
		return (0);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
Packit 61cb5a
	if (ip_ver == 0 && af_sa_supported_ipv(ifa->ifa_addr) == 4) {
Packit 61cb5a
		DEBUG2_PRINTF("%s doesn't support ipv6. Saving ipv4 as fallback", ai_s);
Packit 61cb5a
Packit 61cb5a
		return (2);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	DEBUG_PRINTF("Found local addr %s as device %s", ai_s, ifa->ifa_name);
Packit 61cb5a
	return (1);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Return length of sockaddr structure.
Packit 61cb5a
 */
Packit 61cb5a
socklen_t
Packit 61cb5a
af_sa_len(const struct sockaddr *sa)
Packit 61cb5a
{
Packit 61cb5a
	socklen_t res;
Packit 61cb5a
Packit 61cb5a
	switch (sa->sa_family) {
Packit 61cb5a
	case AF_INET:
Packit 61cb5a
		res = sizeof(struct sockaddr_in);
Packit 61cb5a
		break;
Packit 61cb5a
	case AF_INET6:
Packit 61cb5a
		res = sizeof(struct sockaddr_in6);
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Internal program error");
Packit 61cb5a
		errx(1,"Internal program error");
Packit 61cb5a
		break;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (res);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Return port number in network order from addr
Packit 61cb5a
 */
Packit 61cb5a
uint16_t
Packit 61cb5a
af_sa_port(const struct sockaddr *addr)
Packit 61cb5a
{
Packit 61cb5a
	uint16_t port;
Packit 61cb5a
Packit 61cb5a
	switch (addr->sa_family) {
Packit 61cb5a
	case AF_INET:
Packit 61cb5a
		port = (((struct sockaddr_in *)addr)->sin_port);
Packit 61cb5a
		break;
Packit 61cb5a
	case AF_INET6:
Packit 61cb5a
		port = (((struct sockaddr_in6 *)addr)->sin6_port);
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Internal program error");
Packit 61cb5a
		err(1, "Internal program error");
Packit 61cb5a
		break;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (port);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Set port number in network order to addr
Packit 61cb5a
 */
Packit 61cb5a
void
Packit 61cb5a
af_sa_set_port(struct sockaddr *addr, uint16_t port)
Packit 61cb5a
{
Packit 61cb5a
Packit 61cb5a
	switch (addr->sa_family) {
Packit 61cb5a
	case AF_INET:
Packit 61cb5a
		((struct sockaddr_in *)addr)->sin_port = port;
Packit 61cb5a
		break;
Packit 61cb5a
	case AF_INET6:
Packit 61cb5a
		((struct sockaddr_in6 *)addr)->sin6_port = port;
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Internal program error");
Packit 61cb5a
		err(1, "Internal program error");
Packit 61cb5a
		break;
Packit 61cb5a
	}
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Return supported ip version. This function doesn't go deeply to structure. It can return 4 (ipv4
Packit 61cb5a
 * is supported), 6 (ipv6 is supported) or 0 (nether ipv4 or ipv6 are supported).
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_sa_supported_ipv(const struct sockaddr *sa)
Packit 61cb5a
{
Packit 61cb5a
	int ipv;
Packit 61cb5a
Packit 61cb5a
	ipv = 0;
Packit 61cb5a
Packit 61cb5a
	switch (sa->sa_family) {
Packit 61cb5a
	case AF_INET:
Packit 61cb5a
		ipv = 4;
Packit 61cb5a
		break;
Packit 61cb5a
	case AF_INET6:
Packit 61cb5a
		ipv = 6;
Packit 61cb5a
		break;
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (ipv);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Fill in sockaddr dest pointer with in addr any for family from src and port from src.
Packit 61cb5a
 */
Packit 61cb5a
void
Packit 61cb5a
af_sa_to_any_addr(struct sockaddr *dest, const struct sockaddr *src)
Packit 61cb5a
{
Packit 61cb5a
	uint16_t port;
Packit 61cb5a
Packit 61cb5a
	switch (src->sa_family) {
Packit 61cb5a
	case PF_INET:
Packit 61cb5a
		port = ntohs(((struct sockaddr_in *)src)->sin_port);
Packit 61cb5a
		break;
Packit 61cb5a
	case PF_INET6:
Packit 61cb5a
		port = ntohs(((struct sockaddr_in6 *)src)->sin6_port);
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		DEBUG_PRINTF("Unknown ai family %d", src->sa_family);
Packit 61cb5a
		errx(1, "Unknown ai family %d", src->sa_family);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	af_create_any_addr(dest, src->sa_family, port);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Convert sockaddr address to string. Returned value is dst or NULL on fail.
Packit 61cb5a
 */
Packit 61cb5a
char *
Packit 61cb5a
af_sa_to_str(const struct sockaddr *sa, char dst[INET6_ADDRSTRLEN])
Packit 61cb5a
{
Packit 61cb5a
Packit 61cb5a
	dst[0] = 0;
Packit 61cb5a
Packit 61cb5a
	switch (sa->sa_family) {
Packit 61cb5a
	case PF_INET:
Packit 61cb5a
		inet_ntop(sa->sa_family, &((struct sockaddr_in *)(sa))->sin_addr, dst,
Packit 61cb5a
		    INET6_ADDRSTRLEN);
Packit 61cb5a
		break;
Packit 61cb5a
	case PF_INET6:
Packit 61cb5a
		inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)(sa))->sin6_addr, dst,
Packit 61cb5a
		    INET6_ADDRSTRLEN);
Packit 61cb5a
		break;
Packit 61cb5a
	default:
Packit 61cb5a
		return (NULL);
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (dst);
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Return length of sockaddr_storage structure.
Packit 61cb5a
 */
Packit 61cb5a
socklen_t
Packit 61cb5a
af_sas_len(const struct sockaddr_storage *sas)
Packit 61cb5a
{
Packit 61cb5a
	return (af_sa_len((const struct sockaddr *)sas));
Packit 61cb5a
}
Packit 61cb5a
Packit 61cb5a
/*
Packit 61cb5a
 * Compares two sockaddr structures. Only family and addr is compared. If
Packit 61cb5a
 * sockaddr differs 0 is returned, otherwise not 0.
Packit 61cb5a
 */
Packit 61cb5a
int
Packit 61cb5a
af_sockaddr_eq(const struct sockaddr *sa1, const struct sockaddr *sa2)
Packit 61cb5a
{
Packit 61cb5a
	int res;
Packit 61cb5a
Packit 61cb5a
	res = 0;
Packit 61cb5a
Packit 61cb5a
	if (sa1->sa_family == sa2->sa_family) {
Packit 61cb5a
		switch (sa1->sa_family) {
Packit 61cb5a
		case AF_INET:
Packit 61cb5a
			res = (((struct sockaddr_in *)sa1)->sin_addr.s_addr ==
Packit 61cb5a
			    ((struct sockaddr_in *)sa2)->sin_addr.s_addr);
Packit 61cb5a
			break;
Packit 61cb5a
		case AF_INET6:
Packit 61cb5a
			res = IN6_ARE_ADDR_EQUAL(
Packit 61cb5a
			    &((struct sockaddr_in6 *)sa1)->sin6_addr,
Packit 61cb5a
			    &((struct sockaddr_in6 *)sa2)->sin6_addr);
Packit 61cb5a
			break;
Packit 61cb5a
		default:
Packit 61cb5a
			err(1, "Unknown sockaddr family");
Packit 61cb5a
			break;
Packit 61cb5a
		}
Packit 61cb5a
	}
Packit 61cb5a
Packit 61cb5a
	return (res);
Packit 61cb5a
}