217 lines
5.6 KiB
C
217 lines
5.6 KiB
C
/*
|
|
* 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 <gvanem@yahoo.no> 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);
|
|
}
|
|
|