int add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, u_int flags, const char *description, char *errbuf) { pcap_t *p; pcap_if_t *curdev, *prevdev, *nextdev; int this_instance; char open_errbuf[PCAP_ERRBUF_SIZE]; /* * Is there already an entry in the list for this interface? */ for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { if (strcmp(name, curdev->name) == 0) break; /* yes, we found it */ } if (curdev == NULL) { /* * No, we didn't find it. * * Can we open this interface for live capture? * * We do this check so that interfaces that are * supplied by the interface enumeration mechanism * we're using but that don't support packet capture * aren't included in the list. Loopback interfaces * on Solaris are an example of this; we don't just * omit loopback interfaces on all platforms because * you *can* capture on loopback interfaces on some * OSes. * * On OS X, we don't do this check if the device * name begins with "wlt"; at least some versions * of OS X offer monitor mode capturing by having * a separate "monitor mode" device for each wireless * adapter, rather than by implementing the ioctls * that {Free,Net,Open,DragonFly}BSD provide. * Opening that device puts the adapter into monitor * mode, which, at least for some adapters, causes * them to deassociate from the network with which * they're associated. * * Instead, we try to open the corresponding "en" * device (so that we don't end up with, for users * without sufficient privilege to open capture * devices, a list of adapters that only includes * the wlt devices). */ #ifdef __APPLE__ if (strncmp(name, "wlt", 3) == 0) { char *en_name; size_t en_name_len; /* * Try to allocate a buffer for the "en" * device's name. */ en_name_len = strlen(name) - 1; en_name = malloc(en_name_len + 1); if (en_name == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } strcpy(en_name, "en"); strcat(en_name, name + 3); p = pcap_open_live(en_name, 68, 0, 0, open_errbuf); free(en_name); } else #endif /* __APPLE */ p = pcap_open_live(name, 68, 0, 0, open_errbuf); if (p == NULL) { /* * No. Don't bother including it. * Don't treat this as an error, though. */ *curdev_ret = NULL; return (0); } pcap_close(p); /* * Yes, we can open it. * Allocate a new entry. */ curdev = malloc(sizeof(pcap_if_t)); if (curdev == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } /* * Fill in the entry. */ curdev->next = NULL; curdev->name = strdup(name); if (curdev->name == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curdev); return (-1); } if (description != NULL) { /* * We have a description for this interface. */ curdev->description = strdup(description); if (curdev->description == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curdev->name); free(curdev); return (-1); } } else { /* * We don't. */ curdev->description = NULL; } curdev->addresses = NULL; /* list starts out as empty */ curdev->flags = 0; if (ISLOOPBACK(name, flags)) curdev->flags |= PCAP_IF_LOOPBACK; /* * Add it to the list, in the appropriate location. * First, get the instance number of this interface. */ this_instance = get_instance(name); /* * Now look for the last interface with an instance number * less than or equal to the new interface's instance * number - except that non-loopback interfaces are * arbitrarily treated as having interface numbers less * than those of loopback interfaces, so the loopback * interfaces are put at the end of the list. * * We start with "prevdev" being NULL, meaning we're before * the first element in the list. */ prevdev = NULL; for (;;) { /* * Get the interface after this one. */ if (prevdev == NULL) { /* * The next element is the first element. */ nextdev = *alldevs; } else nextdev = prevdev->next; /* * Are we at the end of the list? */ if (nextdev == NULL) { /* * Yes - we have to put the new entry * after "prevdev". */ break; } /* * Is the new interface a non-loopback interface * and the next interface a loopback interface? */ if (!(curdev->flags & PCAP_IF_LOOPBACK) && (nextdev->flags & PCAP_IF_LOOPBACK)) { /* * Yes, we should put the new entry * before "nextdev", i.e. after "prevdev". */ break; } /* * Is the new interface's instance number less * than the next interface's instance number, * and is it the case that the new interface is a * non-loopback interface or the next interface is * a loopback interface? * * (The goal of both loopback tests is to make * sure that we never put a loopback interface * before any non-loopback interface and that we * always put a non-loopback interface before all * loopback interfaces.) */ if (this_instance < get_instance(nextdev->name) && (!(curdev->flags & PCAP_IF_LOOPBACK) || (nextdev->flags & PCAP_IF_LOOPBACK))) { /* * Yes - we should put the new entry * before "nextdev", i.e. after "prevdev". */ break; } prevdev = nextdev; } /* * Insert before "nextdev". */ curdev->next = nextdev; /* * Insert after "prevdev" - unless "prevdev" is null, * in which case this is the first interface. */ if (prevdev == NULL) { /* * This is the first interface. Pass back a * pointer to it, and put "curdev" before * "nextdev". */ *alldevs = curdev; } else prevdev->next = curdev; } *curdev_ret = curdev; return (0); }
/* * Look for a given device in the specified list of devices. * * If we find it, return 0 and set *curdev_ret to point to it. * * If we don't find it, check whether we can open it: * * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for * it, as that probably means it exists but doesn't support * packet capture. * * Otherwise, attempt to add an entry for it, with the specified * ifnet flags and description, and, if that succeeds, return 0 * and set *curdev_ret to point to the new entry, otherwise * return PCAP_ERROR and set errbuf to an error message. */ int add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, u_int flags, const char *description, char *errbuf) { pcap_t *p; pcap_if_t *curdev, *prevdev, *nextdev; u_int this_figure_of_merit, nextdev_figure_of_merit; char open_errbuf[PCAP_ERRBUF_SIZE]; int ret; /* * Is there already an entry in the list for this interface? */ for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { if (strcmp(name, curdev->name) == 0) break; /* yes, we found it */ } if (curdev == NULL) { /* * No, we didn't find it. * * Can we open this interface for live capture? * * We do this check so that interfaces that are * supplied by the interface enumeration mechanism * we're using but that don't support packet capture * aren't included in the list. Loopback interfaces * on Solaris are an example of this; we don't just * omit loopback interfaces on all platforms because * you *can* capture on loopback interfaces on some * OSes. * * On OS X, we don't do this check if the device * name begins with "wlt"; at least some versions * of OS X offer monitor mode capturing by having * a separate "monitor mode" device for each wireless * adapter, rather than by implementing the ioctls * that {Free,Net,Open,DragonFly}BSD provide. * Opening that device puts the adapter into monitor * mode, which, at least for some adapters, causes * them to deassociate from the network with which * they're associated. * * Instead, we try to open the corresponding "en" * device (so that we don't end up with, for users * without sufficient privilege to open capture * devices, a list of adapters that only includes * the wlt devices). */ #ifdef __APPLE__ if (strncmp(name, "wlt", 3) == 0) { char *en_name; size_t en_name_len; /* * Try to allocate a buffer for the "en" * device's name. */ en_name_len = strlen(name) - 1; en_name = malloc(en_name_len + 1); if (en_name == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } strcpy(en_name, "en"); strcat(en_name, name + 3); p = pcap_create(en_name, open_errbuf); free(en_name); } else #endif /* __APPLE */ p = pcap_create(name, open_errbuf); if (p == NULL) { /* * The attempt to create the pcap_t failed; * that's probably an indication that we're * out of memory. * * Don't bother including this interface, * but don't treat it as an error. */ *curdev_ret = NULL; return (0); } /* Small snaplen, so we don't try to allocate much memory. */ pcap_set_snaplen(p, 68); ret = pcap_activate(p); pcap_close(p); switch (ret) { case PCAP_ERROR_NO_SUCH_DEVICE: case PCAP_ERROR_IFACE_NOT_UP: /* * We expect these two errors - they're the * reason we try to open the device. * * PCAP_ERROR_NO_SUCH_DEVICE typically means * "there's no such device *known to the * OS's capture mechanism*", so, even though * it might be a valid network interface, you * can't capture on it (e.g., the loopback * device in Solaris up to Solaris 10, or * the vmnet devices in OS X with VMware * Fusion). We don't include those devices * in our list of devices, as there's no * point in doing so - they're not available * for capture. * * PCAP_ERROR_IFACE_NOT_UP means that the * OS's capture mechanism doesn't work on * interfaces not marked as up; some capture * mechanisms *do* support that, so we no * longer reject those interfaces out of hand, * but we *do* want to reject them if they * can't be opened for capture. */ *curdev_ret = NULL; return (0); } /* * Yes, we can open it, or we can't, for some other * reason. * * If we can open it, we want to offer it for * capture, as you can capture on it. If we can't, * we want to offer it for capture, so that, if * the user tries to capture on it, they'll get * an error and they'll know why they can't * capture on it (e.g., insufficient permissions) * or they'll report it as a problem (and then * have the error message to provide as information). * * Allocate a new entry. */ curdev = malloc(sizeof(pcap_if_t)); if (curdev == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } /* * Fill in the entry. */ curdev->next = NULL; curdev->name = strdup(name); if (curdev->name == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curdev); return (-1); } if (description != NULL) { /* * We have a description for this interface. */ curdev->description = strdup(description); if (curdev->description == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curdev->name); free(curdev); return (-1); } } else { /* * We don't. */ curdev->description = NULL; } curdev->addresses = NULL; /* list starts out as empty */ curdev->flags = 0; if (ISLOOPBACK(name, flags)) curdev->flags |= PCAP_IF_LOOPBACK; if (ISUP(flags)) curdev->flags |= PCAP_IF_UP; if (ISRUNNING(flags)) curdev->flags |= PCAP_IF_RUNNING; /* * Add it to the list, in the appropriate location. * First, get the "figure of merit" for this * interface. */ this_figure_of_merit = get_figure_of_merit(curdev); /* * Now look for the last interface with an figure of merit * less than or equal to the new interface's figure of * merit. * * We start with "prevdev" being NULL, meaning we're before * the first element in the list. */ prevdev = NULL; for (;;) { /* * Get the interface after this one. */ if (prevdev == NULL) { /* * The next element is the first element. */ nextdev = *alldevs; } else nextdev = prevdev->next; /* * Are we at the end of the list? */ if (nextdev == NULL) { /* * Yes - we have to put the new entry * after "prevdev". */ break; } /* * Is the new interface's figure of merit less * than the next interface's figure of merit, * meaning that the new interface is better * than the next interface? */ nextdev_figure_of_merit = get_figure_of_merit(nextdev); if (this_figure_of_merit < nextdev_figure_of_merit) { /* * Yes - we should put the new entry * before "nextdev", i.e. after "prevdev". */ break; } prevdev = nextdev; } /* * Insert before "nextdev". */ curdev->next = nextdev; /* * Insert after "prevdev" - unless "prevdev" is null, * in which case this is the first interface. */ if (prevdev == NULL) { /* * This is the first interface. Pass back a * pointer to it, and put "curdev" before * "nextdev". */ *alldevs = curdev; } else prevdev->next = curdev; } *curdev_ret = curdev; return (0); }
static int add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, char *name, u_int flags, const char *description, char *errbuf) { pcap_t *p; pcap_if_t *curdev, *prevdev, *nextdev; int this_instance; /* * Can we open this interface for live capture? */ p = pcap_open_live(name, 68, 0, 0, errbuf); if (p == NULL) { /* * No. Don't bother including it. * Don't treat this as an error, though. */ *curdev_ret = NULL; return (0); } pcap_close(p); /* * Is there already an entry in the list for this interface? */ for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { if (strcmp(name, curdev->name) == 0) break; /* yes, we found it */ } if (curdev == NULL) { /* * No, we didn't find it. * Allocate a new entry. */ curdev = malloc(sizeof(pcap_if_t)); if (curdev == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } /* * Fill in the entry. */ curdev->next = NULL; curdev->name = malloc(strlen(name) + 1); strcpy(curdev->name, name); if (description != NULL) { /* * We have a description for this interface. */ curdev->description = malloc(strlen(description) + 1); strcpy(curdev->description, description); } else { /* * We don't. */ curdev->description = NULL; } curdev->addresses = NULL; /* list starts out as empty */ curdev->flags = 0; if (ISLOOPBACK(name, flags)) curdev->flags |= PCAP_IF_LOOPBACK; /* * Add it to the list, in the appropriate location. * First, get the instance number of this interface. */ this_instance = get_instance(name); /* * Now look for the last interface with an instance number * less than or equal to the new interface's instance * number - except that non-loopback interfaces are * arbitrarily treated as having interface numbers less * than those of loopback interfaces, so the loopback * interfaces are put at the end of the list. * * We start with "prevdev" being NULL, meaning we're before * the first element in the list. */ prevdev = NULL; for (;;) { /* * Get the interface after this one. */ if (prevdev == NULL) { /* * The next element is the first element. */ nextdev = *alldevs; } else nextdev = prevdev->next; /* * Are we at the end of the list? */ if (nextdev == NULL) { /* * Yes - we have to put the new entry * after "prevdev". */ break; } /* * Is the new interface a non-loopback interface * and the next interface a loopback interface? */ if (!(curdev->flags & PCAP_IF_LOOPBACK) && (nextdev->flags & PCAP_IF_LOOPBACK)) { /* * Yes, we should put the new entry * before "nextdev", i.e. after "prevdev". */ break; } /* * Is the new interface's instance number less * than the next interface's instance number, * and is it the case that the new interface is a * non-loopback interface or the next interface is * a loopback interface? * * (The goal of both loopback tests is to make * sure that we never put a loopback interface * before any non-loopback interface and that we * always put a non-loopback interface before all * loopback interfaces.) */ if (this_instance < get_instance(nextdev->name) && (!(curdev->flags & PCAP_IF_LOOPBACK) || (nextdev->flags & PCAP_IF_LOOPBACK))) { /* * Yes - we should put the new entry * before "nextdev", i.e. after "prevdev". */ break; } prevdev = nextdev; } /* * Insert before "nextdev". */ curdev->next = nextdev; /* * Insert after "prevdev" - unless "prevdev" is null, * in which case this is the first interface. */ if (prevdev == NULL) { /* * This is the first interface. Pass back a * pointer to it, and put "curdev" before * "nextdev". */ *alldevs = curdev; } else prevdev->next = curdev; } *curdev_ret = curdev; return (0); }
/* * Return the interface list */ int ifaddrlist(register struct ifaddrlist **ipaddrp, register char *errbuf, size_t l) { #ifdef HAVE_GETIFADDRS struct ifaddrs *ifap, *ifa; int nipaddr; struct ifaddrlist *al; struct ifaddrlist *ifaddrlist; unsigned int maxif; struct sockaddr_in *sin; #if 1 maxif = if_maxindex() * 3; /* 3 is a magic number... */ #else maxif = 64; #endif ifaddrlist = (struct ifaddrlist *)malloc(maxif * sizeof(struct ifaddrlist)); if (ifaddrlist == NULL) return -1; if (getifaddrs(&ifap) != 0) return -1; al = ifaddrlist; nipaddr = 0; for (ifa = ifap; ifa && nipaddr < maxif; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_INET) continue; if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == htonl(INADDR_ANY)) continue; if ((ifa->ifa_flags & IFF_UP) == 0) continue; #ifdef IFF_LOOPBACK if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue; #else if (strcmp(ifa->ifa_name, "lo0") == 0) continue; #endif sin = (struct sockaddr_in *)ifa->ifa_addr; al->addr = sin->sin_addr.s_addr; al->device = strdup(ifa->ifa_name); ++al; ++nipaddr; } *ipaddrp = ifaddrlist; #ifdef HAVE_FREEIFADDRS freeifaddrs(ifap); #else free(ifap); #endif return nipaddr; #else register int fd, nipaddr; #ifdef HAVE_SOCKADDR_SA_LEN register int n; #endif register struct ifreq *ifrp, *ifend, *ifnext, *mp; register struct sockaddr_in *sin; register struct ifaddrlist *al; struct ifconf ifc; struct ifreq *ibuf, ifr; char device[sizeof(ifr.ifr_name) + 1]; struct ifaddrlist *ifaddrlist; unsigned int maxif; #if 1 maxif = if_maxindex() * 3; /* 3 is a magic number... */ #else maxif = 64; #endif ifaddrlist = (struct ifaddrlist *)malloc(maxif * sizeof(struct ifaddrlist)); if (ifaddrlist == NULL) return -1; ibuf = (struct ifreq *)malloc(maxif * sizeof(struct ifreq)); if (ibuf == NULL) { free(ifaddrlist); return -1; } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { (void)snprintf(errbuf, l, "socket: %s", strerror(errno)); free(ifaddrlist); free(ibuf); return (-1); } ifc.ifc_len = maxif * sizeof(struct ifreq); ifc.ifc_buf = (caddr_t)ibuf; if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || ifc.ifc_len < sizeof(struct ifreq)) { (void)snprintf(errbuf, l, "SIOCGIFCONF: %s", strerror(errno)); (void)close(fd); free(ifaddrlist); free(ibuf); return (-1); } ifrp = ibuf; ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); al = ifaddrlist; mp = NULL; nipaddr = 0; for (; ifrp < ifend; ifrp = ifnext) { #ifdef HAVE_SOCKADDR_SA_LEN n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); if (n < sizeof(*ifrp)) ifnext = ifrp + 1; else ifnext = (struct ifreq *)((char *)ifrp + n); if (ifrp->ifr_addr.sa_family != AF_INET) continue; #else ifnext = ifrp + 1; #endif if (((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == htonl(INADDR_ANY)) continue; /* * Need a template to preserve address info that is * used below to locate the next entry. (Otherwise, * SIOCGIFFLAGS stomps over it because the requests * are returned in a union.) */ strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifrp->ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { if (errno == ENXIO) continue; (void)snprintf(errbuf, l, "SIOCGIFFLAGS: %.*s: %s", (int)sizeof(ifr.ifr_name), ifr.ifr_name, strerror(errno)); (void)close(fd); free(ifaddrlist); free(ibuf); return (-1); } /* Must be up and not the loopback */ if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr)) continue; (void)strncpy(device, ifr.ifr_name, sizeof(ifr.ifr_name)); device[sizeof(device) - 1] = '\0'; if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { (void)snprintf(errbuf, l, "SIOCGIFADDR: %s: %s", device, strerror(errno)); (void)close(fd); free(ifaddrlist); free(ibuf); return (-1); } sin = (struct sockaddr_in *)&ifr.ifr_addr; al->addr = sin->sin_addr.s_addr; al->device = strdup(device); ++al; ++nipaddr; } (void)close(fd); *ipaddrp = ifaddrlist; free(ibuf); return (nipaddr); #endif }