Home | History | Annotate | Line # | Download | only in mDNSPosix
mDNSBSD.c revision 1.1.16.1
      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 
     32 ssize_t
     33 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
     34     struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp,
     35     u_char *ttl)
     36 {
     37     struct msghdr msg;
     38     struct iovec iov[1];
     39     ssize_t n;
     40 
     41 #ifdef CMSG_FIRSTHDR
     42     struct cmsghdr  *cmptr;
     43     union {
     44         struct cmsghdr cm;
     45         char control[1024];
     46     } control_un;
     47 
     48     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
     49 
     50     msg.msg_control = control_un.control;
     51     msg.msg_controllen = sizeof(control_un.control);
     52     msg.msg_flags = 0;
     53 #else
     54     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
     55 #endif /* CMSG_FIRSTHDR */
     56 
     57     msg.msg_name = (char *) sa;
     58     msg.msg_namelen = *salenptr;
     59     iov[0].iov_base = (char *)ptr;
     60     iov[0].iov_len = nbytes;
     61     msg.msg_iov = iov;
     62     msg.msg_iovlen = 1;
     63 
     64     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
     65         return(n);
     66 
     67     *salenptr = msg.msg_namelen;    /* pass back results */
     68     if (pktp) {
     69         /* 0.0.0.0, i/f = -1 */
     70         /* We set the interface to -1 so that the caller can
     71            tell whether we returned a meaningful value or
     72            just some default.  Previously this code just
     73            set the value to 0, but I'm concerned that 0
     74            might be a valid interface value.
     75          */
     76         memset(pktp, 0, sizeof(struct my_in_pktinfo));
     77         pktp->ipi_ifindex = -1;
     78     }
     79 /* end recvfrom_flags1 */
     80 
     81 /* include recvfrom_flags2 */
     82 #ifndef CMSG_FIRSTHDR
     83     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
     84     *flagsp = 0;                    /* pass back results */
     85     return(n);
     86 #else
     87 
     88     *flagsp = msg.msg_flags;        /* pass back results */
     89     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
     90         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
     91         return(n);
     92 
     93     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
     94          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
     95 
     96 #ifdef  IP_PKTINFO
     97 #if in_pktinfo_definition_is_missing
     98         struct in_pktinfo
     99         {
    100             int ipi_ifindex;
    101             struct in_addr ipi_spec_dst;
    102             struct in_addr ipi_addr;
    103         };
    104 #endif
    105         if (cmptr->cmsg_level == IPPROTO_IP &&
    106             cmptr->cmsg_type == IP_PKTINFO) {
    107             struct in_pktinfo *tmp;
    108             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    109 
    110             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
    111             sin->sin_family = AF_INET;
    112             sin->sin_addr = tmp->ipi_addr;
    113             sin->sin_port = 0;
    114             pktp->ipi_ifindex = tmp->ipi_ifindex;
    115             continue;
    116         }
    117 #endif
    118 
    119 #ifdef  IP_RECVDSTADDR
    120         if (cmptr->cmsg_level == IPPROTO_IP &&
    121             cmptr->cmsg_type == IP_RECVDSTADDR) {
    122             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    123 
    124             sin->sin_family = AF_INET;
    125             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
    126             sin->sin_port = 0;
    127             continue;
    128         }
    129 #endif
    130 
    131 #ifdef  IP_RECVIF
    132         if (cmptr->cmsg_level == IPPROTO_IP &&
    133             cmptr->cmsg_type == IP_RECVIF) {
    134             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
    135 #ifndef HAVE_BROKEN_RECVIF_NAME
    136             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
    137             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
    138 #endif
    139             pktp->ipi_ifindex = sdl->sdl_index;
    140 #ifdef HAVE_BROKEN_RECVIF_NAME
    141             if (sdl->sdl_index == 0) {
    142                 pktp->ipi_ifindex = *(uint_t*)sdl;
    143             }
    144 #endif
    145             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
    146             // null terminated because of memset above
    147             continue;
    148         }
    149 #endif
    150 
    151 #ifdef  IP_RECVTTL
    152         if (cmptr->cmsg_level == IPPROTO_IP &&
    153             cmptr->cmsg_type == IP_RECVTTL) {
    154             *ttl = *(u_char*)CMSG_DATA(cmptr);
    155             continue;
    156         }
    157         else if (cmptr->cmsg_level == IPPROTO_IP &&
    158                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
    159             *ttl = *(int*)CMSG_DATA(cmptr);
    160             continue;
    161         }
    162 #endif
    163 
    164 #if defined(IPV6_PKTINFO) && HAVE_IPV6
    165         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    166             cmptr->cmsg_type  == IPV6_2292_PKTINFO) {
    167             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
    168             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
    169 
    170             sin6->sin6_family   = AF_INET6;
    171 #ifndef NOT_HAVE_SA_LEN
    172             sin6->sin6_len      = sizeof(*sin6);
    173 #endif
    174             sin6->sin6_addr     = ip6_info->ipi6_addr;
    175             sin6->sin6_flowinfo = 0;
    176             sin6->sin6_scope_id = 0;
    177             sin6->sin6_port     = 0;
    178             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
    179             continue;
    180         }
    181 #endif
    182 
    183 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
    184         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    185             cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
    186             *ttl = *(int*)CMSG_DATA(cmptr);
    187             continue;
    188         }
    189 #endif
    190         assert(0);  // unknown ancillary data
    191     }
    192     return(n);
    193 #endif /* CMSG_FIRSTHDR */
    194 }
    195