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