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