root/source3/lib/interfaces.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. make_netmask
  2. make_bcast_or_net
  3. make_bcast
  4. make_net
  5. _get_interfaces
  6. iface_comp
  7. get_interfaces

   1 /*
   2    Unix SMB/CIFS implementation.
   3    return a list of network interfaces
   4    Copyright (C) Andrew Tridgell 1998
   5    Copyright (C) Jeremy Allison 2007
   6 
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11 
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16 
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 
  23 /****************************************************************************
  24  Create a struct sockaddr_storage with the netmask bits set to 1.
  25 ****************************************************************************/
  26 
  27 bool make_netmask(struct sockaddr_storage *pss_out,
     /* [<][>][^][v][top][bottom][index][help] */
  28                         const struct sockaddr_storage *pss_in,
  29                         unsigned long masklen)
  30 {
  31         *pss_out = *pss_in;
  32         /* Now apply masklen bits of mask. */
  33 #if defined(HAVE_IPV6)
  34         if (pss_in->ss_family == AF_INET6) {
  35                 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
  36                 unsigned int i;
  37 
  38                 if (masklen > 128) {
  39                         return false;
  40                 }
  41                 for (i = 0; masklen >= 8; masklen -= 8, i++) {
  42                         *p++ = 0xff;
  43                 }
  44                 /* Deal with the partial byte. */
  45                 *p++ &= (0xff & ~(0xff>>masklen));
  46                 i++;
  47                 for (;i < sizeof(struct in6_addr); i++) {
  48                         *p++ = '\0';
  49                 }
  50                 return true;
  51         }
  52 #endif
  53         if (pss_in->ss_family == AF_INET) {
  54                 if (masklen > 32) {
  55                         return false;
  56                 }
  57                 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
  58                         htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
  59                 return true;
  60         }
  61         return false;
  62 }
  63 
  64 /****************************************************************************
  65  Create a struct sockaddr_storage set to the broadcast or network adress from
  66  an incoming sockaddr_storage.
  67 ****************************************************************************/
  68 
  69 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
     /* [<][>][^][v][top][bottom][index][help] */
  70                         const struct sockaddr_storage *pss_in,
  71                         const struct sockaddr_storage *nmask,
  72                         bool make_bcast_p)
  73 {
  74         unsigned int i = 0, len = 0;
  75         char *pmask = NULL;
  76         char *p = NULL;
  77         *pss_out = *pss_in;
  78 
  79         /* Set all zero netmask bits to 1. */
  80 #if defined(HAVE_IPV6)
  81         if (pss_in->ss_family == AF_INET6) {
  82                 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
  83                 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
  84                 len = 16;
  85         }
  86 #endif
  87         if (pss_in->ss_family == AF_INET) {
  88                 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
  89                 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
  90                 len = 4;
  91         }
  92 
  93         for (i = 0; i < len; i++, p++, pmask++) {
  94                 if (make_bcast_p) {
  95                         *p = (*p & *pmask) | (*pmask ^ 0xff);
  96                 } else {
  97                         /* make_net */
  98                         *p = (*p & *pmask);
  99                 }
 100         }
 101 }
 102 
 103 void make_bcast(struct sockaddr_storage *pss_out,
     /* [<][>][^][v][top][bottom][index][help] */
 104                         const struct sockaddr_storage *pss_in,
 105                         const struct sockaddr_storage *nmask)
 106 {
 107         make_bcast_or_net(pss_out, pss_in, nmask, true);
 108 }
 109 
 110 void make_net(struct sockaddr_storage *pss_out,
     /* [<][>][^][v][top][bottom][index][help] */
 111                         const struct sockaddr_storage *pss_in,
 112                         const struct sockaddr_storage *nmask)
 113 {
 114         make_bcast_or_net(pss_out, pss_in, nmask, false);
 115 }
 116 
 117 /****************************************************************************
 118  Try the "standard" getifaddrs/freeifaddrs interfaces.
 119  Also gets IPv6 interfaces.
 120 ****************************************************************************/
 121 
 122 /****************************************************************************
 123  Get the netmask address for a local interface.
 124 ****************************************************************************/
 125 
 126 static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
     /* [<][>][^][v][top][bottom][index][help] */
 127 {
 128         struct iface_struct *ifaces;
 129         struct ifaddrs *iflist = NULL;
 130         struct ifaddrs *ifptr = NULL;
 131         int count;
 132         int total = 0;
 133         size_t copy_size;
 134 
 135         if (getifaddrs(&iflist) < 0) {
 136                 return -1;
 137         }
 138 
 139         count = 0;
 140         for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
 141                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
 142                         continue;
 143                 }
 144                 if (!(ifptr->ifa_flags & IFF_UP)) {
 145                         continue;
 146                 }
 147                 count += 1;
 148         }
 149 
 150         ifaces = talloc_array(mem_ctx, struct iface_struct, count);
 151         if (ifaces == NULL) {
 152                 errno = ENOMEM;
 153                 return -1;
 154         }
 155 
 156         /* Loop through interfaces, looking for given IP address */
 157         for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
 158 
 159                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
 160                         continue;
 161                 }
 162 
 163                 /* Check the interface is up. */
 164                 if (!(ifptr->ifa_flags & IFF_UP)) {
 165                         continue;
 166                 }
 167 
 168                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
 169 
 170                 copy_size = sizeof(struct sockaddr_in);
 171 
 172                 ifaces[total].flags = ifptr->ifa_flags;
 173 
 174 #if defined(HAVE_IPV6)
 175                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
 176                         copy_size = sizeof(struct sockaddr_in6);
 177                 }
 178 #endif
 179 
 180                 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
 181                 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
 182 
 183                 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
 184                         make_bcast(&ifaces[total].bcast,
 185                                 &ifaces[total].ip,
 186                                 &ifaces[total].netmask);
 187                 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
 188                                ifptr->ifa_dstaddr ) {
 189                         memcpy(&ifaces[total].bcast,
 190                                 ifptr->ifa_dstaddr,
 191                                 copy_size);
 192                 } else {
 193                         continue;
 194                 }
 195 
 196                 strlcpy(ifaces[total].name, ifptr->ifa_name,
 197                         sizeof(ifaces[total].name));
 198                 total++;
 199         }
 200 
 201         freeifaddrs(iflist);
 202 
 203         *pifaces = ifaces;
 204         return total;
 205 }
 206 
 207 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
     /* [<][>][^][v][top][bottom][index][help] */
 208 {
 209         int r;
 210 
 211 #if defined(HAVE_IPV6)
 212         /*
 213          * If we have IPv6 - sort these interfaces lower
 214          * than any IPv4 ones.
 215          */
 216         if (i1->ip.ss_family == AF_INET6 &&
 217                         i2->ip.ss_family == AF_INET) {
 218                 return -1;
 219         } else if (i1->ip.ss_family == AF_INET &&
 220                         i2->ip.ss_family == AF_INET6) {
 221                 return 1;
 222         }
 223 
 224         if (i1->ip.ss_family == AF_INET6) {
 225                 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
 226                 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
 227 
 228                 r = memcmp(&s1->sin6_addr,
 229                                 &s2->sin6_addr,
 230                                 sizeof(struct in6_addr));
 231                 if (r) {
 232                         return r;
 233                 }
 234 
 235                 s1 = (struct sockaddr_in6 *)&i1->netmask;
 236                 s2 = (struct sockaddr_in6 *)&i2->netmask;
 237 
 238                 r = memcmp(&s1->sin6_addr,
 239                                 &s2->sin6_addr,
 240                                 sizeof(struct in6_addr));
 241                 if (r) {
 242                         return r;
 243                 }
 244         }
 245 #endif
 246 
 247         /* AIX uses __ss_family instead of ss_family inside of
 248            sockaddr_storage. Instead of trying to figure out which field to
 249            use, we can just cast it to a sockaddr.
 250          */
 251 
 252         if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
 253                 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
 254                 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
 255 
 256                 r = ntohl(s1->sin_addr.s_addr) -
 257                         ntohl(s2->sin_addr.s_addr);
 258                 if (r) {
 259                         return r;
 260                 }
 261 
 262                 s1 = (struct sockaddr_in *)&i1->netmask;
 263                 s2 = (struct sockaddr_in *)&i2->netmask;
 264 
 265                 return ntohl(s1->sin_addr.s_addr) -
 266                         ntohl(s2->sin_addr.s_addr);
 267         }
 268         return 0;
 269 }
 270 
 271 /* this wrapper is used to remove duplicates from the interface list generated
 272    above */
 273 int get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
     /* [<][>][^][v][top][bottom][index][help] */
 274 {
 275         struct iface_struct *ifaces;
 276         int total, i, j;
 277 
 278         total = _get_interfaces(mem_ctx, &ifaces);
 279         if (total <= 0) return total;
 280 
 281         /* now we need to remove duplicates */
 282         qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
 283 
 284         for (i=1;i<total;) {
 285                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
 286                         for (j=i-1;j<total-1;j++) {
 287                                 ifaces[j] = ifaces[j+1];
 288                         }
 289                         total--;
 290                 } else {
 291                         i++;
 292                 }
 293         }
 294 
 295         *pifaces = ifaces;
 296         return total;
 297 }
 298 

/* [<][>][^][v][top][bottom][index][help] */