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