]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSPosix/mDNSUNP.c
mDNSResponder-176.2.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / mDNSUNP.c
index 32a016cdd2ba15f13fdc2638afe196667db856aa..852883d7baea669b66b7c78b5984889b686a8f17 100755 (executable)
@@ -2,28 +2,65 @@
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
 
     Change History (most recent first):
 
 $Log: mDNSUNP.c,v $
+Revision 1.36  2008/04/21 18:21:22  mkrochma
+<rdar://problem/5877307> Need to free ifi_netmask
+Submitted by Igor Seleznev
+
+Revision 1.35  2007/11/15 21:36:19  cheshire
+<rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
+
+Revision 1.34  2006/08/14 23:24:47  cheshire
+Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
+
+Revision 1.33  2006/03/13 23:14:21  cheshire
+<rdar://problem/4427969> Compile problems on FreeBSD
+Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
+
+Revision 1.32  2005/12/21 02:56:43  cheshire
+<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
+
+Revision 1.31  2005/12/21 02:46:05  cheshire
+<rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
+
+Revision 1.30  2005/11/29 20:03:02  mkrochma
+Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
+
+Revision 1.29  2005/11/12 02:23:10  cheshire
+<rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
+
+Revision 1.28  2005/10/31 22:09:45  cheshire
+Buffer "char addr6[33]" was seven bytes too small
+
+Revision 1.27  2005/06/29 15:54:21  cheshire
+<rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
+Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
+
+Revision 1.26  2005/04/08 21:43:59  ksekar
+<rdar://problem/4083426>  mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
+Submitted by Andrew de Quincey
+
+Revision 1.25  2005/04/08 21:37:57  ksekar
+<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
+
+Revision 1.24  2005/04/08 21:30:16  ksekar
+<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
+Patch submitted by Bernd Kuhls
+
 Revision 1.23  2004/12/01 04:25:05  cheshire
 <rdar://problem/3872803> Darwin patches for Solaris and Suse
 Provide daemon() for platforms that don't have it
@@ -111,6 +148,15 @@ First checkin
 #include <unistd.h>
 #include <stdio.h>
 
+/* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
+   macro, usually defined in <sys/param.h> or someplace like that, to make sure the
+   CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
+   should be set to the name of the header to include to get the ALIGN(P) macro.
+*/
+#ifdef NEED_ALIGN_MACRO
+#include NEED_ALIGN_MACRO
+#endif
+
 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but 
    other platforms don't even have that include file.  So, 
    if we haven't yet got a definition, let's try to find 
@@ -129,10 +175,136 @@ First checkin
     #include <net/if_dl.h>
 #endif
 
-#if defined(AF_INET6) && HAVE_IPV6
-#include <netinet6/in6_var.h>
+#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+// NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
 #endif
 
