2
* Copyright (C) 1998-2004 Luca Deri <deri@ntop.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
* NOTE: About the tables in this program and vendortable.h...
25
* The official list is maintained by iana at
26
* http://www.iana.org/assignments/novell-sap-numbers
28
* While there is Makefile code to download and rebuild the structure (make dnsapt sapt),
29
* as of 01-2003, it doesn't work.
31
* The file format has been changed, the sapt.sed file is lost, and besides it builds a
32
* saptable.h file which you would manually have to insert into vendor.c.
34
* OTOP, Novell doesn't change things very often.
37
* The official list is updated daily at http://standards.ieee.org/regauth/oui/oui.txt
38
* The vendor table data does change, frequently, albeit irrelevantly to most of us.
39
* The ntop version of oui.txt is updated infrequently.
41
* To update (if say, you're seeing a lot of unknown values), download the list:
45
* Warning: the mac address list frequently discussed on the 'net at
46
* http://www.cavebear.com/CaveBear/Ethernet/vendor.html hasn't been
49
* If you want to save (disk) space, an oui.txt customized with only the ones
50
* you really need is certainly possible.
53
* The special mac table is referenced - lookupHost() in hash.c calls
54
* getSpecialMacInfo() in util.c - each time a new (pseudo) local host
57
* I (Burton) am unaware of any official or even pseudo-offical list.
59
* A 'special' MAC is one that's assigned (often in an RFC, IEEE standard,
60
* by consensus or in some other unusual way). It doesn't represent a PHYSICAL
61
* device or manufacturer.
65
* For example, 0x0180C2-000000 through -00000f, are reserved in
66
* "ANSI/IEEE Standard 802.1D (1998 edition)". See page 70 in
67
* http://standards.ieee.org/getieee802/download/802.1D-1998.pdf
69
* For example, the 2nd bit of a MAC address denotes an LAA, a Locally Assigned
70
* Address value. See IEEE 802.3-2002 (or earlier versions).
71
* Because bits are xmitted low to high , this stream, 0100000000000000...
72
* is MAC address 0x02000000. (See RFC 1638)
74
* These don't represent a manufacturer, but are values arbitrarily
75
* set by some network admin...
77
* Also, see http://www.iana.org/assignments/ppp-numbers for CF0000xxxxxx
81
* NOTE: About optimzing hash size...
83
* See the #define TEST_HASHSIZE_xxxxxx's below.
85
* Enabling it may run for a bit, as it tests each possible odd value from
86
* some low number up to whatever the MAX_ value is in globals-defines.h.
87
* (Testing will stop if a zero collision value is found).
89
* Testing will produce a running list, showing the best so far.
91
* TEST_HASHSIZE: Testing specialMacHash...wait
92
* TEST_HASHSIZE: specialMacHash 51 16
93
* TEST_HASHSIZE: specialMacHash 53 13
94
* TEST_HASHSIZE: specialMacHash 55 11
95
* TEST_HASHSIZE: specialMacHash 65 8
96
* TEST_HASHSIZE: specialMacHash 79 5
97
* TEST_HASHSIZE: specialMacHash 125 3
98
* TEST_HASHSIZE: specialMacHash 133 2
99
* TEST_HASHSIZE: specialMacHash 141 1
100
* TEST_HASHSIZE: specialMacHash BEST is 0 collisions, size 167
102
* The ipxsap table is referenced only for reporting - so a few collisions
107
unsigned long ipxsapId;
113
static char* macInputFiles[] = {
119
static IPXSAPInfo ipxSAP[] = {
120
{ 0x0000, "Unknown" },
122
{ 0x0002, "User Group" },
123
{ 0x0003, "Print Queue" },
124
{ 0x0004, "File server" },
125
{ 0x0005, "Job server" },
126
{ 0x0007, "Print server" },
127
{ 0x0008, "Archive server" },
128
{ 0x0009, "Archive server" },
129
{ 0x000a, "Job queue" },
130
{ 0x000b, "Administration" },
131
{ 0x0021, "NAS SNA gateway" },
132
{ 0x0024, "Remote bridge" },
133
{ 0x0026, "Bridge server" },
134
{ 0x0027, "TCP/IP gateway" },
135
{ 0x002d, "Time Synchronization VAP" },
136
{ 0x002e, "Archive Server Dynamic SAP" },
137
{ 0x0047, "Advertising print server" },
138
{ 0x004b, "Btrieve VAP 5.0" },
139
{ 0x004c, "SQL VAP" },
140
{ 0x0050, "Btrieve VAP" },
141
{ 0x0053, "Print Queue VAP" },
142
{ 0x007a, "TES NetWare for VMS" },
143
{ 0x0098, "NetWare access server" },
144
{ 0x009a, "Named Pipes server" },
145
{ 0x009e, "Portable NetWare Unix" },
146
{ 0x0107, "NetWare 386" },
147
{ 0x0111, "Test server" },
148
{ 0x0133, "NetWare Name Service" },
149
{ 0x0166, "NetWare management" },
150
{ 0x023f, "SMS Testing and Development" },
151
{ 0x026a, "NetWare management" },
152
{ 0x026b, "Time synchronization" },
153
{ 0x027b, "NetWare Management Agent" },
154
{ 0x0278, "NetWare Directory server" },
155
{ 0x030c, "HP LaserJet / Quick Silver" },
156
{ 0x0355, "Arcada Software" },
157
{ 0x0361, "NETINELO" },
158
{ 0x037e, "Powerchute UPS Monitoring" },
159
{ 0x03e1, "UnixWare Application Server" },
160
{ 0x044c, "Archive" },
161
{ 0x055d, "Attachmate SNA gateway" },
162
{ 0x0610, "Adaptec SCSI Management" },
163
{ 0x0640, "NT Server-RPC/GW for NW/Win95 User Level Sec" },
164
{ 0x064e, "NT Server-IIS" },
165
{ 0x0810, "ELAN License Server Demo" },
166
{ 0x8002, "Intel NetPort Print Server" },
170
IPXSAPInfo* ipxSAPhash[MAX_IPXSAP_NAME_HASH];
174
/* *********************************** */
176
static int addIPXSAPTableEntry(IPXSAPInfo* theMacHash[],
180
unsigned long ipxsapValue;
181
int hashLoadCollisions=0;
183
#ifdef PARM_USE_MACHASH_INVERT
184
ipxsapValue = 256*256*(unsigned long)(entry->ipxsapId & 0xff)
185
+ 256*(unsigned long)((entry->ipxsapId >> 8) & 0xff)
186
+ (unsigned long)((entry->ipxsapId >> 16) & 0xff);
188
idx = (u_int)(entry->ipxsapId % tableLen);
190
idx = (u_int)((u_int)ipxsapValue % tableLen);
193
traceEvent(CONST_TRACE_INFO, "DEBUG: addIPXSAPTableEntry(%06x, %s) gives %ld (mod %d = %d)",
201
/* Count # of collisions during load - only ONCE per item */
202
if(theMacHash[idx] != NULL) {
203
hashLoadCollisions++;
205
traceEvent(CONST_TRACE_INFO, "DEBUG: HashLoad Collision - %d %x '%s",
206
idx, entry->ipxsapId, entry->ipxsapName);
211
if(theMacHash[idx] == NULL) {
212
theMacHash[idx] = entry;
215
idx = (idx+1)%tableLen;
218
return hashLoadCollisions;
221
/* *********************************** */
223
char* getSAPInfo(u_int16_t sapInfo, short encodeString) {
225
unsigned long ipxsapValue = (unsigned long)sapInfo;
228
idx = (u_int)((u_int)sapInfo % MAX_IPXSAP_NAME_HASH);
231
cursor = ipxSAPhash[idx];
233
if(ipxSAPhash[idx] == NULL) {
236
} else if(ipxSAPhash[idx] != NULL) {
237
if(ipxSAPhash[idx]->ipxsapId == ipxsapValue) {
239
static char ipxsapName[256];
242
for(a=0, b=0; ipxSAPhash[idx]->ipxsapName[a] != '\0'; a++)
243
if(ipxSAPhash[idx]->ipxsapName[a] == ' ') {
244
ipxsapName[b++] = '&';
245
ipxsapName[b++] = 'n';
246
ipxsapName[b++] = 'b';
247
ipxsapName[b++] = 's';
248
ipxsapName[b++] = 'p';
249
ipxsapName[b++] = ';';
251
ipxsapName[b++] = ipxSAPhash[idx]->ipxsapName[a];
253
ipxsapName[b] = '\0';
256
return(ipxSAPhash[idx]->ipxsapName);
260
idx = (idx+1)%MAX_IPXSAP_NAME_HASH;
263
return(""); /* NOTREACHED */
266
/* *********************************** */
268
static char* getMACInfo(int special, u_char* ethAddress, short encodeString) {
269
datum key_data, data_data;
270
static char tmpBuf[96];
272
char etherbuf[LEN_ETHERNET_ADDRESS_DISPLAY];
274
workBuf = etheraddr_string(ethAddress, etherbuf);
275
memcpy(&tmpBuf, workBuf, LEN_ETHERNET_ADDRESS_DISPLAY+1);
277
traceEvent(CONST_TRACE_INFO, "VENDOR_DEBUG: %slookup '%s'",
278
special == 1 ? "special " : "", tmpBuf);
281
if(special == TRUE) {
283
/* Search the database for the specified MAC address - full 48 bit */
285
key_data.dptr = tmpBuf;
286
key_data.dsize = strlen(tmpBuf)+1;
289
traceEvent(CONST_TRACE_INFO, "VENDOR_DEBUG: Fetching 48bit '%s'", tmpBuf);
292
data_data = gdbm_fetch(myGlobals.macPrefixFile, key_data);
294
if(data_data.dptr == NULL) {
295
/* Maybe this is just the initial MAC (e.g 00:11:22) */
296
if(key_data.dsize > 8) {
297
key_data.dptr[8] = '\0';
302
if((data_data.dptr != NULL) && (((MACInfo*)data_data.dptr)->isSpecial = 's')) {
303
strncpy(tmpBuf, ((MACInfo*)data_data.dptr)->vendorName, sizeof(tmpBuf));
304
free(data_data.dptr);
305
myGlobals.numVendorLookupFound48bit++;
312
tmpBuf[LEN_ETHERNET_VENDOR_DISPLAY-1] = '\0'; /* Mask off left 24 bits */
313
key_data.dptr = tmpBuf;
314
key_data.dsize = strlen(tmpBuf)+1;
317
traceEvent(CONST_TRACE_INFO, "VENDOR_DEBUG: Fetching 24bit '%s'", tmpBuf);
320
data_data = gdbm_fetch(myGlobals.macPrefixFile, key_data);
322
if(data_data.dptr != NULL) {
323
if(((special == TRUE) && (((MACInfo*)data_data.dptr)->isSpecial = 's')) ||
324
((special == FALSE) && (((MACInfo*)data_data.dptr)->isSpecial != 's'))) {
325
strncpy(tmpBuf, ((MACInfo*)data_data.dptr)->vendorName, sizeof(tmpBuf));
326
free(data_data.dptr);
327
myGlobals.numVendorLookupFound24bit++;
333
/* Hand coded for LAA/Multicast */
334
if(((ethAddress[5] & 0x01) == 0) && ((ethAddress[6] & 0x01) == 0)) {
336
This is a dummy MAC that instead contains an IP addresses
337
in the first four bytes
339
Example: 0D:68:2B:C1:00:00
344
/* Hand coded for LAA/Multicast */
345
if((ethAddress[0] & 0x01) != 0) {
346
myGlobals.numVendorLookupFoundMulticast++;
350
if((ethAddress[0] & 0x02) != 0) {
351
myGlobals.numVendorLookupFoundLAA++;
352
return("LAA (Locally assigned address)");
355
traceEvent(CONST_TRACE_NOISY, "MAC prefix '%s' not found in vendor database", tmpBuf);
360
/* *********************************** */
362
char* getVendorInfo(u_char* ethAddress, short encodeString) {
365
if(memcmp(ethAddress, myGlobals.otherHostEntry->ethAddress, LEN_ETHERNET_ADDRESS) == 0)
368
ret = getMACInfo(1, ethAddress, encodeString);
369
myGlobals.numVendorLookupCalls++;
371
if((ret != NULL) && (ret[0] != '\0'))
377
/* *********************************** */
379
char* getSpecialMacInfo(HostTraffic* el, short encodeString) {
380
char* ret = getMACInfo(1, (u_char*)&(el->ethAddress), encodeString);
381
myGlobals.numVendorLookupSpecialCalls++;
383
if((ret != NULL) && (ret[0] != '\0'))
389
/* *********************************** */
391
void createVendorTable(struct stat *dbStat) {
392
int idx, numRead, numLoaded;
394
char tmpLine[LEN_GENERAL_WORK_BUFFER];
395
char tmpMACkey[LEN_ETHERNET_ADDRESS_DISPLAY+1];
396
char *tmpMAC, *tmpTag1, *tmpTag2, *tmpVendor, *strtokState;
397
struct macInfo macInfoEntry;
398
datum data_data, key_data;
399
u_char compressedFormat;
401
#ifdef TEST_HASHSIZE_IPXSAP
403
int i, j, best, besti;
405
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "TEST_HASHSIZE: Testing ipxSAP (%s) from 51 -> %d...wait",
406
#ifdef PARM_USE_MACHASH_INVERT
411
MAX_IPXSAP_NAME_HASH);
414
for (i=51; i<=MAX_IPXSAP_NAME_HASH; i += 2) {
416
for(idx=0; ipxSAP[idx].ipxsapName != NULL; idx++)
417
j += addIPXSAPTableEntry(ipxSAPhash, &ipxSAP[idx], i);
422
} else if( j < best ) {
425
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "TEST_HASHSIZE: ipxSAP %3d %3d", i, j);
427
memset(ipxSAPhash, 0, sizeof(ipxSAPhash));
429
traceEvent(CONST_TRACE_ALWAYSDISPLAY, "TEST_HASHSIZE: ipxSAP BEST is %d collisions, size %d", best, besti);
433
myGlobals.ipxsapHashLoadSize = sizeof(ipxSAPhash);
434
for(idx=0; ipxSAP[idx].ipxsapName != NULL; idx++) {
435
myGlobals.ipxsapHashLoadSize += sizeof(IPXSAPInfo) + strlen(ipxSAP[idx].ipxsapName);
436
myGlobals.ipxsapHashLoadCollisions +=
437
addIPXSAPTableEntry(ipxSAPhash, &ipxSAP[idx], MAX_IPXSAP_NAME_HASH);
441
* Ok, so we've loaded the static table.
442
* Now load the gdbm database for the real stuff
443
* (database was created and opened in initGdbm() in initialize.c)
445
* Here's a sample entry from oui.txt:
448
company_id Organization
452
00-00-00 (hex) XEROX CORPORATION
453
000000 (base 16) XEROX CORPORATION
458
* and from (our, specially created) special.txt:
460
018024 (special 24) Kalpana Etherswitch
461
0180C2000000 (special 48) Bridge Sp. Tree/OSI Route
463
* We use the (base 16) as our key and add similar values for special
464
* mac entries so we could co-mingled them.
466
* Note that any line without the 2nd word of '(base' or '(special' is
467
* simply ignored - allows comments if you're careful.
471
traceEvent(CONST_TRACE_INFO, "VENDOR: Loading MAC address table.");
472
for(idx=0; macInputFiles[idx] != NULL; idx++) {
473
fd=checkForInputFile("VENDOR",
481
while(readInputFile(fd,
486
tmpLine, sizeof(tmpLine),
489
myGlobals.numVendorLookupRead++;
490
if( (strstr(tmpLine, "(base") == NULL) &&
491
(strstr(tmpLine, "(special") == NULL) ) {
494
tmpMAC = strtok_r(tmpLine, " \t", &strtokState);
495
if(tmpMAC == NULL) continue;
496
tmpTag1 = strtok_r(NULL, " \t", &strtokState);
497
if(tmpTag1 == NULL) continue;
498
if((strcmp(tmpTag1, "(base") == 0) || (strcmp(tmpTag1, "(special") == 0)) {
499
tmpTag2 = strtok_r(NULL, " \t", &strtokState);
500
if(tmpTag2 == NULL) continue;
501
tmpVendor = strtok_r(NULL, "\n", &strtokState);
502
if(tmpVendor == NULL) continue;
503
/* Skip leading blanks and tabs*/
504
while ( (tmpVendor[0] == ' ') || (tmpVendor[0] == '\t') ) tmpVendor++;
505
memset(&macInfoEntry, 0, sizeof(macInfoEntry));
506
if(strcmp(tmpTag1, "(special") == 0) {
507
macInfoEntry.isSpecial = 's';
509
macInfoEntry.isSpecial = 'r';
511
memcpy(&(macInfoEntry.vendorName[0]),
513
min(strlen(tmpVendor)+1, sizeof(macInfoEntry.vendorName)-1));
514
data_data.dptr = (void*)(&macInfoEntry);
515
data_data.dsize = sizeof(macInfoEntry);
517
strncat(tmpMACkey, tmpMAC, 2);
518
strncat(tmpMACkey, ":", (sizeof(tmpMACkey) - strlen(tmpMACkey) - 1));
519
strncat(tmpMACkey, tmpMAC+2, 2);
520
strncat(tmpMACkey, ":", (sizeof(tmpMACkey) - strlen(tmpMACkey) - 1));
521
strncat(tmpMACkey, tmpMAC+4, 2);
522
if(strcmp(tmpTag2, "48)") == 0) {
523
/* special 48 - full tag */
524
strncat(tmpMACkey, ":", (sizeof(tmpMACkey) - strlen(tmpMACkey) - 1));
525
strncat(tmpMACkey, tmpMAC+6, 2);
526
strncat(tmpMACkey, ":", (sizeof(tmpMACkey) - strlen(tmpMACkey) - 1));
527
strncat(tmpMACkey, tmpMAC+8, 2);
528
strncat(tmpMACkey, ":", (sizeof(tmpMACkey) - strlen(tmpMACkey) - 1));
529
strncat(tmpMACkey, tmpMAC+10, 2);
531
key_data.dptr = tmpMACkey;
532
key_data.dsize = strlen(tmpMACkey)+1;
533
if(gdbm_store(myGlobals.macPrefixFile, key_data, data_data, GDBM_REPLACE) != 0) {
534
traceEvent(CONST_TRACE_WARNING,
535
"VENDOR: unable to add record '%s': {%d, %s} - skipped",
536
tmpMACkey, macInfoEntry.isSpecial, macInfoEntry.vendorName);
539
myGlobals.numVendorLookupAdded++;
540
if(macInfoEntry.isSpecial == 's')
541
myGlobals.numVendorLookupAddedSpecial++;
543
traceEvent(CONST_TRACE_INFO, "VENDOR_DEBUG: Added '%s': {%c, %s}",
544
tmpMACkey, macInfoEntry.isSpecial, macInfoEntry.vendorName);
550
traceEvent(CONST_TRACE_INFO, "VENDOR: ...loaded %d records", numLoaded);
553
traceEvent(CONST_TRACE_INFO,
554
"VENDOR: ntop continues ok");
557
} /* for macInputFiles */