mDNSUNP.c revision 1.4 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.4 pettai */
17 1.1 tsarna
18 1.1 tsarna #include "mDNSUNP.h"
19 1.1 tsarna
20 1.1 tsarna #include <errno.h>
21 1.1 tsarna #include <assert.h>
22 1.1 tsarna #include <string.h>
23 1.1 tsarna #include <stdlib.h>
24 1.1 tsarna #include <sys/uio.h>
25 1.1 tsarna #include <sys/ioctl.h>
26 1.1 tsarna #include <signal.h>
27 1.1 tsarna #include <unistd.h>
28 1.1 tsarna #include <stdio.h>
29 1.1 tsarna
30 1.1 tsarna /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
31 1.1 tsarna macro, usually defined in <sys/param.h> or someplace like that, to make sure the
32 1.1 tsarna CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
33 1.1 tsarna should be set to the name of the header to include to get the ALIGN(P) macro.
34 1.1 tsarna */
35 1.1 tsarna #ifdef NEED_ALIGN_MACRO
36 1.1 tsarna #include NEED_ALIGN_MACRO
37 1.1 tsarna #endif
38 1.1 tsarna
39 1.1 tsarna /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
40 1.1 tsarna other platforms don't even have that include file. So,
41 1.1 tsarna if we haven't yet got a definition, let's try to find
42 1.1 tsarna <sys/sockio.h>.
43 1.1 tsarna */
44 1.1 tsarna
45 1.1 tsarna #ifndef SIOCGIFCONF
46 1.1 tsarna #include <sys/sockio.h>
47 1.1 tsarna #endif
48 1.1 tsarna
49 1.1 tsarna /* sockaddr_dl is only referenced if we're using IP_RECVIF,
50 1.1 tsarna so only include the header in that case.
51 1.1 tsarna */
52 1.1 tsarna
53 1.1 tsarna #ifdef IP_RECVIF
54 1.1 tsarna #include <net/if_dl.h>
55 1.1 tsarna #endif
56 1.1 tsarna
57 1.2 tsarna #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX && !defined(sun)
58 1.2 tsarna #if defined(__FreeBSD__) || defined(__DragonFly__)
59 1.1 tsarna #include <net/if_var.h>
60 1.2 tsarna #endif
61 1.1 tsarna #include <netinet/in_var.h>
62 1.1 tsarna // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
63 1.1 tsarna #endif
64 1.1 tsarna
65 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
66 1.1 tsarna #include <netdb.h>
67 1.1 tsarna #include <arpa/inet.h>
68 1.1 tsarna
69 1.1 tsarna /* Converts a prefix length to IPv6 network mask */
70 1.1 tsarna void plen_to_mask(int plen, char *addr) {
71 1.1 tsarna int i;
72 1.1 tsarna int colons=7; /* Number of colons in IPv6 address */
73 1.1 tsarna int bits_in_block=16; /* Bits per IPv6 block */
74 1.1 tsarna for(i=0;i<=colons;i++) {
75 1.1 tsarna int block, ones=0xffff, ones_in_block;
76 1.4 pettai if (plen>bits_in_block) ones_in_block=bits_in_block;
77 1.4 pettai else ones_in_block=plen;
78 1.1 tsarna block = ones & (ones << (bits_in_block-ones_in_block));
79 1.1 tsarna i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
80 1.1 tsarna plen -= ones_in_block;
81 1.1 tsarna }
82 1.1 tsarna }
83 1.1 tsarna
84 1.1 tsarna /* Gets IPv6 interface information from the /proc filesystem in linux*/
85 1.1 tsarna struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
86 1.1 tsarna {
87 1.1 tsarna struct ifi_info *ifi, *ifihead, **ifipnext;
88 1.1 tsarna FILE *fp;
89 1.1 tsarna char addr[8][5];
90 1.1 tsarna int flags, myflags, index, plen, scope;
91 1.1 tsarna char ifname[9], lastname[IFNAMSIZ];
92 1.1 tsarna char addr6[32+7+1]; /* don't forget the seven ':' */
93 1.1 tsarna struct addrinfo hints, *res0;
94 1.1 tsarna struct sockaddr_in6 *sin6;
95 1.1 tsarna struct in6_addr *addrptr;
96 1.1 tsarna int err;
97 1.1 tsarna
98 1.1 tsarna res0=NULL;
99 1.1 tsarna ifihead = NULL;
100 1.1 tsarna ifipnext = &ifihead;
101 1.1 tsarna lastname[0] = 0;
102 1.1 tsarna
103 1.1 tsarna if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
104 1.1 tsarna while (fscanf(fp,
105 1.1 tsarna "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
106 1.1 tsarna addr[0],addr[1],addr[2],addr[3],
107 1.1 tsarna addr[4],addr[5],addr[6],addr[7],
108 1.1 tsarna &index, &plen, &scope, &flags, ifname) != EOF) {
109 1.1 tsarna
110 1.4 pettai char ipv6addr[INET6_ADDRSTRLEN];
111 1.4 pettai
112 1.1 tsarna myflags = 0;
113 1.1 tsarna if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
114 1.1 tsarna if (doaliases == 0)
115 1.1 tsarna continue; /* already processed this interface */
116 1.1 tsarna myflags = IFI_ALIAS;
117 1.1 tsarna }
118 1.1 tsarna memcpy(lastname, ifname, IFNAMSIZ);
119 1.1 tsarna ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
120 1.1 tsarna if (ifi == NULL) {
121 1.1 tsarna goto gotError;
122 1.1 tsarna }
123 1.1 tsarna
124 1.1 tsarna *ifipnext = ifi; /* prev points to this new one */
125 1.1 tsarna ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
126 1.1 tsarna
127 1.1 tsarna sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
128 1.1 tsarna addr[0],addr[1],addr[2],addr[3],
129 1.1 tsarna addr[4],addr[5],addr[6],addr[7]);
130 1.1 tsarna
131 1.1 tsarna /* Add address of the interface */
132 1.1 tsarna memset(&hints, 0, sizeof(hints));
133 1.1 tsarna hints.ai_family = AF_INET6;
134 1.1 tsarna hints.ai_flags = AI_NUMERICHOST;
135 1.1 tsarna err = getaddrinfo(addr6, NULL, &hints, &res0);
136 1.1 tsarna if (err) {
137 1.1 tsarna goto gotError;
138 1.1 tsarna }
139 1.1 tsarna ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
140 1.1 tsarna if (ifi->ifi_addr == NULL) {
141 1.1 tsarna goto gotError;
142 1.1 tsarna }
143 1.1 tsarna memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
144 1.1 tsarna
145 1.1 tsarna /* Add netmask of the interface */
146 1.1 tsarna plen_to_mask(plen, ipv6addr);
147 1.1 tsarna ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
148 1.1 tsarna if (ifi->ifi_addr == NULL) {
149 1.1 tsarna goto gotError;
150 1.1 tsarna }
151 1.1 tsarna sin6=calloc(1, sizeof(struct sockaddr_in6));
152 1.1 tsarna addrptr=calloc(1, sizeof(struct in6_addr));
153 1.1 tsarna inet_pton(family, ipv6addr, addrptr);
154 1.1 tsarna sin6->sin6_family=family;
155 1.1 tsarna sin6->sin6_addr=*addrptr;
156 1.1 tsarna sin6->sin6_scope_id=scope;
157 1.1 tsarna memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
158 1.1 tsarna free(sin6);
159 1.1 tsarna
160 1.1 tsarna
161 1.1 tsarna /* Add interface name */
162 1.1 tsarna memcpy(ifi->ifi_name, ifname, IFI_NAME);
163 1.1 tsarna
164 1.1 tsarna /* Add interface index */
165 1.1 tsarna ifi->ifi_index = index;
166 1.1 tsarna
167 1.1 tsarna /* If interface is in /proc then it is up*/
168 1.1 tsarna ifi->ifi_flags = IFF_UP;
169 1.1 tsarna
170 1.1 tsarna freeaddrinfo(res0);
171 1.1 tsarna res0=NULL;
172 1.1 tsarna }
173 1.1 tsarna }
174 1.1 tsarna goto done;
175 1.1 tsarna
176 1.1 tsarna gotError:
177 1.1 tsarna if (ifihead != NULL) {
178 1.1 tsarna free_ifi_info(ifihead);
179 1.1 tsarna ifihead = NULL;
180 1.1 tsarna }
181 1.1 tsarna if (res0 != NULL) {
182 1.1 tsarna freeaddrinfo(res0);
183 1.1 tsarna res0=NULL;
184 1.1 tsarna }
185 1.1 tsarna done:
186 1.1 tsarna return(ifihead); /* pointer to first structure in linked list */
187 1.1 tsarna }
188 1.1 tsarna #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
189 1.1 tsarna
190 1.1 tsarna struct ifi_info *get_ifi_info(int family, int doaliases)
191 1.1 tsarna {
192 1.1 tsarna int junk;
193 1.1 tsarna struct ifi_info *ifi, *ifihead, **ifipnext;
194 1.1 tsarna int sockfd, sockf6, len, lastlen, flags, myflags;
195 1.1 tsarna #ifdef NOT_HAVE_IF_NAMETOINDEX
196 1.1 tsarna int index = 200;
197 1.1 tsarna #endif
198 1.1 tsarna char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
199 1.1 tsarna struct ifconf ifc;
200 1.1 tsarna struct ifreq *ifr, ifrcopy;
201 1.1 tsarna struct sockaddr_in *sinptr;
202 1.1 tsarna
203 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6
204 1.1 tsarna struct sockaddr_in6 *sinptr6;
205 1.1 tsarna #endif
206 1.1 tsarna
207 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
208 1.4 pettai if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
209 1.1 tsarna #endif
210 1.1 tsarna
211 1.1 tsarna sockfd = -1;
212 1.1 tsarna sockf6 = -1;
213 1.1 tsarna buf = NULL;
214 1.1 tsarna ifihead = NULL;
215 1.1 tsarna
216 1.1 tsarna sockfd = socket(AF_INET, SOCK_DGRAM, 0);
217 1.1 tsarna if (sockfd < 0) {
218 1.1 tsarna goto gotError;
219 1.1 tsarna }
220 1.1 tsarna
221 1.1 tsarna lastlen = 0;
222 1.1 tsarna len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
223 1.1 tsarna for ( ; ; ) {
224 1.1 tsarna buf = (char*)malloc(len);
225 1.1 tsarna if (buf == NULL) {
226 1.1 tsarna goto gotError;
227 1.1 tsarna }
228 1.1 tsarna ifc.ifc_len = len;
229 1.1 tsarna ifc.ifc_buf = buf;
230 1.1 tsarna if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
231 1.1 tsarna if (errno != EINVAL || lastlen != 0) {
232 1.1 tsarna goto gotError;
233 1.1 tsarna }
234 1.1 tsarna } else {
235 1.1 tsarna if (ifc.ifc_len == lastlen)
236 1.1 tsarna break; /* success, len has not changed */
237 1.1 tsarna lastlen = ifc.ifc_len;
238 1.1 tsarna }
239 1.1 tsarna len += 10 * sizeof(struct ifreq); /* increment */
240 1.1 tsarna free(buf);
241 1.1 tsarna }
242 1.1 tsarna ifihead = NULL;
243 1.1 tsarna ifipnext = &ifihead;
244 1.1 tsarna lastname[0] = 0;
245 1.1 tsarna /* end get_ifi_info1 */
246 1.1 tsarna
247 1.1 tsarna /* include get_ifi_info2 */
248 1.1 tsarna for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
249 1.1 tsarna ifr = (struct ifreq *) ptr;
250 1.1 tsarna
251 1.1 tsarna /* Advance to next one in buffer */
252 1.1 tsarna if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
253 1.1 tsarna ptr += sizeof(struct ifreq);
254 1.1 tsarna else
255 1.1 tsarna ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
256 1.1 tsarna
257 1.1 tsarna // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
258 1.1 tsarna
259 1.1 tsarna if (ifr->ifr_addr.sa_family != family)
260 1.1 tsarna continue; /* ignore if not desired address family */
261 1.1 tsarna
262 1.1 tsarna myflags = 0;
263 1.1 tsarna if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
264 1.1 tsarna *cptr = 0; /* replace colon will null */
265 1.1 tsarna if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
266 1.1 tsarna if (doaliases == 0)
267 1.1 tsarna continue; /* already processed this interface */
268 1.1 tsarna myflags = IFI_ALIAS;
269 1.1 tsarna }
270 1.1 tsarna memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
271 1.1 tsarna
272 1.1 tsarna ifrcopy = *ifr;
273 1.1 tsarna if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
274 1.1 tsarna goto gotError;
275 1.1 tsarna }
276 1.1 tsarna
277 1.1 tsarna flags = ifrcopy.ifr_flags;
278 1.1 tsarna if ((flags & IFF_UP) == 0)
279 1.1 tsarna continue; /* ignore if interface not up */
280 1.1 tsarna
281 1.3 roy /* Skip addresses we can't use */
282 1.3 roy #ifdef SIOCGIFAFLAG_IN6
283 1.3 roy if (ifr->ifr_addr.sa_family == AF_INET6) {
284 1.3 roy struct in6_ifreq ifr6;
285 1.3 roy
286 1.3 roy if (sockf6 == -1)
287 1.3 roy sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
288 1.3 roy memset(&ifr6, 0, sizeof(ifr6));
289 1.3 roy memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name));
290 1.3 roy memcpy(&ifr6.ifr_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_addr));
291 1.3 roy if (ioctl(sockf6, SIOCGIFAFLAG_IN6, &ifr6) < 0)
292 1.3 roy goto gotError;
293 1.3 roy if (ifr6.ifr_ifru.ifru_flags6 &
294 1.3 roy (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))
295 1.3 roy continue;
296 1.3 roy }
297 1.3 roy #endif
298 1.3 roy
299 1.1 tsarna ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
300 1.1 tsarna if (ifi == NULL) {
301 1.1 tsarna goto gotError;
302 1.1 tsarna }
303 1.1 tsarna *ifipnext = ifi; /* prev points to this new one */
304 1.1 tsarna ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
305 1.1 tsarna
306 1.1 tsarna ifi->ifi_flags = flags; /* IFF_xxx values */
307 1.1 tsarna ifi->ifi_myflags = myflags; /* IFI_xxx values */
308 1.1 tsarna #ifndef NOT_HAVE_IF_NAMETOINDEX
309 1.1 tsarna ifi->ifi_index = if_nametoindex(ifr->ifr_name);
310 1.1 tsarna #else
311 1.1 tsarna ifrcopy = *ifr;
312 1.1 tsarna #ifdef SIOCGIFINDEX
313 1.1 tsarna if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
314 1.1 tsarna ifi->ifi_index = ifrcopy.ifr_index;
315 1.1 tsarna else
316 1.1 tsarna #endif
317 1.1 tsarna ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
318 1.1 tsarna #endif
319 1.1 tsarna memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
320 1.1 tsarna ifi->ifi_name[IFI_NAME-1] = '\0';
321 1.1 tsarna /* end get_ifi_info2 */
322 1.1 tsarna /* include get_ifi_info3 */
323 1.1 tsarna switch (ifr->ifr_addr.sa_family) {
324 1.1 tsarna case AF_INET:
325 1.1 tsarna sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
326 1.1 tsarna if (ifi->ifi_addr == NULL) {
327 1.1 tsarna ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
328 1.1 tsarna if (ifi->ifi_addr == NULL) {
329 1.1 tsarna goto gotError;
330 1.1 tsarna }
331 1.1 tsarna memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
332 1.1 tsarna
333 1.1 tsarna #ifdef SIOCGIFNETMASK
334 1.1 tsarna if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) goto gotError;
335 1.1 tsarna ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
336 1.1 tsarna if (ifi->ifi_netmask == NULL) goto gotError;
337 1.1 tsarna sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
338 1.1 tsarna /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
339 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
340 1.1 tsarna sinptr->sin_len = sizeof(struct sockaddr_in);
341 1.1 tsarna #endif
342 1.1 tsarna sinptr->sin_family = AF_INET;
343 1.1 tsarna memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
344 1.1 tsarna #endif
345 1.1 tsarna
346 1.1 tsarna #ifdef SIOCGIFBRDADDR
347 1.1 tsarna if (flags & IFF_BROADCAST) {
348 1.1 tsarna if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
349 1.1 tsarna goto gotError;
350 1.1 tsarna }
351 1.1 tsarna sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
352 1.1 tsarna /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
353 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
354 1.1 tsarna sinptr->sin_len = sizeof( struct sockaddr_in );
355 1.1 tsarna #endif
356 1.1 tsarna sinptr->sin_family = AF_INET;
357 1.1 tsarna ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
358 1.1 tsarna if (ifi->ifi_brdaddr == NULL) {
359 1.1 tsarna goto gotError;
360 1.1 tsarna }
361 1.1 tsarna memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
362 1.1 tsarna }
363 1.1 tsarna #endif
364 1.1 tsarna
365 1.1 tsarna #ifdef SIOCGIFDSTADDR
366 1.1 tsarna if (flags & IFF_POINTOPOINT) {
367 1.1 tsarna if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
368 1.1 tsarna goto gotError;
369 1.1 tsarna }
370 1.1 tsarna sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
371 1.1 tsarna /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
372 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
373 1.1 tsarna sinptr->sin_len = sizeof( struct sockaddr_in );
374 1.1 tsarna #endif
375 1.1 tsarna sinptr->sin_family = AF_INET;
376 1.1 tsarna ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
377 1.1 tsarna if (ifi->ifi_dstaddr == NULL) {
378 1.1 tsarna goto gotError;
379 1.1 tsarna }
380 1.1 tsarna memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
381 1.1 tsarna }
382 1.1 tsarna #endif
383 1.1 tsarna }
384 1.1 tsarna break;
385 1.1 tsarna
386 1.1 tsarna #if defined(AF_INET6) && HAVE_IPV6
387 1.1 tsarna case AF_INET6:
388 1.1 tsarna sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
389 1.1 tsarna if (ifi->ifi_addr == NULL) {
390 1.1 tsarna ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
391 1.1 tsarna if (ifi->ifi_addr == NULL) {
392 1.1 tsarna goto gotError;
393 1.1 tsarna }
394 1.1 tsarna
395 1.1 tsarna /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
396 1.1 tsarna /* We need to strip that out */
397 1.1 tsarna if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
398 1.1 tsarna sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
399 1.1 tsarna memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
400 1.1 tsarna
401 1.1 tsarna #ifdef SIOCGIFNETMASK_IN6
402 1.1 tsarna {
403 1.1 tsarna struct in6_ifreq ifr6;
404 1.1 tsarna if (sockf6 == -1)
405 1.1 tsarna sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
406 1.1 tsarna memset(&ifr6, 0, sizeof(ifr6));
407 1.1 tsarna memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
408 1.1 tsarna memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
409 1.1 tsarna if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError;
410 1.1 tsarna ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
411 1.1 tsarna if (ifi->ifi_netmask == NULL) goto gotError;
412 1.1 tsarna sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
413 1.1 tsarna memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
414 1.1 tsarna }
415 1.1 tsarna #endif
416 1.1 tsarna }
417 1.1 tsarna break;
418 1.1 tsarna #endif
419 1.1 tsarna
420 1.1 tsarna default:
421 1.1 tsarna break;
422 1.1 tsarna }
423 1.1 tsarna }
424 1.1 tsarna goto done;
425 1.1 tsarna
426 1.1 tsarna gotError:
427 1.1 tsarna if (ifihead != NULL) {
428 1.1 tsarna free_ifi_info(ifihead);
429 1.1 tsarna ifihead = NULL;
430 1.1 tsarna }
431 1.1 tsarna
432 1.1 tsarna done:
433 1.1 tsarna if (buf != NULL) {
434 1.1 tsarna free(buf);
435 1.1 tsarna }
436 1.1 tsarna if (sockfd != -1) {
437 1.1 tsarna junk = close(sockfd);
438 1.1 tsarna assert(junk == 0);
439 1.1 tsarna }
440 1.1 tsarna if (sockf6 != -1) {
441 1.1 tsarna junk = close(sockf6);
442 1.1 tsarna assert(junk == 0);
443 1.1 tsarna }
444 1.1 tsarna return(ifihead); /* pointer to first structure in linked list */
445 1.1 tsarna }
446 1.1 tsarna /* end get_ifi_info3 */
447 1.1 tsarna
448 1.1 tsarna /* include free_ifi_info */
449 1.1 tsarna void
450 1.1 tsarna free_ifi_info(struct ifi_info *ifihead)
451 1.1 tsarna {
452 1.1 tsarna struct ifi_info *ifi, *ifinext;
453 1.1 tsarna
454 1.1 tsarna for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
455 1.1 tsarna if (ifi->ifi_addr != NULL)
456 1.1 tsarna free(ifi->ifi_addr);
457 1.1 tsarna if (ifi->ifi_netmask != NULL)
458 1.1 tsarna free(ifi->ifi_netmask);
459 1.1 tsarna if (ifi->ifi_brdaddr != NULL)
460 1.1 tsarna free(ifi->ifi_brdaddr);
461 1.1 tsarna if (ifi->ifi_dstaddr != NULL)
462 1.1 tsarna free(ifi->ifi_dstaddr);
463 1.1 tsarna ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
464 1.1 tsarna free(ifi); /* the ifi_info{} itself */
465 1.1 tsarna }
466 1.1 tsarna }
467 1.1 tsarna /* end free_ifi_info */
468 1.1 tsarna
469 1.1 tsarna ssize_t
470 1.1 tsarna recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
471 1.1 tsarna struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
472 1.1 tsarna {
473 1.1 tsarna struct msghdr msg;
474 1.1 tsarna struct iovec iov[1];
475 1.1 tsarna ssize_t n;
476 1.1 tsarna
477 1.1 tsarna #ifdef CMSG_FIRSTHDR
478 1.1 tsarna struct cmsghdr *cmptr;
479 1.1 tsarna union {
480 1.1 tsarna struct cmsghdr cm;
481 1.1 tsarna char control[1024];
482 1.1 tsarna } control_un;
483 1.1 tsarna
484 1.1 tsarna *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
485 1.1 tsarna
486 1.1 tsarna msg.msg_control = control_un.control;
487 1.1 tsarna msg.msg_controllen = sizeof(control_un.control);
488 1.1 tsarna msg.msg_flags = 0;
489 1.1 tsarna #else
490 1.1 tsarna memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */
491 1.1 tsarna #endif /* CMSG_FIRSTHDR */
492 1.1 tsarna
493 1.1 tsarna msg.msg_name = (char *) sa;
494 1.1 tsarna msg.msg_namelen = *salenptr;
495 1.1 tsarna iov[0].iov_base = (char *)ptr;
496 1.1 tsarna iov[0].iov_len = nbytes;
497 1.1 tsarna msg.msg_iov = iov;
498 1.1 tsarna msg.msg_iovlen = 1;
499 1.1 tsarna
500 1.1 tsarna if ( (n = recvmsg(fd, &msg, *flagsp)) < 0)
501 1.1 tsarna return(n);
502 1.1 tsarna
503 1.1 tsarna *salenptr = msg.msg_namelen; /* pass back results */
504 1.1 tsarna if (pktp) {
505 1.1 tsarna /* 0.0.0.0, i/f = -1 */
506 1.1 tsarna /* We set the interface to -1 so that the caller can
507 1.1 tsarna tell whether we returned a meaningful value or
508 1.1 tsarna just some default. Previously this code just
509 1.1 tsarna set the value to 0, but I'm concerned that 0
510 1.1 tsarna might be a valid interface value.
511 1.1 tsarna */
512 1.1 tsarna memset(pktp, 0, sizeof(struct my_in_pktinfo));
513 1.1 tsarna pktp->ipi_ifindex = -1;
514 1.1 tsarna }
515 1.1 tsarna /* end recvfrom_flags1 */
516 1.1 tsarna
517 1.1 tsarna /* include recvfrom_flags2 */
518 1.1 tsarna #ifndef CMSG_FIRSTHDR
519 1.1 tsarna #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
520 1.1 tsarna *flagsp = 0; /* pass back results */
521 1.1 tsarna return(n);
522 1.1 tsarna #else
523 1.1 tsarna
524 1.1 tsarna *flagsp = msg.msg_flags; /* pass back results */
525 1.1 tsarna if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) ||
526 1.1 tsarna (msg.msg_flags & MSG_CTRUNC) || pktp == NULL)
527 1.1 tsarna return(n);
528 1.1 tsarna
529 1.1 tsarna for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
530 1.1 tsarna cmptr = CMSG_NXTHDR(&msg, cmptr)) {
531 1.1 tsarna
532 1.1 tsarna #ifdef IP_PKTINFO
533 1.1 tsarna #if in_pktinfo_definition_is_missing
534 1.1 tsarna struct in_pktinfo
535 1.1 tsarna {
536 1.1 tsarna int ipi_ifindex;
537 1.1 tsarna struct in_addr ipi_spec_dst;
538 1.1 tsarna struct in_addr ipi_addr;
539 1.1 tsarna };
540 1.1 tsarna #endif
541 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
542 1.1 tsarna cmptr->cmsg_type == IP_PKTINFO) {
543 1.1 tsarna struct in_pktinfo *tmp;
544 1.1 tsarna struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
545 1.1 tsarna
546 1.1 tsarna tmp = (struct in_pktinfo *) CMSG_DATA(cmptr);
547 1.1 tsarna sin->sin_family = AF_INET;
548 1.1 tsarna sin->sin_addr = tmp->ipi_addr;
549 1.1 tsarna sin->sin_port = 0;
550 1.1 tsarna pktp->ipi_ifindex = tmp->ipi_ifindex;
551 1.1 tsarna continue;
552 1.1 tsarna }
553 1.1 tsarna #endif
554 1.1 tsarna
555 1.1 tsarna #ifdef IP_RECVDSTADDR
556 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
557 1.1 tsarna cmptr->cmsg_type == IP_RECVDSTADDR) {
558 1.1 tsarna struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr;
559 1.1 tsarna
560 1.1 tsarna sin->sin_family = AF_INET;
561 1.1 tsarna sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr);
562 1.1 tsarna sin->sin_port = 0;
563 1.1 tsarna continue;
564 1.1 tsarna }
565 1.1 tsarna #endif
566 1.1 tsarna
567 1.1 tsarna #ifdef IP_RECVIF
568 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
569 1.1 tsarna cmptr->cmsg_type == IP_RECVIF) {
570 1.1 tsarna struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr);
571 1.1 tsarna #ifndef HAVE_BROKEN_RECVIF_NAME
572 1.1 tsarna int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1);
573 1.1 tsarna strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen);
574 1.1 tsarna #endif
575 1.1 tsarna pktp->ipi_ifindex = sdl->sdl_index;
576 1.1 tsarna #ifdef HAVE_BROKEN_RECVIF_NAME
577 1.1 tsarna if (sdl->sdl_index == 0) {
578 1.1 tsarna pktp->ipi_ifindex = *(uint_t*)sdl;
579 1.1 tsarna }
580 1.1 tsarna #endif
581 1.1 tsarna assert(pktp->ipi_ifname[IFI_NAME - 1] == 0);
582 1.1 tsarna // null terminated because of memset above
583 1.1 tsarna continue;
584 1.1 tsarna }
585 1.1 tsarna #endif
586 1.1 tsarna
587 1.1 tsarna #ifdef IP_RECVTTL
588 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IP &&
589 1.1 tsarna cmptr->cmsg_type == IP_RECVTTL) {
590 1.1 tsarna *ttl = *(u_char*)CMSG_DATA(cmptr);
591 1.1 tsarna continue;
592 1.1 tsarna }
593 1.1 tsarna else if (cmptr->cmsg_level == IPPROTO_IP &&
594 1.1 tsarna cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
595 1.1 tsarna *ttl = *(int*)CMSG_DATA(cmptr);
596 1.1 tsarna continue;
597 1.1 tsarna }
598 1.1 tsarna #endif
599 1.1 tsarna
600 1.1 tsarna #if defined(IPV6_PKTINFO) && HAVE_IPV6
601 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IPV6 &&
602 1.1 tsarna cmptr->cmsg_type == IPV6_PKTINFO) {
603 1.1 tsarna struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr;
604 1.1 tsarna struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr);
605 1.1 tsarna
606 1.1 tsarna sin6->sin6_family = AF_INET6;
607 1.1 tsarna #ifndef NOT_HAVE_SA_LEN
608 1.1 tsarna sin6->sin6_len = sizeof(*sin6);
609 1.1 tsarna #endif
610 1.1 tsarna sin6->sin6_addr = ip6_info->ipi6_addr;
611 1.1 tsarna sin6->sin6_flowinfo = 0;
612 1.1 tsarna sin6->sin6_scope_id = 0;
613 1.1 tsarna sin6->sin6_port = 0;
614 1.1 tsarna pktp->ipi_ifindex = ip6_info->ipi6_ifindex;
615 1.1 tsarna continue;
616 1.1 tsarna }
617 1.1 tsarna #endif
618 1.1 tsarna
619 1.1 tsarna #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
620 1.1 tsarna if (cmptr->cmsg_level == IPPROTO_IPV6 &&
621 1.1 tsarna cmptr->cmsg_type == IPV6_HOPLIMIT) {
622 1.1 tsarna *ttl = *(int*)CMSG_DATA(cmptr);
623 1.1 tsarna continue;
624 1.1 tsarna }
625 1.1 tsarna #endif
626 1.1 tsarna assert(0); // unknown ancillary data
627 1.1 tsarna }
628 1.1 tsarna return(n);
629 1.1 tsarna #endif /* CMSG_FIRSTHDR */
630 1.1 tsarna }
631 1.1 tsarna
632 1.1 tsarna // **********************************************************************************************
633 1.1 tsarna
634 1.1 tsarna // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
635 1.1 tsarna // Returns 0 on success, -1 on failure.
636 1.1 tsarna
637 1.1 tsarna #ifdef NOT_HAVE_DAEMON
638 1.1 tsarna #include <fcntl.h>
639 1.1 tsarna #include <sys/stat.h>
640 1.1 tsarna #include <sys/signal.h>
641 1.1 tsarna
642 1.1 tsarna int daemon(int nochdir, int noclose)
643 1.1 tsarna {
644 1.1 tsarna switch (fork())
645 1.1 tsarna {
646 1.1 tsarna case -1: return (-1); // Fork failed
647 1.1 tsarna case 0: break; // Child -- continue
648 1.1 tsarna default: _exit(0); // Parent -- exit
649 1.1 tsarna }
650 1.1 tsarna
651 1.1 tsarna if (setsid() == -1) return(-1);
652 1.1 tsarna
653 1.1 tsarna signal(SIGHUP, SIG_IGN);
654 1.1 tsarna
655 1.1 tsarna switch (fork()) // Fork again, primarily for reasons of Unix trivia
656 1.1 tsarna {
657 1.1 tsarna case -1: return (-1); // Fork failed
658 1.1 tsarna case 0: break; // Child -- continue
659 1.1 tsarna default: _exit(0); // Parent -- exit
660 1.1 tsarna }
661 1.1 tsarna
662 1.1 tsarna if (!nochdir) (void)chdir("/");
663 1.1 tsarna umask(0);
664 1.1 tsarna
665 1.1 tsarna if (!noclose)
666 1.1 tsarna {
667 1.1 tsarna int fd = open("/dev/null", O_RDWR, 0);
668 1.1 tsarna if (fd != -1)
669 1.1 tsarna {
670 1.1 tsarna // Avoid unnecessarily duplicating a file descriptor to itself
671 1.1 tsarna if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO);
672 1.1 tsarna if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO);
673 1.1 tsarna if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO);
674 1.1 tsarna if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
675 1.1 tsarna (void)close (fd);
676 1.1 tsarna }
677 1.1 tsarna }
678 1.1 tsarna return (0);
679 1.1 tsarna }
680 1.1 tsarna #endif /* NOT_HAVE_DAEMON */
681