Home | History | Annotate | Line # | Download | only in mDNSPosix
mDNSUNP.c revision 1.13
      1   1.1    tsarna /* -*- Mode: C; tab-width: 4 -*-
      2   1.1    tsarna  *
      3  1.13  christos  * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
      4   1.1    tsarna  *
      5   1.1    tsarna  * Licensed under the Apache License, Version 2.0 (the "License");
      6   1.1    tsarna  * you may not use this file except in compliance with the License.
      7   1.1    tsarna  * You may obtain a copy of the License at
      8   1.8  christos  *
      9   1.1    tsarna  *     http://www.apache.org/licenses/LICENSE-2.0
     10   1.8  christos  *
     11   1.1    tsarna  * Unless required by applicable law or agreed to in writing, software
     12   1.1    tsarna  * distributed under the License is distributed on an "AS IS" BASIS,
     13   1.1    tsarna  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14   1.1    tsarna  * See the License for the specific language governing permissions and
     15   1.1    tsarna  * limitations under the License.
     16   1.4    pettai  */
     17   1.1    tsarna 
     18   1.1    tsarna #include "mDNSUNP.h"
     19   1.1    tsarna 
     20   1.1    tsarna #include <errno.h>
     21   1.1    tsarna #include <assert.h>
     22   1.1    tsarna #include <string.h>
     23   1.1    tsarna #include <stdlib.h>
     24   1.1    tsarna #include <sys/uio.h>
     25   1.1    tsarna #include <sys/ioctl.h>
     26   1.1    tsarna #include <signal.h>
     27   1.1    tsarna #include <unistd.h>
     28   1.1    tsarna #include <stdio.h>
     29   1.1    tsarna 
     30   1.1    tsarna /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
     31   1.1    tsarna    macro, usually defined in <sys/param.h> or someplace like that, to make sure the
     32   1.1    tsarna    CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
     33   1.1    tsarna    should be set to the name of the header to include to get the ALIGN(P) macro.
     34   1.8  christos  */
     35   1.1    tsarna #ifdef NEED_ALIGN_MACRO
     36   1.1    tsarna #include NEED_ALIGN_MACRO
     37   1.1    tsarna #endif
     38   1.1    tsarna 
     39   1.8  christos /* sockaddr_dl is only referenced if we're using IP_RECVIF,
     40   1.1    tsarna    so only include the header in that case.
     41   1.8  christos  */
     42   1.1    tsarna 
     43   1.1    tsarna #ifdef  IP_RECVIF
     44   1.1    tsarna     #include <net/if_dl.h>
     45   1.1    tsarna #endif
     46   1.1    tsarna 
     47   1.8  christos ssize_t
     48   1.1    tsarna recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
     49   1.1    tsarna                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
     50   1.1    tsarna {
     51   1.8  christos     struct msghdr msg;
     52   1.8  christos     struct iovec iov[1];
     53   1.8  christos     ssize_t n;
     54   1.1    tsarna 
     55   1.1    tsarna #ifdef CMSG_FIRSTHDR
     56   1.1    tsarna     struct cmsghdr  *cmptr;
     57   1.1    tsarna     union {
     58   1.8  christos         struct cmsghdr cm;
     59   1.8  christos         char control[1024];
     60   1.1    tsarna     } control_un;
     61   1.1    tsarna 
     62   1.8  christos     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
     63   1.1    tsarna 
     64   1.1    tsarna     msg.msg_control = control_un.control;
     65   1.1    tsarna     msg.msg_controllen = sizeof(control_un.control);
     66   1.1    tsarna     msg.msg_flags = 0;
     67   1.1    tsarna #else
     68   1.1    tsarna     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
     69   1.1    tsarna #endif /* CMSG_FIRSTHDR */
     70   1.1    tsarna 
     71   1.1    tsarna     msg.msg_name = (char *) sa;
     72   1.1    tsarna     msg.msg_namelen = *salenptr;
     73   1.1    tsarna     iov[0].iov_base = (char *)ptr;
     74   1.1    tsarna     iov[0].iov_len = nbytes;
     75   1.1    tsarna     msg.msg_iov = iov;
     76   1.1    tsarna     msg.msg_iovlen = 1;
     77   1.1    tsarna 
     78   1.1    tsarna     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
     79   1.1    tsarna         return(n);
     80   1.1    tsarna 
     81   1.1    tsarna     *salenptr = msg.msg_namelen;    /* pass back results */
     82   1.1    tsarna     if (pktp) {
     83   1.1    tsarna         /* 0.0.0.0, i/f = -1 */
     84   1.8  christos         /* We set the interface to -1 so that the caller can
     85   1.8  christos            tell whether we returned a meaningful value or
     86   1.8  christos            just some default.  Previously this code just
     87   1.8  christos            set the value to 0, but I'm concerned that 0
     88   1.1    tsarna            might be a valid interface value.
     89   1.8  christos          */
     90   1.1    tsarna         memset(pktp, 0, sizeof(struct my_in_pktinfo));
     91   1.1    tsarna         pktp->ipi_ifindex = -1;
     92   1.1    tsarna     }
     93   1.1    tsarna /* end recvfrom_flags1 */
     94   1.1    tsarna 
     95   1.1    tsarna /* include recvfrom_flags2 */
     96   1.1    tsarna #ifndef CMSG_FIRSTHDR
     97   1.8  christos     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
     98   1.1    tsarna     *flagsp = 0;                    /* pass back results */
     99   1.1    tsarna     return(n);
    100   1.1    tsarna #else
    101   1.1    tsarna 
    102   1.1    tsarna     *flagsp = msg.msg_flags;        /* pass back results */
    103   1.1    tsarna     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
    104   1.1    tsarna         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
    105   1.1    tsarna         return(n);
    106   1.1    tsarna 
    107   1.1    tsarna     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
    108   1.1    tsarna          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
    109   1.1    tsarna 
    110   1.1    tsarna #ifdef  IP_PKTINFO
    111   1.1    tsarna #if in_pktinfo_definition_is_missing
    112   1.8  christos         struct in_pktinfo
    113   1.8  christos         {
    114   1.8  christos             int ipi_ifindex;
    115   1.8  christos             struct in_addr ipi_spec_dst;
    116   1.8  christos             struct in_addr ipi_addr;
    117   1.8  christos         };
    118   1.1    tsarna #endif
    119   1.8  christos         if (cmptr->cmsg_level == IPPROTO_IP &&
    120   1.1    tsarna             cmptr->cmsg_type == IP_PKTINFO) {
    121   1.1    tsarna             struct in_pktinfo *tmp;
    122   1.1    tsarna             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    123   1.8  christos 
    124   1.1    tsarna             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
    125   1.1    tsarna             sin->sin_family = AF_INET;
    126   1.1    tsarna             sin->sin_addr = tmp->ipi_addr;
    127   1.1    tsarna             sin->sin_port = 0;
    128   1.1    tsarna             pktp->ipi_ifindex = tmp->ipi_ifindex;
    129   1.1    tsarna             continue;
    130   1.1    tsarna         }
    131   1.1    tsarna #endif
    132   1.1    tsarna 
    133   1.1    tsarna #ifdef  IP_RECVDSTADDR
    134   1.1    tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    135   1.1    tsarna             cmptr->cmsg_type == IP_RECVDSTADDR) {
    136   1.1    tsarna             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
    137   1.8  christos 
    138   1.1    tsarna             sin->sin_family = AF_INET;
    139   1.1    tsarna             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
    140   1.1    tsarna             sin->sin_port = 0;
    141   1.1    tsarna             continue;
    142   1.1    tsarna         }
    143   1.1    tsarna #endif
    144   1.1    tsarna 
    145   1.1    tsarna #ifdef  IP_RECVIF
    146   1.1    tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    147   1.1    tsarna             cmptr->cmsg_type == IP_RECVIF) {
    148   1.1    tsarna             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
    149   1.1    tsarna #ifndef HAVE_BROKEN_RECVIF_NAME
    150   1.1    tsarna             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
    151   1.1    tsarna             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
    152   1.1    tsarna #endif
    153   1.1    tsarna             pktp->ipi_ifindex = sdl->sdl_index;
    154   1.1    tsarna #ifdef HAVE_BROKEN_RECVIF_NAME
    155   1.8  christos             if (sdl->sdl_index == 0) {
    156   1.8  christos                 pktp->ipi_ifindex = *(uint_t*)sdl;
    157   1.8  christos             }
    158   1.8  christos #endif
    159   1.1    tsarna             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
    160   1.1    tsarna             // null terminated because of memset above
    161   1.1    tsarna             continue;
    162   1.1    tsarna         }
    163   1.1    tsarna #endif
    164   1.1    tsarna 
    165   1.1    tsarna #ifdef  IP_RECVTTL
    166   1.1    tsarna         if (cmptr->cmsg_level == IPPROTO_IP &&
    167   1.1    tsarna             cmptr->cmsg_type == IP_RECVTTL) {
    168   1.8  christos             *ttl = *(u_char*)CMSG_DATA(cmptr);
    169   1.1    tsarna             continue;
    170   1.1    tsarna         }
    171   1.1    tsarna         else if (cmptr->cmsg_level == IPPROTO_IP &&
    172   1.8  christos                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
    173   1.8  christos             *ttl = *(int*)CMSG_DATA(cmptr);
    174   1.1    tsarna             continue;
    175   1.1    tsarna         }
    176   1.1    tsarna #endif
    177   1.1    tsarna 
    178   1.1    tsarna #if defined(IPV6_PKTINFO) && HAVE_IPV6
    179   1.8  christos         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    180   1.8  christos             cmptr->cmsg_type  == IPV6_2292_PKTINFO) {
    181   1.1    tsarna             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
    182   1.8  christos             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
    183   1.8  christos 
    184   1.1    tsarna             sin6->sin6_family   = AF_INET6;
    185   1.1    tsarna #ifndef NOT_HAVE_SA_LEN
    186   1.1    tsarna             sin6->sin6_len      = sizeof(*sin6);
    187   1.1    tsarna #endif
    188   1.1    tsarna             sin6->sin6_addr     = ip6_info->ipi6_addr;
    189   1.1    tsarna             sin6->sin6_flowinfo = 0;
    190   1.1    tsarna             sin6->sin6_scope_id = 0;
    191   1.1    tsarna             sin6->sin6_port     = 0;
    192   1.8  christos             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
    193   1.1    tsarna             continue;
    194   1.1    tsarna         }
    195   1.1    tsarna #endif
    196   1.1    tsarna 
    197   1.1    tsarna #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
    198   1.8  christos         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
    199   1.8  christos             cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
    200   1.8  christos             *ttl = *(int*)CMSG_DATA(cmptr);
    201   1.1    tsarna             continue;
    202   1.1    tsarna         }
    203   1.1    tsarna #endif
    204   1.1    tsarna         assert(0);  // unknown ancillary data
    205   1.1    tsarna     }
    206   1.1    tsarna     return(n);
    207   1.1    tsarna #endif /* CMSG_FIRSTHDR */
    208   1.1    tsarna }
    209   1.1    tsarna 
    210   1.1    tsarna // **********************************************************************************************
    211   1.1    tsarna 
    212   1.1    tsarna // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
    213   1.1    tsarna // Returns 0 on success, -1 on failure.
    214   1.1    tsarna 
    215   1.1    tsarna #ifdef NOT_HAVE_DAEMON
    216   1.1    tsarna #include <fcntl.h>
    217   1.1    tsarna #include <sys/stat.h>
    218   1.1    tsarna #include <sys/signal.h>
    219   1.1    tsarna 
    220   1.1    tsarna int daemon(int nochdir, int noclose)
    221   1.8  christos {
    222   1.8  christos     switch (fork())
    223   1.1    tsarna     {
    224   1.8  christos     case -1: return (-1);       // Fork failed
    225   1.8  christos     case 0:  break;             // Child -- continue
    226   1.8  christos     default: _exit(0);          // Parent -- exit
    227   1.1    tsarna     }
    228   1.8  christos 
    229   1.8  christos     if (setsid() == -1) return(-1);
    230   1.8  christos 
    231   1.8  christos     signal(SIGHUP, SIG_IGN);
    232   1.8  christos 
    233   1.8  christos     switch (fork())             // Fork again, primarily for reasons of Unix trivia
    234   1.8  christos     {
    235   1.8  christos     case -1: return (-1);       // Fork failed
    236   1.8  christos     case 0:  break;             // Child -- continue
    237   1.8  christos     default: _exit(0);          // Parent -- exit
    238   1.8  christos     }
    239   1.8  christos 
    240   1.8  christos     if (!nochdir) (void)chdir("/");
    241   1.8  christos     umask(0);
    242   1.8  christos 
    243   1.8  christos     if (!noclose)
    244   1.8  christos     {
    245   1.8  christos         int fd = open("/dev/null", O_RDWR, 0);
    246   1.8  christos         if (fd != -1)
    247   1.8  christos         {
    248   1.8  christos             // Avoid unnecessarily duplicating a file descriptor to itself
    249   1.8  christos             if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
    250   1.8  christos             if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
    251   1.8  christos             if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
    252   1.8  christos             if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
    253   1.8  christos                 (void)close (fd);
    254   1.8  christos         }
    255   1.8  christos     }
    256   1.8  christos     return (0);
    257   1.8  christos }
    258   1.1    tsarna #endif /* NOT_HAVE_DAEMON */
    259