| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that: (1) source code distributions |
| * retain the above copyright notice and this paragraph in its entirety, (2) |
| * distributions including binary code include the above copyright notice and |
| * this paragraph in its entirety in the documentation or other materials |
| * provided with the distribution, and (3) all advertising materials mentioning |
| * features or use of this software display the following acknowledgement: |
| * ``This product includes software developed by the University of California, |
| * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
| * the University nor the names of its contributors may be used to endorse |
| * or promote products derived from this software without specific prior |
| * written permission. |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * tcpdump/Win32 functions for reading and parsing system's Ethernet |
| * address file: |
| * '%SystemRoot%/drivers/etc/ethers' (Win-NT+) |
| * or '%Windir%/etc/ethers' (Win-9x/ME) |
| * |
| * G. Vanem <[email protected]> 2012. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <netdissect-stdinc.h> |
| |
| #include "missing/win_ether_ntohost.h" |
| |
| #include "netdissect.h" |
| #include "addrtoname.h" |
| |
| typedef struct ether_entry { |
| ether_address eth_addr; /* MAC address */ |
| char *name; /* name of MAC-address */ |
| struct ether_entry *next; |
| } ether_entry; |
| |
| static struct ether_entry *eth0 = NULL; |
| |
| /* |
| * The reason to avoid using 'pcap_next_etherent()' in addrtoname.c |
| * are several: |
| * 1) wpcap.dll and 'pcap_next_etherent()' could have been built in |
| * debug-mode (-MDd) or release-mode (-MD) and tcpdump in |
| * the opposite model. |
| * 2) If this is built by MSVC, wpcap.dll could have been built by |
| * MingW. It has no debug-model. |
| * 3) It may not have been exported from wpcap.dll (present in wpcap.def). |
| * |
| * So we shoe-horn the building of tcpdump with '-DUSE_ETHER_NTOHOST' to |
| * make 'init_etherarray()' call the below 'ether_ntohost()' instead. |
| */ |
| #if !defined(USE_ETHER_NTOHOST) |
| #error "'-DUSE_ETHER_NTOHOST' must be set" |
| #endif |
| |
| /* |
| * Return TRUE if running under Win-95/98/ME. |
| */ |
| static BOOL is_win9x (void) |
| { |
| OSVERSIONINFO ovi; |
| DWORD os_ver = GetVersion(); |
| DWORD major_ver = LOBYTE (LOWORD(os_ver)); |
| |
| return (os_ver >= 0x80000000 && major_ver >= 4); |
| } |
| |
| /* |
| * Return path to "%SystemRoot%/drivers/etc/<file>" (Win-NT+) |
| * or to "%Windir%/etc/<file>" (Win-9x/ME) |
| */ |
| const char *etc_path (const char *file) |
| { |
| BOOL win9x = is_win9x(); |
| const char *env = win9x ? getenv("WinDir") : getenv("SystemRoot"); |
| static char path[MAX_PATH]; |
| |
| if (!env) |
| return (file); |
| |
| if (win9x) |
| snprintf (path, sizeof(path), "%s\\etc\\%s", env, file); |
| else |
| snprintf (path, sizeof(path), "%s\\system32\\drivers\\etc\\%s", env, file); |
| |
| return (path); |
| } |
| |
| /* |
| * Parse a string-buf containing an MAC address and name. |
| * Accepts MAC addresses on both "xx:xx:xx.." and "xx-xx-xx.." forms. |
| * |
| * We could have used pcap_ether_aton(), but problem 3) above could apply. |
| * or we could have cut & pasted 'pcap_next_etherent(FILE *fp)' below. |
| */ |
| #define MIN_LEN sizeof("0:0:0:0:0:0 X") |
| |
| static |
| int parse_ether_buf (const char *buf, char **result, struct ether_addr *e) |
| { |
| const char *fmt; |
| char *name; |
| char *str = (char*)buf; |
| unsigned eth [sizeof(*e)]; |
| int i; |
| |
| /* Find first non-blank in 'buf' */ |
| while (str[0] && str[1] && isspace((int)str[0])) |
| str++; |
| |
| if (*str == '#' || *str == ';' || *str == '\n' || strlen(str) < MIN_LEN) |
| return (0); |
| |
| if (str[2] == ':') |
| fmt = "%02x:%02x:%02x:%02x:%02x:%02x"; |
| else |
| fmt = "%02x-%02x-%02x-%02x-%02x-%02x"; |
| |
| if (sscanf(str, fmt, ð[0], ð[1], ð[2], ð[3], ð[4], ð[5]) != MAC_ADDR_LEN) |
| return (0); |
| |
| str = strtok (str, " \t"); |
| name = strtok (NULL, " #\t\n"); |
| |
| if (!str || !name || strlen(name) < 1) |
| return (0); |
| |
| *result = name; |
| |
| for (i = 0; i < MAC_ADDR_LEN; i++) |
| e->octet[i] = eth[i]; |
| |
| return (1); |
| } |
| |
| static void free_ethers (void) |
| { |
| struct ether_entry *e, *next; |
| |
| for (e = eth0; e; e = next) { |
| next = e->next; |
| free(e->name); |
| free(e); |
| } |
| eth0 = NULL; |
| } |
| |
| static int init_ethers (void) |
| { |
| char buf[BUFSIZE]; |
| FILE *fp = fopen (etc_path("ethers"), "r"); |
| |
| if (!fp) |
| return (0); |
| |
| while (fgets(buf,sizeof(buf),fp)) |
| { |
| struct ether_entry *e; |
| char *name; |
| ether_address eth; |
| |
| if (!parse_ether_buf(buf,&name,ð)) |
| continue; |
| |
| e = calloc (sizeof(*e), 1); |
| if (!e) |
| break; |
| |
| memcpy(&e->eth_addr, ð, MAC_ADDR_LEN); |
| e->name = strdup(name); |
| if (!e->name) { |
| free(e); |
| break; |
| } |
| |
| e->next = eth0; |
| eth0 = e; |
| } |
| fclose(fp); |
| atexit(free_ethers); |
| return (1); |
| } |
| |
| /* |
| * Map an ethernet address 'e' to a 'name'. |
| * Returns 0 on success. |
| * |
| * This function is called at startup by init_etherarray() and then |
| * by etheraddr_string() as needed. To avoid doing an expensive fopen() |
| * on each call, the contents of 'etc_path("ethers")' is cached here in |
| * a linked-list 'eth0'. |
| */ |
| int ether_ntohost (char *name, struct ether_addr *e) |
| { |
| const struct ether_entry *cache; |
| static int init = 0; |
| |
| if (!init) { |
| init_ethers(); |
| init = 1; |
| } |
| |
| for (cache = eth0; cache; cache = cache->next) |
| if (!memcmp(&e->octet, &cache->eth_addr, MAC_ADDR_LEN)) { |
| strcpy (name,cache->name); |
| return (0); |
| } |
| return (1); |
| } |
| |