/* * 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 2012. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "ether.h" #include "netdissect.h" #include "addrtoname.h" typedef struct ether_addr { unsigned char octet[ETHER_ADDR_LEN]; } ether_address; 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/" (Win-NT+) * or to "%Windir%/etc/" (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]) != ETHER_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 < ETHER_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, ð, ETHER_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, ETHER_ADDR_LEN)) { strcpy (name,cache->name); return (0); } return (1); }