int pcap_add_if(pcap_if_t **devlist, const char *name, u_int flags, const char *description, char *errbuf) { pcap_if_t *curdev; return (add_or_find_if(&curdev, devlist, name, flags, description, errbuf)); }
/* * Try to get a description for a given device, and then look for that * device in the specified list of devices. * * If we find it, then, if the specified address isn't null, add it to * the list of addresses for the device and return 0. * * 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, add the * specified address to its list of addresses if that address is * non-null, set *curdev_ret to point to the new entry, and * return 0, otherwise return PCAP_ERROR and set errbuf to an * error message. * * (We can get called with a null address because we might get a list * of interface name/address combinations from the underlying OS, with * the address being absent in some cases, rather than a list of * interfaces with each interface having a list of addresses, so this * call may be the only call made to add to the list, and we want to * add interfaces even if they have no addresses.) */ int add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, struct sockaddr *addr, size_t addr_size, struct sockaddr *netmask, size_t netmask_size, struct sockaddr *broadaddr, size_t broadaddr_size, struct sockaddr *dstaddr, size_t dstaddr_size, char *errbuf) { char *description; pcap_if_t *curdev; description = get_if_description(name); if (add_or_find_if(&curdev, alldevs, name, flags, description, errbuf) == -1) { free(description); /* * Error - give up. */ return (-1); } free(description); if (curdev == NULL) { /* * Device wasn't added because it can't be opened. * Not a fatal error. */ return (0); } if (addr == NULL) { /* * There's no address to add; this entry just meant * "here's a new interface". */ return (0); } /* * "curdev" is an entry for this interface, and we have an * address for it; add an entry for that address to the * interface's list of addresses. * * Allocate the new entry and fill it in. */ return (add_addr_to_dev(curdev, addr, addr_size, netmask, netmask_size, broadaddr, broadaddr_size, dstaddr, dstaddr_size, errbuf)); }
/* * XXX - on FreeBSDs that support it, should it get the sysctl named * "dev.{adapter family name}.{adapter unit}.%desc" to get a description * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" * with my Cisco 350 card, so the name isn't entirely descriptive. The * "dev.an.0.%pnpinfo" has a better description, although one might argue * that the problem is really a driver bug - if it can find out that it's * a Cisco 340 or 350, rather than an old Aironet card, it should use * that in the description. * * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD * and OpenBSD let you get a description, but it's not generated by the OS, * it's set with another ioctl that ifconfig supports; we use that to get * a description in FreeBSD and OpenBSD, but if there is no such * description available, it still might be nice to get some description * string based on the device type or something such as that. * * In OS X, the System Configuration framework can apparently return * names in 10.4 and later. * * It also appears that freedesktop.org's HAL offers an "info.product" * string, but the HAL specification says it "should not be used in any * UI" and "subsystem/capability specific properties" should be used * instead and, in any case, I think HAL is being deprecated in * favor of other stuff such as DeviceKit. DeviceKit doesn't appear * to have any obvious product information for devices, but maybe * I haven't looked hard enough. * * Using the System Configuration framework, or HAL, or DeviceKit, or * whatever, would require that libpcap applications be linked with * the frameworks/libraries in question. That shouldn't be a problem * for programs linking with the shared version of libpcap (unless * you're running on AIX - which I think is the only UN*X that doesn't * support linking a shared library with other libraries on which it * depends, and having an executable linked only with the first shared * library automatically pick up the other libraries when started - * and using HAL or whatever). Programs linked with the static * version of libpcap would have to use pcap-config with the --static * flag in order to get the right linker flags in order to pick up * the additional libraries/frameworks; those programs need that anyway * for libpcap 1.1 and beyond on Linux, as, by default, it requires * -lnl. * * Do any other UN*Xes, or desktop environments support getting a * description? */ int add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, struct sockaddr *addr, size_t addr_size, struct sockaddr *netmask, size_t netmask_size, struct sockaddr *broadaddr, size_t broadaddr_size, struct sockaddr *dstaddr, size_t dstaddr_size, char *errbuf) { pcap_if_t *curdev; char *description = NULL; pcap_addr_t *curaddr, *prevaddr, *nextaddr; #ifdef SIOCGIFDESCR int s; struct ifreq ifrdesc; #ifndef IFDESCRSIZE size_t descrlen = 64; #else size_t descrlen = IFDESCRSIZE; #endif /* IFDESCRSIZE */ #endif /* SIOCGIFDESCR */ #ifdef SIOCGIFDESCR /* * Get the description for the interface. */ memset(&ifrdesc, 0, sizeof ifrdesc); strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); s = socket(AF_INET, SOCK_DGRAM, 0); if (s >= 0) { #ifdef __FreeBSD__ /* * On FreeBSD, if the buffer isn't big enough for the * description, the ioctl succeeds, but the description * isn't copied, ifr_buffer.length is set to the description * length, and ifr_buffer.buffer is set to NULL. */ for (;;) { free(description); if ((description = malloc(descrlen)) != NULL) { ifrdesc.ifr_buffer.buffer = description; ifrdesc.ifr_buffer.length = descrlen; if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { if (ifrdesc.ifr_buffer.buffer == description) break; else descrlen = ifrdesc.ifr_buffer.length; } else { /* * Failed to get interface description. */ free(description); description = NULL; break; } } else break; } #else /* __FreeBSD__ */ /* * The only other OS that currently supports * SIOCGIFDESCR is OpenBSD, and it has no way * to get the description length - it's clamped * to a maximum of IFDESCRSIZE. */ if ((description = malloc(descrlen)) != NULL) { ifrdesc.ifr_data = (caddr_t)description; if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { /* * Failed to get interface description. */ free(description); description = NULL; } } #endif /* __FreeBSD__ */ close(s); if (description != NULL && strlen(description) == 0) { free(description); description = NULL; } } #endif /* SIOCGIFDESCR */ if (add_or_find_if(&curdev, alldevs, name, flags, description, errbuf) == -1) { free(description); /* * Error - give up. */ return (-1); } free(description); if (curdev == NULL) { /* * Device wasn't added because it can't be opened. * Not a fatal error. */ return (0); } /* * "curdev" is an entry for this interface; add an entry for this * address to its list of addresses. * * Allocate the new entry and fill it in. */ curaddr = malloc(sizeof(pcap_addr_t)); if (curaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } curaddr->next = NULL; if (addr != NULL) { curaddr->addr = dup_sockaddr(addr, addr_size); if (curaddr->addr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); } } else curaddr->addr = NULL; if (netmask != NULL) { curaddr->netmask = dup_sockaddr(netmask, netmask_size); if (curaddr->netmask == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->addr != NULL) free(curaddr->addr); free(curaddr); return (-1); } } else curaddr->netmask = NULL; if (broadaddr != NULL) { curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); if (curaddr->broadaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->netmask != NULL) free(curaddr->netmask); if (curaddr->addr != NULL) free(curaddr->addr); free(curaddr); return (-1); } } else curaddr->broadaddr = NULL; if (dstaddr != NULL) { curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); if (curaddr->dstaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->broadaddr != NULL) free(curaddr->broadaddr); if (curaddr->netmask != NULL) free(curaddr->netmask); if (curaddr->addr != NULL) free(curaddr->addr); free(curaddr); return (-1); } } else curaddr->dstaddr = NULL; /* * Find the end of the list of addresses. */ for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { nextaddr = prevaddr->next; if (nextaddr == NULL) { /* * This is the end of the list. */ break; } } if (prevaddr == NULL) { /* * The list was empty; this is the first member. */ curdev->addresses = curaddr; } else { /* * "prevaddr" is the last member of the list; append * this member to it. */ prevaddr->next = curaddr; } return (0); }
static int add_addr_to_iflist(pcap_if_t **alldevs, char *name, u_int flags, struct sockaddr *addr, struct sockaddr *netmask, struct sockaddr *broadaddr, struct sockaddr *dstaddr, char *errbuf) { pcap_if_t *curdev; pcap_addr_t *curaddr, *prevaddr, *nextaddr; if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) { /* * Error - give up. */ return (-1); } if (curdev == NULL) { /* * Device wasn't added because it can't be opened. * Not a fatal error. */ return (0); } /* * "curdev" is an entry for this interface; add an entry for this * address to its list of addresses. * * Allocate the new entry and fill it in. */ curaddr = malloc(sizeof(pcap_addr_t)); if (curaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } curaddr->next = NULL; if (addr != NULL) { curaddr->addr = dup_sockaddr(addr); if (curaddr->addr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); } } else curaddr->addr = NULL; if (netmask != NULL) { curaddr->netmask = dup_sockaddr(netmask); if (curaddr->netmask == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); } } else curaddr->netmask = NULL; if (broadaddr != NULL) { curaddr->broadaddr = dup_sockaddr(broadaddr); if (curaddr->broadaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); } } else curaddr->broadaddr = NULL; if (dstaddr != NULL) { curaddr->dstaddr = dup_sockaddr(dstaddr); if (curaddr->dstaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); } } else curaddr->dstaddr = NULL; /* * Find the end of the list of addresses. */ for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { nextaddr = prevaddr->next; if (nextaddr == NULL) { /* * This is the end of the list. */ break; } } if (prevaddr == NULL) { /* * The list was empty; this is the first member. */ curdev->addresses = curaddr; } else { /* * "prevaddr" is the last member of the list; append * this member to it. */ prevaddr->next = curaddr; } return (0); }
static int pcap_add_if_win32(pcap_if_t **devlist, char *name, const char *desc, char *errbuf) { pcap_if_t *curdev; npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; LONG if_addr_size; int res = 0; if_addr_size = MAX_NETWORK_ADDRESSES; /* * Add an entry for this interface, with no addresses. */ if (add_or_find_if(&curdev, devlist, (char *)name, 0, (char *)desc, errbuf) == -1) { /* * Failure. */ return (-1); } /* * Get the list of addresses for the interface. */ if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) { /* * Failure. * * We don't return an error, because this can happen with * NdisWan interfaces, and we want to supply them even * if we can't supply their addresses. * * We return an entry with an empty address list. */ return (0); } /* * Now add the addresses. */ while (if_addr_size-- > 0) { /* * "curdev" is an entry for this interface; add an entry for * this address to its list of addresses. */ if(curdev == NULL) break; res = add_addr_to_list(curdev, (struct sockaddr *)&if_addrs[if_addr_size].IPAddress, (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask, (struct sockaddr *)&if_addrs[if_addr_size].Broadcast, NULL, errbuf); if (res == -1) { /* * Failure. */ break; } } return (res); }
/* * XXX - on FreeBSDs that support it, should it get the sysctl named * "dev.{adapter family name}.{adapter unit}.%desc" to get a description * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" * with my Cisco 350 card, so the name isn't entirely descriptive. The * "dev.an.0.%pnpinfo" has a better description, although one might argue * that the problem is really a driver bug - if it can find out that it's * a Cisco 340 or 350, rather than an old Aironet card, it should use * that in the description. * * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? OpenBSD * lets you get a description, but it's not generated by the OS, it's * set with another ioctl that ifconfig supports; we use that to get * the description in OpenBSD. * * In OS X, the System Configuration framework can apparently return * names in 10.4 and later; it also appears that freedesktop.org's HAL * offers an "info.product" string, but the HAL specification says * it "should not be used in any UI" and "subsystem/capability * specific properties" should be used instead. Using that would * require that libpcap applications be linked with the frameworks/ * libraries in question, which would be a bit of a pain unless we * offer, for example, a pkg-config: * * http://pkg-config.freedesktop.org/wiki/ * * script, so applications can just use that script to find out what * libraries you need to link with when linking with libpcap. * pkg-config is GPLed; I don't know whether that would prevent its * use with a BSD-licensed library such as libpcap. * * Do any other UN*Xes, or desktop environments support getting a * description? */ int add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags, struct sockaddr *addr, size_t addr_size, struct sockaddr *netmask, size_t netmask_size, struct sockaddr *broadaddr, size_t broadaddr_size, struct sockaddr *dstaddr, size_t dstaddr_size, char *errbuf) { pcap_if_t *curdev; char *description = NULL; pcap_addr_t *curaddr, *prevaddr, *nextaddr; #ifdef SIOCGIFDESCR struct ifreq ifrdesc; char ifdescr[IFDESCRSIZE]; int s; #endif #ifdef SIOCGIFDESCR /* * Get the description for the interface. */ memset(&ifrdesc, 0, sizeof ifrdesc); strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); ifrdesc.ifr_data = (caddr_t)&ifdescr; s = socket(AF_INET, SOCK_DGRAM, 0); if (s >= 0) { if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0 && strlen(ifrdesc.ifr_data) != 0) description = ifrdesc.ifr_data; close(s); } #endif if (add_or_find_if(&curdev, alldevs, name, flags, description, errbuf) == -1) { /* * Error - give up. */ return (-1); } if (curdev == NULL) { /* * Device wasn't added because it can't be opened. * Not a fatal error. */ return (0); } /* * "curdev" is an entry for this interface; add an entry for this * address to its list of addresses. * * Allocate the new entry and fill it in. */ curaddr = malloc(sizeof(pcap_addr_t)); if (curaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (-1); } curaddr->next = NULL; if (addr != NULL) { curaddr->addr = dup_sockaddr(addr, addr_size); if (curaddr->addr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); free(curaddr); return (-1); } } else curaddr->addr = NULL; if (netmask != NULL) { curaddr->netmask = dup_sockaddr(netmask, netmask_size); if (curaddr->netmask == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->addr != NULL) free(curaddr->addr); free(curaddr); return (-1); } } else curaddr->netmask = NULL; if (broadaddr != NULL) { curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); if (curaddr->broadaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->netmask != NULL) free(curaddr->netmask); if (curaddr->addr != NULL) free(curaddr->addr); free(curaddr); return (-1); } } else curaddr->broadaddr = NULL; if (dstaddr != NULL) { curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); if (curaddr->dstaddr == NULL) { (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); if (curaddr->broadaddr != NULL) free(curaddr->broadaddr); if (curaddr->netmask != NULL) free(curaddr->netmask); if (curaddr->addr != NULL) free(curaddr->addr); free(curaddr); return (-1); } } else curaddr->dstaddr = NULL; /* * Find the end of the list of addresses. */ for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { nextaddr = prevaddr->next; if (nextaddr == NULL) { /* * This is the end of the list. */ break; } } if (prevaddr == NULL) { /* * The list was empty; this is the first member. */ curdev->addresses = curaddr; } else { /* * "prevaddr" is the last member of the list; append * this member to it. */ prevaddr->next = curaddr; } return (0); }