Home | History | Annotate | Line # | Download | only in mDNSPosix
mDNSBSD.c revision 1.1.2.2
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include "mDNSUNP.h"
     19 #include <ifaddrs.h>
     20 
     21 #include <assert.h>
     22 #include <err.h>
     23 #include <errno.h>
     24 #include <string.h>
     25 #include <stdlib.h>
     26 #include <unistd.h>
     27 #include <netinet/in.h>
     28 #include <netinet/in_var.h>
     29 #include <net/if_dl.h>
     30 
     31 static int
     32 copyaddr(struct sockaddr **dst, const struct sockaddr *src, socklen_t len)
     33 {
     34 	if (src == NULL)
     35 		return 1;
     36 
     37 	*dst = calloc(1, len);
     38 	if (*dst == NULL)
     39 		return 0;
     40 
     41 	memcpy(*dst, src, len);
     42 	return 1;
     43 }
     44 
     45 struct ifi_info *
     46 get_ifi_info(int family, int doaliases)
     47 {
     48 	struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
     49 	struct ifaddrs *ifal, *ifa;
     50 
     51 	if (getifaddrs(&ifal) == -1) {
     52 		warn("getifaddrs");
     53 		return NULL;
     54 	}
     55 
     56 	ifihead = NULL;
     57 	ifipnext = &ifihead;
     58 
     59 	for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
     60 		struct sockaddr *sa = ifa->ifa_addr;
     61 		int flags = ifa->ifa_flags;
     62 		int addrflags = ifa->ifa_addrflags;
     63 
     64 #if 0
     65 		/*
     66 		 * Include the loopback so that we return at least one
     67 		 * address, so that mdnsd does not exit before we get
     68 		 * a dhcp address
     69 		 */
     70 		if (flags & IFF_LOOPBACK)
     71 			continue;	/* ignore loopback interfaces */
     72 #endif
     73 
     74 		if ((flags & IFF_UP) == 0)
     75 			continue;	/* ignore if interface not up */
     76 
     77 		if (sa == NULL || sa->sa_family != family)
     78 			continue; 	/* ignore if not the desired family */
     79 
     80 		switch (sa->sa_family) {
     81 		case AF_INET:
     82 			if (addrflags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
     83 				continue;
     84 
     85 			break;
     86 #if defined(AF_INET6) && HAVE_IPV6
     87 		case AF_INET6:
     88 			if (addrflags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
     89 				continue;
     90 #endif
     91 			break;
     92 		default:
     93 			continue;
     94 		}
     95 
     96 		ifi = calloc(1, sizeof(*ifi));
     97 		if (ifi == NULL)
     98 			goto gotError;
     99 
    100 		ifipold   = *ifipnext;		/* need this later */
    101 		ifiptr    = ifipnext;
    102 		*ifipnext = ifi;		/* prev points to new one */
    103 		ifipnext  = &ifi->ifi_next;	/* pointer to next one */
    104 
    105 		ifi->ifi_flags = flags;		/* IFF_xxx values */
    106 		ifi->ifi_myflags = 0;		/* IFI_xxx values */
    107 		ifi->ifi_index = if_nametoindex(ifa->ifa_name);
    108 		memcpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME);
    109 		ifi->ifi_name[IFI_NAME-1] = '\0';
    110 		if (!copyaddr(&ifi->ifi_addr, ifa->ifa_addr, sa->sa_len))
    111 			goto gotError;
    112 		if (!copyaddr(&ifi->ifi_netmask, ifa->ifa_netmask, sa->sa_len))
    113 			goto gotError;
    114 
    115 		if ((flags & IFF_BROADCAST) && !copyaddr(&ifi->ifi_brdaddr,
    116 		    ifa->ifa_broadaddr, sa->sa_len))
    117 			goto gotError;
    118 		if ((flags & IFF_POINTOPOINT) && !copyaddr(&ifi->ifi_dstaddr,
    119 		    ifa->ifa_dstaddr, sa->sa_len))
    120 			goto gotError;
    121 	}
    122 
    123 	goto done;
    124 
    125 gotError:
    126 	warn("can't allocate memory");
    127 	if (ifihead != NULL) {
    128 		free_ifi_info(ifihead);
    129 		ifihead = NULL;
    130 	}
    131 
    132 	freeifaddrs(ifal);
    133 done:
    134 	return ifihead;    /* pointer to first structure in linked list */
    135 }
    136 
    137 void
    138 free_ifi_info(struct ifi_info *ifihead)
    139 {
    140 	struct ifi_info *ifi, *ififree;
    141 
    142 	for (ifi = ifihead; (ififree = ifi) != NULL;) {
    143 		free(ifi->ifi_addr);
    144 		free(ifi->ifi_netmask);
    145 		free(ifi->ifi_brdaddr);
    146 		free(ifi->ifi_dstaddr);
    147 		ifi = ifi->ifi_next;
    148 		free(ififree);
    149 	}
    150 }
    151 
    152 ssize_t
    153 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
    154     struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp,
    155     u_char *ttl)
    156 {
    157     struct msghdr msg;
    158     struct iovec iov[1];
    159     ssize_t n;
    160 
    161 #ifdef CMSG_FIRSTHDR
    162     struct cmsghdr  *cmptr;
    163     union {
    164         struct cmsghdr cm;
    165         char control[1024];
    166     } control_un;
    167 
    168     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
    169 
    170     msg.msg_control = control_un.control;
    171     msg.msg_controllen = sizeof(control_un.control);
    172     msg.msg_flags = 0;
    173 #else
    174     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
    175 #endif /* CMSG_FIRSTHDR */
    176 
    177     msg.msg_name = (char *) sa;
    178     msg.msg_namelen = *salenptr;
    179     iov[0].iov_base = (char *)ptr;
    180     iov[0].iov_len = nbytes;
    181     msg.msg_iov = iov;
    182     msg.msg_iovlen = 1;
    183 
    184     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
    185         return(n);
    186 
    187     *salenptr = msg.msg_namelen;    /* pass back results */
    188     if (pktp) {
    189         /* 0.0.0.0, i/f = -1 */
    190         /* We set the interface to -1 so that the caller can
    191            tell whether we returned a meaningful value or
    192            just some default.  Previously this code just
    193            set the value to 0, but I'm concerned that 0
    194            might be a valid interface value.
    195          */
    196         memset(pktp, 0, sizeof(struct my_in_pktinfo));
    197         pktp->ipi_ifindex = -1;
    198     }
    199 /* end recvfrom_flags1 */
    200 
    201 /* include recvfrom_flags2 */
    202 #ifndef CMSG_FIRSTHDR
    203     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
    204     *flagsp = 0;                    /* pass back results */
    205     return(n);
    206 #else
    207 
    208     *flagsp = msg.msg_flags;        /* pass back results */
    209     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
    210         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
    211         return(n);
    212 
    213     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
    214          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
    215 
    216 #ifdef  IP_PKTINFO
    217 #if in_pktinfo_definition_is_missing
    218         struct in_pktinfo
    219         {
    220             int ipi_ifindex;
    221             struct in_addr ipi_spec_dst;
    222             struct in_addr ipi_addr;
    223         };
    224 #endif
    225         if (cmptr->cmsg_level == IPPROTO_IP &&
    226             cmptr->cmsg_type == IP_PKTINFO) {
    227             struct in_pktinfo *tmp;
    228             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    229 
    230             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
    231             sin->sin_family = AF_INET;
    232             sin->sin_addr = tmp->ipi_addr;
    233             sin->sin_port = 0;
    234             pktp->ipi_ifindex = tmp->ipi_ifindex;
    235             continue;
    236         }
    237 #endif
    238 
    239 #ifdef  IP_RECVDSTADDR
    240         if (cmptr->cmsg_level == IPPROTO_IP &&
    241             cmptr->cmsg_type == IP_RECVDSTADDR) {
    242             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    243 
    244             sin->sin_family = AF_INET;
    245             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
    246             sin->sin_port = 0;
    247             continue;
    248         }
    249 #endif
    250 
    251 #ifdef  IP_RECVIF
    252         if (cmptr->cmsg_level == IPPROTO_IP &&
    253             cmptr->cmsg_type == IP_RECVIF) {
    254             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
    255 #ifndef HAVE_BROKEN_RECVIF_NAME
    256             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
    257             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
    258 #endif
    259             pktp->ipi_ifindex = sdl->sdl_index;
    260 #ifdef HAVE_BROKEN_RECVIF_NAME
    261             if (sdl->sdl_index == 0) {
    262                 pktp->ipi_ifindex = *(uint_t*)sdl;
    263             }
    264 #endif
    265             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
    266             // null terminated because of memset above
    267             continue;
    268         }
    269 #endif
    270 
    271 #ifdef  IP_RECVTTL
    272         if (cmptr->cmsg_level == IPPROTO_IP &&
    273             cmptr->cmsg_type == IP_RECVTTL) {
    274             *ttl = *(u_char*)CMSG_DATA(cmptr);
    275             continue;
    276         }
    277         else if (cmptr->cmsg_level == IPPROTO_IP &&
    278                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
    279             *ttl = *(int*)CMSG_DATA(cmptr);
    280             continue;
    281         }
    282 #endif
    283 
    284 #if defined(IPV6_PKTINFO) && HAVE_IPV6
    285         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    286             cmptr->cmsg_type  == IPV6_2292_PKTINFO) {
    287             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
    288             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
    289 
    290             sin6->sin6_family   = AF_INET6;
    291 #ifndef NOT_HAVE_SA_LEN
    292             sin6->sin6_len      = sizeof(*sin6);
    293 #endif
    294             sin6->sin6_addr     = ip6_info->ipi6_addr;
    295             sin6->sin6_flowinfo = 0;
    296             sin6->sin6_scope_id = 0;
    297             sin6->sin6_port     = 0;
    298             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
    299             continue;
    300         }
    301 #endif
    302 
    303 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
    304         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    305             cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
    306             *ttl = *(int*)CMSG_DATA(cmptr);
    307             continue;
    308         }
    309 #endif
    310         assert(0);  // unknown ancillary data
    311     }
    312     return(n);
    313 #endif /* CMSG_FIRSTHDR */
    314 }
    315