15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/* -*- Mode: C; tab-width: 4 -*-
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License");
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     http://www.apache.org/licenses/LICENSE-2.0
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS,
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "mDNSUNP.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/uio.h>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ioctl.h>
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   macro, usually defined in <sys/param.h> or someplace like that, to make sure the
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   should be set to the name of the header to include to get the ALIGN(P) macro.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NEED_ALIGN_MACRO
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include NEED_ALIGN_MACRO
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   other platforms don't even have that include file.  So,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if we haven't yet got a definition, let's try to find
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   <sys/sockio.h>.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SIOCGIFCONF
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #include <sys/sockio.h>
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* sockaddr_dl is only referenced if we're using IP_RECVIF,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   so only include the header in that case.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifdef  IP_RECVIF
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #include <net/if_dl.h>
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <net/if_var.h>
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in_var.h>
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netdb.h>
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h>
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Converts a prefix length to IPv6 network mask */
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void plen_to_mask(int plen, char *addr) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int i;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int colons=7; /* Number of colons in IPv6 address */
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int bits_in_block=16; /* Bits per IPv6 block */
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for(i=0;i<=colons;i++) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int block, ones=0xffff, ones_in_block;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (plen>bits_in_block) ones_in_block=bits_in_block;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		else                    ones_in_block=plen;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		block = ones & (ones << (bits_in_block-ones_in_block));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		plen -= ones_in_block;
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		}
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	}
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Gets IPv6 interface information from the /proc filesystem in linux*/
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	{
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	FILE *fp = NULL;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char addr[8][5];
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int flags, myflags, index, plen, scope;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char ifname[9], lastname[IFNAMSIZ];
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char addr6[32+7+1]; /* don't forget the seven ':' */
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct addrinfo hints, *res0;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct sockaddr_in6 *sin6;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct in6_addr *addrptr;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int err;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int sockfd = -1;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct ifreq ifr;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	res0=NULL;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ifihead = NULL;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ifipnext = &ifihead;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	lastname[0] = 0;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (sockfd < 0) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			goto gotError;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		while (fscanf(fp,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					  "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					  addr[0],addr[1],addr[2],addr[3],
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					  addr[4],addr[5],addr[6],addr[7],
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					  &index, &plen, &scope, &flags, ifname) != EOF) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			myflags = 0;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				if (doaliases == 0)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					continue;   /* already processed this interface */
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				myflags = IFI_ALIAS;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			strncpy(lastname, ifname, IFNAMSIZ);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (ifi == NULL) {
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)				goto gotError;
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			}
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			ifipold   = *ifipnext;       /* need this later */
127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			ifiptr    = ifipnext;
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			*ifipnext = ifi;            /* prev points to this new one */
129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)			sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					addr[0],addr[1],addr[2],addr[3],
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)					addr[4],addr[5],addr[6],addr[7]);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* Add address of the interface */
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			memset(&hints, 0, sizeof(hints));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hints.ai_family = AF_INET6;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			hints.ai_flags = AI_NUMERICHOST;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			err = getaddrinfo(addr6, NULL, &hints, &res0);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (err) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				goto gotError;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (ifi->ifi_addr == NULL) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				goto gotError;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* Add netmask of the interface */
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			char ipv6addr[INET6_ADDRSTRLEN];
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			plen_to_mask(plen, ipv6addr);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (ifi->ifi_addr == NULL) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				goto gotError;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			sin6=calloc(1, sizeof(struct sockaddr_in6));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			addrptr=calloc(1, sizeof(struct in6_addr));
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			inet_pton(family, ipv6addr, addrptr);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			sin6->sin6_family=family;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			sin6->sin6_addr=*addrptr;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			sin6->sin6_scope_id=scope;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			free(sin6);
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			/* Add interface name */
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			strncpy(ifi->ifi_name, ifname, IFI_NAME);
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			/* Add interface index */
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			ifi->ifi_index = index;
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			/* Add interface flags*/
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)			if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)				if (errno == EADDRNOTAVAIL) {
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)					/*
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)					 * If the main interface is configured with no IP address but
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)					 * an alias interface exists with an IP address, you get
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)					 * EADDRNOTAVAIL for the main interface
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					 */
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					free(ifi->ifi_addr);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					free(ifi);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					ifipnext  = ifiptr;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					*ifipnext = ifipold;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					continue;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				} else {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					goto gotError;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ifi->ifi_flags = ifr.ifr_flags;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			freeaddrinfo(res0);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			res0=NULL;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	goto done;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	gotError:
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (ifihead != NULL) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		free_ifi_info(ifihead);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ifihead = NULL;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (res0 != NULL) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		freeaddrinfo(res0);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		res0=NULL;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	done:
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (sockfd != -1) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// __ANDROID__ : replaced assert(close(..))
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int sockfd_closed = close(sockfd);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		assert(sockfd_closed == 0);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// __ANDROID__ : if fp was opened, it needs to be closed
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (fp != NULL) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		int fd_closed = fclose(fp);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		assert(fd_closed == 0);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return(ifihead);    /* pointer to first structure in linked list */
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ifi_info *get_ifi_info(int family, int doaliases)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int                 junk;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int                 sockfd, sockf6, len, lastlen, flags, myflags;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NOT_HAVE_IF_NAMETOINDEX
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int                 index = 200;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct ifconf       ifc;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct ifreq        *ifr, ifrcopy;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct sockaddr_in  *sinptr;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct sockaddr_in6 *sinptr6;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	sockfd = -1;
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    sockf6 = -1;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf = NULL;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ifihead = NULL;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (sockfd < 0) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        goto gotError;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    lastlen = 0;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for ( ; ; ) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buf = (char*)malloc(len);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (buf == NULL) {
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            goto gotError;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifc.ifc_len = len;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifc.ifc_buf = buf;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (errno != EINVAL || lastlen != 0) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                goto gotError;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (ifc.ifc_len == lastlen)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;      /* success, len has not changed */
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            lastlen = ifc.ifc_len;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        len += 10 * sizeof(struct ifreq);   /* increment */
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        free(buf);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ifihead = NULL;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ifipnext = &ifihead;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lastname[0] = 0;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* end get_ifi_info1 */
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* include get_ifi_info2 */
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifr = (struct ifreq *) ptr;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Advance to next one in buffer */
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ptr += sizeof(struct ifreq);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ifr->ifr_addr.sa_family != family)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;   /* ignore if not desired address family */
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        myflags = 0;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            *cptr = 0;      /* replace colon will null */
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (doaliases == 0)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                continue;   /* already processed this interface */
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            myflags = IFI_ALIAS;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifrcopy = *ifr;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            goto gotError;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        flags = ifrcopy.ifr_flags;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ((flags & IFF_UP) == 0)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            continue;   /* ignore if interface not up */
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (ifi == NULL) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            goto gotError;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ifipold   = *ifipnext;       /* need this later */
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ifiptr    = ifipnext;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*ifipnext = ifi;             /* prev points to this new one */
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifi->ifi_flags = flags;     /* IFF_xxx values */
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifi->ifi_myflags = myflags; /* IFI_xxx values */
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_IF_NAMETOINDEX
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifi->ifi_index = if_nametoindex(ifr->ifr_name);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifrcopy = *ifr;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SIOCGIFINDEX
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ifi->ifi_index = ifrcopy.ifr_index;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ifi->ifi_index = index++;	/* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ifi->ifi_name[IFI_NAME-1] = '\0';
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* end get_ifi_info2 */
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* include get_ifi_info3 */
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (ifr->ifr_addr.sa_family) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case AF_INET:
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (ifi->ifi_addr == NULL) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (ifi->ifi_addr == NULL) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    goto gotError;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef  SIOCGIFNETMASK
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					if (errno == EADDRNOTAVAIL) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						/*
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						 * If the main interface is configured with no IP address but
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						 * an alias interface exists with an IP address, you get
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						 * EADDRNOTAVAIL for the main interface
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						 */
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						free(ifi->ifi_addr);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						free(ifi);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						ifipnext  = ifiptr;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						*ifipnext = ifipold;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						continue;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					} else {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						goto gotError;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				if (ifi->ifi_netmask == NULL) goto gotError;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_SA_LEN
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				sinptr->sin_len    = sizeof(struct sockaddr_in);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				sinptr->sin_family = AF_INET;
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)				memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
375f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#ifdef  SIOCGIFBRDADDR
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                if (flags & IFF_BROADCAST) {
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        goto gotError;
381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    }
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					/* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NOT_HAVE_SA_LEN
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					sinptr->sin_len    = sizeof( struct sockaddr_in );
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					sinptr->sin_family = AF_INET;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    if (ifi->ifi_brdaddr == NULL) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        goto gotError;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef  SIOCGIFDSTADDR
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (flags & IFF_POINTOPOINT) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        goto gotError;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#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
472gotError:
473    if (ifihead != NULL) {
474        free_ifi_info(ifihead);
475        ifihead = NULL;
476    }
477
478done:
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 */
495void
496free_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
515ssize_t
516recvfrom_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
580struct 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
688int daemon(int nochdir, int noclose)
689    {
690	switch (fork())
691		{
692		case -1: return (-1);	// Fork failed
693		case 0: break;		// Child -- continue
694		default: _exit(0);	// Parent -- exit
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 */
727