mDNSBSD.c revision 1.1.16.1 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
32 ssize_t
33 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
34 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp,
35 u_char *ttl)
36 {
37 struct msghdr msg;
38 struct iovec iov[1];
39 ssize_t n;
40
41 #ifdef CMSG_FIRSTHDR
42 struct cmsghdr *cmptr;
43 union {
44 struct cmsghdr cm;
45 char control[1024];
46 } control_un;
47
48 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
49
50 msg.msg_control = control_un.control;
51 msg.msg_controllen = sizeof(control_un.control);
52 msg.msg_flags = 0;
53 #else
54 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
55 #endif /* CMSG_FIRSTHDR */
56
57 msg.msg_name = (char *) sa;
58 msg.msg_namelen = *salenptr;
59 iov[0].iov_base = (char *)ptr;
60 iov[0].iov_len = nbytes;
61 msg.msg_iov = iov;
62 msg.msg_iovlen = 1;
63
64 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
65 return(n);
66
67 *salenptr = msg.msg_namelen; /* pass back results */
68 if (pktp) {
69 /* 0.0.0.0, i/f = -1 */
70 /* We set the interface to -1 so that the caller can
71 tell whether we returned a meaningful value or
72 just some default. Previously this code just
73 set the value to 0, but I'm concerned that 0
74 might be a valid interface value.
75 */
76 memset(pktp, 0, sizeof(struct my_in_pktinfo));
77 pktp->ipi_ifindex = -1;
78 }
79 /* end recvfrom_flags1 */
80
81 /* include recvfrom_flags2 */
82 #ifndef CMSG_FIRSTHDR
83 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
84 *flagsp = 0; /* pass back results */
85 return(n);
86 #else
87
88 *flagsp = msg.msg_flags; /* pass back results */
89 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
90 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
91 return(n);
92
93 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
94 cmptr = CMSG_NXTHDR(&msg, cmptr)) {
95
96 #ifdef IP_PKTINFO
97 #if in_pktinfo_definition_is_missing
98 struct in_pktinfo
99 {
100 int ipi_ifindex;
101 struct in_addr ipi_spec_dst;
102 struct in_addr ipi_addr;
103 };
104 #endif
105 if (cmptr->cmsg_level == IPPROTO_IP &&
106 cmptr->cmsg_type == IP_PKTINFO) {
107 struct in_pktinfo *tmp;
108 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
109
110 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
111 sin->sin_family = AF_INET;
112 sin->sin_addr = tmp->ipi_addr;
113 sin->sin_port = 0;
114 pktp->ipi_ifindex = tmp->ipi_ifindex;
115 continue;
116 }
117 #endif
118
119 #ifdef IP_RECVDSTADDR
120 if (cmptr->cmsg_level == IPPROTO_IP &&
121 cmptr->cmsg_type == IP_RECVDSTADDR) {
122 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
123
124 sin->sin_family = AF_INET;
125 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
126 sin->sin_port = 0;
127 continue;
128 }
129 #endif
130
131 #ifdef IP_RECVIF
132 if (cmptr->cmsg_level == IPPROTO_IP &&
133 cmptr->cmsg_type == IP_RECVIF) {
134 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
135 #ifndef HAVE_BROKEN_RECVIF_NAME
136 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
137 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
138 #endif
139 pktp->ipi_ifindex = sdl->sdl_index;
140 #ifdef HAVE_BROKEN_RECVIF_NAME
141 if (sdl->sdl_index == 0) {
142 pktp->ipi_ifindex = *(uint_t*)sdl;
143 }
144 #endif
145 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
146 // null terminated because of memset above
147 continue;
148 }
149 #endif
150
151 #ifdef IP_RECVTTL
152 if (cmptr->cmsg_level == IPPROTO_IP &&
153 cmptr->cmsg_type == IP_RECVTTL) {
154 *ttl = *(u_char*)CMSG_DATA(cmptr);
155 continue;
156 }
157 else if (cmptr->cmsg_level == IPPROTO_IP &&
158 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
159 *ttl = *(int*)CMSG_DATA(cmptr);
160 continue;
161 }
162 #endif
163
164 #if defined(IPV6_PKTINFO) && HAVE_IPV6
165 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
166 cmptr->cmsg_type == IPV6_2292_PKTINFO) {
167 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
168 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
169
170 sin6->sin6_family = AF_INET6;
171 #ifndef NOT_HAVE_SA_LEN
172 sin6->sin6_len = sizeof(*sin6);
173 #endif
174 sin6->sin6_addr = ip6_info->ipi6_addr;
175 sin6->sin6_flowinfo = 0;
176 sin6->sin6_scope_id = 0;
177 sin6->sin6_port = 0;
178 pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
179 continue;
180 }
181 #endif
182
183 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
184 if (cmptr->cmsg_level == IPPROTO_IPV6 &&
185 cmptr->cmsg_type == IPV6_2292_HOPLIMIT) {
186 *ttl = *(int*)CMSG_DATA(cmptr);
187 continue;
188 }
189 #endif
190 assert(0); // unknown ancillary data
191 }
192 return(n);
193 #endif /* CMSG_FIRSTHDR */
194 }
195