mDNSBSD.c revision 1.1.4.2 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