Annotation of embedaddon/libnet/src/libnet_if_addr.c, revision 1.1.1.4

1.1       misho       1: /*
1.1.1.2   misho       2:  *  $Id: libnet_if_addr.c,v 1.23 2004/04/13 17:32:28 mike Exp $
1.1       misho       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: 
1.1.1.4 ! misho      33: #include "common.h"
        !            34: 
1.1       misho      35: #ifdef HAVE_SYS_SOCKIO_H
                     36: #include <sys/sockio.h>
                     37: #endif
1.1.1.4 ! misho      38: 
1.1       misho      39: #include "../include/ifaddrlist.h"
                     40: 
                     41: #define MAX_IPADDR 512
                     42: 
                     43: #if !(__WIN32__)
                     44: 
                     45: /*
                     46:  * By testing if we can retrieve the FLAGS of an iface
                     47:  * we can know if it exists or not and if it is up.
                     48:  */
                     49: int 
                     50: libnet_check_iface(libnet_t *l)
                     51: {
                     52:     struct ifreq ifr;
                     53:     int fd, res;
                     54: 
                     55:     fd = socket(AF_INET, SOCK_DGRAM, 0);
                     56:     if (fd < 0)
                     57:     {
1.1.1.4 ! misho      58:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s() socket: %s", __func__,
1.1       misho      59:                 strerror(errno));
                     60:         return (-1);
                     61:     }
                     62: 
                     63:     strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) -1);
                     64:     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
                     65:     
                     66:     res = ioctl(fd, SIOCGIFFLAGS, (int8_t *)&ifr);
                     67:     if (res < 0)
                     68:     {
1.1.1.4 ! misho      69:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s() ioctl: %s", __func__,
1.1       misho      70:                 strerror(errno));
                     71:     }
                     72:     else
                     73:     {
                     74:         if ((ifr.ifr_flags & IFF_UP) == 0)
                     75:         {
1.1.1.4 ! misho      76:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): %s is down",
1.1       misho      77:                     __func__, l->device);
                     78:            res = -1;
                     79:         }
                     80:     }
                     81:     close(fd);
1.1.1.4 ! misho      82: 
1.1       misho      83:     return (res);
                     84: }
                     85: 
1.1.1.4 ! misho      86: #endif
        !            87: 
        !            88: #if defined(__OpenBSD__) ||  defined(__linux__)
        !            89: #include <sys/types.h>
        !            90:     #ifdef __OpenBSD__
        !            91:     #include <sys/socket.h>
        !            92:     #endif
        !            93: #include <ifaddrs.h>
        !            94: 
        !            95: int
        !            96: libnet_ifaddrlist(register struct libnet_ifaddr_list **ipaddrp, char *dev, register char *errbuf)
        !            97: {
        !            98:     static struct libnet_ifaddr_list ifaddrlist[MAX_IPADDR];
        !            99:     struct ifaddrs *ifap, *ifa;
        !           100:     int i = 0;
        !           101:     memset (ifaddrlist, 0 , sizeof(ifaddrlist));
        !           102: 
        !           103:     if (getifaddrs(&ifap) != 0)
        !           104:     {
        !           105:         snprintf(errbuf, LIBNET_ERRBUF_SIZE, "%s(): getifaddrs: %s",
        !           106:                     __func__, strerror(errno));
        !           107:         return 0;
        !           108:     }
        !           109:     for (ifa = ifap; ifa; ifa = ifa->ifa_next)
        !           110:     {
        !           111:         if (ifa->ifa_flags & IFF_LOOPBACK)
        !           112:             continue;
        !           113: 
        !           114:         if (ifa->ifa_addr->sa_family == AF_INET )
        !           115:         {
        !           116:             ifaddrlist[i].device = strdup(ifa->ifa_name);
        !           117:             if (ifaddrlist[i].device == NULL) {
        !           118:                 snprintf(errbuf, LIBNET_ERRBUF_SIZE, "%s(): OOM", __func__);
        !           119:                 continue;
        !           120:             }
        !           121:             ifaddrlist[i].addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
        !           122:             ++i;
        !           123:         }
        !           124:     }
        !           125: 
        !           126:     freeifaddrs(ifap);
        !           127:     *ipaddrp = ifaddrlist;
        !           128:     return (i);
        !           129: }
        !           130: 
        !           131: 
        !           132: #else
        !           133: #if !(__WIN32__)
        !           134: 
