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