+#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
+#include <netdb.h>
+#include <arpa/inet.h>
+
+/* Converts a prefix length to IPv6 network mask */
+void plen_to_mask(int plen, char *addr) {
+       int i;
+       int colons=7; /* Number of colons in IPv6 address */
+       int bits_in_block=16; /* Bits per IPv6 block */
+       for(i=0;i<=colons;i++) {
+               int block, ones=0xffff, ones_in_block;
+               if(plen>bits_in_block) ones_in_block=bits_in_block;
+               else                   ones_in_block=plen;
+               block = ones & (ones << (bits_in_block-ones_in_block));
+               i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
+               plen -= ones_in_block;
+               }
+       }
+
+/* Gets IPv6 interface information from the /proc filesystem in linux*/
+struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases)
+       {
+       struct ifi_info *ifi, *ifihead, **ifipnext;
+       FILE *fp;
+       char addr[8][5];
+       int flags, myflags, index, plen, scope;
+       char ifname[9], lastname[IFNAMSIZ];
+       char addr6[32+7+1]; /* don't forget the seven ':' */
+       struct addrinfo hints, *res0;
+       struct sockaddr_in6 *sin6;
+       struct in6_addr *addrptr;
+       int err;
+
+       res0=NULL;
+       ifihead = NULL;
+       ifipnext = &ifihead;
+       lastname[0] = 0;
+
+       if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
+               while (fscanf(fp,
+                                         "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n",
+                                         addr[0],addr[1],addr[2],addr[3],
+                                         addr[4],addr[5],addr[6],addr[7],
+                                         &index, &plen, &scope, &flags, ifname) != EOF) {
+
+                       myflags = 0;
+                       if (strncmp(lastname, ifname, IFNAMSIZ) == 0) {
+                               if (doaliases == 0)
+                                       continue;   /* already processed this interface */
+                               myflags = IFI_ALIAS;
+                               }
+                       memcpy(lastname, ifname, IFNAMSIZ);
+                       ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
+                       if (ifi == NULL) {
+                               goto gotError;
+                               }
+
+                       *ifipnext = ifi;            /* prev points to this new one */
+                       ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
+
+                       sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
+                                       addr[0],addr[1],addr[2],addr[3],
+                                       addr[4],addr[5],addr[6],addr[7]);
+
+                       /* Add address of the interface */
+                       memset(&hints, 0, sizeof(hints));
+                       hints.ai_family = AF_INET6;
+                       hints.ai_flags = AI_NUMERICHOST;
+                       err = getaddrinfo(addr6, NULL, &hints, &res0);
+                       if (err) {
+                               goto gotError;
+                               }
+                       ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
+                       if (ifi->ifi_addr == NULL) {
+                               goto gotError;
+                               }
+                       memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
+
+                       /* Add netmask of the interface */
+                       char ipv6addr[INET6_ADDRSTRLEN];
+                       plen_to_mask(plen, ipv6addr);
+                       ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
+                       if (ifi->ifi_addr == NULL) {
+                               goto gotError;
+                               }
+                       sin6=calloc(1, sizeof(struct sockaddr_in6));
+                       addrptr=calloc(1, sizeof(struct in6_addr));
+                       inet_pton(family, ipv6addr, addrptr);
+                       sin6->sin6_family=family;
+                       sin6->sin6_addr=*addrptr;
+                       sin6->sin6_scope_id=scope;
+                       memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6));
+                       free(sin6);
+
+
+                       /* Add interface name */
+                       memcpy(ifi->ifi_name, ifname, IFI_NAME);
+
+                       /* Add interface index */
+                       ifi->ifi_index = index;
+
+                       /* If interface is in /proc then it is up*/
+                       ifi->ifi_flags = IFF_UP;
+
+                       freeaddrinfo(res0);
+                       res0=NULL;
+                       }
+               }
+       goto done;
+
+       gotError:
+       if (ifihead != NULL) {
+               free_ifi_info(ifihead);
+               ifihead = NULL;
+               }
+       if (res0 != NULL) {
+               freeaddrinfo(res0);
+               res0=NULL;
+               }
+       done:
+       return(ifihead);    /* pointer to first structure in linked list */
+       }
+#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
+
 struct ifi_info *get_ifi_info(int family, int doaliases)
 {
     int                 junk;
@@ -150,7 +322,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
     struct sockaddr_in6 *sinptr6;
 #endif
 
-    sockfd = -1;
+#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
+ if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
+#endif
+
+       sockfd = -1;
     sockf6 = -1;
     buf = NULL;
     ifihead = NULL;
@@ -190,10 +366,13 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
     for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
         ifr = (struct ifreq *) ptr;
 
-               len = GET_SA_LEN(ifr->ifr_addr);
-        ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
-    
-//        fprintf(stderr, "intf %d name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
+        /* Advance to next one in buffer */
+        if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
+            ptr += sizeof(struct ifreq);
+        else
+            ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
+
+//      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
         
         if (ifr->ifr_addr.sa_family != family)
             continue;   /* ignore if not desired address family */
@@ -230,9 +409,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
         ifi->ifi_index = if_nametoindex(ifr->ifr_name);
 #else
         ifrcopy = *ifr;
+#ifdef SIOCGIFINDEX
                if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
             ifi->ifi_index = ifrcopy.ifr_index;
         else
+#endif
             ifi->ifi_index = index++;  /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
 #endif
         memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
@@ -254,6 +435,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                                ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
                                if (ifi->ifi_netmask == NULL) goto gotError;
                                sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
+                               /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
+#ifndef NOT_HAVE_SA_LEN
+                               sinptr->sin_len    = sizeof(struct sockaddr_in);
+#endif
+                               sinptr->sin_family = AF_INET;
                                memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
 #endif
 
@@ -263,6 +449,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                         goto gotError;
                     }
                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
+                                       /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
+#ifndef NOT_HAVE_SA_LEN
+                                       sinptr->sin_len    = sizeof( struct sockaddr_in );
+#endif
+                                       sinptr->sin_family = AF_INET;
                     ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
                     if (ifi->ifi_brdaddr == NULL) {
                         goto gotError;
@@ -277,6 +468,11 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
                         goto gotError;
                     }
                     sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
+                    /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
+#ifndef NOT_HAVE_SA_LEN
+                                       sinptr->sin_len    = sizeof( struct sockaddr_in );
+#endif
+                                       sinptr->sin_family = AF_INET;
                     ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
                     if (ifi->ifi_dstaddr == NULL) {
                         goto gotError;
@@ -358,6 +554,8 @@ free_ifi_info(struct ifi_info *ifihead)
     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
         if (ifi->ifi_addr != NULL)
             free(ifi->ifi_addr);
+        if (ifi->ifi_netmask != NULL)
+            free(ifi->ifi_netmask);
         if (ifi->ifi_brdaddr != NULL)
             free(ifi->ifi_brdaddr);
         if (ifi->ifi_dstaddr != NULL)
@@ -534,6 +732,8 @@ struct in_pktinfo
 #ifdef NOT_HAVE_DAEMON
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/signal.h>
+
 int daemon(int nochdir, int noclose)
     {
        switch (fork())