1.1       misho     135: 
                    136: /*
                    137:  *  Return the interface list
                    138:  */
                    139: 
                    140: #ifdef HAVE_SOCKADDR_SA_LEN
                    141: #define NEXTIFR(i) \
                    142: ((struct ifreq *)((u_char *)&i->ifr_addr + i->ifr_addr.sa_len))
                    143: #else
                    144: #define NEXTIFR(i) (i + 1)
                    145: #endif
                    146: 
                    147: #ifndef BUFSIZE
                    148: #define BUFSIZE 2048
                    149: #endif
                    150: 
                    151: #ifdef HAVE_LINUX_PROCFS
                    152: #define PROC_DEV_FILE "/proc/net/dev"
                    153: #endif
                    154: 
                    155: int
1.1.1.4 ! misho     156: libnet_ifaddrlist(register struct libnet_ifaddr_list **ipaddrp, char *dev, register char *errbuf)
1.1       misho     157: {
                    158:     register struct libnet_ifaddr_list *al;
                    159:     struct ifreq *ifr, *lifr, *pifr, nifr;
1.1.1.2   misho     160:     char device[sizeof(nifr.ifr_name)];
1.1       misho     161:     static struct libnet_ifaddr_list ifaddrlist[MAX_IPADDR];
                    162:     
                    163:     char *p;
                    164:     struct ifconf ifc;
                    165:     struct ifreq ibuf[MAX_IPADDR];
                    166:     register int fd, nipaddr;
                    167:     
                    168: #ifdef HAVE_LINUX_PROCFS
                    169:     FILE *fp;
                    170:     char buf[2048];
                    171: #endif
                    172:     
                    173:     fd = socket(AF_INET, SOCK_DGRAM, 0);
                    174:     if (fd < 0)
                    175:     {
1.1.1.4 ! misho     176:        snprintf(errbuf, LIBNET_ERRBUF_SIZE, "%s(): socket error: %s",
1.1       misho     177:                 __func__, strerror(errno));
                    178:        return (-1);
                    179:     }
                    180: 
                    181: #ifdef HAVE_LINUX_PROCFS
1.1.1.4 ! misho     182:     fp = fopen(PROC_DEV_FILE, "r");
        !           183:     if (!fp)
1.1       misho     184:     {
                    185:        snprintf(errbuf, LIBNET_ERRBUF_SIZE,
1.1.1.4 ! misho     186:                 "%s(): fopen(proc_dev_file) failed: %s",  __func__,
1.1       misho     187:                 strerror(errno));
1.1.1.4 ! misho     188:        goto bad;
1.1       misho     189:     }
                    190: #endif
                    191: 
                    192:     memset(&ifc, 0, sizeof(ifc));
                    193:     ifc.ifc_len = sizeof(ibuf);
                    194:     ifc.ifc_buf = (caddr_t)ibuf;
                    195: 
1.1.1.4 ! misho     196:     if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
1.1       misho     197:     {
                    198:        snprintf(errbuf, LIBNET_ERRBUF_SIZE,
1.1.1.4 ! misho     199:                 "%s(): ioctl(SIOCGIFCONF) error: %s", 
1.1       misho     200:                 __func__, strerror(errno));
1.1.1.4 ! misho     201:        goto bad;
1.1       misho     202:     }
                    203: 
                    204:     pifr = NULL;
                    205:     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
                    206:     
                    207:     al = ifaddrlist;
                    208:     nipaddr = 0;
                    209: 
                    210: #ifdef HAVE_LINUX_PROCFS
                    211:     while (fgets(buf, sizeof(buf), fp))
                    212:     {
1.1.1.4 ! misho     213:         p = strchr(buf, ':');
        !           214:        if (!p)
1.1       misho     215:             continue;
1.1.1.4 ! misho     216: 
1.1       misho     217:         *p = '\0';
1.1.1.4 ! misho     218:         for (p = buf; *p == ' '; p++)
        !           219:            ;
1.1       misho     220:        
                    221:         strncpy(nifr.ifr_name, p, sizeof(nifr.ifr_name) - 1);
                    222:         nifr.ifr_name[sizeof(nifr.ifr_name) - 1] = '\0';
                    223:        
                    224: #else /* !HAVE_LINUX_PROCFS */
                    225: 
                    226:     for (ifr = ifc.ifc_req; ifr < lifr; ifr = NEXTIFR(ifr))
                    227:     {
                    228:        /* XXX LINUX SOLARIS ifalias */
1.1.1.4 ! misho     229:         p = strchr(ifr->ifr_name, ':');
        !           230:        if (p)
        !           231:             *p = '\0';
        !           232: 
1.1       misho     233:        if (pifr && strcmp(ifr->ifr_name, pifr->ifr_name) == 0)
                    234:             continue;
1.1.1.4 ! misho     235: 
1.1       misho     236:        strncpy(nifr.ifr_name, ifr->ifr_name, sizeof(nifr.ifr_name) - 1);
                    237:        nifr.ifr_name[sizeof(nifr.ifr_name) - 1] = '\0';
                    238: #endif
                    239: 
                    240:         /* save device name */
                    241:         strncpy(device, nifr.ifr_name, sizeof(device) - 1);
                    242:         device[sizeof(device) - 1] = '\0';
                    243: 
                    244:         if (ioctl(fd, SIOCGIFFLAGS, &nifr) < 0)
                    245:         {
                    246:             pifr = ifr;
                    247:             continue;
                    248:        }
                    249:         if ((nifr.ifr_flags & IFF_UP) == 0)
                    250:        {
                    251:             pifr = ifr;
                    252:             continue;  
                    253:        }
                    254: 
                    255:         if (dev == NULL && LIBNET_ISLOOPBACK(&nifr))
                    256:        {
                    257:             pifr = ifr;
                    258:             continue;
                    259:        }
                    260:        
                    261:         strncpy(nifr.ifr_name, device, sizeof(device) - 1);
                    262:         nifr.ifr_name[sizeof(nifr.ifr_name) - 1] = '\0';
                    263:         if (ioctl(fd, SIOCGIFADDR, (int8_t *)&nifr) < 0)
                    264:         {
                    265:             if (errno != EADDRNOTAVAIL)
                    266:             {
                    267:                 snprintf(errbuf, LIBNET_ERRBUF_SIZE,
1.1.1.4 ! misho     268:                         "%s(): SIOCGIFADDR: dev=%s: %s", __func__, device,
1.1       misho     269:                         strerror(errno));
1.1.1.4 ! misho     270:                 goto bad;
1.1       misho     271:            }
                    272:             else /* device has no IP address => set to 0 */
                    273:             {
                    274:                 al->addr = 0;
                    275:             }
                    276:         }
                    277:         else
                    278:         {
                    279:             al->addr = ((struct sockaddr_in *)&nifr.ifr_addr)->sin_addr.s_addr;
                    280:         }
1.1.1.2   misho     281:         
                    282:         free(al->device);
1.1       misho     283: 
1.1.1.4 ! misho     284:         al->device = strdup(device);
        !           285:         if (al->device == NULL)
1.1       misho     286:         {
                    287:             snprintf(errbuf, LIBNET_ERRBUF_SIZE, 
1.1.1.4 ! misho     288:                     "%s(): strdup not enough memory", __func__);
        !           289:             goto bad;
1.1       misho     290:         }
                    291: 
                    292:         ++al;
                    293:         ++nipaddr;
                    294: 
                    295: #ifndef HAVE_LINUX_PROCFS
                    296:         pifr = ifr;
                    297: #endif
                    298: 
                    299:     } /* while|for */
                    300:        
                    301: #ifdef HAVE_LINUX_PROCFS
                    302:     if (ferror(fp))
                    303:     {
                    304:         snprintf(errbuf, LIBNET_ERRBUF_SIZE,
1.1.1.4 ! misho     305:                 "%s(): ferror: %s", __func__, strerror(errno));
        !           306:        goto bad;
1.1       misho     307:     }
                    308:     fclose(fp);
                    309: #endif
                    310: 
1.1.1.4 ! misho     311:     close(fd);
1.1       misho     312:     *ipaddrp = ifaddrlist;
1.1.1.4 ! misho     313: 
1.1       misho     314:     return (nipaddr);
1.1.1.4 ! misho     315: 
        !           316:     bad:
        !           317: #ifdef HAVE_LINUX_PROCFS
        !           318:     if (fp)
        !           319:        fclose(fp);
        !           320: #endif
        !           321:     close(fd);
        !           322:     return (-1);
1.1       misho     323: }
                    324: #else
1.1.1.4 ! misho     325: /* WIN32 support *
        !           326:  * TODO move win32 support into win32 specific source file */
        !           327: 
1.1       misho     328: /* From tcptraceroute, convert a numeric IP address to a string */
                    329: #define IPTOSBUFFERS    12
1.1.1.2   misho     330: static int8_t *iptos(uint32_t in)
1.1       misho     331: {
                    332:     static int8_t output[IPTOSBUFFERS][ 3 * 4 + 3 + 1];
                    333:     static int16_t which;
1.1.1.2   misho     334:     uint8_t *p;
1.1       misho     335: 
1.1.1.2   misho     336:     p = (uint8_t *)&in;
1.1       misho     337:     which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
                    338:     snprintf(output[which], IPTOSBUFFERS, "%d.%d.%d.%d", 
                    339:             p[0], p[1], p[2], p[3]);
                    340:     return output[which];
                    341: }
                    342: 
                    343: int
1.1.1.4 ! misho     344: libnet_ifaddrlist(register struct libnet_ifaddr_list **ipaddrp, char *dev_unused, register char *errbuf)
1.1       misho     345: {
1.1.1.4 ! misho     346:     int nipaddr = 0;
        !           347:     int i = 0;
1.1       misho     348:     static struct libnet_ifaddr_list ifaddrlist[MAX_IPADDR];
1.1.1.4 ! misho     349:     pcap_if_t *devlist = NULL;
        !           350:     pcap_if_t *dev = NULL;
1.1       misho     351:     int8_t err[PCAP_ERRBUF_SIZE];
                    352: 
                    353:     /* Retrieve the interfaces list */
1.1.1.4 ! misho     354:     if (pcap_findalldevs(&devlist, err) == -1)
1.1       misho     355:     {
                    356:         snprintf(errbuf, LIBNET_ERRBUF_SIZE, 
1.1.1.4 ! misho     357:                 "%s(): error in pcap_findalldevs: %s", __func__, err);
1.1       misho     358:         return (-1);
                    359:     }
                    360: 
1.1.1.4 ! misho     361:     for (dev = devlist; dev; dev = dev->next)
1.1       misho     362:     {
1.1.1.4 ! misho     363:         struct pcap_addr* pcapaddr;
        !           364:         for(pcapaddr = dev->addresses; pcapaddr; pcapaddr = pcapaddr->next) {
        !           365:             struct sockaddr* addr = pcapaddr->addr;
        !           366: #if 0
        !           367:             printf("if name '%s' description '%s' loop? %d\n", dev->name, dev->description, dev->flags);
        !           368:             {
        !           369:                 char p[NI_MAXHOST] = "";
        !           370:                 int sz = sizeof(struct sockaddr_storage);
        !           371:                 int r;
        !           372:                 r = getnameinfo(addr, sz, p, sizeof(p), NULL,0, NI_NUMERICHOST);
        !           373:                 printf("  addr %s\n", r ? gai_strerror(r) : p);
        !           374:             }
        !           375: #endif
        !           376: 
        !           377:             if (dev->flags & PCAP_IF_LOOPBACK)
        !           378:                 continue;
        !           379: 
        !           380:             /* this code ignores IPv6 addresses, a limitation of the libnet_ifaddr_list struct */
        !           381: 
        !           382:             if (addr->sa_family == AF_INET) {
        !           383:                 ifaddrlist[i].device = strdup(dev->name);
        !           384:                 ifaddrlist[i].addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
        !           385:                 ++i;
        !           386:                 ++nipaddr;
        !           387:             }
        !           388:         }
1.1       misho     389:     }
                    390: 
1.1.1.4 ! misho     391:     pcap_freealldevs(devlist);
1.1.1.3   misho     392: 
1.1       misho     393:     *ipaddrp = ifaddrlist;
1.1.1.4 ! misho     394: 
        !           395:     return nipaddr;
1.1       misho     396: }
                    397: #endif /* __WIN32__ */
                    398: 
1.1.1.4 ! misho     399: #endif /* __OpenBSD__ */
        !           400: 
1.1       misho     401: int
                    402: libnet_select_device(libnet_t *l)
                    403: {
                    404:     int c, i;
                    405:     struct libnet_ifaddr_list *address_list, *al;
1.1.1.2   misho     406:     uint32_t addr;
1.1       misho     407: 
                    408: 
                    409:     if (l == NULL)
                    410:     { 
                    411:         return (-1);
                    412:     }
                    413: 
                    414:     if (l->device && !isdigit(l->device[0]))
                    415:     {
                    416: #if !(__WIN32__)
                    417:        if (libnet_check_iface(l) < 0)
                    418:        {
                    419:             /* err msg set in libnet_check_iface() */
                    420:            return (-1);
                    421:        }
                    422: #endif
                    423:        return (1);
                    424:     }
                    425: 
                    426:     /*
                    427:      *  Number of interfaces.
                    428:      */
1.1.1.3   misho     429:     c = libnet_ifaddrlist(&address_list, l->device, l->err_buf);
1.1       misho     430:     if (c < 0)
                    431:     {
                    432:         return (-1);
                    433:     }
                    434:     else if (c == 0)
                    435:     {
                    436:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
1.1.1.4 ! misho     437:                 "%s(): no network interface found", __func__);
1.1       misho     438:         return (-1);
                    439:     }
                    440:        
                    441:     al = address_list;
                    442:     if (l->device)
                    443:     {
1.1.1.4 ! misho     444:         addr = libnet_name2addr4(l, l->device, LIBNET_DONT_RESOLVE);
1.1       misho     445: 
                    446:         for (i = c; i; --i, ++address_list)
                    447:         {
1.1.1.4 ! misho     448:             if (
        !           449:                     0 == strcmp(l->device, address_list->device)
        !           450:                     || 
        !           451:                     address_list->addr == addr
        !           452:                )
1.1       misho     453:             {
                    454:                 /* free the "user supplied device" - see libnet_init() */
                    455:                 free(l->device);
                    456:                 l->device =  strdup(address_list->device);
                    457:                 goto good;
                    458:             }
                    459:         }
                    460:         if (i <= 0)
                    461:         {
                    462:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
1.1.1.4 ! misho     463:                     "%s(): can't find interface for IP %s", __func__,
1.1       misho     464:                     l->device);
                    465:            goto bad;
                    466:         }
                    467:     }
                    468:     else
                    469:     {
                    470:         l->device = strdup(address_list->device);
                    471:     }
                    472: 
                    473: good:
                    474:     for (i = 0; i < c; i++)
                    475:     {
                    476:         free(al[i].device);
1.1.1.2   misho     477:         al[i].device = NULL;
1.1       misho     478:     }
                    479:     return (1);
                    480: 
                    481: bad:
                    482:     for (i = 0; i < c; i++)
                    483:     {
                    484:         free(al[i].device);
1.1.1.2   misho     485:         al[i].device = NULL;
1.1       misho     486:     }
                    487:     return (-1);
                    488: }
                    489: 
1.1.1.4 ! misho     490: /**
        !           491:  * Local Variables:
        !           492:  *  indent-tabs-mode: nil
        !           493:  *  c-file-style: "stroustrup"
        !           494:  * End:
        !           495:  */

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