Annotation of embedaddon/libnet/src/libnet_if_addr.c, revision 1.1
1.1 ! misho 1: /*
! 2: * $Id: libnet_if_addr.c,v 1.22 2004/03/04 20:51:07 kkuehl Exp $
! 3: *
! 4: * libnet
! 5: * libnet_if_addr.c - interface selection code
! 6: *
! 7: * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
! 8: * All rights reserved.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 29: * SUCH DAMAGE.
! 30: *
! 31: */
! 32:
! 33: #if (HAVE_CONFIG_H)
! 34: #include "../include/config.h"
! 35: #endif
! 36: #if (!(_WIN32) || (__CYGWIN__))
! 37: #include "../include/libnet.h"
! 38: #else
! 39: #include "../include/win32/libnet.h"
! 40: #endif
! 41: #ifdef HAVE_SYS_SOCKIO_H
! 42: #include <sys/sockio.h>
! 43: #endif
! 44: #include "../include/ifaddrlist.h"
! 45:
! 46: #define MAX_IPADDR 512
! 47:
! 48: #if !(__WIN32__)
! 49:
! 50: /*
! 51: * By testing if we can retrieve the FLAGS of an iface
! 52: * we can know if it exists or not and if it is up.
! 53: */
! 54: int
! 55: libnet_check_iface(libnet_t *l)
! 56: {
! 57: struct ifreq ifr;
! 58: int fd, res;
! 59:
! 60: fd = socket(AF_INET, SOCK_DGRAM, 0);
! 61: if (fd < 0)
! 62: {
! 63: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s() socket: %s\n", __func__,
! 64: strerror(errno));
! 65: return (-1);
! 66: }
! 67:
! 68: strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) -1);
! 69: ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
! 70:
! 71: res = ioctl(fd, SIOCGIFFLAGS, (int8_t *)&ifr);
! 72:
! 73: if (res < 0)
! 74: {
! 75: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s() ioctl: %s\n", __func__,
! 76: strerror(errno));
! 77: }
! 78: else
! 79: {
! 80: if ((ifr.ifr_flags & IFF_UP) == 0)
! 81: {
! 82: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): %s is down\n",
! 83: __func__, l->device);
! 84: res = -1;
! 85: }
! 86: }
! 87: close(fd);
! 88: return (res);
! 89: }
! 90:
! 91:
! 92: /*
! 93: * Return the interface list
! 94: */
! 95:
! 96: #ifdef HAVE_SOCKADDR_SA_LEN
! 97: #define NEXTIFR(i) \
! 98: ((struct ifreq *)((u_char *)&i->ifr_addr + i->ifr_addr.sa_len))
! 99: #else
! 100: #define NEXTIFR(i) (i + 1)
! 101: #endif
! 102:
! 103: #ifndef BUFSIZE
! 104: #define BUFSIZE 2048
! 105: #endif
! 106:
! 107: #ifdef HAVE_LINUX_PROCFS
! 108: #define PROC_DEV_FILE "/proc/net/dev"
! 109: #endif
! 110:
! 111: int
! 112: libnet_ifaddrlist(register struct libnet_ifaddr_list **ipaddrp, int8_t *dev,
! 113: register int8_t *errbuf)
! 114: {
! 115: register struct libnet_ifaddr_list *al;
! 116: struct ifreq *ifr, *lifr, *pifr, nifr;
! 117: int8_t device[sizeof(nifr.ifr_name)];
! 118: static struct libnet_ifaddr_list ifaddrlist[MAX_IPADDR];
! 119:
! 120: char *p;
! 121: struct ifconf ifc;
! 122: struct ifreq ibuf[MAX_IPADDR];
! 123: register int fd, nipaddr;
! 124:
! 125: #ifdef HAVE_LINUX_PROCFS
! 126: FILE *fp;
! 127: char buf[2048];
! 128: #endif
! 129:
! 130: fd = socket(AF_INET, SOCK_DGRAM, 0);
! 131: if (fd < 0)
! 132: {
! 133: snprintf(errbuf, LIBNET_ERRBUF_SIZE, "%s(): socket error: %s\n",
! 134: __func__, strerror(errno));
! 135: return (-1);
! 136: }
! 137:
! 138: #ifdef HAVE_LINUX_PROCFS
! 139: if ((fp = fopen(PROC_DEV_FILE, "r")) == NULL)
! 140: {
! 141: snprintf(errbuf, LIBNET_ERRBUF_SIZE,
! 142: "%s(): fopen(proc_dev_file) failed: %s\n", __func__,
! 143: strerror(errno));
! 144: return (-1);
! 145: }
! 146: #endif
! 147:
! 148: memset(&ifc, 0, sizeof(ifc));
! 149: ifc.ifc_len = sizeof(ibuf);
! 150: ifc.ifc_buf = (caddr_t)ibuf;
! 151:
! 152: if(ioctl(fd, SIOCGIFCONF, &ifc) < 0)
! 153: {
! 154: snprintf(errbuf, LIBNET_ERRBUF_SIZE,
! 155: "%s(): ioctl(SIOCGIFCONF) error: %s\n",
! 156: __func__, strerror(errno));
! 157: return(-1);
! 158: }
! 159:
! 160: pifr = NULL;
! 161: lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
! 162:
! 163: al = ifaddrlist;
! 164: nipaddr = 0;
! 165:
! 166: #ifdef HAVE_LINUX_PROCFS
! 167: while (fgets(buf, sizeof(buf), fp))
! 168: {
! 169: if ((p = strchr(buf, ':')) == NULL)
! 170: {
! 171: continue;
! 172: }
! 173: *p = '\0';
! 174: for(p = buf; *p == ' '; p++) ;
! 175:
! 176: strncpy(nifr.ifr_name, p, sizeof(nifr.ifr_name) - 1);
! 177: nifr.ifr_name[sizeof(nifr.ifr_name) - 1] = '\0';
! 178:
! 179: #else /* !HAVE_LINUX_PROCFS */
! 180:
! 181: for (ifr = ifc.ifc_req; ifr < lifr; ifr = NEXTIFR(ifr))
! 182: {
! 183: /* XXX LINUX SOLARIS ifalias */
! 184: if((p = strchr(ifr->ifr_name, ':')))
! 185: {
! 186: *p='\0';
! 187: }
! 188: if (pifr && strcmp(ifr->ifr_name, pifr->ifr_name) == 0)
! 189: {
! 190: continue;
! 191: }
! 192: strncpy(nifr.ifr_name, ifr->ifr_name, sizeof(nifr.ifr_name) - 1);
! 193: nifr.ifr_name[sizeof(nifr.ifr_name) - 1] = '\0';
! 194: #endif
! 195:
! 196: /* save device name */
! 197: strncpy(device, nifr.ifr_name, sizeof(device) - 1);
! 198: device[sizeof(device) - 1] = '\0';
! 199:
! 200: if (ioctl(fd, SIOCGIFFLAGS, &nifr) < 0)
! 201: {
! 202: pifr = ifr;
! 203: continue;
! 204: }
! 205: if ((nifr.ifr_flags & IFF_UP) == 0)
! 206: {
! 207: pifr = ifr;
! 208: continue;
! 209: }
! 210:
! 211: if (dev == NULL && LIBNET_ISLOOPBACK(&nifr))
! 212: {
! 213: pifr = ifr;
! 214: continue;
! 215: }
! 216:
! 217: strncpy(nifr.ifr_name, device, sizeof(device) - 1);
! 218: nifr.ifr_name[sizeof(nifr.ifr_name) - 1] = '\0';
! 219: if (ioctl(fd, SIOCGIFADDR, (int8_t *)&nifr) < 0)
! 220: {
! 221: if (errno != EADDRNOTAVAIL)
! 222: {
! 223: snprintf(errbuf, LIBNET_ERRBUF_SIZE,
! 224: "%s(): SIOCGIFADDR: dev=%s: %s\n", __func__, device,
! 225: strerror(errno));
! 226: close(fd);
! 227: return (-1);
! 228: }
! 229: else /* device has no IP address => set to 0 */
! 230: {
! 231: al->addr = 0;
! 232: }
! 233: }
! 234: else
! 235: {
! 236: al->addr = ((struct sockaddr_in *)&nifr.ifr_addr)->sin_addr.s_addr;
! 237: }
! 238:
! 239: if ((al->device = strdup(device)) == NULL)
! 240: {
! 241: snprintf(errbuf, LIBNET_ERRBUF_SIZE,
! 242: "%s(): strdup not enough memory\n", __func__);
! 243: return(-1);
! 244: }
! 245:
! 246: ++al;
! 247: ++nipaddr;
! 248:
! 249: #ifndef HAVE_LINUX_PROCFS
! 250: pifr = ifr;
! 251: #endif
! 252:
! 253: } /* while|for */
! 254:
! 255: #ifdef HAVE_LINUX_PROCFS
! 256: if (ferror(fp))
! 257: {
! 258: snprintf(errbuf, LIBNET_ERRBUF_SIZE,
! 259: "%s(): ferror: %s\n", __func__, strerror(errno));
! 260: return (-1);
! 261: }
! 262: fclose(fp);
! 263: #endif
! 264:
! 265: *ipaddrp = ifaddrlist;
! 266: return (nipaddr);
! 267: }
! 268: #else
! 269: /* From tcptraceroute, convert a numeric IP address to a string */
! 270: #define IPTOSBUFFERS 12
! 271: static int8_t *iptos(u_int32_t in)
! 272: {
! 273: static int8_t output[IPTOSBUFFERS][ 3 * 4 + 3 + 1];
! 274: static int16_t which;
! 275: u_int8_t *p;
! 276:
! 277: p = (u_int8_t *)∈
! 278: which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
! 279: snprintf(output[which], IPTOSBUFFERS, "%d.%d.%d.%d",
! 280: p[0], p[1], p[2], p[3]);
! 281: return output[which];
! 282: }
! 283:
! 284: int
! 285: libnet_ifaddrlist(register struct libnet_ifaddr_list **ipaddrp, int8_t *dev,
! 286: register int8_t *errbuf)
! 287: {
! 288: int nipaddr = 0; int i = 0;
! 289:
! 290: static struct libnet_ifaddr_list ifaddrlist[MAX_IPADDR];
! 291: pcap_if_t *alldevs;
! 292: pcap_if_t *d;
! 293: int8_t err[PCAP_ERRBUF_SIZE];
! 294:
! 295: /* Retrieve the interfaces list */
! 296: if (pcap_findalldevs(&alldevs, err) == -1)
! 297: {
! 298: snprintf(errbuf, LIBNET_ERRBUF_SIZE,
! 299: "%s(): error in pcap_findalldevs: %s\n", __func__, err);
! 300: return (-1);
! 301: }
! 302:
! 303: /* Scan the list printing every entry */
! 304: for (d = alldevs; d; d = d->next)
! 305: {
! 306: if((!d->addresses) || (d->addresses->addr->sa_family != AF_INET))
! 307: continue;
! 308: if(d->flags & PCAP_IF_LOOPBACK)
! 309: continue;
! 310:
! 311: /* XXX - strdup */
! 312: ifaddrlist[i].device = strdup(d->name);
! 313: ifaddrlist[i].addr = (u_int32_t)
! 314: strdup(iptos(((struct sockaddr_in *)
! 315: d->addresses->addr)->sin_addr.s_addr));
! 316: ++i;
! 317: ++nipaddr;
! 318: }
! 319:
! 320: *ipaddrp = ifaddrlist;
! 321: return (nipaddr);
! 322: }
! 323: #endif /* __WIN32__ */
! 324:
! 325: int
! 326: libnet_select_device(libnet_t *l)
! 327: {
! 328: int c, i;
! 329: int8_t err_buf[LIBNET_ERRBUF_SIZE];
! 330: struct libnet_ifaddr_list *address_list, *al;
! 331: u_int32_t addr;
! 332:
! 333:
! 334: if (l == NULL)
! 335: {
! 336: return (-1);
! 337: }
! 338:
! 339: if (l->device && !isdigit(l->device[0]))
! 340: {
! 341: #if !(__WIN32__)
! 342: if (libnet_check_iface(l) < 0)
! 343: {
! 344: /* err msg set in libnet_check_iface() */
! 345: return (-1);
! 346: }
! 347: #endif
! 348: return (1);
! 349: }
! 350:
! 351: /*
! 352: * Number of interfaces.
! 353: */
! 354: c = libnet_ifaddrlist(&address_list, l->device, err_buf);
! 355: if (c < 0)
! 356: {
! 357: /* err msg set in libnet_ifaddrlist() */
! 358: return (-1);
! 359: }
! 360: else if (c == 0)
! 361: {
! 362: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
! 363: "%s(): no network interface found\n", __func__);
! 364: return (-1);
! 365: }
! 366:
! 367: al = address_list;
! 368: if (l->device)
! 369: {
! 370: /*
! 371: * Then we have an IP address in l->device => do lookup
! 372: */
! 373: addr = libnet_name2addr4(l, l->device, 0);
! 374:
! 375: for (i = c; i; --i, ++address_list)
! 376: {
! 377: if (((addr == -1) && !(strncmp(l->device, address_list->device,
! 378: strlen(l->device)))) ||
! 379: (address_list->addr == addr))
! 380: {
! 381: /* free the "user supplied device" - see libnet_init() */
! 382: free(l->device);
! 383: l->device = strdup(address_list->device);
! 384: goto good;
! 385: }
! 386: }
! 387: if (i <= 0)
! 388: {
! 389: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
! 390: "%s(): can't find interface for IP %s\n", __func__,
! 391: l->device);
! 392: goto bad;
! 393: }
! 394: }
! 395: else
! 396: {
! 397: l->device = strdup(address_list->device);
! 398: }
! 399:
! 400: good:
! 401: for (i = 0; i < c; i++)
! 402: {
! 403: free(al[i].device);
! 404: }
! 405: return (1);
! 406:
! 407: bad:
! 408: for (i = 0; i < c; i++)
! 409: {
! 410: free(al[i].device);
! 411: }
! 412: return (-1);
! 413: }
! 414:
! 415: /* EOF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>