mDNSUNP.c revision 1.1 1 1.1 tsarna /* -*- Mode: C; tab-width: 4 -*-
2 1.1 tsarna *
3 1.1 tsarna * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 1.1 tsarna *
5 1.1 tsarna * Licensed under the Apache License, Version 2.0 (the "License");
6 1.1 tsarna * you may not use this file except in compliance with the License.
7 1.1 tsarna * You may obtain a copy of the License at
8 1.1 tsarna *
9 1.1 tsarna * http://www.apache.org/licenses/LICENSE-2.0
10 1.1 tsarna *
11 1.1 tsarna * Unless required by applicable law or agreed to in writing, software
12 1.1 tsarna * distributed under the License is distributed on an "AS IS" BASIS,
13 1.1 tsarna * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 1.1 tsarna * See the License for the specific language governing permissions and
15 1.1 tsarna * limitations under the License.
16 1.1 tsarna
17 1.1 tsarna Change History (most recent first):
18 1.1 tsarna
19 1.1 tsarna Log: mDNSUNP.c,v $
20 1.1 tsarna Revision 1.40 2009/01/13 05:31:34 mkrochma
21 1.1 tsarna <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
22 1.1 tsarna
23 1.1 tsarna Revision 1.39 2009/01/11 03:20:06 mkrochma
24 1.1 tsarna <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
25 1.1 tsarna
26 1.1 tsarna Revision 1.38 2009/01/10 22:54:42 mkrochma
27 1.1 tsarna <rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux
28 1.1 tsarna
29 1.1 tsarna Revision 1.37 2008/10/23 22:33:24 cheshire
30 1.1 tsarna Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
31 1.1 tsarna
32 1.1 tsarna Revision 1.36 2008/04/21 18:21:22 mkrochma
33 1.1 tsarna <rdar://problem/5877307> Need to free ifi_netmask
34 1.1 tsarna Submitted by Igor Seleznev
35 1.1 tsarna
36 1.1 tsarna Revision 1.35 2007/11/15 21:36:19 cheshire
37 1.1 tsarna <rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
38 1.1 tsarna
39 1.1 tsarna Revision 1.34 2006/08/14 23:24:47 cheshire
40 1.1 tsarna Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
41 1.1 tsarna
42 1.1 tsarna Revision 1.33 2006/03/13 23:14:21 cheshire
43 1.1 tsarna <rdar://problem/4427969> Compile problems on FreeBSD
44 1.1 tsarna Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
45 1.1 tsarna
46 1.1 tsarna Revision 1.32 2005/12/21 02:56:43 cheshire
47 1.1 tsarna <rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
48 1.1 tsarna
49 1.1 tsarna Revision 1.31 2005/12/21 02:46:05 cheshire
50 1.1 tsarna <rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
51 1.1 tsarna
52 1.1 tsarna Revision 1.30 2005/11/29 20:03:02 mkrochma
53 1.1 tsarna Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
54 1.1 tsarna
55 1.1 tsarna Revision 1.29 2005/11/12 02:23:10 cheshire
56 1.1 tsarna <rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
57 1.1 tsarna
58 1.1 tsarna Revision 1.28 2005/10/31 22:09:45 cheshire
59 1.1 tsarna Buffer "char addr6[33]" was seven bytes too small
60 1.1 tsarna
61 1.1 tsarna Revision 1.27 2005/06/29 15:54:21 cheshire
62 1.1 tsarna <rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
63 1.1 tsarna Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
64 1.1 tsarna
65 1.1 tsarna Revision 1.26 2005/04/08 21:43:59 ksekar
66 1.1 tsarna <rdar://problem/4083426> mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
67 1.1 tsarna Submitted by Andrew de Quincey
68 1.1 tsarna
69 1.1 tsarna Revision 1.25 2005/04/08 21:37:57 ksekar
70 1.1 tsarna <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
71 1.1 tsarna
72 1.1 tsarna Revision 1.24 2005/04/08 21:30:16 ksekar
73 1.1 tsarna <rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
74 1.1 tsarna Patch submitted by Bernd Kuhls
75 1.1 tsarna
76 1.1 tsarna Revision 1.23 2004/12/01 04:25:05 cheshire
77 1.1 tsarna <rdar://problem/3872803> Darwin patches for Solaris and Suse
78 1.1 tsarna Provide daemon() for platforms that don't have it
79 1.1 tsarna
80 1.1 tsarna Revision 1.22 2004/11/30 22:37:01 cheshire
81 1.1 tsarna Update copyright dates and add "Mode: C; tab-width: 4" headers
82 1.1 tsarna
83 1.1 tsarna Revision 1.21 2004/11/08 22:13:59 rpantos
84 1.1 tsarna Create sockf6 lazily when v6 interface found.
85 1.1 tsarna
86 1.1 tsarna Revision 1.20 2004/10/16 00:17:01 cheshire
87 1.1 tsarna <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
88 1.1 tsarna
89 1.1 tsarna Revision 1.19 2004/07/20 01:47:36 rpantos
90 1.1 tsarna NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
91 1.1 tsarna
92 1.1 tsarna Revision 1.18 2004/07/08 21:30:21 rpantos
93 1.1 tsarna
94 1.1 tsarna Revision 1.17 2004/06/25 00:26:27 rpantos
95 1.1 tsarna Changes to fix the Posix build on Solaris.
96 1.1 tsarna
97 1.1 tsarna Revision 1.16 2004/03/20 05:37:09 cheshire
98 1.1 tsarna Fix contributed by Terry Lambert & Alfred Perlstein:
99 1.1 tsarna Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
100 1.1 tsarna
101 1.1 tsarna Revision 1.15 2004/02/14 01:09:45 rpantos
102 1.1 tsarna Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
103 1.1 tsarna
104 1.1 tsarna Revision 1.14 2003/12/11 18:53:40 cheshire
105 1.1 tsarna Fix compiler warning reported by Paul Guyot
106 1.1 tsarna
107 1.1 tsarna Revision 1.13 2003/12/08 20:47:02 rpantos
108 1.1 tsarna Add support for mDNSResponder on Linux.
109 1.1 tsarna
110 1.1 tsarna Revision 1.12 2003/09/02 20:47:13 cheshire
111 1.1 tsarna Fix signed/unsigned warning
112 1.1 tsarna
113 1.1 tsarna Revision 1.11 2003/08/12 19:56:26 cheshire
114 1.1 tsarna Update to APSL 2.0
115 1.1 tsarna
116 1.1 tsarna Revision 1.10 2003/08/06 18:20:51 cheshire
117 1.1 tsarna Makefile cleanup
118 1.1 tsarna
119 1.1 tsarna Revision 1.9 2003/07/14 18:11:54 cheshire
120 1.1 tsarna Fix stricter compiler warnings
121 1.1 tsarna
122 1.1 tsarna Revision 1.8 2003/07/02 21:19:59 cheshire
123 1.1 tsarna <rdar://problem/3313413> Update copyright notices, etc., in source code comments
124 1.1 tsarna
125 1.1 tsarna Revision 1.7 2003/03/20 21:10:31 cheshire
126 1.1 tsarna Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
127 1.1 tsarna
128 1.1 tsarna Revision 1.6 2003/03/13 03:46:21 cheshire
129 1.1 tsarna Fixes to make the code build on Linux
130 1.1 tsarna
131 1.1 tsarna Revision 1.5 2003/02/07 03:02:02 cheshire
132 1.1 tsarna Submitted by: Mitsutaka Watanabe
133 1.1 tsarna The code saying "index += 1;" was effectively making up random interface index values.
134 1.1 tsarna The right way to find the correct interface index is if_nametoindex();
135 1.1 tsarna
136 1.1 tsarna Revision 1.4 2002/12/23 22:13:31 jgraessl
137 1.1 tsarna
138 1.1 tsarna Reviewed by: Stuart Cheshire
139 1.1 tsarna Initial IPv6 support for mDNSResponder.
140 1.1 tsarna
141 1.1 tsarna Revision 1.3 2002/09/21 20:44:53 zarzycki
142 1.1 tsarna Added APSL info
143 1.1 tsarna
144 1.1 tsarna Revision 1.2 2002/09/19 04:20:44 cheshire
145 1.1 tsarna Remove high-ascii characters that confuse some systems
146 1.1 tsarna
147 1.1 tsarna Revision 1.1 2002/09/17 06:24:34 cheshire
148 1.1 tsarna First checkin
149 1.1 tsarna
150 1.1 tsarna */
151 1.1 tsarna
152 1.1 tsarna #include "mDNSUNP.h"
153 1.1 tsarna
154 1.1 tsarna #include <errno.h>
155 1.1 tsarna #include <assert.h>
156 1.1 tsarna #include <string.h>
157 1.1 tsarna #include <stdlib.h>
158 1.1 tsarna #include <sys/uio.h>
159 1.1 tsarna #include <sys/ioctl.h>
160 1.1 tsarna #include <signal.h>
161 1.1 tsarna #include <unistd.h>
162 1.1 tsarna #include <stdio.h>
163 1.1 tsarna
164 1.1 tsarna /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
165 1.1 tsarna macro, usually defined in <sys/param.h> or someplace like that, to make sure the
166 1.1 tsarna CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
167 1.1 tsarna should be set to the name of the header to include to get the ALIGN(P) macro.
168 1.1 tsarna */
169 1.1 tsarna #ifdef NEED_ALIGN_MACRO
170 1.1 tsarna #include NEED_ALIGN_MACRO
171 1.1 tsarna #endif
172 1.1 tsarna
173 1.1 tsarna /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
174 1.1 tsarna other platforms don't even have that include file. So,
175 1.1 tsarna if we haven't yet got a definition, let's try to find
176 1.1 tsarna <sys/sockio.h>.
177 1.1 tsarna */
178 1.1 tsarna
179 1.1 tsarna #ifndef SIOCGIFCONF
180 1.1 tsarna #include <sys/sockio.h>
181 1.1 tsarna #endif
182 1.1 tsarna
183 1.1 tsarna /* sockaddr_dl is only referenced if we're using IP_RECVIF,
184 1.1 tsarna so only include the header in that case.
185 1.1 tsarna */
186 1.1 tsarna
187 1.1 tsarna #ifdef IP_RECVIF
188 1.1 tsarna #include <net/if_dl.h>
189 1.1 tsarna #endif
190 1.1 tsarna
191 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
192 1.1 tsarna #include <net/if_var.h>
193 1.1 tsarna #include <netinet/in_var.h>
194 1.1 tsarna // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
195 1.1 tsarna #endif
196 1.1 tsarna
197 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
198 1.1 tsarna #include <netdb.h>
199 1.1 tsarna #include <arpa/inet.h>
200 1.1 tsarna
201 1.1 tsarna /* Converts a prefix length to IPv6 network mask */
202 1.1 tsarna void plen_to_mask(int plen, char *addr) {
203 1.1 tsarna int i;
204 1.1 tsarna int colons=7; /* Number of colons in IPv6 address */
205 1.1 tsarna int bits_in_block=16; /* Bits per IPv6 block */
206 1.1 tsarna for(i=0;i<=colons;i++) {
207 1.1 tsarna int block, ones=0xffff, ones_in_block;
208 1.1 tsarna if(plen>bits_in_block) ones_in_block=bits_in_block;
209 1.1 tsarna else ones_in_block=plen;
210 1.1 tsarna block = ones & (ones << (bits_in_block-ones_in_block));
211 1.1 tsarna i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
212 1.1 tsarna plen -= ones_in_block;
213 1.1 tsarna }
214 1.1 tsarna }
215 1.1 tsarna
216 1.1 tsarna /* Gets IPv6 interface information from the /proc filesystem in linux*/
217 1.1 tsarna struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
218 1.1 tsarna {
219 1.1 tsarna struct ifi_info *ifi, *ifihead, **ifipnext;
220 1.1 tsarna FILE *fp;
221 1.1 tsarna char addr[8][5];
222 1.1 tsarna int flags, myflags, index, plen, scope;
223 1.1 tsarna char ifname[9], lastname[IFNAMSIZ];
224 1.1 tsarna char addr6[32+7+1]; /* don't forget the seven ':' */
225 1.1 tsarna struct addrinfo hints, *res0;
226 1.1 tsarna struct sockaddr_in6 *sin6;
227 1.1 tsarna struct in6_addr *addrptr;
228 1.1 tsarna int err;
229 1.1 tsarna
230 1.1 tsarna res0=NULL;
231 1.1 tsarna ifihead = NULL;
232 1.1 tsarna ifipnext = &ifihead;
233 1.1 tsarna lastname[0] = 0;
234 1.1 tsarna
235 1.1 tsarna if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
236 1.1 tsarna while (fscanf(fp,
237 1.1 tsarna "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
238 1.1 tsarna addr[0],addr[1],addr[2],addr[3],
239 1.1 tsarna addr[4],addr[5],addr[6],addr[7],
240 1.1 tsarna &index, &plen, &scope, &flags, ifname) != EOF) {
241 1.1 tsarna
242 1.1 tsarna myflags = 0;
243 1.1 tsarna if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
244 1.1 tsarna if (doaliases == 0)
245 1.1 tsarna continue; /* already processed this interface */
246 1.1 tsarna myflags = IFI_ALIAS;
247 1.1 tsarna }
248 1.1 tsarna memcpy(lastname, ifname, IFNAMSIZ);
249 1.1 tsarna ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
250 1.1 tsarna if (ifi == NULL) {
251 1.1 tsarna goto gotError;
252 1.1 tsarna }
253 1.1 tsarna
254 1.1 tsarna *ifipnext = ifi; /* prev points to this new one */
255 1.1 tsarna ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
256 1.1 tsarna
257 1.1 tsarna sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
258 1.1 tsarna addr[0],addr[1],addr[2],addr[3],
259 1.1 tsarna addr[4],addr[5],addr[6],addr[7]);
260 1.1 tsarna
261 1.1 tsarna /* Add address of the interface */
262 1.1 tsarna memset(&hints, 0, sizeof(hints));
263 1.1 tsarna hints.ai_family = AF_INET6;
264 1.1 tsarna hints.ai_flags = AI_NUMERICHOST;
265 1.1 tsarna err = getaddrinfo(addr6, NULL, &hints, &res0);
266 1.1 tsarna if (err) {
267 1.1 tsarna goto gotError;
268 1.1 tsarna }
269 1.1 tsarna ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
270 1.1 tsarna if (ifi->ifi_addr == NULL) {
271 1.1 tsarna goto gotError;
272 1.1 tsarna }
273 1.1 tsarna memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
274 1.1 tsarna
275 1.1 tsarna /* Add netmask of the interface */
276 1.1 tsarna char ipv6addr[INET6_ADDRSTRLEN];
277 1.1 tsarna plen_to_mask(plen, ipv6addr);
278 1.1 tsarna ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
279 1.1 tsarna if (ifi->ifi_addr == NULL) {
280 1.1 tsarna goto gotError;
281 1.1 tsarna }
282 1.1 tsarna sin6=calloc(1, sizeof(struct sockaddr_in6));
283 1.1 tsarna addrptr=calloc(1, sizeof(struct in6_addr));
284 1.1 tsarna inet_pton(family, ipv6addr, addrptr);
285 1.1 tsarna sin6->sin6_family=family;
286 1.1 tsarna sin6->sin6_addr=*addrptr;
287 1.1 tsarna sin6->sin6_scope_id=scope;
288 1.1 tsarna memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
289 1.1 tsarna free(sin6);
290 1.1 tsarna
291 1.1 tsarna
292 1.1 tsarna /* Add interface name */
293 1.1 tsarna memcpy(ifi->ifi_name, ifname, IFI_NAME);
294 1.1 tsarna
295 1.1 tsarna /* Add interface index */
296 1.1 tsarna ifi->ifi_index = index;
297 1.1 tsarna
298 1.1 tsarna /* If interface is in /proc then it is up*/
299 1.1 tsarna ifi->ifi_flags = IFF_UP;
300 1.1 tsarna
301 1.1 tsarna freeaddrinfo(res0);
302 1.1 tsarna res0=NULL;
303 1.1 tsarna }
304 1.1 tsarna }
305 1.1 tsarna goto done;
306 1.1 tsarna
307 1.1 tsarna gotError:
308 1.1 tsarna if (ifihead != NULL) {
309 1.1 tsarna free_ifi_info(ifihead);
310 1.1 tsarna ifihead = NULL;
311 1.1 tsarna }
312 1.1 tsarna if (res0 != NULL) {
313 1.1 tsarna freeaddrinfo(res0);
314 1.1 tsarna res0=NULL;
315 1.1 tsarna }
316 1.1 tsarna done:
317 1.1 tsarna return(ifihead); /* pointer to first structure in linked list */
318 1.1 tsarna }
319 1.1 tsarna #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
320 1.1 tsarna
321 1.1 tsarna struct ifi_info *get_ifi_info(int family, int doaliases)
322 1.1 tsarna {
323 1.1 tsarna int junk;
324 1.1 tsarna struct ifi_info *ifi, *ifihead, **ifipnext;
325 1.1 tsarna int sockfd, sockf6, len, lastlen, flags, myflags;
326 1.1 tsarna #ifdef NOT_HAVE_IF_NAMETOINDEX
327 1.1 tsarna int index = 200;
328 1.1 tsarna #endif
329 1.1 tsarna char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
330 1.1 tsarna struct ifconf ifc;
331 1.1 tsarna struct ifreq *ifr, ifrcopy;
332 1.1 tsarna struct sockaddr_in *sinptr;
333 1.1 tsarna
334 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6
335 1.1 tsarna struct sockaddr_in6 *sinptr6;
336 1.1 tsarna #endif
337 1.1 tsarna
338 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
339 1.1 tsarna if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
340 1.1 tsarna #endif
341 1.1 tsarna
342 1.1 tsarna sockfd = -1;
343 1.1 tsarna sockf6 = -1;
344 1.1 tsarna buf = NULL;
345 1.1 tsarna ifihead = NULL;
346 1.1 tsarna
347 1.1 tsarna sockfd = socket(AF_INET, SOCK_DGRAM, 0);
348 1.1 tsarna if (sockfd < 0) {
349 1.1 tsarna goto gotError;
350 1.1 tsarna }
351 1.1 tsarna
352 1.1 tsarna lastlen = 0;
353 1.1 tsarna len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
354 1.1 tsarna for ( ; ; ) {
355 1.1 tsarna buf = (char*)malloc(len);
356 1.1 tsarna if (buf == NULL) {
357 1.1 tsarna goto gotError;
358 1.1 tsarna }
359 1.1 tsarna ifc.ifc_len = len;
360 1.1 tsarna ifc.ifc_buf = buf;
361 1.1 tsarna if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
362 1.1 tsarna if (errno != EINVAL || lastlen != 0) {
363 1.1 tsarna goto gotError;
364 1.1 tsarna }
365 1.1 tsarna } else {
366 1.1 tsarna if (ifc.ifc_len == lastlen)
367 1.1 tsarna break; /* success, len has not changed */
368 1.1 tsarna lastlen = ifc.ifc_len;
369 1.1 tsarna }
370 1.1 tsarna len += 10 * sizeof(struct ifreq); /* increment */
371 1.1 tsarna free(buf);
372 1.1 tsarna }
373 1.1 tsarna ifihead = NULL;
374 1.1 tsarna ifipnext = &ifihead;
375 1.1 tsarna lastname[0] = 0;
376 1.1 tsarna /* end get_ifi_info1 */
377 1.1 tsarna
378 1.1 tsarna /* include get_ifi_info2 */
379 1.1 tsarna for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
380 1.1 tsarna ifr = (struct ifreq *) ptr;
381 1.1 tsarna
382 1.1 tsarna /* Advance to next one in buffer */
383 1.1 tsarna if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
384 1.1 tsarna ptr += sizeof(struct ifreq);
385 1.1 tsarna else
386 1.1 tsarna ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
387 1.1 tsarna
388 1.1 tsarna // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
389 1.1 tsarna
390 1.1 tsarna if (ifr->ifr_addr.sa_family != family)
391 1.1 tsarna continue; /* ignore if not desired address family */
392 1.1 tsarna
393 1.1 tsarna myflags = 0;
394 1.1 tsarna if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
395 1.1 tsarna *cptr = 0; /* replace colon will null */
396 1.1 tsarna if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
397 1.1 tsarna if (doaliases == 0)
398 1.1 tsarna continue; /* already processed this interface */
399 1.1 tsarna myflags = IFI_ALIAS;
400 1.1 tsarna }
401 1.1 tsarna memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
402 1.1 tsarna
403 1.1 tsarna ifrcopy = *ifr;
404 1.1 tsarna if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
405 1.1 tsarna goto gotError;
406 1.1 tsarna }
407 1.1 tsarna
408 1.1 tsarna flags = ifrcopy.ifr_flags;
409 1.1 tsarna if ((flags & IFF_UP) == 0)
410 1.1 tsarna continue; /* ignore if interface not up */
411 1.1 tsarna
412 1.1 tsarna ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
413 1.1 tsarna if (ifi == NULL) {
414 1.1 tsarna goto gotError;
415 1.1 tsarna }
416 1.1 tsarna *ifipnext = ifi; /* prev points to this new one */
417 1.1 tsarna ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
418 1.1 tsarna
419 1.1 tsarna ifi->ifi_flags = flags; /* IFF_xxx values */
420 1.1 tsarna ifi->ifi_myflags = myflags; /* IFI_xxx values */
421 1.1 tsarna #ifndef NOT_HAVE_IF_NAMETOINDEX
422 1.1 tsarna ifi->ifi_index = if_nametoindex(ifr->ifr_name);
423 1.1 tsarna #else
424 1.1 tsarna ifrcopy = *ifr;
425 1.1 tsarna #ifdef SIOCGIFINDEX
426 1.1 tsarna if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
427 1.1 tsarna ifi->ifi_index = ifrcopy.ifr_index;
428 1.1 tsarna else
429 1.1 tsarna #endif
430 1.1 tsarna ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
431 1.1 tsarna #endif
432 1.1 tsarna memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
433 1.1 tsarna ifi->ifi_name[IFI_NAME-1] = '\0';
434 1.1 tsarna /* end get_ifi_info2 */
435 1.1 tsarna /* include get_ifi_info3 */
436 1.1 tsarna switch (ifr->ifr_addr.sa_family) {
437 1.1 tsarna case AF_INET:
438 1.1 tsarna sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
439 1.1 tsarna if (ifi->ifi_addr == NULL) {
440 1.1 tsarna ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
441 1.1 tsarna if (ifi->ifi_addr == NULL) {
442 1.1 tsarna goto gotError;
443 1.1 tsarna }
444 1.1 tsarna memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
445 1.1 tsarna
446 1.1 tsarna #ifdef SIOCGIFNETMASK
447 1.1 tsarna if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
448 1.1 tsarna ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
449 1.1 tsarna if (ifi->ifi_netmask == NULL) goto gotError;
450 1.1 tsarna sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
451 1.1 tsarna /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
452 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
453 1.1 tsarna sinptr->sin_len = sizeof(struct sockaddr_in);
454 1.1 tsarna #endif
455 1.1 tsarna sinptr->sin_family = AF_INET;
456 1.1 tsarna memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
457 1.1 tsarna #endif
458 1.1 tsarna
459 1.1 tsarna #ifdef SIOCGIFBRDADDR
460 1.1 tsarna if (flags & IFF_BROADCAST) {
461 1.1 tsarna if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
462 1.1 tsarna goto gotError;
463 1.1 tsarna }
464 1.1 tsarna sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
465 1.1 tsarna /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
466 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
467 1.1 tsarna sinptr->sin_len = sizeof( struct sockaddr_in );
468 1.1 tsarna #endif
469 1.1 tsarna sinptr->sin_family = AF_INET;
470 1.1 tsarna ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
471 1.1 tsarna if (ifi->ifi_brdaddr == NULL) {
472 1.1 tsarna goto gotError;
473 1.1 tsarna }
474 1.1 tsarna memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
475 1.1 tsarna }
476 1.1 tsarna #endif
477 1.1 tsarna
478 1.1 tsarna #ifdef SIOCGIFDSTADDR
479 1.1 tsarna if (flags & IFF_POINTOPOINT) {
480 1.1 tsarna if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
481 1.1 tsarna goto gotError;
482 1.1 tsarna }
483 1.1 tsarna sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
484 1.1 tsarna /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
485 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
486 1.1 tsarna sinptr->sin_len = sizeof( struct sockaddr_in );
487 1.1 tsarna #endif
488 1.1 tsarna sinptr->sin_family = AF_INET;
489 1.1 tsarna ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
490 1.1 tsarna if (ifi->ifi_dstaddr == NULL) {
491 1.1 tsarna goto gotError;
492 1.1 tsarna }
493 1.1 tsarna memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
494 1.1 tsarna }
495 1.1 tsarna #endif
496 1.1 tsarna }
497 1.1 tsarna break;
498 1.1 tsarna
499 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6
500 1.1 tsarna case AF_INET6:
501 1.1 tsarna sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
502 1.1 tsarna if (ifi->ifi_addr == NULL) {
503 1.1 tsarna ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
504 1.1 tsarna if (ifi->ifi_addr == NULL) {
505 1.1 tsarna goto gotError;
506 1.1 tsarna }
507 1.1 tsarna
508 1.1 tsarna /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
509 1.1 tsarna /* We need to strip that out */
510 1.1 tsarna if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
511 1.1 tsarna sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
512 1.1 tsarna memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
513 1.1 tsarna
514 1.1 tsarna #ifdef SIOCGIFNETMASK_IN6
515 1.1 tsarna {
516 1.1 tsarna struct in6_ifreq ifr6;
517 1.1 tsarna if (sockf6 == -1)
518 1.1 tsarna sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
519 1.1 tsarna memset(&ifr6, 0, sizeof(ifr6));
520 1.1 tsarna memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
521 1.1 tsarna memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
522 1.1 tsarna if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
523 1.1 tsarna ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
524 1.1 tsarna if (ifi->ifi_netmask == NULL) goto gotError;
525 1.1 tsarna sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
526 1.1 tsarna memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
527 1.1 tsarna }
528 1.1 tsarna #endif
529 1.1 tsarna }
530 1.1 tsarna break;
531 1.1 tsarna #endif
532 1.1 tsarna
533 1.1 tsarna default:
534 1.1 tsarna break;
535 1.1 tsarna }
536 1.1 tsarna }
537 1.1 tsarna goto done;
538 1.1 tsarna
539 1.1 tsarna gotError:
540 1.1 tsarna if (ifihead != NULL) {
541 1.1 tsarna free_ifi_info(ifihead);
542 1.1 tsarna ifihead = NULL;
543 1.1 tsarna }
544 1.1 tsarna
545 1.1 tsarna done:
546 1.1 tsarna if (buf != NULL) {
547 1.1 tsarna free(buf);
548 1.1 tsarna }
549 1.1 tsarna if (sockfd != -1) {
550 1.1 tsarna junk = close(sockfd);
551 1.1 tsarna assert(junk == 0);
552 1.1 tsarna }
553 1.1 tsarna if (sockf6 != -1) {
554 1.1 tsarna junk = close(sockf6);
555 1.1 tsarna assert(junk == 0);
556 1.1 tsarna }
557 1.1 tsarna return(ifihead); /* pointer to first structure in linked list */
558 1.1 tsarna }
559 1.1 tsarna /* end get_ifi_info3 */
560 1.1 tsarna
561 1.1 tsarna /* include free_ifi_info */
562 1.1 tsarna void
563 1.1 tsarna free_ifi_info(struct ifi_info *ifihead)
564 1.1 tsarna {
565 1.1 tsarna struct ifi_info *ifi, *ifinext;
566 1.1 tsarna
567 1.1 tsarna for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
568 1.1 tsarna if (ifi->ifi_addr != NULL)
569 1.1 tsarna free(ifi->ifi_addr);
570 1.1 tsarna if (ifi->ifi_netmask != NULL)
571 1.1 tsarna free(ifi->ifi_netmask);
572 1.1 tsarna if (ifi->ifi_brdaddr != NULL)
573 1.1 tsarna free(ifi->ifi_brdaddr);
574 1.1 tsarna if (ifi->ifi_dstaddr != NULL)
575 1.1 tsarna free(ifi->ifi_dstaddr);
576 1.1 tsarna ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
577 1.1 tsarna free(ifi); /* the ifi_info{} itself */
578 1.1 tsarna }
579 1.1 tsarna }
580 1.1 tsarna /* end free_ifi_info */
581 1.1 tsarna
582 1.1 tsarna ssize_t
583 1.1 tsarna recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
584 1.1 tsarna struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
585 1.1 tsarna {
586 1.1 tsarna struct msghdr msg;
587 1.1 tsarna struct iovec iov[1];
588 1.1 tsarna ssize_t n;
589 1.1 tsarna
590 1.1 tsarna #ifdef CMSG_FIRSTHDR
591 1.1 tsarna struct cmsghdr *cmptr;
592 1.1 tsarna union {
593 1.1 tsarna struct cmsghdr cm;
594 1.1 tsarna char control[1024];
595 1.1 tsarna } control_un;
596 1.1 tsarna
597 1.1 tsarna *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
598 1.1 tsarna
599 1.1 tsarna msg.msg_control = control_un.control;
600 1.1 tsarna msg.msg_controllen = sizeof(control_un.control);
601 1.1 tsarna msg.msg_flags = 0;
602 1.1 tsarna #else
603 1.1 tsarna memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
604 1.1 tsarna #endif /* CMSG_FIRSTHDR */
605 1.1 tsarna
606 1.1 tsarna msg.msg_name = (char *) sa;
607 1.1 tsarna msg.msg_namelen = *salenptr;
608 1.1 tsarna iov[0].iov_base = (char *)ptr;
609 1.1 tsarna iov[0].iov_len = nbytes;
610 1.1 tsarna msg.msg_iov = iov;
611 1.1 tsarna msg.msg_iovlen = 1;
612 1.1 tsarna
613 1.1 tsarna if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
614 1.1 tsarna return(n);
615 1.1 tsarna
616 1.1 tsarna *salenptr = msg.msg_namelen; /* pass back results */
617 1.1 tsarna if (pktp) {
618 1.1 tsarna /* 0.0.0.0, i/f = -1 */
619 1.1 tsarna /* We set the interface to -1 so that the caller can
620 1.1 tsarna tell whether we returned a meaningful value or
621 1.1 tsarna just some default. Previously this code just
622 1.1 tsarna set the value to 0, but I'm concerned that 0
623 1.1 tsarna might be a valid interface value.
624 1.1 tsarna */
625 1.1 tsarna memset(pktp, 0, sizeof(struct my_in_pktinfo));
626 1.1 tsarna pktp->ipi_ifindex = -1;
627 1.1 tsarna }
628 1.1 tsarna /* end recvfrom_flags1 */
629 1.1 tsarna
630 1.1 tsarna /* include recvfrom_flags2 */
631 1.1 tsarna #ifndef CMSG_FIRSTHDR
632 1.1 tsarna #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
633 1.1 tsarna *flagsp = 0; /* pass back results */
634 1.1 tsarna return(n);
635 1.1 tsarna #else
636 1.1 tsarna
637 1.1 tsarna *flagsp = msg.msg_flags; /* pass back results */
638 1.1 tsarna if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
639 1.1 tsarna (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
640 1.1 tsarna return(n);
641 1.1 tsarna
642 1.1 tsarna for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
643 1.1 tsarna cmptr = CMSG_NXTHDR(&msg, cmptr)) {
644 1.1 tsarna
645 1.1 tsarna #ifdef IP_PKTINFO
646 1.1 tsarna #if in_pktinfo_definition_is_missing
647 1.1 tsarna struct in_pktinfo
648 1.1 tsarna {
649 1.1 tsarna int ipi_ifindex;
650 1.1 tsarna struct in_addr ipi_spec_dst;
651 1.1 tsarna struct in_addr ipi_addr;
652 1.1 tsarna };
653 1.1 tsarna #endif
654 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
655 1.1 tsarna cmptr->cmsg_type == IP_PKTINFO) {
656 1.1 tsarna struct in_pktinfo *tmp;
657 1.1 tsarna struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
658 1.1 tsarna
659 1.1 tsarna tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
660 1.1 tsarna sin->sin_family = AF_INET;
661 1.1 tsarna sin->sin_addr = tmp->ipi_addr;
662 1.1 tsarna sin->sin_port = 0;
663 1.1 tsarna pktp->ipi_ifindex = tmp->ipi_ifindex;
664 1.1 tsarna continue;
665 1.1 tsarna }
666 1.1 tsarna #endif
667 1.1 tsarna
668 1.1 tsarna #ifdef IP_RECVDSTADDR
669 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
670 1.1 tsarna cmptr->cmsg_type == IP_RECVDSTADDR) {
671 1.1 tsarna struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
672 1.1 tsarna
673 1.1 tsarna sin->sin_family = AF_INET;
674 1.1 tsarna sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
675 1.1 tsarna sin->sin_port = 0;
676 1.1 tsarna continue;
677 1.1 tsarna }
678 1.1 tsarna #endif
679 1.1 tsarna
680 1.1 tsarna #ifdef IP_RECVIF
681 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
682 1.1 tsarna cmptr->cmsg_type == IP_RECVIF) {
683 1.1 tsarna struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
684 1.1 tsarna #ifndef HAVE_BROKEN_RECVIF_NAME
685 1.1 tsarna int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
686 1.1 tsarna strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
687 1.1 tsarna #endif
688 1.1 tsarna pktp->ipi_ifindex = sdl->sdl_index;
689 1.1 tsarna #ifdef HAVE_BROKEN_RECVIF_NAME
690 1.1 tsarna if (sdl->sdl_index == 0) {
691 1.1 tsarna pktp->ipi_ifindex = *(uint_t*)sdl;
692 1.1 tsarna }
693 1.1 tsarna #endif
694 1.1 tsarna assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
695 1.1 tsarna // null terminated because of memset above
696 1.1 tsarna continue;
697 1.1 tsarna }
698 1.1 tsarna #endif
699 1.1 tsarna
700 1.1 tsarna #ifdef IP_RECVTTL
701 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
702 1.1 tsarna cmptr->cmsg_type == IP_RECVTTL) {
703 1.1 tsarna *ttl = *(u_char*)CMSG_DATA(cmptr);
704 1.1 tsarna continue;
705 1.1 tsarna }
706 1.1 tsarna else if (cmptr->cmsg_level == IPPROTO_IP &&
707 1.1 tsarna cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
708 1.1 tsarna *ttl = *(int*)CMSG_DATA(cmptr);
709 1.1 tsarna continue;
710 1.1 tsarna }
711 1.1 tsarna #endif
712 1.1 tsarna
713 1.1 tsarna #if defined(IPV6_PKTINFO) && HAVE_IPV6
714 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IPV6 &&
715 1.1 tsarna cmptr->cmsg_type == IPV6_PKTINFO) {
716 1.1 tsarna struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
717 1.1 tsarna struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
718 1.1 tsarna
719 1.1 tsarna sin6->sin6_family = AF_INET6;
720 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
721 1.1 tsarna sin6->sin6_len = sizeof(*sin6);
722 1.1 tsarna #endif
723 1.1 tsarna sin6->sin6_addr = ip6_info->ipi6_addr;
724 1.1 tsarna sin6->sin6_flowinfo = 0;
725 1.1 tsarna sin6->sin6_scope_id = 0;
726 1.1 tsarna sin6->sin6_port = 0;
727 1.1 tsarna pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
728 1.1 tsarna continue;
729 1.1 tsarna }
730 1.1 tsarna #endif
731 1.1 tsarna
732 1.1 tsarna #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
733 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IPV6 &&
734 1.1 tsarna cmptr->cmsg_type == IPV6_HOPLIMIT) {
735 1.1 tsarna *ttl = *(int*)CMSG_DATA(cmptr);
736 1.1 tsarna continue;
737 1.1 tsarna }
738 1.1 tsarna #endif
739 1.1 tsarna assert(0); // unknown ancillary data
740 1.1 tsarna }
741 1.1 tsarna return(n);
742 1.1 tsarna #endif /* CMSG_FIRSTHDR */
743 1.1 tsarna }
744 1.1 tsarna
745 1.1 tsarna // **********************************************************************************************
746 1.1 tsarna
747 1.1 tsarna // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
748 1.1 tsarna // Returns 0 on success, -1 on failure.
749 1.1 tsarna
750 1.1 tsarna #ifdef NOT_HAVE_DAEMON
751 1.1 tsarna #include <fcntl.h>
752 1.1 tsarna #include <sys/stat.h>
753 1.1 tsarna #include <sys/signal.h>
754 1.1 tsarna
755 1.1 tsarna int daemon(int nochdir, int noclose)
756 1.1 tsarna {
757 1.1 tsarna switch (fork())
758 1.1 tsarna {
759 1.1 tsarna case -1: return (-1); // Fork failed
760 1.1 tsarna case 0: break; // Child -- continue
761 1.1 tsarna default: _exit(0); // Parent -- exit
762 1.1 tsarna }
763 1.1 tsarna
764 1.1 tsarna if (setsid() == -1) return(-1);
765 1.1 tsarna
766 1.1 tsarna signal(SIGHUP, SIG_IGN);
767 1.1 tsarna
768 1.1 tsarna switch (fork()) // Fork again, primarily for reasons of Unix trivia
769 1.1 tsarna {
770 1.1 tsarna case -1: return (-1); // Fork failed
771 1.1 tsarna case 0: break; // Child -- continue
772 1.1 tsarna default: _exit(0); // Parent -- exit
773 1.1 tsarna }
774 1.1 tsarna
775 1.1 tsarna if (!nochdir) (void)chdir("/");
776 1.1 tsarna umask(0);
777 1.1 tsarna
778 1.1 tsarna if (!noclose)
779 1.1 tsarna {
780 1.1 tsarna int fd = open("/dev/null", O_RDWR, 0);
781 1.1 tsarna if (fd != -1)
782 1.1 tsarna {
783 1.1 tsarna // Avoid unnecessarily duplicating a file descriptor to itself
784 1.1 tsarna if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
785 1.1 tsarna if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
786 1.1 tsarna if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
787 1.1 tsarna if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
788 1.1 tsarna (void)close (fd);
789 1.1 tsarna }
790 1.1 tsarna }
791 1.1 tsarna return (0);
792 1.1 tsarna }
793 1.1 tsarna #endif /* NOT_HAVE_DAEMON */
794