]> The Tcpdump Group git mirrors - tcpdump/blob - win32/src/ether_ntohost.c
PIM: Use more ND_TCHECK_n() macros
[tcpdump] / win32 / src / ether_ntohost.c
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@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 "netdissect.h"
33 #include "addrtoname.h"
34
35 typedef struct ether_addr {
36 unsigned char octet[MAC_ADDR_LEN];
37 } ether_address;
38
39 typedef struct ether_entry {
40 ether_address eth_addr; /* MAC address */
41 char *name; /* name of MAC-address */
42 struct ether_entry *next;
43 } ether_entry;
44
45 static struct ether_entry *eth0 = NULL;
46
47 /*
48 * The reason to avoid using 'pcap_next_etherent()' in addrtoname.c
49 * are several:
50 * 1) wpcap.dll and 'pcap_next_etherent()' could have been built in
51 * debug-mode (-MDd) or release-mode (-MD) and tcpdump in
52 * the opposite model.
53 * 2) If this is built by MSVC, wpcap.dll could have been built by
54 * MingW. It has no debug-model.
55 * 3) It may not have been exported from wpcap.dll (present in wpcap.def).
56 *
57 * So we shoe-horn the building of tcpdump with '-DUSE_ETHER_NTOHOST' to
58 * make 'init_etherarray()' call the below 'ether_ntohost()' instead.
59 */
60 #if !defined(USE_ETHER_NTOHOST)
61 #error "'-DUSE_ETHER_NTOHOST' must be set"
62 #endif
63
64 /*
65 * Return TRUE if running under Win-95/98/ME.
66 */
67 static BOOL is_win9x (void)
68 {
69 OSVERSIONINFO ovi;
70 DWORD os_ver = GetVersion();
71 DWORD major_ver = LOBYTE (LOWORD(os_ver));
72
73 return (os_ver >= 0x80000000 && major_ver >= 4);
74 }
75
76 /*
77 * Return path to "%SystemRoot%/drivers/etc/<file>" (Win-NT+)
78 * or to "%Windir%/etc/<file>" (Win-9x/ME)
79 */
80 const char *etc_path (const char *file)
81 {
82 BOOL win9x = is_win9x();
83 const char *env = win9x ? getenv("WinDir") : getenv("SystemRoot");
84 static char path[MAX_PATH];
85
86 if (!env)
87 return (file);
88
89 if (win9x)
90 snprintf (path, sizeof(path), "%s\\etc\\%s", env, file);
91 else
92 snprintf (path, sizeof(path), "%s\\system32\\drivers\\etc\\%s", env, file);
93
94 return (path);
95 }
96
97 /*
98 * Parse a string-buf containing an MAC address and name.
99 * Accepts MAC addresses on both "xx:xx:xx.." and "xx-xx-xx.." forms.
100 *
101 * We could have used pcap_ether_aton(), but problem 3) above could apply.
102 * or we could have cut & pasted 'pcap_next_etherent(FILE *fp)' below.
103 */
104 #define MIN_LEN sizeof("0:0:0:0:0:0 X")
105
106 static
107 int parse_ether_buf (const char *buf, char **result, struct ether_addr *e)
108 {
109 const char *fmt;
110 char *name;
111 char *str = (char*)buf;
112 unsigned eth [sizeof(*e)];
113 int i;
114
115 /* Find first non-blank in 'buf' */
116 while (str[0] && str[1] && isspace((int)str[0]))
117 str++;
118
119 if (*str == '#' || *str == ';' || *str == '\n' || strlen(str) < MIN_LEN)
120 return (0);
121
122 if (str[2] == ':')
123 fmt = "%02x:%02x:%02x:%02x:%02x:%02x";
124 else
125 fmt = "%02x-%02x-%02x-%02x-%02x-%02x";
126
127 if (sscanf(str, fmt, &eth[0], &eth[1], &eth[2], &eth[3], &eth[4], &eth[5]) != MAC_ADDR_LEN)
128 return (0);
129
130 str = strtok (str, " \t");
131 name = strtok (NULL, " #\t\n");
132
133 if (!str || !name || strlen(name) < 1)
134 return (0);
135
136 *result = name;
137
138 for (i = 0; i < MAC_ADDR_LEN; i++)
139 e->octet[i] = eth[i];
140
141 return (1);
142 }
143
144 static void free_ethers (void)
145 {
146 struct ether_entry *e, *next;
147
148 for (e = eth0; e; e = next) {
149 next = e->next;
150 free(e->name);
151 free(e);
152 }
153 eth0 = NULL;
154 }
155
156 static int init_ethers (void)
157 {
158 char buf[BUFSIZE];
159 FILE *fp = fopen (etc_path("ethers"), "r");
160
161 if (!fp)
162 return (0);
163
164 while (fgets(buf,sizeof(buf),fp))
165 {
166 struct ether_entry *e;
167 char *name;
168 ether_address eth;
169
170 if (!parse_ether_buf(buf,&name,&eth))
171 continue;
172
173 e = calloc (sizeof(*e), 1);
174 if (!e)
175 break;
176
177 memcpy(&e->eth_addr, &eth, MAC_ADDR_LEN);
178 e->name = strdup(name);
179 if (!e->name) {
180 free(e);
181 break;
182 }
183
184 e->next = eth0;
185 eth0 = e;
186 }
187 fclose(fp);
188 atexit(free_ethers);
189 return (1);
190 }
191
192 /*
193 * Map an ethernet address 'e' to a 'name'.
194 * Returns 0 on success.
195 *
196 * This function is called at startup by init_etherarray() and then
197 * by etheraddr_string() as needed. To avoid doing an expensive fopen()
198 * on each call, the contents of 'etc_path("ethers")' is cached here in
199 * a linked-list 'eth0'.
200 */
201 int ether_ntohost (char *name, struct ether_addr *e)
202 {
203 const struct ether_entry *cache;
204 static int init = 0;
205
206 if (!init) {
207 init_ethers();
208 init = 1;
209 }
210
211 for (cache = eth0; cache; cache = cache->next)
212 if (!memcmp(&e->octet, &cache->eth_addr, MAC_ADDR_LEN)) {
213 strcpy (name,cache->name);
214 return (0);
215 }
216 return (1);
217 }
218