mDNSUNP.c revision 4b22b9337f359bfd063322244f5336cc7c6ffcfa
/* -*- 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
*
*
* 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.
Change History (most recent first):
$Log: mDNSUNP.c,v $
Revision 1.34 2006/08/14 23:24:47 cheshire
Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
Revision 1.33 2006/03/13 23:14:21 cheshire
<rdar://problem/4427969> Compile problems on FreeBSD
Revision 1.32 2005/12/21 02:56:43 cheshire
<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
Revision 1.31 2005/12/21 02:46:05 cheshire
Revision 1.30 2005/11/29 20:03:02 mkrochma
Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
Revision 1.29 2005/11/12 02:23:10 cheshire
<rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
Revision 1.28 2005/10/31 22:09:45 cheshire
Buffer "char addr6[33]" was seven bytes too small
Revision 1.27 2005/06/29 15:54:21 cheshire
<rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
Revision 1.26 2005/04/08 21:43:59 ksekar
<rdar://problem/4083426> mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
Submitted by Andrew de Quincey
Revision 1.25 2005/04/08 21:37:57 ksekar
<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
Revision 1.24 2005/04/08 21:30:16 ksekar
Patch submitted by Bernd Kuhls
Revision 1.23 2004/12/01 04:25:05 cheshire
<rdar://problem/3872803> Darwin patches for Solaris and Suse
Provide daemon() for platforms that don't have it
Revision 1.22 2004/11/30 22:37:01 cheshire
Update copyright dates and add "Mode: C; tab-width: 4" headers
Revision 1.21 2004/11/08 22:13:59 rpantos
Create sockf6 lazily when v6 interface found.
Revision 1.20 2004/10/16 00:17:01 cheshire
<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
Revision 1.19 2004/07/20 01:47:36 rpantos
NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
Revision 1.18 2004/07/08 21:30:21 rpantos
Revision 1.17 2004/06/25 00:26:27 rpantos
Changes to fix the Posix build on Solaris.
Revision 1.16 2004/03/20 05:37:09 cheshire
Fix contributed by Terry Lambert & Alfred Perlstein:
Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
Revision 1.15 2004/02/14 01:09:45 rpantos
Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
Revision 1.14 2003/12/11 18:53:40 cheshire
Fix compiler warning reported by Paul Guyot
Revision 1.13 2003/12/08 20:47:02 rpantos
Add support for mDNSResponder on Linux.
Revision 1.12 2003/09/02 20:47:13 cheshire
Revision 1.11 2003/08/12 19:56:26 cheshire
Update to APSL 2.0
Revision 1.10 2003/08/06 18:20:51 cheshire
Makefile cleanup
Revision 1.9 2003/07/14 18:11:54 cheshire
Fix stricter compiler warnings
Revision 1.8 2003/07/02 21:19:59 cheshire
<rdar://problem/3313413> Update copyright notices, etc., in source code comments
Revision 1.7 2003/03/20 21:10:31 cheshire
Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
Revision 1.6 2003/03/13 03:46:21 cheshire
Fixes to make the code build on Linux
Revision 1.5 2003/02/07 03:02:02 cheshire
Submitted by: Mitsutaka Watanabe
The code saying "index += 1;" was effectively making up random interface index values.
The right way to find the correct interface index is if_nametoindex();
Revision 1.4 2002/12/23 22:13:31 jgraessl
Reviewed by: Stuart Cheshire
Initial IPv6 support for mDNSResponder.
Revision 1.3 2002/09/21 20:44:53 zarzycki
Added APSL info
Revision 1.2 2002/09/19 04:20:44 cheshire
Remove high-ascii characters that confuse some systems
Revision 1.1 2002/09/17 06:24:34 cheshire
First checkin
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "mDNSUNP.h"
#include "mDNSDebug.h"
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
/* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
should be set to the name of the header to include to get the ALIGN(P) macro.
*/
#ifdef NEED_ALIGN_MACRO
#include NEED_ALIGN_MACRO
#endif
other platforms don't even have that include file. So,
if we haven't yet got a definition, let's try to find
*/
#ifndef SIOCGIFCONF
#endif
/* sockaddr_dl is only referenced if we're using IP_RECVIF,
so only include the header in that case.
*/
#ifdef IP_RECVIF
#endif
#if !HAVE_SOLARIS
#else
#include <alloca.h>
#ifdef HAVE_SOLARIS_ZONES
#include <zone.h>
#endif /* HAVE_SOLARIS_ZONES */
#endif /* !HAVE_SOLARIS */
#endif
#if HAVE_LINUX
#include <netdb.h>
/* Converts a prefix length to IPv6 network mask */
int i;
for(i=0;i<=colons;i++) {
else ones_in_block=plen;
plen -= ones_in_block;
}
}
/* Gets IPv6 interface information from the /proc filesystem in linux*/
{
struct sockaddr_in6 *sin6;
int err;
lastname[0] = 0;
"%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
myflags = 0;
if (doaliases == 0)
continue; /* already processed this interface */
}
goto gotError;
}
/* Add address of the interface */
if (err) {
goto gotError;
}
goto gotError;
}
/* Add netmask of the interface */
char ipv6addr[INET6_ADDRSTRLEN];
goto gotError;
}
/* Add interface name */
/* Add interface index */
/* If interface is in /proc then it is up*/
}
}
goto done;
}
}
done:
return(ifihead); /* pointer to first structure in linked list */
}
#endif /* LINUX */
#endif /* defined(AF_INET6) && HAVE_IPV6 */
#if HAVE_SOLARIS
/*
* Converts prefix length to network mask. Assumes
* addr points to a zeroed out buffer and prefix <= sizeof(addr)
* Unlike plen_to_mask returns netmask in binary form and not
* in text form.
*/
*addr++ = 0xff;
}
/*
* This function goes through all the IP interfaces associated with a
* physical interface and finds the best matched one for use by mDNS.
* Returns NULL when none of the IP interfaces associated with a physical
* interface are usable. Otherwise returns the best matched interface
* information and a pointer to the best matched lifreq.
*/
struct ifi_info *
{
char *chptr;
int i;
/*
* Check all logical interfaces associated with the physical
* interface and figure out which one works best for us.
*/
continue; /* skip interface */
/* Strip logical interface number before checking ifname */
*chptr = '\0';
/*
* Check ifname to see if the logical interface is associated
* with the physical interface we are interested in.
*/
continue;
#ifdef HAVE_SOLARIS_ZONES
/* Check the zone associated with the address */
/* interface removed */
continue;
return(NULL);
}
continue;
#endif
/* interface removed */
continue;
return(NULL);
}
/* ignore address if not up */
continue;
/*
* Avoid address if any of the following flags are set:
* IFF_NOFAILOVER: IPMP test address for use only by in.mpathd
* IFF_NOXMIT: no packets transmitted over interface
* IFF_NOLOCAL: no address
* IFF_PRIVATE: is not advertised
*/
| IFF_NOLOCAL | IFF_PRIVATE))
continue;
/*
* Check if we found a better interface by checking
* the flags. If flags are identical we prefer
* the new found interface.
*/
/* If interface has a different set of flags */
if (diff_flags != 0) {
/* Check flags in increasing order of ones we prefer */
/* Address temporary? */
if ((diff_flags & IFF_TEMPORARY) &&
(ifflags & IFF_TEMPORARY))
continue;
/* Deprecated address? */
if ((diff_flags & IFF_DEPRECATED) &&
(ifflags & IFF_DEPRECATED))
continue;
/* Last best-matched interface address has preferred? */
if ((diff_flags & IFF_PREFERRED) &&
((ifflags & IFF_PREFERRED) == 0))
continue;
}
}
/* Set best match interface & flags */
}
return(NULL);
/* Found a match: return the interface information */
return(NULL);
if (strlcpy(ifi->ifi_name, (*best_lifr)->lifr_name, sizeof(ifi->ifi_name)) >= sizeof(ifi->ifi_name)) {
return(NULL);
}
return(ifi);
}
/*
* Returns a list of IP interface information on Solaris. The function
* returns all IP interfaces on the system with IPv4 address assigned
* when passed AF_INET and returns IP interfaces with IPv6 address assigned
* when AF_INET6 is passed.
*/
{
int sockfd;
int len;
char *buf;
char *cptr;
struct sockaddr_in *sinptr;
struct sockaddr_in6 *sinptr6;
#endif
if (sockfd < 0)
goto gotError;
lifn.lifn_flags = 0;
goto gotError;
/*
* Pad interface count to detect & retrieve any
* additional interfaces between IFNUM & IFCONF calls.
*/
lifc.lifc_flags = 0;
goto gotError;
goto again;
continue;
/*
* See if we have already processed the interface
* by checking the interface names.
*/
goto gotError;
*cptr = '\0';
/*
* If any of the interfaces found so far share the physical
* interface name then we have already processed the interface.
*/
/* Retrieve physical interface name */
/* Strip logical interface number before checking ifname */
*cptr = '\0';
break;
}
continue; /* already processed */
/*
* New interface, find the one with the preferred source
* address for our use in Multicast DNS.
*/
continue;
case AF_INET6:
goto gotError;
goto gotError;
break;
#endif
case AF_INET:
goto gotError;
/* interface removed */
continue;
}
goto gotError;
}
goto gotError;
break;
default:
/* never reached */
break;
}
}
return(ifihead); /* pointer to first structure in linked list */
if (sockfd != -1)
return(NULL);
}
#endif /* HAVE_SOLARIS */
{
int junk;
#ifdef NOT_HAVE_IF_NAMETOINDEX
int index = 200;
#endif
struct sockaddr_in *sinptr;
struct sockaddr_in6 *sinptr6;
#endif
return get_ifi_info_solaris(family);
#endif
sockfd = -1;
sockf6 = -1;
if (sockfd < 0) {
goto gotError;
}
lastlen = 0;
for ( ; ; ) {
goto gotError;
}
goto gotError;
}
} else {
break; /* success, len has not changed */
}
}
lastname[0] = 0;
/* end get_ifi_info1 */
/* include get_ifi_info2 */
/* Advance to next one in buffer */
else
// fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
continue; /* ignore if not desired address family */
myflags = 0;
*cptr = 0; /* replace colon will null */
if (doaliases == 0)
continue; /* already processed this interface */
}
goto gotError;
}
continue; /* ignore if interface not up */
goto gotError;
}
#ifndef NOT_HAVE_IF_NAMETOINDEX
#else
#ifdef SIOCGIFINDEX
else
#endif
#endif
/* end get_ifi_info2 */
/* include get_ifi_info3 */
case AF_INET:
goto gotError;
}
#ifdef SIOCGIFNETMASK
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
#ifndef NOT_HAVE_SA_LEN
#endif
#endif
#ifdef SIOCGIFBRDADDR
if (flags & IFF_BROADCAST) {
goto gotError;
}
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
#ifndef NOT_HAVE_SA_LEN
#endif
goto gotError;
}
}
#endif
#ifdef SIOCGIFDSTADDR
if (flags & IFF_POINTOPOINT) {
goto gotError;
}
/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
#ifndef NOT_HAVE_SA_LEN
#endif
goto gotError;
}
}
#endif
}
break;
case AF_INET6:
goto gotError;
}
/* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
/* We need to strip that out */
#ifdef SIOCGIFNETMASK_IN6
{
if (sockf6 == -1)
}
#endif
}
break;
#endif
default:
break;
}
}
goto done;
}
done:
}
if (sockfd != -1) {
}
if (sockf6 != -1) {
}
return(ifihead); /* pointer to first structure in linked list */
}
/* end get_ifi_info3 */
/* include free_ifi_info */
void
{
}
}
/* end free_ifi_info */
{
ssize_t n;
#ifdef CMSG_FIRSTHDR
union {
char control[1024];
} control_un;
#else
#endif /* CMSG_FIRSTHDR */
return(n);
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.
*/
}
/* 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
return(n);
#ifdef IP_PKTINFO
struct in_pktinfo
{
int ipi_ifindex;
struct in_addr ipi_spec_dst;
};
#endif
struct in_pktinfo *tmp;
continue;
}
#endif
#ifdef IP_RECVDSTADDR
continue;
}
#endif
#ifdef IP_RECVIF
#ifndef HAVE_BROKEN_RECVIF_NAME
#endif
// null terminated because of memset above
continue;
}
#endif
#ifdef IP_RECVTTL
continue;
}
continue;
}
#endif
#if defined(IPV6_PKTINFO) && HAVE_IPV6
#ifndef NOT_HAVE_SA_LEN
#endif
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
continue;
}
#endif
#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
continue;
}
#endif
assert(0); // unknown ancillary data
}
return(n);
#endif /* CMSG_FIRSTHDR */
}
// **********************************************************************************************
// daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
// Returns 0 on success, -1 on failure.
#ifdef NOT_HAVE_DAEMON
#include <fcntl.h>
#include <signal.h>
{
switch (fork())
{
case -1: return (-1); // Fork failed
case 0: break; // Child -- continue
default: _exit(0); // Parent -- exit
}
switch (fork()) // Fork again, primarily for reasons of Unix trivia
{
case -1: return (-1); // Fork failed
case 0: break; // Child -- continue
default: _exit(0); // Parent -- exit
}
umask(0);
if (!noclose)
{
if (fd != -1)
{
// Avoid unnecessarily duplicating a file descriptor to itself
}
}
return (0);
}
#endif /* NOT_HAVE_DAEMON */