1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that: (1) source code distributions 4 * retain the above copyright notice and this paragraph in its entirety, (2) 5 * distributions including binary code include the above copyright notice and 6 * this paragraph in its entirety in the documentation or other materials 7 * provided with the distribution, and (3) all advertising materials mentioning 8 * features or use of this software display the following acknowledgement: 9 * ``This product includes software developed by the University of California, 10 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 11 * the University nor the names of its contributors may be used to endorse 12 * or promote products derived from this software without specific prior 13 * written permission. 14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 * 18 * tcpdump/Win32 functions for reading and parsing system's Ethernet 19 * address file: 20 * '%SystemRoot%/drivers/etc/ethers' (Win-NT+) 21 * or '%Windir%/etc/ethers' (Win-9x/ME) 22 * 23 * G. Vanem <gvanem (at) yahoo.no> 2012. 24 */ 25 26 #ifdef HAVE_CONFIG_H 27 #include "config.h" 28 #endif 29 30 #include <netdissect-stdinc.h> 31 32 #include "ether.h" 33 #include "netdissect.h" 34 #include "addrtoname.h" 35 36 typedef struct ether_addr { 37 unsigned char octet[ETHER_ADDR_LEN]; 38 } ether_address; 39 40 typedef struct ether_entry { 41 ether_address eth_addr; /* MAC address */ 42 char *name; /* name of MAC-address */ 43 struct ether_entry *next; 44 } ether_entry; 45 46 static struct ether_entry *eth0 = NULL; 47 48 /* 49 * The reason to avoid using 'pcap_next_etherent()' in addrtoname.c 50 * are several: 51 * 1) wpcap.dll and 'pcap_next_etherent()' could have been built in 52 * debug-mode (-MDd) or release-mode (-MD) and tcpdump in 53 * the opposite model. 54 * 2) If this is built by MSVC, wpcap.dll could have been built by 55 * MingW. It has no debug-model. 56 * 3) It may not have been exported from wpcap.dll (present in wpcap.def). 57 * 58 * So we shoe-horn the building of tcpdump with '-DUSE_ETHER_NTOHOST' to 59 * make 'init_etherarray()' call the below 'ether_ntohost()' instead. 60 */ 61 #if !defined(USE_ETHER_NTOHOST) 62 #error "'-DUSE_ETHER_NTOHOST' must be set" 63 #endif 64 65 /* 66 * Return TRUE if running under Win-95/98/ME. 67 */ 68 static BOOL is_win9x (void) 69 { 70 OSVERSIONINFO ovi; 71 DWORD os_ver = GetVersion(); 72 DWORD major_ver = LOBYTE (LOWORD(os_ver)); 73 74 return (os_ver >= 0x80000000 && major_ver >= 4); 75 } 76 77 /* 78 * Return path to "%SystemRoot%/drivers/etc/<file>" (Win-NT+) 79 * or to "%Windir%/etc/<file>" (Win-9x/ME) 80 */ 81 const char *etc_path (const char *file) 82 { 83 BOOL win9x = is_win9x(); 84 const char *env = win9x ? getenv("WinDir") : getenv("SystemRoot"); 85 static char path[MAX_PATH]; 86 87 if (!env) 88 return (file); 89 90 if (win9x) 91 snprintf (path, sizeof(path), "%s\\etc\\%s", env, file); 92 else 93 snprintf (path, sizeof(path), "%s\\system32\\drivers\\etc\\%s", env, file); 94 95 return (path); 96 } 97 98 /* 99 * Parse a string-buf containing an MAC address and name. 100 * Accepts MAC addresses on both "xx:xx:xx.." and "xx-xx-xx.." forms. 101 * 102 * We could have used pcap_ether_aton(), but problem 3) above could apply. 103 * or we could have cut & pasted 'pcap_next_etherent(FILE *fp)' below. 104 */ 105 #define MIN_LEN sizeof("0:0:0:0:0:0 X") 106 107 static 108 int parse_ether_buf (const char *buf, char **result, struct ether_addr *e) 109 { 110 const char *fmt; 111 char *name; 112 char *str = (char*)buf; 113 unsigned eth [sizeof(*e)]; 114 int i; 115 116 /* Find first non-blank in 'buf' */ 117 while (str[0] && str[1] && isspace((int)str[0])) 118 str++; 119 120 if (*str == '#' || *str == ';' || *str == '\n' || strlen(str) < MIN_LEN) 121 return (0); 122 123 if (str[2] == ':') 124 fmt = "%02x:%02x:%02x:%02x:%02x:%02x"; 125 else 126 fmt = "%02x-%02x-%02x-%02x-%02x-%02x"; 127 128 if (sscanf(str, fmt, ð[0], ð[1], ð[2], ð[3], ð[4], ð[5]) != ETHER_ADDR_LEN) 129 return (0); 130 131 str = strtok (str, " \t"); 132 name = strtok (NULL, " #\t\n"); 133 134 if (!str || !name || strlen(name) < 1) 135 return (0); 136 137 *result = name; 138 139 for (i = 0; i < ETHER_ADDR_LEN; i++) 140 e->octet[i] = eth[i]; 141 142 return (1); 143 } 144 145 static void free_ethers (void) 146 { 147 struct ether_entry *e, *next; 148 149 for (e = eth0; e; e = next) { 150 next = e->next; 151 free(e->name); 152 free(e); 153 } 154 eth0 = NULL; 155 } 156 157 static int init_ethers (void) 158 { 159 char buf[BUFSIZE]; 160 FILE *fp = fopen (etc_path("ethers"), "r"); 161 162 if (!fp) 163 return (0); 164 165 while (fgets(buf,sizeof(buf),fp)) 166 { 167 struct ether_entry *e; 168 char *name; 169 ether_address eth; 170 171 if (!parse_ether_buf(buf,&name,ð)) 172 continue; 173 174 e = calloc (sizeof(*e), 1); 175 if (!e) 176 break; 177 178 memcpy(&e->eth_addr, ð, ETHER_ADDR_LEN); 179 e->name = strdup(name); 180 if (!e->name) { 181 free(e); 182 break; 183 } 184 185 e->next = eth0; 186 eth0 = e; 187 } 188 fclose(fp); 189 atexit(free_ethers); 190 return (1); 191 } 192 193 /* 194 * Map an ethernet address 'e' to a 'name'. 195 * Returns 0 on success. 196 * 197 * This function is called at startup by init_etherarray() and then 198 * by etheraddr_string() as needed. To avoid doing an expensive fopen() 199 * on each call, the contents of 'etc_path("ethers")' is cached here in 200 * a linked-list 'eth0'. 201 */ 202 int ether_ntohost (char *name, struct ether_addr *e) 203 { 204 const struct ether_entry *cache; 205 static int init = 0; 206 207 if (!init) { 208 init_ethers(); 209 init = 1; 210 } 211 212 for (cache = eth0; cache; cache = cache->next) 213 if (!memcmp(&e->octet, &cache->eth_addr, ETHER_ADDR_LEN)) { 214 strcpy (name,cache->name); 215 return (0); 216 } 217 return (1); 218 } 219 220