File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / arping / src / findif_sysctl.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 18 13:16:10 2016 UTC (7 years, 8 months ago) by misho
Branches: arping, MAIN
CVS tags: v2_21, v2_15_cross, v2_15, HEAD
arping v2.15

    1: /* arping/src/findif_sysctl.c
    2:  *
    3:  *  Copyright (C) 2000-2014 Thomas Habets <thomas@habets.se>
    4:  *
    5:  *  This program is free software; you can redistribute it and/or modify
    6:  *  it under the terms of the GNU General Public License as published by
    7:  *  the Free Software Foundation; either version 2 of the License, or
    8:  *  (at your option) any later version.
    9:  *
   10:  *  This program 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
   13:  *  GNU 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: #if HAVE_LIBNET_H
   44: #include <libnet.h>
   45: #endif
   46: 
   47: #include "arping.h"
   48: 
   49: #ifndef SALIGN
   50: #define SALIGN (sizeof(int32_t) - 1)
   51: #endif
   52: 
   53: #ifndef SA_SIZE
   54: #define SA_SIZE(sa) ((sa)->sa_len \
   55:                      ? (((sa)->sa_len + SALIGN) & ~SALIGN)\
   56:                      : (SALIGN + 1))
   57: #endif
   58: 
   59: 
   60: /**
   61:  *
   62:  */
   63: const char *
   64: arping_lookupdev(uint32_t srcip,
   65:                  uint32_t dstip,
   66:                  char *ebuf)
   67: {
   68:         int mib[6] = {
   69:                 CTL_NET,
   70:                 PF_ROUTE,
   71:                 0,              /* Protocol */
   72:                 AF_INET,        /* Address family */
   73:                 NET_RT_IFLIST,
   74:                 0
   75:         };
   76:         int c;
   77: 
   78:         /* buffer */
   79:         char *buf_memory = NULL;
   80:         char *lim;
   81:         size_t bufsize;
   82: 
   83:         /* Matching interfaces */
   84:         int match_count = 0;
   85: 
   86:         /* best match */
   87:         in_addr_t best_mask = 0;
   88:         struct in_addr best_addr;
   89: 
   90:         /* Results */
   91:         static char ifName[IFNAMSIZ];
   92:         *ebuf = 0;
   93: 
   94:         /* Allocate buffer and retrieve data. */
   95:         for (c = 0;;) {
   96:                 if (sysctl(mib, 6, NULL, &bufsize, NULL, 0) < 0) {
   97:                         snprintf(ebuf, LIBNET_ERRBUF_SIZE,
   98:                                  "sysctl: get buffer size error: %s",
   99:                                  strerror(errno));
  100:                         goto failed;
  101:                 }
  102:                 if ((buf_memory = malloc(bufsize)) == NULL) {
  103:                         snprintf(ebuf, LIBNET_ERRBUF_SIZE,
  104:                                  "malloc: error: %s", strerror(errno));
  105:                         goto failed;
  106:                 }
  107:                 if (sysctl(mib, 6, buf_memory, &bufsize, NULL, 0) == 0) {
  108:                         break;
  109:                 }
  110:                 if (errno != ENOMEM || ++c >= 10 ) {
  111:                         snprintf(ebuf, LIBNET_ERRBUF_SIZE,
  112:                                  "sysctl: get ifaces error: %s",
  113:                                  strerror(errno));
  114:                         goto failed;
  115:                 }
  116:                 if (verbose > 2) {
  117:                         printf("sysctl: buffer size changed.");
  118:                 }
  119:                 free(buf_memory);
  120:                 buf_memory = NULL;
  121:         }
  122: 
  123:         const char* buf = buf_memory;
  124:         lim = buf + bufsize;
  125: 
  126:         /* Loop through all interfaces */
  127:         while (buf < lim) {
  128:                 struct sockaddr_dl *sdl;
  129:                 char  tmpIfName[IFNAMSIZ];
  130:                 int   i;
  131: 
  132:                 struct if_msghdr *ifh = (struct if_msghdr *)buf;
  133:                 if (ifh->ifm_type != RTM_IFINFO) {
  134:                         snprintf(ebuf, LIBNET_ERRBUF_SIZE,
  135:                                  "Wrong data in NET_RT_IFLIST.");
  136:                         return NULL;
  137:                 }
  138:                 sdl = (struct sockaddr_dl *)(buf +
  139:                                              sizeof(struct if_msghdr) -
  140:                                              sizeof(struct if_data) +
  141:                                              sizeof(struct if_data));
  142: 
  143:                 i = sdl->sdl_nlen < sizeof(ifName)
  144:                         ? sdl->sdl_nlen
  145:                         : (sizeof(tmpIfName)-1);
  146:                 memcpy(tmpIfName, sdl->sdl_data, i);
  147:                 tmpIfName[i] = 0;
  148: 
  149:                 buf += ifh->ifm_msglen;
  150: 
  151:                 /* Loop through all addresses of interface. */
  152:                 while (buf < lim) {
  153:                         struct ifa_msghdr *ifht = (struct ifa_msghdr *)buf;
  154:                         char*  addrptr;
  155:                         struct sockaddr_in *if_addr = NULL;
  156:                         struct sockaddr_in *if_nmsk = NULL;
  157:                         struct sockaddr_in *if_bcst = NULL;
  158:                         in_addr_t mask;
  159: 
  160:                         if (ifht->ifam_type != RTM_NEWADDR) {
  161:                                 break;
  162:                         }
  163: 
  164:                         addrptr = buf + sizeof(struct ifa_msghdr);
  165:                         buf += ifht->ifam_msglen;
  166: 
  167:                         if (ifh->ifm_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) {
  168:                                 continue;
  169:                         }
  170: 
  171:                         /* Loop through all the address attributes. */
  172:                         for (c=1; c < (1<<RTAX_MAX); c<<=1) {
  173:                                 size_t len;
  174:                                 struct sockaddr_in *sa;
  175:                                 sa = addrptr;
  176:                                 switch (c & ifht->ifam_addrs) {
  177:                                 case 0:
  178:                                         continue;
  179:                                 case RTA_NETMASK:
  180:                                         if_nmsk = sa;
  181:                                         break;
  182:                                 case RTA_IFA:
  183:                                         if_addr = sa;
  184:                                         break;
  185:                                 case RTA_BRD:
  186:                                         if_bcst = sa;
  187:                                         break;
  188:                                 }
  189:                                 addrptr += SA_SIZE((struct sockaddr*)sa);
  190:                         }
  191: 
  192:                         if (!if_addr || !if_nmsk || !if_bcst) {
  193:                                 continue;
  194:                         }
  195: 
  196:                         if (if_addr->sin_family != AF_INET) {
  197:                                 continue;
  198:                         }
  199: 
  200:                         if ((dstip & if_nmsk->sin_addr.s_addr)
  201:                             != (if_addr->sin_addr.s_addr
  202:                                 & if_nmsk->sin_addr.s_addr)) {
  203:                                 continue;
  204:                         }
  205: 
  206:                         match_count++;
  207: 
  208:                         if (verbose > 1) {
  209:                                 printf("Specified addr matches "
  210:                                        "interface '%s':\n", tmpIfName);
  211:                                 printf("  IP addr %s, ",
  212:                                        inet_ntoa(if_addr->sin_addr));
  213:                                 printf("mask %s, ",
  214:                                        inet_ntoa(if_nmsk->sin_addr));
  215:                                 printf("bcast %s\n",
  216:                                        inet_ntoa(if_bcst->sin_addr));
  217:                         }
  218: 
  219:                         mask = ntohl(if_nmsk->sin_addr.s_addr);
  220:                         if (mask > best_mask) {
  221:                                 memcpy(ifName,
  222:                                        tmpIfName,
  223:                                        sizeof(ifName));
  224:                                 best_mask = mask;
  225:                                 best_addr = if_addr->sin_addr;
  226:                         }
  227:                 }
  228:         }
  229: 
  230:         if (match_count == 0 ) {
  231:                 if (verbose) {
  232:                         snprintf(ebuf, LIBNET_ERRBUF_SIZE,
  233:                                  "No interface found that matches"
  234:                                  " specified IP.");
  235:                 }
  236:                 goto failed;
  237:         }
  238: 
  239:         if (verbose && match_count > 1) {
  240:                 printf("arping: Using interface '%s' with src IP %s due "
  241:                        "to longer mask.\n", ifName, inet_ntoa(best_addr));
  242:         }
  243: #if 0
  244:         if (ifce_ip != 0) {
  245:                 *ifce_ip = best_addr.s_addr;
  246:         }
  247: #endif
  248:         free(buf_memory);
  249:         return ifName;
  250: 
  251:  failed:
  252:         free(buf_memory);
  253: 	return NULL;
  254: }
  255: 
  256: /* ---- Emacs Variables ----
  257:  * Local Variables:
  258:  * c-basic-offset: 8
  259:  * indent-tabs-mode: nil
  260:  * End:
  261:  */

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