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