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