From 34dea2740ad262c064213919d6ce5c28a160f40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 18 Mar 2008 14:36:35 +0000 Subject: [PATCH] * pcap_platform_finddevs() was not implemented at all (and did not return an error string explaining the situation), causing bug #1934. * When called without specifying an interface, it now chooses the first suitable interface from the list as documented. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24441 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/tcpdump/libpcap/pcap-haiku.cpp | 104 +++++++++++++++++- 1 file changed, 99 insertions(+), 5 deletions(-) diff --git a/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp b/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp index 11a513d0c4..b1f57da384 100644 --- a/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp +++ b/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -137,8 +138,8 @@ pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats) extern "C" pcap_t * -pcap_open_live(const char *device, int snapLength, int /*promisc*/, int /*timeout*/, - char *errorBuffer) +pcap_open_live(const char *device, int snapLength, int /*promisc*/, + int /*timeout*/, char *errorBuffer) { // TODO: handle promiscous mode! @@ -247,7 +248,100 @@ pcap_open_live(const char *device, int snapLength, int /*promisc*/, int /*timeou extern "C" int -pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +pcap_platform_finddevs(pcap_if_t** _allDevices, char* errorBuffer) { - return -1; + // we need a socket to talk to the networking stack + int socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (socket < 0) { + snprintf(errorBuffer, PCAP_ERRBUF_SIZE, + "The networking stack doesn't seem to be available.\n"); + return -1; + } + + // get a list of all interfaces + + ifconf config; + config.ifc_len = sizeof(config.ifc_value); + if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0) { + close(socket); + return -1; + } + + uint32 count = (uint32)config.ifc_value; + if (count == 0) { + snprintf(errorBuffer, PCAP_ERRBUF_SIZE, + "There are no interfaces defined!\n"); + close(socket); + return -1; + } + + void *buffer = malloc(count * sizeof(struct ifreq)); + if (buffer == NULL) { + snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Out of memory.\n"); + close(socket); + return -1; + } + + config.ifc_len = count * sizeof(struct ifreq); + config.ifc_buf = buffer; + if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0) { + close(socket); + return -1; + } + + ifreq *interface = (ifreq *)buffer; + pcap_if_t* last = NULL; + + for (uint32 i = 0; i < count; i++) { + pcap_if_t* pcapInterface = (pcap_if_t*)malloc(sizeof(pcap_if_t)); + if (pcapInterface == NULL) + continue; + + if (last == NULL) + *_allDevices = pcapInterface; + else + last->next = pcapInterface; + + pcapInterface->next = NULL; + pcapInterface->name = strdup(interface->ifr_name); + pcapInterface->description = NULL; + pcapInterface->addresses = NULL; + pcapInterface->flags = 0; + + // get interface type + + int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); + if (linkSocket < 0) { + fprintf(stderr, "No link level: %s\n", strerror(errno)); + } else { + struct ifreq request; + if (!prepare_request(request, interface->ifr_name)) { + snprintf(errorBuffer, PCAP_ERRBUF_SIZE, + "Interface name \"%s\" is too long.", interface->ifr_name); + close(linkSocket); + close(socket); + return -1; + } + + if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) + == 0) { + prepare_request(request, request.ifr_parameter.device); + if (ioctl(linkSocket, SIOCGIFADDR, &request, + sizeof(struct ifreq)) == 0) { + sockaddr_dl &link = *(sockaddr_dl *)&request.ifr_addr; + + if (link.sdl_type == IFT_LOOP) + pcapInterface->flags = PCAP_IF_LOOPBACK; + } + } + close(linkSocket); + } + + interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + + interface->ifr_addr.sa_len); + } + + free(buffer); + close(socket); + return 0; }