/* * intf-win32.c * * Copyright (c) 2002 Dug Song * * $Id: intf-win32.c 632 2006-08-10 04:36:52Z dugsong $ */ #ifdef _WIN32 #include "dnet_winconfig.h" #else #include "config.h" #endif #include #include #include #include #include #include #include "dnet.h" #include "pcap.h" #include #include struct intf_handle { pcap_if_t *pcapdevs; }; static int _pcapdev_to_entry(intf_t *intf, const pcap_if_t *pdev, unsigned int index, struct intf_entry *entry) { PACKET_OID_DATA *data; u_char buf[512]; LPADAPTER lpa; struct addr *ap, *lap; pcap_addr_t *addr; u_int intf_len; /* The total length of the entry may be passed inside entry. Remember it and clear the entry. */ intf_len = entry->intf_len; memset(entry, 0, sizeof(*entry)); entry->intf_len = intf_len; entry->intf_flags = 0; if (pdev->flags & PCAP_IF_LOOPBACK) { entry->intf_type = INTF_TYPE_LOOPBACK; entry->intf_flags |= INTF_FLAG_LOOPBACK; snprintf(entry->intf_name, sizeof(entry->intf_name), "lo%u", index); } else { entry->intf_type = INTF_TYPE_ETH; entry->intf_flags |= INTF_FLAG_MULTICAST; snprintf(entry->intf_name, sizeof(entry->intf_name), "eth%u", index); } /* Get interface flags. */ entry->intf_flags |= INTF_FLAG_UP; /* intf_mtu */ /* Get addresses. */ ap = entry->intf_alias_addrs; lap = ap + ((entry->intf_len - sizeof(*entry)) / sizeof(entry->intf_alias_addrs[0])); for (addr = pdev->addresses; addr != NULL; addr = addr->next) { if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) { addr_ston(addr->addr, &entry->intf_addr); addr_stob(addr->netmask, &entry->intf_addr.addr_bits); } else if (ap < lap) { if (addr_ston(addr->addr, ap) != -1 && addr_stob(addr->netmask, &ap->addr_bits) != -1) { ap++; entry->intf_alias_num++; } } } entry->intf_len = (u_int) ((u_char *)ap - (u_char *)entry); lpa = PacketOpenAdapter(pdev->name); if (lpa == NULL) return (-1); if (lpa->hFile == INVALID_HANDLE_VALUE) { PacketCloseAdapter(lpa); return (-1); } /* Get hardware address. */ if (entry->intf_type == INTF_TYPE_ETH) { data = (PACKET_OID_DATA *) buf; data->Oid = OID_802_3_CURRENT_ADDRESS; data->Length = sizeof(buf) - sizeof(*data); if (PacketRequest(lpa, FALSE, data) != TRUE) { PacketCloseAdapter(lpa); return (-1); } if (data->Length != ETH_ADDR_LEN) { PacketCloseAdapter(lpa); return (-1); } entry->intf_link_addr.addr_type = ADDR_TYPE_ETH; entry->intf_link_addr.addr_bits = ETH_ADDR_BITS; memcpy(&entry->intf_link_addr.addr_eth, data->Data, ETH_ADDR_LEN); } PacketCloseAdapter(lpa); return 0; } intf_t * intf_open(void) { return (calloc(1, sizeof(intf_t))); } int intf_get(intf_t *intf, struct intf_entry *entry) { char *p; pcap_if_t *pdev; int index, n; p = entry->intf_name; while (isalpha((int) (unsigned char) *p)) p++; index = atoi(p); n = 0; for (pdev = intf->pcapdevs; pdev != NULL; pdev = pdev->next) { if (n == index) break; n++; } if (pdev != NULL && _pcapdev_to_entry(intf, pdev, index, entry) == 0) return 0; return -1; } int intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src) { pcap_if_t *pdev; pcap_addr_t *addr; unsigned int i; for (i = 0, pdev = intf->pcapdevs; pdev != NULL; i++, pdev = pdev->next) { for (addr = pdev->addresses; addr != NULL; addr = addr->next) { struct addr dnet_addr; if (addr_ston(addr->addr, &dnet_addr) == -1) continue; if (addr_cmp(src, &dnet_addr) == 0) { if (_pcapdev_to_entry(intf, pdev, i, entry) == 0) return 0; } } } errno = ENXIO; return (-1); } #if 0 int intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst) { MIB_IFROW ifrow; if (dst->addr_type != ADDR_TYPE_IP) { errno = EINVAL; return (-1); } if (GetBestInterface(dst->addr_ip, &ifrow.dwIndex) != NO_ERROR) return (-1); if (GetIfEntry(&ifrow) != NO_ERROR) return (-1); if (_refresh_tables(intf) < 0) return (-1); _ifrow_to_entry(intf, &ifrow, entry); return (0); } #endif int intf_set(intf_t *intf, const struct intf_entry *entry) { /* * XXX - could set interface up/down via SetIfEntry(), * but what about the rest of the configuration? :-( * {Add,Delete}IPAddress for 2000/XP only */ #if 0 /* Set interface address. XXX - 2000/XP only? */ if (entry->intf_addr.addr_type == ADDR_TYPE_IP) { ULONG ctx = 0, inst = 0; UINT ip, mask; memcpy(&ip, &entry->intf_addr.addr_ip, IP_ADDR_LEN); addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN); if (AddIPAddress(ip, mask, _find_ifindex(intf, entry->intf_name), &ctx, &inst) != NO_ERROR) { return (-1); } return (0); } #endif errno = ENOSYS; SetLastError(ERROR_NOT_SUPPORTED); return (-1); } int intf_loop(intf_t *intf, intf_handler callback, void *arg) { struct intf_entry *entry; u_char ebuf[1024]; pcap_if_t *pcapdevs, *pdev; unsigned int index; int ret = 0; if (pcap_findalldevs(&pcapdevs, NULL) == -1) return (-1); entry = (struct intf_entry *) ebuf; for (pdev = pcapdevs, index = 0; pdev != NULL; pdev = pdev->next, index++) { entry->intf_len = sizeof(ebuf); if (_pcapdev_to_entry(intf, pdev, index, entry) == -1) continue; if ((ret = (*callback)(entry, arg)) != 0) break; } return (ret); } intf_t * intf_close(intf_t *intf) { if (intf->pcapdevs != NULL) pcap_freealldevs(intf->pcapdevs); return (NULL); } /* Converts a libdnet interface name to its pcap equivalent. The pcap name is stored in pcapdev up to a length of pcapdevlen, including the terminating '\0'. Returns -1 on error. */ int intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen) { const char *p; pcap_if_t *pcapdevs, *pdev; int index, n; p = intf_name; while (isalpha((int) (unsigned char) *p)) p++; index = atoi(p); if (pcap_findalldevs(&pcapdevs, NULL) == -1) return (-1); n = 0; for (pdev = pcapdevs; pdev != NULL; pdev = pdev->next) { if (n == index) break; n++; } if (pdev != NULL) strlcpy(pcapdev, pdev->name, pcapdevlen); pcap_freealldevs(pcapdevs); if (pdev == NULL) return -1; else return 0; }