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