Add a simpler version to do interface enumeration that uses getifaddrs(3)
This commit is contained in:
parent
3f33c7bd5f
commit
29fb438a54
314
external/apache2/mDNSResponder/dist/mDNSPosix/mDNSBSD.c
vendored
Normal file
314
external/apache2/mDNSResponder/dist/mDNSPosix/mDNSBSD.c
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
/* -*- Mode: C; tab-width: 4 -*-
|
||||
*
|
||||
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mDNSUNP.h"
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
static int
|
||||
copyaddr(struct sockaddr **dst, const struct sockaddr *src, socklen_t len)
|
||||
{
|
||||
if (src == NULL)
|
||||
return 1;
|
||||
|
||||
*dst = calloc(1, len);
|
||||
if (*dst == NULL)
|
||||
return 0;
|
||||
|
||||
memcpy(*dst, src, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ifi_info *
|
||||
get_ifi_info(int family, int doaliases)
|
||||
{
|
||||
struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
|
||||
struct ifaddrs *ifal, *ifa;
|
||||
|
||||
if (getifaddrs(&ifal) == -1) {
|
||||
warn("getifaddrs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ifihead = NULL;
|
||||
ifipnext = &ifihead;
|
||||
|
||||
for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
|
||||
struct sockaddr *sa = ifa->ifa_addr;
|
||||
int flags = ifa->ifa_flags;
|
||||
int addrflags = ifa->ifa_addrflags;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Include the loopback so that we return at least one
|
||||
* address, so that mdnsd does not exit before we get
|
||||
* a dhcp address
|
||||
*/
|
||||
if (flags & IFF_LOOPBACK)
|
||||
continue; /* ignore loopback interfaces */
|
||||
#endif
|
||||
|
||||
if ((flags & IFF_UP) == 0)
|
||||
continue; /* ignore if interface not up */
|
||||
|
||||
if (sa == NULL || sa->sa_family != family)
|
||||
continue; /* ignore if not the desired family */
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
if (addrflags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
|
||||
continue;
|
||||
|
||||
break;
|
||||
#if defined(AF_INET6) && HAVE_IPV6
|
||||
case AF_INET6:
|
||||
if (addrflags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
|
||||
continue;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
ifi = calloc(1, sizeof(*ifi));
|
||||
if (ifi == NULL)
|
||||
goto gotError;
|
||||
|
||||
ifipold = *ifipnext; /* need this later */
|
||||
ifiptr = ifipnext;
|
||||
*ifipnext = ifi; /* prev points to new one */
|
||||
ifipnext = &ifi->ifi_next; /* pointer to next one */
|
||||
|
||||
ifi->ifi_flags = flags; /* IFF_xxx values */
|
||||
ifi->ifi_myflags = 0; /* IFI_xxx values */
|
||||
ifi->ifi_index = if_nametoindex(ifa->ifa_name);
|
||||
memcpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME);
|
||||
ifi->ifi_name[IFI_NAME-1] = '\0';
|
||||
if (!copyaddr(&ifi->ifi_addr, ifa->ifa_addr, sa->sa_len))
|
||||
goto gotError;
|
||||
if (!copyaddr(&ifi->ifi_netmask, ifa->ifa_netmask, sa->sa_len))
|
||||
goto gotError;
|
||||
|
||||
if ((flags & IFF_BROADCAST) && !copyaddr(&ifi->ifi_brdaddr,
|
||||
ifa->ifa_broadaddr, sa->sa_len))
|
||||
goto gotError;
|
||||
if ((flags & IFF_POINTOPOINT) && !copyaddr(&ifi->ifi_dstaddr,
|
||||
ifa->ifa_dstaddr, sa->sa_len))
|
||||
goto gotError;
|
||||
}
|
||||
|
||||
goto done;
|
||||
|
||||
gotError:
|
||||
warn("can't allocate memory");
|
||||
if (ifihead != NULL) {
|
||||
free_ifi_info(ifihead);
|
||||
ifihead = NULL;
|
||||
}
|
||||
|
||||
freeifaddrs(ifal);
|
||||
done:
|
||||
return ifihead; /* pointer to first structure in linked list */
|
||||
}
|
||||
|
||||
void
|
||||
free_ifi_info(struct ifi_info *ifihead)
|
||||
{
|
||||
struct ifi_info *ifi, *ififree;
|
||||
|
||||
for (ifi = ifihead; (ififree = ifi) != NULL;) {
|
||||
free(ifi->ifi_addr);
|
||||
free(ifi->ifi_netmask);
|
||||
free(ifi->ifi_brdaddr);
|
||||
free(ifi->ifi_dstaddr);
|
||||
ifi = ifi->ifi_next;
|
||||
free(ififree);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
|
||||
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp,
|
||||
u_char *ttl)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
ssize_t n;
|
||||
|
||||
#ifdef CMSG_FIRSTHDR
|
||||
struct cmsghdr *cmptr;
|
||||
union {
|
||||
struct cmsghdr cm;
|
||||
char control[1024];
|
||||
} control_un;
|
||||
|
||||
*ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
|
||||
|
||||
msg.msg_control = control_un.control;
|
||||
msg.msg_controllen = sizeof(control_un.control);
|
||||
msg.msg_flags = 0;
|
||||
#else
|
||||
memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
|
||||
#endif /* CMSG_FIRSTHDR */
|
||||
|
||||
msg.msg_name = (char *) sa;
|
||||
msg.msg_namelen = *salenptr;
|
||||
iov[0].iov_base = (char *)ptr;
|
||||
iov[0].iov_len = nbytes;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
|
||||
return(n);
|
||||
|
||||
*salenptr = msg.msg_namelen; /* pass back results */
|
||||
if (pktp) {
|
||||
/* 0.0.0.0, i/f = -1 */
|
||||
/* We set the interface to -1 so that the caller can
|
||||
tell whether we returned a meaningful value or
|
||||
just some default. Previously this code just
|
||||
set the value to 0, but I'm concerned that 0
|
||||
might be a valid interface value.
|
||||
*/
|
||||
memset(pktp, 0, sizeof(struct my_in_pktinfo));
|
||||
pktp->ipi_ifindex = -1;
|
||||
}
|
||||
/* end recvfrom_flags1 */
|
||||
|
||||
/* include recvfrom_flags2 */
|
||||
#ifndef CMSG_FIRSTHDR
|
||||
#warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
|
||||
*flagsp = 0; /* pass back results */
|
||||
return(n);
|
||||
#else
|
||||
|
||||
*flagsp = msg.msg_flags; /* pass back results */
|
||||
if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
|
||||
(msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
|
||||
return(n);
|
||||
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
|
||||
cmptr = CMSG_NXTHDR(&msg, cmptr)) {
|
||||
|
||||
#ifdef IP_PKTINFO
|
||||
#if in_pktinfo_definition_is_missing
|
||||
struct in_pktinfo
|
||||
{
|
||||
int ipi_ifindex;
|
||||
struct in_addr ipi_spec_dst;
|
||||
struct in_addr ipi_addr;
|
||||
};
|
||||
#endif
|
||||
if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||
cmptr->cmsg_type == IP_PKTINFO) {
|
||||
struct in_pktinfo *tmp;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
|
||||
|
||||
tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr = tmp->ipi_addr;
|
||||
sin->sin_port = 0;
|
||||
pktp->ipi_ifindex = tmp->ipi_ifindex;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IP_RECVDSTADDR
|
||||
if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||
cmptr->cmsg_type == IP_RECVDSTADDR) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
|
||||
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
|
||||
sin->sin_port = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IP_RECVIF
|
||||
if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||
cmptr->cmsg_type == IP_RECVIF) {
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
|
||||
#ifndef HAVE_BROKEN_RECVIF_NAME
|
||||
int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
|
||||
strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
|
||||
#endif
|
||||
pktp->ipi_ifindex = sdl->sdl_index;
|
||||
#ifdef HAVE_BROKEN_RECVIF_NAME
|
||||
if (sdl->sdl_index == 0) {
|
||||
pktp->ipi_ifindex = *(uint_t*)sdl;
|
||||
}
|
||||
#endif
|
||||
assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
|
||||
// null terminated because of memset above
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IP_RECVTTL
|
||||
if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||
cmptr->cmsg_type == IP_RECVTTL) {
|
||||
*ttl = *(u_char*)CMSG_DATA(cmptr);
|
||||
continue;
|
||||
}
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||
cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
|
||||
*ttl = *(int*)CMSG_DATA(cmptr);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_PKTINFO) && HAVE_IPV6
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
|
||||
cmptr->cmsg_type == IPV6_2292_PKTINFO) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
|
||||
struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
|
||||
|
||||
sin6->sin6_family = AF_INET6;
|
||||
#ifndef NOT_HAVE_SA_LEN
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
#endif
|
||||
sin6->sin6_addr = ip6_info->ipi6_addr;
|
||||
sin6->sin6_flowinfo = 0;
|
||||
sin6->sin6_scope_id = 0;
|
||||
sin6->sin6_port = 0;
|
||||
pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
|
||||
cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
|
||||
*ttl = *(int*)CMSG_DATA(cmptr);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
assert(0); // unknown ancillary data
|
||||
}
|
||||
return(n);
|
||||
#endif /* CMSG_FIRSTHDR */
|
||||
}
|
@ -303,8 +303,16 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
|
||||
if ((flags & IFF_UP) == 0)
|
||||
continue; /* ignore if interface not up */
|
||||
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Include the loopback so that we return at least one
|
||||
* address, so that mdnsd does not exit before we get
|
||||
* a dhcp address
|
||||
*/
|
||||
if ((flags & IFF_LOOPBACK))
|
||||
continue; /* ignore loopback interfaces */
|
||||
#endif
|
||||
|
||||
/* Skip addresses we can't use */
|
||||
#ifdef SIOCGIFAFLAG_IN
|
||||
|
Loading…
Reference in New Issue
Block a user