|
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 |
}
|