File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / arping / src / findif_sysctl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:26:43 2014 UTC (10 years, 1 month ago) by misho
Branches: arping, MAIN
CVS tags: v2_13, HEAD
arping 2.13

    1: /* arping/src/findif_sysctl.c
    2:  *
    3:  *  Copyright (C) 2000-2011 Thomas Habets <thomas@habets.se>
    4:  *
    5:  *  This library is free software; you can redistribute it and/or
    6:  *  modify it under the terms of the GNU General Public
    7:  *  License as published by the Free Software Foundation; either
    8:  *  version 2 of the License, or (at your option) any later version.
    9:  *
   10:  *  This library is distributed in the hope that it will be useful,
   11:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:  *  General Public License for more details.
   14:  *
   15:  *  You should have received a copy of the GNU General Public License along
   16:  *  with this program; if not, write to the Free Software Foundation, Inc.,
   17:  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   18:  */
   19: /**
   20:  * This file should never be used. Systems that are chosen for sysctl()
   21:  * should always have getifaddrs() which is preferred to this.
   22:  */
   23: #if HAVE_CONFIG_H
   24: #include "config.h"
   25: #endif
   26: 
   27: #include <stdio.h>
   28: #include <stdlib.h>
   29: #include <string.h>
   30: #include <errno.h>
   31: #include <netinet/in.h>
   32: #include <arpa/inet.h>
   33: 
   34: #include <sys/types.h>
   35: #include <sys/socket.h>
   36: 
   37: #include <sys/param.h>
   38: #include <sys/sysctl.h>
   39: #include <net/if.h>
   40: #include <net/if_dl.h>
   41: #include <net/route.h>
   42: 
   43: #include "arping.h"
   44: 
   45: #ifndef SALIGN
   46: #define SALIGN (sizeof(int32_t) - 1)
   47: #endif
   48: 
   49: #ifndef SA_SIZE
   50: #define SA_SIZE(sa) ((sa)->sa_len \
   51:                      ? (((sa)->sa_len + SALIGN) & ~SALIGN)\
   52:                      : (SALIGN + 1))
   53: #endif
   54: 
   55: 
   56: /**
   57:  *
   58:  */
   59: const char *
   60: arping_lookupdev(uint32_t srcip,
   61:                  uint32_t dstip,
   62:                  char *ebuf)
   63: {
   64:         int mib[6] = {
   65:                 CTL_NET,
   66:                 PF_ROUTE,
   67:                 0,              /* Protocol */
   68:                 AF_INET,        /* Address family */
   69:                 NET_RT_IFLIST,
   70:                 0
   71:         };
   72:         int c;
   73: 
   74:         /* buffer */
   75:         char *buf, *lim;
   76:         size_t bufsize;
   77: 
   78:         /* Matching interfaces */
   79:         int match_count = 0;
   80: 
   81:         /* best match */
   82:         in_addr_t best_mask = 0;
   83:         struct in_addr best_addr;
   84: 
   85:         /* Results */
   86:         static char ifName[IFNAMSIZ];
   87: 
   88:         /* Allocate buffer and retrieve data. */
   89:         for (c = 0;;) {
   90:                 if (sysctl(mib, 6, NULL, &bufsize, NULL, 0) < 0) {
   91:                         strcpy(ebuf, "sysctl: get buffer size error");
   92:                         goto failed;
   93:                 }
   94:                 if ((buf = malloc(bufsize)) == NULL) {
   95:                         strcpy(ebuf, "malloc: error");
   96:                         goto failed;
   97:                 }
   98:                 if (sysctl(mib, 6, buf, &bufsize, NULL, 0) == 0) {
   99:                         break;
  100:                 }
  101:                 if (errno != ENOMEM || ++c >= 10 ) {
  102:                         strcpy(ebuf, "sysctl: get ifaces error");
  103:                         goto failed;
  104:                 }
  105:                 fprintf(stderr, "sysctl: buffer size changed");
  106:                 free(buf);
  107:         }
  108: 
  109:         lim = buf + bufsize;
  110: 
  111:         /* Loop through all interfaces */
  112:         while (buf < lim) {
  113:                 struct sockaddr_dl *sdl;
  114:                 char  tmpIfName[IFNAMSIZ];
  115:                 int   i;
  116: 
  117:                 struct if_msghdr *ifh = (struct if_msghdr *)buf;
  118:                 if (ifh->ifm_type != RTM_IFINFO) {
  119:                         strcpy(ebuf, "Wrong data in NET_RT_IFLIST");
  120:                         return NULL;
  121:                 }
  122:                 sdl = (struct sockaddr_dl *)(buf +
  123:                                              sizeof(struct if_msghdr) -
  124:                                              sizeof(struct if_data) +
  125:                                              sizeof(struct if_data));
  126: 
  127:                 i = sdl->sdl_nlen < sizeof(ifName)
  128:                         ? sdl->sdl_nlen
  129:                         : (sizeof(tmpIfName)-1);
  130:                 memcpy(tmpIfName, sdl->sdl_data, i);
  131:                 tmpIfName[i] = 0;
  132: 
  133:                 buf += ifh->ifm_msglen;
  134: 
  135:                 /* Loop through all addresses of interface. */
  136:                 while (buf < lim) {
  137:                         struct ifa_msghdr *ifht = (struct ifa_msghdr *)buf;
  138:                         char*  addrptr;
  139:                         struct sockaddr_in *if_addr = NULL;
  140:                         struct sockaddr_in *if_nmsk = NULL;
  141:                         struct sockaddr_in *if_bcst = NULL;
  142:                         in_addr_t mask;
  143: 
  144:                         if (ifht->ifam_type != RTM_NEWADDR) {
  145:                                 break;
  146:                         }
  147: 
  148:                         addrptr = buf + sizeof(struct ifa_msghdr);
  149:                         buf += ifht->ifam_msglen;
  150: 
  151:                         if (ifh->ifm_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) {
  152:                                 continue;
  153:                         }
  154: 
  155:                         /* Loop through all the address attributes. */
  156:                         for (c=1; c < (1<<RTAX_MAX); c<<=1) {
  157:                                 size_t len;
  158:                                 struct sockaddr_in *sa;
  159:                                 sa = addrptr;
  160:                                 switch (c & ifht->ifam_addrs) {
  161:                                 case 0:
  162:                                         continue;
  163:                                 case RTA_NETMASK:
  164:                                         if_nmsk = sa;
  165:                                         break;
  166:                                 case RTA_IFA:
  167:                                         if_addr = sa;
  168:                                         break;
  169:                                 case RTA_BRD:
  170:                                         if_bcst = sa;
  171:                                         break;
  172:                                 }
  173:                                 addrptr += SA_SIZE((struct sockaddr*)sa);
  174:                         }
  175: 
  176:                         if (!if_addr || !if_nmsk || !if_bcst) {
  177:                                 continue;
  178:                         }
  179: 
  180:                         if (if_addr->sin_family != AF_INET) {
  181:                                 continue;
  182:                         }
  183: 
  184:                         if ((dstip & if_nmsk->sin_addr.s_addr)
  185:                             != (if_addr->sin_addr.s_addr
  186:                                 & if_nmsk->sin_addr.s_addr)) {
  187:                                 continue;
  188:                         }
  189: 
  190:                         match_count++;
  191: 
  192:                         if (verbose) {
  193:                                 printf("Specified addr matches "
  194:                                        "interface '%s':\n", tmpIfName);
  195:                                 printf("  IP addr %s, ",
  196:                                        inet_ntoa(if_addr->sin_addr));
  197:                                 printf("mask %s, ",
  198:                                        inet_ntoa(if_nmsk->sin_addr));
  199:                                 printf("bcast %s\n",
  200:                                        inet_ntoa(if_bcst->sin_addr));
  201:                         }
  202: 
  203:                         mask = ntohl(if_nmsk->sin_addr.s_addr);
  204:                         if (mask > best_mask) {
  205:                                 memcpy(ifName,
  206:                                        tmpIfName,
  207:                                        sizeof(ifName));
  208:                                 best_mask = mask;
  209:                                 best_addr = if_addr->sin_addr;
  210:                         }
  211:                 }
  212:         }
  213: 
  214:         if (match_count == 0 ) {
  215:                 if (verbose) {
  216:                         strcpy(ebuf,
  217:                                "No interface found that matches specified IP");
  218:                 }
  219:                 goto failed;
  220:         }
  221: 
  222:         if (verbose && match_count > 1) {
  223:                 printf("Using interface '%s' with src IP %s due to longer "
  224:                        "mask.\n", ifName, inet_ntoa(best_addr));
  225:         }
  226: #if 0
  227:         if (ifce_ip != 0) {
  228:                 *ifce_ip = best_addr.s_addr;
  229:         }
  230: #endif
  231:         return ifName;
  232: 
  233:  failed:
  234: 	return NULL;
  235: }
  236: 
  237: /* ---- Emacs Variables ----
  238:  * Local Variables:
  239:  * c-basic-offset: 8
  240:  * indent-tabs-mode: nil
  241:  * End:
  242:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>