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