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