Initial revision
[obnox/wireshark/wip.git] / resolv.c
1 /* resolv.c
2  * Routines for network object lookup
3  *
4  * Laurent Deniel <deniel@worldnet.fr>
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  *
26  * To do:
27  *
28  * - Add ethernet address resolution
29  * - In a future live capture and decode mode, 
30  *   add hostname entries in hash table from DNS packet decoding.
31  *
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #ifndef AVOID_DNS_TIMEOUT
39 #define AVOID_DNS_TIMEOUT
40 #endif
41
42 #include <gtk/gtk.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #ifdef HAVE_SYS_TYPES_H
48 # include <sys/types.h>
49 #endif
50
51 #ifdef HAVE_NETINET_IN_H
52 # include <netinet/in.h>
53 #endif
54
55 #include <netdb.h>
56 #include <signal.h>
57 #include <sys/socket.h>
58
59 #ifdef AVOID_DNS_TIMEOUT
60 # include <setjmp.h>
61 #endif
62
63 #include "packet.h"
64 #include "resolv.h"
65
66 #define MAXNAMELEN      64      /* max name length (hostname and port name) */
67 #define HASHHOSTSIZE    1024
68 #define HASHPORTSIZE    256
69
70 /* hash table used for host and port lookup */
71
72 typedef struct hashname {
73   u_int                 addr;
74   u_char                name[MAXNAMELEN];
75   struct hashname       *next;
76 } hashname_t;
77
78 static hashname_t *host_table[HASHHOSTSIZE];
79 static hashname_t *udp_port_table[HASHPORTSIZE];
80 static hashname_t *tcp_port_table[HASHPORTSIZE];
81
82 /* global variable that indicates if name resolving is actif */
83
84 int g_resolving_actif = 1;      /* routines are active by default */
85
86 /* local function definitions */
87
88 static u_char *serv_name_lookup(u_int port, u_int proto)
89 {
90
91   hashname_t *tp;
92   hashname_t **table;
93   char *serv_proto = NULL;
94   struct servent *servp;
95   int i;
96
97   switch(proto) {
98   case IPPROTO_UDP:
99     table = udp_port_table;
100     serv_proto = "udp";
101     break;
102   case IPPROTO_TCP:
103     table = tcp_port_table;
104     serv_proto = "tcp";
105     break;
106   default:
107     /* not yet implemented */
108     return NULL;
109     /*NOTREACHED*/
110     break;
111   } /* proto */
112   
113   i = port & (HASHPORTSIZE - 1);
114   tp = table[ i & (HASHPORTSIZE - 1)];
115
116   if( tp == NULL ) {
117     tp = table[ i & (HASHPORTSIZE - 1)] = 
118       (hashname_t *)g_malloc(sizeof(hashname_t));
119   } else {  
120     while(1) {
121       if( tp->addr == port ) {
122         return tp->name;
123       }
124       if (tp->next == NULL) {
125         tp->next = (hashname_t *)g_malloc(sizeof(hashname_t));
126         tp = tp->next;
127         break;
128       }
129       tp = tp->next;
130     }
131   }
132   
133   /* fill in a new entry */
134   tp->addr = port;
135   tp->next = NULL;
136
137   if ((servp = getservbyport(htons(port), serv_proto)) == NULL) {
138     /* unknown port */
139     sprintf(tp->name, "%d", port);
140   } else {
141     strncpy(tp->name, servp->s_name, MAXNAMELEN);
142   }
143
144   return (tp->name);
145
146 } /* serv_name_lookup */
147
148 #ifdef AVOID_DNS_TIMEOUT
149
150 #define DNS_TIMEOUT     5       /* max sec per call */
151
152 jmp_buf hostname_env;
153
154 static void abort_network_query(int sig)
155 {
156   longjmp(hostname_env, 1);
157 }
158 #endif /* AVOID_DNS_TIMEOUT */
159
160 static u_char *host_name_lookup(u_int addr)
161 {
162
163   hashname_t *tp;
164   hashname_t **table = host_table;
165   struct hostent *hostp;
166
167   tp = table[ addr & (HASHHOSTSIZE - 1)];
168
169   if( tp == NULL ) {
170     tp = table[ addr & (HASHHOSTSIZE - 1)] = 
171       (hashname_t *)g_malloc(sizeof(hashname_t));
172   } else {  
173     while(1) {
174       if( tp->addr == addr ) {
175         return tp->name;
176       }
177       if (tp->next == NULL) {
178         tp->next = (hashname_t *)g_malloc(sizeof(hashname_t));
179         tp = tp->next;
180         break;
181       }
182       tp = tp->next;
183     }
184   }
185   
186   /* fill in a new entry */
187   tp->addr = addr;
188   tp->next = NULL;
189
190 #ifdef AVOID_DNS_TIMEOUT
191
192   /* Quick hack to avoid DNS/YP timeout */
193
194   if (!setjmp(hostname_env)) {
195     signal(SIGALRM, abort_network_query);
196     alarm(DNS_TIMEOUT);
197 #endif
198     hostp = gethostbyaddr((char *)&addr, 4, AF_INET);
199 #ifdef AVOID_DNS_TIMEOUT
200     alarm(0);
201 #endif
202     if (hostp != NULL) {
203       strncpy(tp->name, hostp->h_name, MAXNAMELEN);
204       return tp->name;
205     }
206 #ifdef AVOID_DNS_TIMEOUT
207   }
208 #endif
209
210   /* unknown host or DNS timeout */
211
212   sprintf(tp->name, "%s", ip_to_str((guint8 *)&addr));  
213   return (tp->name);
214
215 } /* host_name_lookup */
216
217 /* external functions */
218
219 extern u_char *get_hostname(u_int addr) 
220 {
221   if (!g_resolving_actif)
222     return ip_to_str((guint8 *)&addr);
223
224   return host_name_lookup(addr);
225 }
226
227 extern u_char *get_udp_port(u_int port) 
228 {
229   static gchar  str[3][MAXNAMELEN];
230   static gchar *cur;
231
232   if (!g_resolving_actif) {
233     if (cur == &str[0][0]) {
234       cur = &str[1][0];
235     } else if (cur == &str[1][0]) {  
236       cur = &str[2][0];
237     } else {  
238       cur = &str[0][0];
239     }
240     sprintf(cur, "%d", port);
241     return cur;
242   }
243
244   return serv_name_lookup(port, IPPROTO_UDP);
245
246 } /* get_udp_port */
247
248
249 extern u_char *get_tcp_port(u_int port) 
250 {
251   static gchar  str[3][MAXNAMELEN];
252   static gchar *cur;
253
254   if (!g_resolving_actif) {
255     if (cur == &str[0][0]) {
256       cur = &str[1][0];
257     } else if (cur == &str[1][0]) {  
258       cur = &str[2][0];
259     } else {  
260       cur = &str[0][0];
261     }
262     sprintf(cur, "%d", port);
263     return cur;
264   }
265
266   return serv_name_lookup(port, IPPROTO_TCP);
267
268 } /* get_tcp_port */
269