xref: /netbsd-src/external/apache2/mDNSResponder/dist/mDNSPosix/mDNSBSD.c (revision e670fd5c413e99c2f6a37901bb21c537fcd322d2)
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 static int
32 copyaddr(struct sockaddr **dst, const struct sockaddr *src, socklen_t len)
33 {
34 	if (src == NULL)
35 		return 1;
36 
37 	*dst = calloc(1, len);
38 	if (*dst == NULL)
39 		return 0;
40 
41 	memcpy(*dst, src, len);
42 	return 1;
43 }
44 
45 struct ifi_info *
46 get_ifi_info(int family, int doaliases)
47 {
48 	struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
49 	struct ifaddrs *ifal, *ifa;
50 
51 	if (getifaddrs(&ifal) == -1) {
52 		warn("getifaddrs");
53 		return NULL;
54 	}
55 
56 	ifihead = NULL;
57 	ifipnext = &ifihead;
58 
59 	for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
60 		struct sockaddr *sa = ifa->ifa_addr;
61 		int flags = ifa->ifa_flags;
62 		int addrflags = ifa->ifa_addrflags;
63 
64 #if 0
65 		/*
66 		 * Include the loopback so that we return at least one
67 		 * address, so that mdnsd does not exit before we get
68 		 * a dhcp address
69 		 */
70 		if (flags & IFF_LOOPBACK)
71 			continue;	/* ignore loopback interfaces */
72 #endif
73 
74 		if ((flags & IFF_UP) == 0)
75 			continue;	/* ignore if interface not up */
76 
77 		if (sa == NULL || sa->sa_family != family)
78 			continue; 	/* ignore if not the desired family */
79 
80 		switch (sa->sa_family) {
81 		case AF_INET:
82 			if (addrflags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
83 				continue;
84 
85 			break;
86 #if defined(AF_INET6) && HAVE_IPV6
87 		case AF_INET6:
88 			if (addrflags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
89 				continue;
90 #endif
91 			break;
92 		default:
93 			continue;
94 		}
95 
96 		ifi = calloc(1, sizeof(*ifi));
97 		if (ifi == NULL)
98 			goto gotError;
99 
100 		ifipold   = *ifipnext;		/* need this later */
101 		ifiptr    = ifipnext;
102 		*ifipnext = ifi;		/* prev points to new one */
103 		ifipnext  = &ifi->ifi_next;	/* pointer to next one */
104 
105 		ifi->ifi_flags = flags;		/* IFF_xxx values */
106 		ifi->ifi_myflags = 0;		/* IFI_xxx values */
107 		ifi->ifi_index = if_nametoindex(ifa->ifa_name);
108 		memcpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME);
109 		ifi->ifi_name[IFI_NAME-1] = '\0';
110 		if (!copyaddr(&ifi->ifi_addr, ifa->ifa_addr, sa->sa_len))
111 			goto gotError;
112 		if (!copyaddr(&ifi->ifi_netmask, ifa->ifa_netmask, sa->sa_len))
113 			goto gotError;
114 
115 		if ((flags & IFF_BROADCAST) && !copyaddr(&ifi->ifi_brdaddr,
116 		    ifa->ifa_broadaddr, sa->sa_len))
117 			goto gotError;
118 		if ((flags & IFF_POINTOPOINT) && !copyaddr(&ifi->ifi_dstaddr,
119 		    ifa->ifa_dstaddr, sa->sa_len))
120 			goto gotError;
121 	}
122 
123 	goto done;
124 
125 gotError:
126 	warn("can't allocate memory");
127 	if (ifihead != NULL) {
128 		free_ifi_info(ifihead);
129 		ifihead = NULL;
130 	}
131 
132 	freeifaddrs(ifal);
133 done:
134 	return ifihead;    /* pointer to first structure in linked list */
135 }
136 
137 void
138 free_ifi_info(struct ifi_info *ifihead)
139 {
140 	struct ifi_info *ifi, *ififree;
141 
142 	for (ifi = ifihead; (ififree = ifi) != NULL;) {
143 		free(ifi->ifi_addr);
144 		free(ifi->ifi_netmask);
145 		free(ifi->ifi_brdaddr);
146 		free(ifi->ifi_dstaddr);
147 		ifi = ifi->ifi_next;
148 		free(ififree);
149 	}
150 }
151 
152 ssize_t
153 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
154     struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp,
155     u_char *ttl)
156 {
157     struct msghdr msg;
158     struct iovec iov[1];
159     ssize_t n;
160 
161 #ifdef CMSG_FIRSTHDR
162     struct cmsghdr  *cmptr;
163     union {
164         struct cmsghdr cm;
165         char control[1024];
166     } control_un;
167 
168     *ttl = 255;         // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
169 
170     msg.msg_control = control_un.control;
171     msg.msg_controllen = sizeof(control_un.control);
172     msg.msg_flags = 0;
173 #else
174     memset(&msg, 0, sizeof(msg));   /* make certain msg_accrightslen = 0 */
175 #endif /* CMSG_FIRSTHDR */
176 
177     msg.msg_name = (char *) sa;
178     msg.msg_namelen = *salenptr;
179     iov[0].iov_base = (char *)ptr;
180     iov[0].iov_len = nbytes;
181     msg.msg_iov = iov;
182     msg.msg_iovlen = 1;
183 
184     if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
185         return(n);
186 
187     *salenptr = msg.msg_namelen;    /* pass back results */
188     if (pktp) {
189         /* 0.0.0.0, i/f = -1 */
190         /* We set the interface to -1 so that the caller can
191            tell whether we returned a meaningful value or
192            just some default.  Previously this code just
193            set the value to 0, but I'm concerned that 0
194            might be a valid interface value.
195          */
196         memset(pktp, 0, sizeof(struct my_in_pktinfo));
197         pktp->ipi_ifindex = -1;
198     }
199 /* end recvfrom_flags1 */
200 
201 /* include recvfrom_flags2 */
202 #ifndef CMSG_FIRSTHDR
203     #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
204     *flagsp = 0;                    /* pass back results */
205     return(n);
206 #else
207 
208     *flagsp = msg.msg_flags;        /* pass back results */
209     if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
210         (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
211         return(n);
212 
213     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
214          cmptr = CMSG_NXTHDR(&msg, cmptr)) {
215 
216 #ifdef  IP_PKTINFO
217 #if in_pktinfo_definition_is_missing
218         struct in_pktinfo
219         {
220             int ipi_ifindex;
221             struct in_addr ipi_spec_dst;
222             struct in_addr ipi_addr;
223         };
224 #endif
225         if (cmptr->cmsg_level == IPPROTO_IP &&
226             cmptr->cmsg_type == IP_PKTINFO) {
227             struct in_pktinfo *tmp;
228             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
229 
230             tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
231             sin->sin_family = AF_INET;
232             sin->sin_addr = tmp->ipi_addr;
233             sin->sin_port = 0;
234             pktp->ipi_ifindex = tmp->ipi_ifindex;
235             continue;
236         }
237 #endif
238 
239 #ifdef  IP_RECVDSTADDR
240         if (cmptr->cmsg_level == IPPROTO_IP &&
241             cmptr->cmsg_type == IP_RECVDSTADDR) {
242             struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
243 
244             sin->sin_family = AF_INET;
245             sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
246             sin->sin_port = 0;
247             continue;
248         }
249 #endif
250 
251 #ifdef  IP_RECVIF
252         if (cmptr->cmsg_level == IPPROTO_IP &&
253             cmptr->cmsg_type == IP_RECVIF) {
254             struct sockaddr_dl  *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
255 #ifndef HAVE_BROKEN_RECVIF_NAME
256             int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
257             strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
258 #endif
259             pktp->ipi_ifindex = sdl->sdl_index;
260 #ifdef HAVE_BROKEN_RECVIF_NAME
261             if (sdl->sdl_index == 0) {
262                 pktp->ipi_ifindex = *(uint_t*)sdl;
263             }
264 #endif
265             assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
266             // null terminated because of memset above
267             continue;
268         }
269 #endif
270 
271 #ifdef  IP_RECVTTL
272         if (cmptr->cmsg_level == IPPROTO_IP &&
273             cmptr->cmsg_type == IP_RECVTTL) {
274             *ttl = *(u_char*)CMSG_DATA(cmptr);
275             continue;
276         }
277         else if (cmptr->cmsg_level == IPPROTO_IP &&
278                  cmptr->cmsg_type == IP_TTL) {  // some implementations seem to send IP_TTL instead of IP_RECVTTL
279             *ttl = *(int*)CMSG_DATA(cmptr);
280             continue;
281         }
282 #endif
283 
284 #if defined(IPV6_PKTINFO) && HAVE_IPV6
285         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
286             cmptr->cmsg_type  == IPV6_2292_PKTINFO) {
287             struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
288             struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
289 
290             sin6->sin6_family   = AF_INET6;
291 #ifndef NOT_HAVE_SA_LEN
292             sin6->sin6_len      = sizeof(*sin6);
293 #endif
294             sin6->sin6_addr     = ip6_info->ipi6_addr;
295             sin6->sin6_flowinfo = 0;
296             sin6->sin6_scope_id = 0;
297             sin6->sin6_port     = 0;
298             pktp->ipi_ifindex   = ip6_info->ipi6_ifindex;
299             continue;
300         }
301 #endif
302 
303 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
304         if (cmptr->cmsg_level == IPPROTO_IPV6 &&
305             cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
306             *ttl = *(int*)CMSG_DATA(cmptr);
307             continue;
308         }
309 #endif
310         assert(0);  // unknown ancillary data
311     }
312     return(n);
313 #endif /* CMSG_FIRSTHDR */
314 }
315