Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 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; |
Dave Platt | 54bbef0 | 2014-03-25 12:18:59 -0700 | [diff] [blame] | 86 | FILE *fp = NULL; |
Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 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 | } |
Nick Kralevich | 8d61c6e | 2012-07-11 14:30:39 -0700 | [diff] [blame] | 120 | strncpy(lastname, ifname, IFNAMSIZ); |
Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 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 */ |
Nick Kralevich | 8d61c6e | 2012-07-11 14:30:39 -0700 | [diff] [blame] | 167 | strncpy(ifi->ifi_name, ifname, IFI_NAME); |
Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 168 | |
| 169 | /* Add interface index */ |
| 170 | ifi->ifi_index = index; |
| 171 | |
| 172 | /* Add interface flags*/ |
Nick Kralevich | 8d61c6e | 2012-07-11 14:30:39 -0700 | [diff] [blame] | 173 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 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) { |
Dave Platt | f48f8a2 | 2014-03-18 19:01:04 -0700 | [diff] [blame] | 208 | // __ANDROID__ : replaced assert(close(..)) |
| 209 | int sockfd_closed = close(sockfd); |
| 210 | assert(sockfd_closed == 0); |
Dave Platt | 54bbef0 | 2014-03-25 12:18:59 -0700 | [diff] [blame] | 211 | } |
| 212 | // __ANDROID__ : if fp was opened, it needs to be closed |
| 213 | if (fp != NULL) { |
| 214 | int fd_closed = fclose(fp); |
| 215 | assert(fd_closed == 0); |
| 216 | } |
Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 217 | return(ifihead); /* pointer to first structure in linked list */ |
| 218 | } |
| 219 | #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX |
| 220 | |
| 221 | struct ifi_info *get_ifi_info(int family, int doaliases) |
| 222 | { |
| 223 | int junk; |
| 224 | struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; |
| 225 | int sockfd, sockf6, len, lastlen, flags, myflags; |
| 226 | #ifdef NOT_HAVE_IF_NAMETOINDEX |
| 227 | int index = 200; |
| 228 | #endif |
| 229 | char *ptr, *buf, lastname[IFNAMSIZ], *cptr; |
| 230 | struct ifconf ifc; |
| 231 | struct ifreq *ifr, ifrcopy; |
| 232 | struct sockaddr_in *sinptr; |
| 233 | |
| 234 | #if defined(AF_INET6) && HAVE_IPV6 |
| 235 | struct sockaddr_in6 *sinptr6; |
| 236 | #endif |
| 237 | |
| 238 | #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX |
| 239 | if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases); |
| 240 | #endif |
| 241 | |
| 242 | sockfd = -1; |
| 243 | sockf6 = -1; |
| 244 | buf = NULL; |
| 245 | ifihead = NULL; |
| 246 | |
| 247 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); |
| 248 | if (sockfd < 0) { |
| 249 | goto gotError; |
| 250 | } |
| 251 | |
| 252 | lastlen = 0; |
| 253 | len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ |
| 254 | for ( ; ; ) { |
| 255 | buf = (char*)malloc(len); |
| 256 | if (buf == NULL) { |
| 257 | goto gotError; |
| 258 | } |
| 259 | ifc.ifc_len = len; |
| 260 | ifc.ifc_buf = buf; |
| 261 | if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { |
| 262 | if (errno != EINVAL || lastlen != 0) { |
| 263 | goto gotError; |
| 264 | } |
| 265 | } else { |
| 266 | if (ifc.ifc_len == lastlen) |
| 267 | break; /* success, len has not changed */ |
| 268 | lastlen = ifc.ifc_len; |
| 269 | } |
| 270 | len += 10 * sizeof(struct ifreq); /* increment */ |
| 271 | free(buf); |
| 272 | } |
| 273 | ifihead = NULL; |
| 274 | ifipnext = &ifihead; |
| 275 | lastname[0] = 0; |
| 276 | /* end get_ifi_info1 */ |
| 277 | |
| 278 | /* include get_ifi_info2 */ |
| 279 | for (ptr = buf; ptr < buf + ifc.ifc_len; ) { |
| 280 | ifr = (struct ifreq *) ptr; |
| 281 | |
| 282 | /* Advance to next one in buffer */ |
| 283 | if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr)) |
| 284 | ptr += sizeof(struct ifreq); |
| 285 | else |
| 286 | ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr); |
| 287 | |
| 288 | // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family); |
| 289 | |
| 290 | if (ifr->ifr_addr.sa_family != family) |
| 291 | continue; /* ignore if not desired address family */ |
| 292 | |
| 293 | myflags = 0; |
| 294 | if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) |
| 295 | *cptr = 0; /* replace colon will null */ |
| 296 | if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { |
| 297 | if (doaliases == 0) |
| 298 | continue; /* already processed this interface */ |
| 299 | myflags = IFI_ALIAS; |
| 300 | } |
| 301 | memcpy(lastname, ifr->ifr_name, IFNAMSIZ); |
| 302 | |
| 303 | ifrcopy = *ifr; |
| 304 | if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) { |
| 305 | goto gotError; |
| 306 | } |
| 307 | |
| 308 | flags = ifrcopy.ifr_flags; |
| 309 | if ((flags & IFF_UP) == 0) |
| 310 | continue; /* ignore if interface not up */ |
| 311 | |
| 312 | ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); |
| 313 | if (ifi == NULL) { |
| 314 | goto gotError; |
| 315 | } |
| 316 | ifipold = *ifipnext; /* need this later */ |
| 317 | ifiptr = ifipnext; |
| 318 | *ifipnext = ifi; /* prev points to this new one */ |
| 319 | ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ |
| 320 | |
| 321 | ifi->ifi_flags = flags; /* IFF_xxx values */ |
| 322 | ifi->ifi_myflags = myflags; /* IFI_xxx values */ |
| 323 | #ifndef NOT_HAVE_IF_NAMETOINDEX |
| 324 | ifi->ifi_index = if_nametoindex(ifr->ifr_name); |
| 325 | #else |
| 326 | ifrcopy = *ifr; |
| 327 | #ifdef SIOCGIFINDEX |
| 328 | if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy)) |
| 329 | ifi->ifi_index = ifrcopy.ifr_index; |
| 330 | else |
| 331 | #endif |
| 332 | ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */ |
| 333 | #endif |
| 334 | memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); |
| 335 | ifi->ifi_name[IFI_NAME-1] = '\0'; |
| 336 | /* end get_ifi_info2 */ |
| 337 | /* include get_ifi_info3 */ |
| 338 | switch (ifr->ifr_addr.sa_family) { |
| 339 | case AF_INET: |
| 340 | sinptr = (struct sockaddr_in *) &ifr->ifr_addr; |
| 341 | if (ifi->ifi_addr == NULL) { |
| 342 | ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); |
| 343 | if (ifi->ifi_addr == NULL) { |
| 344 | goto gotError; |
| 345 | } |
| 346 | memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in)); |
| 347 | |
| 348 | #ifdef SIOCGIFNETMASK |
| 349 | if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) { |
| 350 | if (errno == EADDRNOTAVAIL) { |
| 351 | /* |
| 352 | * If the main interface is configured with no IP address but |
| 353 | * an alias interface exists with an IP address, you get |
| 354 | * EADDRNOTAVAIL for the main interface |
| 355 | */ |
| 356 | free(ifi->ifi_addr); |
| 357 | free(ifi); |
| 358 | ifipnext = ifiptr; |
| 359 | *ifipnext = ifipold; |
| 360 | continue; |
| 361 | } else { |
| 362 | goto gotError; |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); |
| 367 | if (ifi->ifi_netmask == NULL) goto gotError; |
| 368 | sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr; |
| 369 | /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ |
| 370 | #ifndef NOT_HAVE_SA_LEN |
| 371 | sinptr->sin_len = sizeof(struct sockaddr_in); |
| 372 | #endif |
| 373 | sinptr->sin_family = AF_INET; |
| 374 | memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in)); |
| 375 | #endif |
| 376 | |
| 377 | #ifdef SIOCGIFBRDADDR |
| 378 | if (flags & IFF_BROADCAST) { |
| 379 | if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) { |
| 380 | goto gotError; |
| 381 | } |
| 382 | sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; |
| 383 | /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ |
| 384 | #ifndef NOT_HAVE_SA_LEN |
| 385 | sinptr->sin_len = sizeof( struct sockaddr_in ); |
| 386 | #endif |
| 387 | sinptr->sin_family = AF_INET; |
| 388 | ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); |
| 389 | if (ifi->ifi_brdaddr == NULL) { |
| 390 | goto gotError; |
| 391 | } |
| 392 | memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in)); |
| 393 | } |
| 394 | #endif |
| 395 | |
| 396 | #ifdef SIOCGIFDSTADDR |
| 397 | if (flags & IFF_POINTOPOINT) { |
| 398 | if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) { |
| 399 | goto gotError; |
| 400 | } |
| 401 | sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; |
| 402 | /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */ |
| 403 | #ifndef NOT_HAVE_SA_LEN |
| 404 | sinptr->sin_len = sizeof( struct sockaddr_in ); |
| 405 | #endif |
| 406 | sinptr->sin_family = AF_INET; |
| 407 | ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in)); |
| 408 | if (ifi->ifi_dstaddr == NULL) { |
| 409 | goto gotError; |
| 410 | } |
| 411 | memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in)); |
| 412 | } |
| 413 | #endif |
| 414 | } |
| 415 | break; |
| 416 | |
| 417 | #if defined(AF_INET6) && HAVE_IPV6 |
| 418 | case AF_INET6: |
| 419 | sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr; |
| 420 | if (ifi->ifi_addr == NULL) { |
| 421 | ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); |
| 422 | if (ifi->ifi_addr == NULL) { |
| 423 | goto gotError; |
| 424 | } |
| 425 | |
| 426 | /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */ |
| 427 | /* We need to strip that out */ |
| 428 | if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr)) |
| 429 | sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0; |
| 430 | memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6)); |
| 431 | |
| 432 | #ifdef SIOCGIFNETMASK_IN6 |
| 433 | { |
| 434 | struct in6_ifreq ifr6; |
| 435 | if (sockf6 == -1) |
| 436 | sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); |
| 437 | memset(&ifr6, 0, sizeof(ifr6)); |
| 438 | memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); |
| 439 | memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); |
| 440 | if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) { |
| 441 | if (errno == EADDRNOTAVAIL) { |
| 442 | /* |
| 443 | * If the main interface is configured with no IP address but |
| 444 | * an alias interface exists with an IP address, you get |
| 445 | * EADDRNOTAVAIL for the main interface |
| 446 | */ |
| 447 | free(ifi->ifi_addr); |
| 448 | free(ifi); |
| 449 | ifipnext = ifiptr; |
| 450 | *ifipnext = ifipold; |
| 451 | continue; |
| 452 | } else { |
| 453 | goto gotError; |
| 454 | } |
| 455 | } |
| 456 | ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6)); |
| 457 | if (ifi->ifi_netmask == NULL) goto gotError; |
| 458 | sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr; |
| 459 | memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6)); |
| 460 | } |
| 461 | #endif |
| 462 | } |
| 463 | break; |
| 464 | #endif |
| 465 | |
| 466 | default: |
| 467 | break; |
| 468 | } |
| 469 | } |
| 470 | goto done; |
| 471 | |
| 472 | gotError: |
| 473 | if (ifihead != NULL) { |
| 474 | free_ifi_info(ifihead); |
| 475 | ifihead = NULL; |
| 476 | } |
| 477 | |
| 478 | done: |
| 479 | if (buf != NULL) { |
| 480 | free(buf); |
| 481 | } |
| 482 | if (sockfd != -1) { |
| 483 | junk = close(sockfd); |
| 484 | assert(junk == 0); |
| 485 | } |
| 486 | if (sockf6 != -1) { |
| 487 | junk = close(sockf6); |
| 488 | assert(junk == 0); |
| 489 | } |
| 490 | return(ifihead); /* pointer to first structure in linked list */ |
| 491 | } |
| 492 | /* end get_ifi_info3 */ |
| 493 | |
| 494 | /* include free_ifi_info */ |
| 495 | void |
| 496 | free_ifi_info(struct ifi_info *ifihead) |
| 497 | { |
| 498 | struct ifi_info *ifi, *ifinext; |
| 499 | |
| 500 | for (ifi = ifihead; ifi != NULL; ifi = ifinext) { |
| 501 | if (ifi->ifi_addr != NULL) |
| 502 | free(ifi->ifi_addr); |
| 503 | if (ifi->ifi_netmask != NULL) |
| 504 | free(ifi->ifi_netmask); |
| 505 | if (ifi->ifi_brdaddr != NULL) |
| 506 | free(ifi->ifi_brdaddr); |
| 507 | if (ifi->ifi_dstaddr != NULL) |
| 508 | free(ifi->ifi_dstaddr); |
| 509 | ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */ |
| 510 | free(ifi); /* the ifi_info{} itself */ |
| 511 | } |
| 512 | } |
| 513 | /* end free_ifi_info */ |
| 514 | |
| 515 | ssize_t |
| 516 | recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, |
| 517 | struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl) |
| 518 | { |
| 519 | struct msghdr msg; |
| 520 | struct iovec iov[1]; |
| 521 | ssize_t n; |
| 522 | |
| 523 | #ifdef CMSG_FIRSTHDR |
| 524 | struct cmsghdr *cmptr; |
| 525 | union { |
| 526 | struct cmsghdr cm; |
| 527 | char control[1024]; |
| 528 | } control_un; |
| 529 | |
| 530 | *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be |
| 531 | |
| 532 | msg.msg_control = control_un.control; |
| 533 | msg.msg_controllen = sizeof(control_un.control); |
| 534 | msg.msg_flags = 0; |
| 535 | #else |
| 536 | memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ |
| 537 | #endif /* CMSG_FIRSTHDR */ |
| 538 | |
| 539 | msg.msg_name = (char *) sa; |
| 540 | msg.msg_namelen = *salenptr; |
| 541 | iov[0].iov_base = (char *)ptr; |
| 542 | iov[0].iov_len = nbytes; |
| 543 | msg.msg_iov = iov; |
| 544 | msg.msg_iovlen = 1; |
| 545 | |
| 546 | if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) |
| 547 | return(n); |
| 548 | |
| 549 | *salenptr = msg.msg_namelen; /* pass back results */ |
| 550 | if (pktp) { |
| 551 | /* 0.0.0.0, i/f = -1 */ |
| 552 | /* We set the interface to -1 so that the caller can |
| 553 | tell whether we returned a meaningful value or |
| 554 | just some default. Previously this code just |
| 555 | set the value to 0, but I'm concerned that 0 |
| 556 | might be a valid interface value. |
| 557 | */ |
| 558 | memset(pktp, 0, sizeof(struct my_in_pktinfo)); |
| 559 | pktp->ipi_ifindex = -1; |
| 560 | } |
| 561 | /* end recvfrom_flags1 */ |
| 562 | |
| 563 | /* include recvfrom_flags2 */ |
| 564 | #ifndef CMSG_FIRSTHDR |
| 565 | #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. |
| 566 | *flagsp = 0; /* pass back results */ |
| 567 | return(n); |
| 568 | #else |
| 569 | |
| 570 | *flagsp = msg.msg_flags; /* pass back results */ |
| 571 | if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || |
| 572 | (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) |
| 573 | return(n); |
| 574 | |
| 575 | for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; |
| 576 | cmptr = CMSG_NXTHDR(&msg, cmptr)) { |
| 577 | |
| 578 | #ifdef IP_PKTINFO |
| 579 | #if in_pktinfo_definition_is_missing |
| 580 | struct in_pktinfo |
| 581 | { |
| 582 | int ipi_ifindex; |
| 583 | struct in_addr ipi_spec_dst; |
| 584 | struct in_addr ipi_addr; |
| 585 | }; |
| 586 | #endif |
| 587 | if (cmptr->cmsg_level == IPPROTO_IP && |
| 588 | cmptr->cmsg_type == IP_PKTINFO) { |
| 589 | struct in_pktinfo *tmp; |
| 590 | struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; |
| 591 | |
| 592 | tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); |
| 593 | sin->sin_family = AF_INET; |
| 594 | sin->sin_addr = tmp->ipi_addr; |
| 595 | sin->sin_port = 0; |
| 596 | pktp->ipi_ifindex = tmp->ipi_ifindex; |
| 597 | continue; |
| 598 | } |
| 599 | #endif |
| 600 | |
| 601 | #ifdef IP_RECVDSTADDR |
| 602 | if (cmptr->cmsg_level == IPPROTO_IP && |
| 603 | cmptr->cmsg_type == IP_RECVDSTADDR) { |
| 604 | struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; |
| 605 | |
| 606 | sin->sin_family = AF_INET; |
| 607 | sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); |
| 608 | sin->sin_port = 0; |
| 609 | continue; |
| 610 | } |
| 611 | #endif |
| 612 | |
| 613 | #ifdef IP_RECVIF |
| 614 | if (cmptr->cmsg_level == IPPROTO_IP && |
| 615 | cmptr->cmsg_type == IP_RECVIF) { |
| 616 | struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); |
| 617 | #ifndef HAVE_BROKEN_RECVIF_NAME |
| 618 | int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); |
| 619 | strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); |
| 620 | #endif |
| 621 | pktp->ipi_ifindex = sdl->sdl_index; |
| 622 | #ifdef HAVE_BROKEN_RECVIF_NAME |
| 623 | if (sdl->sdl_index == 0) { |
| 624 | pktp->ipi_ifindex = *(uint_t*)sdl; |
| 625 | } |
| 626 | #endif |
| 627 | assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); |
| 628 | // null terminated because of memset above |
| 629 | continue; |
| 630 | } |
| 631 | #endif |
| 632 | |
| 633 | #ifdef IP_RECVTTL |
| 634 | if (cmptr->cmsg_level == IPPROTO_IP && |
| 635 | cmptr->cmsg_type == IP_RECVTTL) { |
| 636 | *ttl = *(u_char*)CMSG_DATA(cmptr); |
| 637 | continue; |
| 638 | } |
| 639 | else if (cmptr->cmsg_level == IPPROTO_IP && |
| 640 | cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL |
| 641 | *ttl = *(int*)CMSG_DATA(cmptr); |
| 642 | continue; |
| 643 | } |
| 644 | #endif |
| 645 | |
| 646 | #if defined(IPV6_PKTINFO) && HAVE_IPV6 |
| 647 | if (cmptr->cmsg_level == IPPROTO_IPV6 && |
| 648 | cmptr->cmsg_type == IPV6_2292_PKTINFO) { |
| 649 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; |
| 650 | struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); |
| 651 | |
| 652 | sin6->sin6_family = AF_INET6; |
| 653 | #ifndef NOT_HAVE_SA_LEN |
| 654 | sin6->sin6_len = sizeof(*sin6); |
| 655 | #endif |
| 656 | sin6->sin6_addr = ip6_info->ipi6_addr; |
| 657 | sin6->sin6_flowinfo = 0; |
| 658 | sin6->sin6_scope_id = 0; |
| 659 | sin6->sin6_port = 0; |
| 660 | pktp->ipi_ifindex = ip6_info->ipi6_ifindex; |
| 661 | continue; |
| 662 | } |
| 663 | #endif |
| 664 | |
| 665 | #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 |
| 666 | if (cmptr->cmsg_level == IPPROTO_IPV6 && |
| 667 | cmptr->cmsg_type == IPV6_2292_HOPLIMIT) { |
| 668 | *ttl = *(int*)CMSG_DATA(cmptr); |
| 669 | continue; |
| 670 | } |
| 671 | #endif |
| 672 | assert(0); // unknown ancillary data |
| 673 | } |
| 674 | return(n); |
| 675 | #endif /* CMSG_FIRSTHDR */ |
| 676 | } |
| 677 | |
| 678 | // ********************************************************************************************** |
| 679 | |
| 680 | // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4. |
| 681 | // Returns 0 on success, -1 on failure. |
| 682 | |
| 683 | #ifdef NOT_HAVE_DAEMON |
| 684 | #include <fcntl.h> |
| 685 | #include <sys/stat.h> |
| 686 | #include <sys/signal.h> |
| 687 | |
| 688 | int daemon(int nochdir, int noclose) |
| 689 | { |
| 690 | switch (fork()) |
| 691 | { |
| 692 | case -1: return (-1); // Fork failed |
Robert Greenwalt | dd52342 | 2012-03-29 14:43:07 -0700 | [diff] [blame] | 693 | case 0: break; // Child -- continue |
| 694 | default: _exit(0); // Parent -- exit |
Robert Greenwalt | 47e4ceb | 2012-03-26 15:36:57 -0700 | [diff] [blame] | 695 | } |
| 696 | |
| 697 | if (setsid() == -1) return(-1); |
| 698 | |
| 699 | signal(SIGHUP, SIG_IGN); |
| 700 | |
| 701 | switch (fork()) // Fork again, primarily for reasons of Unix trivia |
| 702 | { |
| 703 | case -1: return (-1); // Fork failed |
| 704 | case 0: break; // Child -- continue |
| 705 | default: _exit(0); // Parent -- exit |
| 706 | } |
| 707 | |
| 708 | if (!nochdir) (void)chdir("/"); |
| 709 | umask(0); |
| 710 | |
| 711 | if (!noclose) |
| 712 | { |
| 713 | int fd = open("/dev/null", O_RDWR, 0); |
| 714 | if (fd != -1) |
| 715 | { |
| 716 | // Avoid unnecessarily duplicating a file descriptor to itself |
| 717 | if (fd != STDIN_FILENO) (void)dup2(fd, STDIN_FILENO); |
| 718 | if (fd != STDOUT_FILENO) (void)dup2(fd, STDOUT_FILENO); |
| 719 | if (fd != STDERR_FILENO) (void)dup2(fd, STDERR_FILENO); |
| 720 | if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) |
| 721 | (void)close (fd); |
| 722 | } |
| 723 | } |
| 724 | return (0); |
| 725 | } |
| 726 | #endif /* NOT_HAVE_DAEMON */ |