Add support for Cisco ISL.
[obnox/wireshark/wip.git] / resolv.c
1 /* resolv.c
2  * Routines for network object lookup
3  *
4  * $Id: resolv.c,v 1.22 2000/01/10 17:32:52 gram Exp $
5  *
6  * Laurent Deniel <deniel@worldnet.fr>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #ifndef WIN32
37 #ifndef AVOID_DNS_TIMEOUT
38 #define AVOID_DNS_TIMEOUT
39 #endif
40 #endif
41
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
48 #endif
49
50 #ifdef HAVE_NETINET_IN_H
51 # include <netinet/in.h>
52 #endif
53
54 #ifdef HAVE_NETDB_H
55 #include <netdb.h>
56 #endif
57
58 #ifdef HAVE_ARPA_INET_H
59 #include <arpa/inet.h>
60 #endif
61
62 #include <signal.h>
63
64 #ifdef HAVE_SYS_SOCKET_H
65 #include <sys/socket.h>
66 #endif
67
68 #ifdef AVOID_DNS_TIMEOUT
69 # include <setjmp.h>
70 #endif
71
72 #ifdef NEED_INET_V6DEFS_H
73 # include "inet_v6defs.h"
74 #endif
75
76 #include "packet.h"
77 #include "packet-ipv6.h"
78 #include "packet-ipx.h"
79 #include "globals.h"
80 #include "resolv.h"
81
82 #define MAXMANUFLEN     9       /* max vendor name length with ending '\0' */
83 #define HASHETHSIZE     1024
84 #define HASHHOSTSIZE    1024
85 #define HASHIPXNETSIZE  256
86 #define HASHMANUFSIZE   256
87 #define HASHPORTSIZE    256
88
89 /* hash table used for host and port lookup */
90
91 typedef struct hashname {
92   u_int                 addr;
93   u_char                name[MAXNAMELEN];
94   struct hashname       *next;
95 } hashname_t;
96
97 /* hash table used for IPX network lookup */
98
99 typedef struct hashname hashipxnet_t;
100
101 /* hash tables used for ethernet and manufacturer lookup */
102
103 typedef struct hashmanuf {
104   u_char                addr[3];
105   char                  name[MAXMANUFLEN];
106   struct hashmanuf      *next;
107 } hashmanuf_t;
108
109 typedef struct hashether {
110   u_char                addr[6];
111   char                  name[MAXNAMELEN];
112   gboolean              is_name_from_file;
113   struct hashether      *next;
114 } hashether_t;
115
116 /* internal ethernet type */
117
118 typedef struct _ether
119 {
120   u_char                addr[6];
121   char                  name[MAXNAMELEN];
122 } ether_t;
123
124 /* internal ipxnet type */
125
126 typedef struct _ipxnet
127 {
128   u_int                 addr;
129   char                  name[MAXNAMELEN];
130 } ipxnet_t;
131
132 static hashname_t       *host_table[HASHHOSTSIZE];
133 static hashname_t       *udp_port_table[HASHPORTSIZE];
134 static hashname_t       *tcp_port_table[HASHPORTSIZE];
135 static hashether_t      *eth_table[HASHETHSIZE];
136 static hashmanuf_t      *manuf_table[HASHMANUFSIZE];
137 static hashipxnet_t     *ipxnet_table[HASHIPXNETSIZE];
138
139 static int              eth_resolution_initialized = 0;
140 static int              ipxnet_resolution_initialized = 0;
141
142 /*
143  *  Global variables (can be changed in GUI sections)
144  */
145
146 int g_resolving_actif = 1;              /* routines are active by default */
147
148 gchar *g_ethers_path  = EPATH_ETHERS;
149 gchar *g_pethers_path = NULL;           /* "$HOME"/EPATH_PERSONAL_ETHERS    */
150 gchar *g_ipxnets_path  = EPATH_IPXNETS;
151 gchar *g_pipxnets_path = NULL;          /* "$HOME"/EPATH_PERSONAL_IPXNETS   */
152 gchar *g_manuf_path   = EPATH_MANUF;    /* may only be changed before the   */
153                                         /* first resolving call             */
154
155 /*
156  *  Local function definitions 
157  */
158
159 static u_char *serv_name_lookup(u_int port, u_int proto)
160 {
161
162   hashname_t *tp;
163   hashname_t **table;
164   char *serv_proto = NULL;
165   struct servent *servp;
166   int i;
167
168   switch(proto) {
169   case IPPROTO_UDP:
170     table = udp_port_table;
171     serv_proto = "udp";
172     break;
173   case IPPROTO_TCP:
174     table = tcp_port_table;
175     serv_proto = "tcp";
176     break;
177   default:
178     /* not yet implemented */
179     return NULL;
180     /*NOTREACHED*/
181     break;
182   } /* proto */
183   
184   i = port & (HASHPORTSIZE - 1);
185   tp = table[ i & (HASHPORTSIZE - 1)];
186
187   if( tp == NULL ) {
188     tp = table[ i & (HASHPORTSIZE - 1)] = 
189       (hashname_t *)g_malloc(sizeof(hashname_t));
190   } else {  
191     while(1) {
192       if( tp->addr == port ) {
193         return tp->name;
194       }
195       if (tp->next == NULL) {
196         tp->next = (hashname_t *)g_malloc(sizeof(hashname_t));
197         tp = tp->next;
198         break;
199       }
200       tp = tp->next;
201     }
202   }
203   
204   /* fill in a new entry */
205   tp->addr = port;
206   tp->next = NULL;
207
208   if ((servp = getservbyport(htons(port), serv_proto)) == NULL) {
209     /* unknown port */
210     sprintf(tp->name, "%d", port);
211   } else {
212     strncpy(tp->name, servp->s_name, MAXNAMELEN);
213     tp->name[MAXNAMELEN-1] = '\0';
214   }
215
216   return (tp->name);
217
218 } /* serv_name_lookup */
219
220 #ifdef AVOID_DNS_TIMEOUT
221
222 #define DNS_TIMEOUT     2       /* max sec per call */
223
224 jmp_buf hostname_env;
225
226 static void abort_network_query(int sig)
227 {
228   longjmp(hostname_env, 1);
229 }
230 #endif /* AVOID_DNS_TIMEOUT */
231
232 static u_char *host_name_lookup(u_int addr)
233 {
234
235   hashname_t * volatile tp;
236   hashname_t **table = host_table;
237   struct hostent *hostp;
238
239   tp = table[ addr & (HASHHOSTSIZE - 1)];
240
241   if( tp == NULL ) {
242     tp = table[ addr & (HASHHOSTSIZE - 1)] = 
243       (hashname_t *)g_malloc(sizeof(hashname_t));
244   } else {  
245     while(1) {
246       if( tp->addr == addr ) {
247         return tp->name;
248       }
249       if (tp->next == NULL) {
250         tp->next = (hashname_t *)g_malloc(sizeof(hashname_t));
251         tp = tp->next;
252         break;
253       }
254       tp = tp->next;
255     }
256   }
257   
258   /* fill in a new entry */
259   tp->addr = addr;
260   tp->next = NULL;
261
262 #ifdef AVOID_DNS_TIMEOUT
263     
264   /* Quick hack to avoid DNS/YP timeout */
265   
266   if (!setjmp(hostname_env)) {
267     signal(SIGALRM, abort_network_query);
268     alarm(DNS_TIMEOUT);
269 #endif
270     hostp = gethostbyaddr((char *)&addr, 4, AF_INET);
271 #ifdef AVOID_DNS_TIMEOUT
272     alarm(0);
273 #endif
274     if (hostp != NULL) {
275       strncpy(tp->name, hostp->h_name, MAXNAMELEN);
276       tp->name[MAXNAMELEN-1] = '\0';
277       return tp->name;
278     }
279 #ifdef AVOID_DNS_TIMEOUT
280   }
281 #endif
282
283   /* unknown host or DNS timeout */
284
285   sprintf(tp->name, "%s", ip_to_str((guint8 *)&addr));  
286
287   return (tp->name);
288
289 } /* host_name_lookup */
290
291 static u_char *host_name_lookup6(struct e_in6_addr *addr)
292 {
293   static u_char name[MAXNAMELEN];
294 #ifdef INET6
295   struct hostent *hostp;
296
297 #ifdef AVOID_DNS_TIMEOUT
298     
299   /* Quick hack to avoid DNS/YP timeout */
300   
301   if (!setjmp(hostname_env)) {
302     signal(SIGALRM, abort_network_query);
303     alarm(DNS_TIMEOUT);
304 #endif /* AVOID_DNS_TIMEOUT */
305     hostp = gethostbyaddr((char *)addr, sizeof(*addr), AF_INET6);
306 #ifdef AVOID_DNS_TIMEOUT
307     alarm(0);
308 #endif
309     if (hostp != NULL) {
310       strncpy(name, hostp->h_name, MAXNAMELEN);
311       name[MAXNAMELEN-1] = '\0';
312       return name;
313     }
314 #ifdef AVOID_DNS_TIMEOUT
315   }
316 #endif
317
318   /* unknown host or DNS timeout */
319 #endif /* INET6 */
320   sprintf(name, "%s", ip6_to_str(addr));  
321   return (name);
322 }
323
324 /*
325  *  Miscellaneous functions
326  */
327
328 static int fgetline(char **buf, int *size, FILE *fp)
329 {
330   int len;
331   int c;
332
333   if (fp == NULL)
334     return -1;
335
336   if (*buf == NULL) {
337     if (*size == 0) 
338       *size = BUFSIZ;
339     
340     if ((*buf = g_malloc(*size)) == NULL)
341       return -1;
342   }
343
344   if (feof(fp))
345     return -1;
346     
347   len = 0;
348   while ((c = getc(fp)) != EOF && c != '\n') {
349     if (len+1 >= *size) {
350       if ((*buf = g_realloc(*buf, *size += BUFSIZ)) == NULL)
351         return -1;
352     }
353     (*buf)[len++] = c;
354   }
355
356   if (len == 0 && c == EOF)
357     return -1;
358     
359   (*buf)[len] = '\0';
360     
361   return len;
362
363 } /* fgetline */
364
365
366 /*
367  * Ethernet / manufacturer resolution
368  *
369  * The following functions implement ethernet address resolution and
370  * ethers files parsing (see ethers(4)). 
371  *
372  * /etc/manuf has the same format as ethers(4) except that names are 
373  * truncated to MAXMANUFLEN-1 characters and that an address contains 
374  * only 3 bytes (instead of 6).
375  *
376  * Notes:
377  *
378  * I decide to not use the existing functions (see ethers(3) on some 
379  * operating systems) for the following reasons:
380  * - performance gains (use of hash tables and some other enhancements),
381  * - use of two ethers files (system-wide and per user),
382  * - avoid the use of NIS maps,
383  * - lack of these functions on some systems.
384  *
385  * So the following functions do _not_ behave as the standard ones.
386  *
387  * -- Laurent.
388  */
389
390
391 static int parse_ether_line(char *line, ether_t *eth, int six_bytes)
392 {
393   /*
394    *  See man ethers(4) for /etc/ethers file format
395    *  (not available on all systems).
396    *  We allow both ethernet address separators (':' and '-'),
397    *  as well as Ethereal's '.' separator.
398    */
399
400   gchar *cp;
401   int a0, a1, a2, a3, a4, a5;
402     
403   if ((cp = strchr(line, '#')))
404     *cp = '\0';
405   
406   if ((cp = strtok(line, " \t\n")) == NULL)
407     return -1;
408
409   if (six_bytes) {
410     if (sscanf(cp, "%x:%x:%x:%x:%x:%x", &a0, &a1, &a2, &a3, &a4, &a5) != 6) {
411       if (sscanf(cp, "%x-%x-%x-%x-%x-%x", &a0, &a1, &a2, &a3, &a4, &a5) != 6) {
412         if (sscanf(cp, "%x.%x.%x.%x.%x.%x", &a0, &a1, &a2, &a3, &a4, &a5) != 6)
413           return -1;
414       }
415     }
416   } else {
417     if (sscanf(cp, "%x:%x:%x", &a0, &a1, &a2) != 3) {
418       if (sscanf(cp, "%x-%x-%x", &a0, &a1, &a2) != 3) {
419         if (sscanf(cp, "%x.%x.%x", &a0, &a1, &a2) != 3)
420         return -1;
421       }
422     }
423   }
424
425   if ((cp = strtok(NULL, " \t\n")) == NULL)
426     return -1;
427
428   eth->addr[0] = a0;
429   eth->addr[1] = a1;
430   eth->addr[2] = a2;
431   if (six_bytes) {
432     eth->addr[3] = a3;
433     eth->addr[4] = a4;
434     eth->addr[5] = a5;
435   } else {
436     eth->addr[3] = 0;
437     eth->addr[4] = 0;
438     eth->addr[5] = 0;
439   }
440
441   strncpy(eth->name, cp, MAXNAMELEN);
442   eth->name[MAXNAMELEN-1] = '\0';
443
444   return 0;
445
446 } /* parse_ether_line */
447
448 static FILE *eth_p = NULL;
449
450 static void set_ethent(char *path)
451 {
452   if (eth_p)
453     rewind(eth_p);
454   else
455     eth_p = fopen(path, "r");
456 }
457
458 static void end_ethent(void)
459 {
460   if (eth_p) {
461     fclose(eth_p);
462     eth_p = NULL;
463   }
464 }
465
466 static ether_t *get_ethent(int six_bytes)
467 {
468  
469   static ether_t eth;
470   static int     size = 0;
471   static char   *buf = NULL;
472   
473   if (eth_p == NULL) 
474     return NULL;
475
476   while (fgetline(&buf, &size, eth_p) >= 0) {
477     if (parse_ether_line(buf, &eth, six_bytes) == 0) {
478       return &eth;
479     }
480   }
481     
482   return NULL;
483
484 } /* get_ethent */
485
486 static ether_t *get_ethbyname(u_char *name)
487 {
488   ether_t *eth;
489   
490   set_ethent(g_ethers_path);
491
492   while ((eth = get_ethent(1)) && strncmp(name, eth->name, MAXNAMELEN) != 0)
493     ;
494
495   if (eth == NULL) {
496     end_ethent();
497     
498     set_ethent(g_pethers_path);
499
500     while ((eth = get_ethent(1)) && strncmp(name, eth->name, MAXNAMELEN) != 0)
501       ;
502
503     end_ethent();
504   }
505
506   return eth;
507
508 } /* get_ethbyname */
509
510 static ether_t *get_ethbyaddr(const u_char *addr)
511 {
512
513   ether_t *eth;
514   
515   set_ethent(g_ethers_path);
516
517   while ((eth = get_ethent(1)) && memcmp(addr, eth->addr, 6) != 0)
518     ;
519
520   if (eth == NULL) {
521     end_ethent();
522     
523     set_ethent(g_pethers_path);
524     
525     while ((eth = get_ethent(1)) && memcmp(addr, eth->addr, 6) != 0)
526       ;
527     
528     end_ethent();
529   }
530
531   return eth;
532
533 } /* get_ethbyaddr */
534
535 static void add_manuf_name(u_char *addr, u_char *name)
536 {
537
538   hashmanuf_t *tp;
539   hashmanuf_t **table = manuf_table;
540
541   tp = table[ ((int)addr[2]) & (HASHMANUFSIZE - 1)];
542
543   if( tp == NULL ) {
544     tp = table[ ((int)addr[2]) & (HASHMANUFSIZE - 1)] = 
545       (hashmanuf_t *)g_malloc(sizeof(hashmanuf_t));
546   } else {  
547     while(1) {
548       if (tp->next == NULL) {
549         tp->next = (hashmanuf_t *)g_malloc(sizeof(hashmanuf_t));
550         tp = tp->next;
551         break;
552       }
553       tp = tp->next;
554     }
555   }
556   
557   memcpy(tp->addr, addr, sizeof(tp->addr));
558   strncpy(tp->name, name, MAXMANUFLEN);
559   tp->name[MAXMANUFLEN-1] = '\0';
560   tp->next = NULL;
561
562 } /* add_manuf_name */
563
564 static hashmanuf_t *manuf_name_lookup(const u_char *addr)
565 {
566
567   hashmanuf_t *tp;
568   hashmanuf_t **table = manuf_table;
569
570   tp = table[ ((int)addr[2]) & (HASHMANUFSIZE - 1)];
571   
572   while(tp != NULL) {
573     if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
574       return tp;
575     }
576     tp = tp->next;
577   }
578   
579   return NULL;
580
581 } /* manuf_name_lookup */
582
583 static void initialize_ethers(void)
584 {
585   ether_t *eth;
586
587 #ifdef DEBUG_RESOLV
588   signal(SIGSEGV, SIG_IGN);
589 #endif
590
591   /* Set g_pethers_path here, but don't actually do anything
592    * with it. It's used in get_ethbyname() and get_ethbyaddr()
593    */
594   if (g_pethers_path == NULL) {
595     g_pethers_path = g_malloc(strlen(getenv("HOME")) + 
596                               strlen(EPATH_PERSONAL_ETHERS) + 2);
597     sprintf(g_pethers_path, "%s/%s", 
598             (char *)getenv("HOME"), EPATH_PERSONAL_ETHERS);
599   }
600
601   /* manuf hash table initialization */
602
603   set_ethent(g_manuf_path);
604
605   while ((eth = get_ethent(0))) {
606     add_manuf_name(eth->addr, eth->name);
607   }
608
609   end_ethent();
610
611 } /* initialize_ethers */
612
613 static hashether_t *add_eth_name(u_char *addr, u_char *name)
614 {
615   hashether_t *tp;
616   hashether_t **table = eth_table;
617   int i,j;
618
619   j = (addr[2] << 8) | addr[3];
620   i = (addr[4] << 8) | addr[5];
621
622   tp = table[ (i ^ j) & (HASHETHSIZE - 1)];
623
624   if( tp == NULL ) {
625     tp = table[ (i ^ j) & (HASHETHSIZE - 1)] = 
626       (hashether_t *)g_malloc(sizeof(hashether_t));
627   } else {  
628     while(1) {
629       if (tp->next == NULL) {
630         tp->next = (hashether_t *)g_malloc(sizeof(hashether_t));
631         tp = tp->next;
632         break;
633       }
634       tp = tp->next;
635     }
636   }
637   
638   memcpy(tp->addr, addr, sizeof(tp->addr));
639   strncpy(tp->name, name, MAXNAMELEN);
640   tp->name[MAXNAMELEN-1] = '\0';
641   tp->next = NULL;
642
643   return tp;
644
645 } /* add_eth_name */
646
647 static u_char *eth_name_lookup(const u_char *addr)
648 {
649   hashmanuf_t *manufp;
650   hashether_t *tp;
651   hashether_t **table = eth_table;
652   ether_t *eth;
653   int i,j;
654
655   j = (addr[2] << 8) | addr[3];
656   i = (addr[4] << 8) | addr[5];
657
658   tp = table[ (i ^ j) & (HASHETHSIZE - 1)];
659
660   if( tp == NULL ) {
661     tp = table[ (i ^ j) & (HASHETHSIZE - 1)] = 
662       (hashether_t *)g_malloc(sizeof(hashether_t));
663   } else {  
664     while(1) {
665       if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
666         return tp->name;
667       }
668       if (tp->next == NULL) {
669         tp->next = (hashether_t *)g_malloc(sizeof(hashether_t));
670         tp = tp->next;
671         break;
672       }
673       tp = tp->next;
674     }
675   }
676   
677   /* fill in a new entry */
678
679   memcpy(tp->addr, addr, sizeof(tp->addr));
680   tp->next = NULL;
681
682   if ( (eth = get_ethbyaddr(addr)) == NULL) {
683     /* unknown name */
684
685     if ((manufp = manuf_name_lookup(addr)) == NULL)
686       sprintf(tp->name, "%s", ether_to_str((guint8 *)addr));
687     else
688       sprintf(tp->name, "%s_%02x:%02x:%02x", 
689               manufp->name, addr[3], addr[4], addr[5]);
690
691     tp->is_name_from_file = FALSE;
692
693   } else {
694     strncpy(tp->name, eth->name, MAXNAMELEN);
695     tp->name[MAXNAMELEN-1] = '\0';
696     tp->is_name_from_file = TRUE;
697   }
698
699   return (tp->name);
700
701 } /* eth_name_lookup */
702
703 static u_char *eth_addr_lookup(u_char *name)
704 {
705   ether_t *eth;
706   hashether_t *tp;
707   hashether_t **table = eth_table;
708   int i;
709
710   /* to be optimized (hash table from name to addr) */
711   for (i = 0; i < HASHETHSIZE; i++) {
712     tp = table[i];
713     while (tp) {
714       if (strcmp(tp->name, name) == 0)
715         return tp->addr;
716       tp = tp->next;
717     }
718   }
719
720   /* not in hash table : performs a file lookup */
721
722   if ((eth = get_ethbyname(name)) == NULL)
723     return NULL;
724
725   /* add new entry in hash table */
726
727   tp = add_eth_name(eth->addr, name);
728
729   return tp->addr;
730
731 } /* eth_addr_lookup */
732
733
734 /* IPXNETS */
735 static int parse_ipxnets_line(char *line, ipxnet_t *ipxnet)
736 {
737   /*
738    *  We allow three address separators (':', '-', and '.'),
739    *  as well as no separators
740    */
741
742   gchar         *cp;
743   guint32       a, a0, a1, a2, a3;
744   gboolean      found_single_number = FALSE;
745     
746   if ((cp = strchr(line, '#')))
747     *cp = '\0';
748   
749   if ((cp = strtok(line, " \t\n")) == NULL)
750     return -1;
751
752   /* Either fill a0,a1,a2,a3 and found_single_number is FALSE,
753    * fill a and found_single_number is TRUE,
754    * or return -1
755    */
756   if (sscanf(cp, "%x:%x:%x:%x", &a0, &a1, &a2, &a3) != 4) {
757     if (sscanf(cp, "%x-%x-%x-%x", &a0, &a1, &a2, &a3) != 4) {
758       if (sscanf(cp, "%x.%x.%x.%x", &a0, &a1, &a2, &a3) != 4) {
759         if (sscanf(cp, "%x", &a) == 1) {
760           found_single_number = TRUE;
761         }
762         else {
763           return -1;
764         }
765       }
766     }
767   }
768
769   if ((cp = strtok(NULL, " \t\n")) == NULL)
770     return -1;
771
772   if (found_single_number) {
773         ipxnet->addr = a;
774   }
775   else {
776         ipxnet->addr = (a0 << 24) | (a1 << 16) | (a2 << 8) | a3;
777   }
778
779   strncpy(ipxnet->name, cp, MAXNAMELEN);
780   ipxnet->name[MAXNAMELEN-1] = '\0';
781
782   return 0;
783
784 } /* parse_ipxnets_line */
785
786 static FILE *ipxnet_p = NULL;
787
788 static void set_ipxnetent(char *path)
789 {
790   if (ipxnet_p)
791     rewind(ipxnet_p);
792   else
793     ipxnet_p = fopen(path, "r");
794 }
795
796 static void end_ipxnetent(void)
797 {
798   if (ipxnet_p) {
799     fclose(ipxnet_p);
800     ipxnet_p = NULL;
801   }
802 }
803
804 static ipxnet_t *get_ipxnetent(void)
805 {
806  
807   static ipxnet_t ipxnet;
808   static int     size = 0;
809   static char   *buf = NULL;
810   
811   if (ipxnet_p == NULL) 
812     return NULL;
813
814   while (fgetline(&buf, &size, ipxnet_p) >= 0) {
815     if (parse_ipxnets_line(buf, &ipxnet) == 0) {
816       return &ipxnet;
817     }
818   }
819     
820   return NULL;
821
822 } /* get_ipxnetent */
823
824 static ipxnet_t *get_ipxnetbyname(u_char *name)
825 {
826   ipxnet_t *ipxnet;
827   
828   set_ipxnetent(g_ipxnets_path);
829
830   while ((ipxnet = get_ipxnetent()) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
831     ;
832
833   if (ipxnet == NULL) {
834     end_ipxnetent();
835     
836     set_ipxnetent(g_pipxnets_path);
837
838     while ((ipxnet = get_ipxnetent()) && strncmp(name, ipxnet->name, MAXNAMELEN) != 0)
839       ;
840
841     end_ipxnetent();
842   }
843
844   return ipxnet;
845
846 } /* get_ipxnetbyname */
847
848 static ipxnet_t *get_ipxnetbyaddr(guint32 addr)
849 {
850
851   ipxnet_t *ipxnet;
852   
853   set_ipxnetent(g_ipxnets_path);
854
855   while ((ipxnet = get_ipxnetent()) && (addr != ipxnet->addr) ) ;
856
857   if (ipxnet == NULL) {
858     end_ipxnetent();
859     
860     set_ipxnetent(g_pipxnets_path);
861     
862     while ((ipxnet = get_ipxnetent()) && (addr != ipxnet->addr) )
863       ;
864     
865     end_ipxnetent();
866   }
867
868   return ipxnet;
869
870 } /* get_ipxnetbyaddr */
871
872 static void initialize_ipxnets(void)
873 {
874
875 #ifdef DEBUG_RESOLV
876   signal(SIGSEGV, SIG_IGN);
877 #endif
878
879   /* Set g_pipxnets_path here, but don't actually do anything
880    * with it. It's used in get_ipxnetbyname() and get_ipxnetbyaddr()
881    */
882   if (g_pipxnets_path == NULL) {
883     g_pipxnets_path = g_malloc(strlen(getenv("HOME")) + 
884                               strlen(EPATH_PERSONAL_IPXNETS) + 2);
885     sprintf(g_pipxnets_path, "%s/%s", 
886             (char *)getenv("HOME"), EPATH_PERSONAL_IPXNETS);
887   }
888
889 } /* initialize_ipxnets */
890
891 static hashipxnet_t *add_ipxnet_name(u_int addr, u_char *name)
892 {
893   hashipxnet_t *tp;
894   hashipxnet_t **table = ipxnet_table;
895
896   /* XXX - check goodness of hash function */
897
898   tp = table[ addr & (HASHIPXNETSIZE - 1)];
899
900   if( tp == NULL ) {
901     tp = table[ addr & (HASHIPXNETSIZE - 1)] = 
902       (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
903   } else {  
904     while(1) {
905       if (tp->next == NULL) {
906         tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
907         tp = tp->next;
908         break;
909       }
910       tp = tp->next;
911     }
912   }
913   
914   tp->addr = addr;
915   strncpy(tp->name, name, MAXNAMELEN);
916   tp->name[MAXNAMELEN-1] = '\0';
917   tp->next = NULL;
918
919   return tp;
920
921 } /* add_ipxnet_name */
922
923 static u_char *ipxnet_name_lookup(const u_int addr)
924 {
925   hashipxnet_t *tp;
926   hashipxnet_t **table = ipxnet_table;
927   ipxnet_t *ipxnet;
928
929   tp = table[ addr & (HASHIPXNETSIZE - 1)];
930
931   if( tp == NULL ) {
932     tp = table[ addr & (HASHIPXNETSIZE - 1)] = 
933       (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
934   } else {  
935     while(1) {
936       if (tp->addr == addr) {
937         return tp->name;
938       }
939       if (tp->next == NULL) {
940         tp->next = (hashipxnet_t *)g_malloc(sizeof(hashipxnet_t));
941         tp = tp->next;
942         break;
943       }
944       tp = tp->next;
945     }
946   }
947   
948   /* fill in a new entry */
949
950   tp->addr = addr;
951   tp->next = NULL;
952
953   if ( (ipxnet = get_ipxnetbyaddr(addr)) == NULL) {
954     /* unknown name */
955       sprintf(tp->name, "%X", addr);
956
957   } else {
958     strncpy(tp->name, ipxnet->name, MAXNAMELEN);
959     tp->name[MAXNAMELEN-1] = '\0';
960   }
961
962   return (tp->name);
963
964 } /* ipxnet_name_lookup */
965
966 static u_int ipxnet_addr_lookup(u_char *name, gboolean *success)
967 {
968   ipxnet_t *ipxnet;
969   hashipxnet_t *tp;
970   hashipxnet_t **table = ipxnet_table;
971   int i;
972
973   /* to be optimized (hash table from name to addr) */
974   for (i = 0; i < HASHIPXNETSIZE; i++) {
975     tp = table[i];
976     while (tp) {
977       if (strcmp(tp->name, name) == 0)
978         return tp->addr;
979       tp = tp->next;
980     }
981   }
982
983   /* not in hash table : performs a file lookup */
984
985   if ((ipxnet = get_ipxnetbyname(name)) == NULL) {
986           *success = FALSE;
987           return 0;
988   }
989
990   /* add new entry in hash table */
991
992   tp = add_ipxnet_name(ipxnet->addr, name);
993
994   *success = TRUE;
995   return tp->addr;
996
997 } /* ipxnet_addr_lookup */
998
999
1000 /* 
1001  *  External Functions
1002  */
1003
1004 extern u_char *get_hostname(u_int addr) 
1005 {
1006   if (!g_resolving_actif)
1007     return ip_to_str((guint8 *)&addr);
1008
1009   return host_name_lookup(addr);
1010 }
1011
1012 extern gchar *get_hostname6(struct e_in6_addr *addr) 
1013 {
1014 #ifdef INET6
1015   if (!g_resolving_actif)
1016     return ip6_to_str(addr);
1017   if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MULTICAST(addr))
1018     return ip6_to_str(addr);
1019 #endif
1020   return host_name_lookup6(addr);
1021 }
1022
1023 extern void add_host_name(u_int addr, u_char *name)
1024 {
1025
1026   hashname_t *tp;
1027   hashname_t **table = host_table;
1028
1029   tp = table[ addr & (HASHHOSTSIZE - 1)];
1030
1031   if( tp == NULL ) {
1032     tp = table[ addr & (HASHHOSTSIZE - 1)] = 
1033       (hashname_t *)g_malloc(sizeof(hashname_t));
1034   } else {  
1035     while(1) {
1036       if (tp->next == NULL) {
1037         tp->next = (hashname_t *)g_malloc(sizeof(hashname_t));
1038         tp = tp->next;
1039         break;
1040       }
1041       tp = tp->next;
1042     }
1043   }
1044   
1045   strncpy(tp->name, name, MAXNAMELEN);
1046   tp->name[MAXNAMELEN-1] = '\0';
1047   tp->addr = addr;
1048   tp->next = NULL;
1049
1050 } /* add_host_name */
1051
1052 extern u_char *get_udp_port(u_int port) 
1053 {
1054   static gchar  str[3][MAXNAMELEN];
1055   static gchar *cur;
1056
1057   if (!g_resolving_actif) {
1058     if (cur == &str[0][0]) {
1059       cur = &str[1][0];
1060     } else if (cur == &str[1][0]) {  
1061       cur = &str[2][0];
1062     } else {  
1063       cur = &str[0][0];
1064     }
1065     sprintf(cur, "%d", port);
1066     return cur;
1067   }
1068
1069   return serv_name_lookup(port, IPPROTO_UDP);
1070
1071 } /* get_udp_port */
1072
1073 extern u_char *get_tcp_port(u_int port) 
1074 {
1075   static gchar  str[3][MAXNAMELEN];
1076   static gchar *cur;
1077
1078   if (!g_resolving_actif) {
1079     if (cur == &str[0][0]) {
1080       cur = &str[1][0];
1081     } else if (cur == &str[1][0]) {  
1082       cur = &str[2][0];
1083     } else {  
1084       cur = &str[0][0];
1085     }
1086     sprintf(cur, "%d", port);
1087     return cur;
1088   }
1089
1090   return serv_name_lookup(port, IPPROTO_TCP);
1091
1092 } /* get_tcp_port */
1093
1094 extern u_char *get_ether_name(const u_char *addr)
1095 {
1096   if (!g_resolving_actif)
1097     return ether_to_str((guint8 *)addr);
1098
1099   if (!eth_resolution_initialized) {
1100     initialize_ethers();
1101     eth_resolution_initialized = 1;
1102   }
1103
1104   return eth_name_lookup(addr);
1105
1106 } /* get_ether_name */
1107
1108 /* Look for an ether name in the hash, and return it if found.
1109  * If it's not found, simply return NULL. We DO NOT make a new
1110  * hash entry for it with the hex digits turned into a string.
1111  */
1112 u_char *get_ether_name_if_known(const u_char *addr)
1113 {
1114   hashether_t *tp;
1115   hashether_t **table = eth_table;
1116   int i,j;
1117
1118   /* Initialize ether structs if we're the first
1119    * ether-related function called */
1120   if (!g_resolving_actif)
1121     return NULL;
1122   
1123   if (!eth_resolution_initialized) {
1124     initialize_ethers();
1125     eth_resolution_initialized = 1;
1126   }
1127
1128   j = (addr[2] << 8) | addr[3];
1129   i = (addr[4] << 8) | addr[5];
1130
1131   tp = table[ (i ^ j) & (HASHETHSIZE - 1)];
1132
1133   if( tp == NULL ) {
1134           /* Hash key not found in table.
1135            * Force a lookup (and a hash entry) for addr, then call
1136            * myself. I plan on not getting into an infinite loop because
1137            * eth_name_lookup() is guaranteed to make a hashtable entry,
1138            * so when I call myself again, I can never get into this
1139            * block of code again. Knock on wood...
1140            */
1141           (void) eth_name_lookup(addr);
1142           return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
1143   }
1144   else { 
1145     while(1) {
1146       if (memcmp(tp->addr, addr, sizeof(tp->addr)) == 0) {
1147               if (tp->is_name_from_file) {
1148                 /* A name was found, and its origin is an ethers file */
1149                 return tp->name;
1150               }
1151               else {
1152                 /* A name was found, but it was created, not found in a file */
1153                 return NULL;
1154               }
1155       }
1156       if (tp->next == NULL) {
1157           /* Read my reason above for why I'm sure I can't get into an infinite loop */
1158           (void) eth_name_lookup(addr);
1159           return get_ether_name_if_known(addr); /* a well-placed goto would suffice */
1160       }
1161       tp = tp->next;
1162     }
1163   }
1164   g_assert_not_reached();
1165   return NULL;
1166 }
1167
1168
1169 extern u_char *get_ether_addr(u_char *name)
1170 {
1171
1172   /* force resolution (do not check g_resolving_actif) */
1173
1174   if (!eth_resolution_initialized) {
1175     initialize_ethers();
1176     eth_resolution_initialized = 1;
1177   }
1178
1179   return eth_addr_lookup(name);
1180
1181 } /* get_ether_addr */
1182
1183
1184 extern u_char *get_ipxnet_name(const guint32 addr)
1185 {
1186
1187   if (!g_resolving_actif) {
1188           return ipxnet_to_str_punct(addr, '\0');
1189   }
1190
1191   if (!ipxnet_resolution_initialized) {
1192     initialize_ipxnets();
1193     ipxnet_resolution_initialized = 1;
1194   }
1195
1196   return ipxnet_name_lookup(addr);
1197
1198 } /* get_ipxnet_name */
1199
1200 extern guint32 get_ipxnet_addr(u_char *name, gboolean *known)
1201 {
1202         guint32 addr;
1203         gboolean success;
1204
1205   /* force resolution (do not check g_resolving_actif) */
1206
1207   if (!ipxnet_resolution_initialized) {
1208     initialize_ipxnets();
1209     ipxnet_resolution_initialized = 1;
1210   }
1211
1212   addr =  ipxnet_addr_lookup(name, &success);
1213
1214   *known = success;
1215   return addr;
1216
1217 } /* get_ipxnet_addr */
1218
1219 extern u_char *get_manuf_name(u_char *addr) 
1220 {
1221   static gchar  str[3][MAXMANUFLEN];
1222   static gchar *cur;
1223   hashmanuf_t  *manufp;
1224
1225   if (g_resolving_actif && !eth_resolution_initialized) {
1226     initialize_ethers();
1227     eth_resolution_initialized = 1;
1228   }
1229
1230   if (!g_resolving_actif || ((manufp = manuf_name_lookup(addr)) == NULL)) {
1231     if (cur == &str[0][0]) {
1232       cur = &str[1][0];
1233     } else if (cur == &str[1][0]) {  
1234       cur = &str[2][0];
1235     } else {  
1236       cur = &str[0][0];
1237     }
1238     sprintf(cur, "%02x:%02x:%02x", addr[0], addr[1], addr[2]);
1239     return cur;
1240   }
1241   
1242   return manufp->name;
1243
1244 } /* get_manuf_name */
1245
1246
1247
1248 /* Translate a string, assumed either to be a dotted-quad IP address or
1249  * a host name, to a numeric IP address.  Return TRUE if we succeed and
1250  * set "*addrp" to that numeric IP address; return FALSE if we fail.
1251  * Used more in the dfilter parser rather than in packet dissectors */
1252 gboolean get_host_ipaddr(const char *host, guint32 *addrp)
1253 {
1254         struct in_addr          ipaddr;
1255         struct hostent          *hp;
1256
1257         /*
1258          * don't change it to inet_pton(AF_INET), they are not 100% compatible.
1259          * inet_pton(AF_INET) does not support hexadecimal notation nor
1260          * less-than-4 octet notation.
1261          */
1262         if (!inet_aton(host, &ipaddr)) {
1263                 /* It's not a valid dotted-quad IP address; is it a valid
1264                  * host name? */
1265                 hp = gethostbyname(host);
1266                 if (hp == NULL) {
1267                         /* No. */
1268                         return FALSE;
1269                 } else {
1270                         /* XXX - is "hp->h_length" the size of a
1271                          * "struct in_addr"?  It should be. */
1272                         memcpy(&ipaddr, hp->h_addr, hp->h_length);
1273                 }
1274         }
1275
1276         *addrp = ntohl(ipaddr.s_addr);
1277         return TRUE;
1278 }
1279
1280 /*
1281  * Translate IPv6 numeric address or FQDN hostname, into binary IPv6 address.
1282  * Return TRUE if we succeed and set "*addrp" to that numeric IP address;
1283  * return FALSE if we fail.
1284  */
1285 gboolean get_host_ipaddr6(const char *host, struct e_in6_addr *addrp)
1286 {
1287         struct hostent *hp;
1288
1289         if (inet_pton(AF_INET6, host, addrp) == 1)
1290                 return TRUE;
1291
1292         /* try FQDN */
1293 #ifdef HAVE_GETHOSTBYNAME2
1294         hp = gethostbyname2(host, AF_INET6);
1295 #else
1296         hp = NULL;
1297 #endif
1298         if (hp != NULL && hp->h_length == sizeof(struct e_in6_addr)) {
1299                 memcpy(addrp, hp->h_addr, hp->h_length);
1300                 return TRUE;
1301         }
1302
1303         return FALSE;
1304 }