Damn the torpedos[1], commit it anyway.
[obnox/wireshark/wip.git] / wiretap / iptrace.c
1 /* iptrace.c
2  *
3  * $Id: iptrace.c,v 1.33 2001/03/10 06:33:57 guy Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@xiexie.org>
7  * 
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <string.h>
29 #include "wtap-int.h"
30 #include "file_wrappers.h"
31 #include "buffer.h"
32 #include "iptrace.h"
33
34 static gboolean iptrace_read_1_0(wtap *wth, int *err, int *data_offset);
35 static int iptrace_seek_read_1_0(wtap *wth, int seek_off,
36     union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size);
37
38 static gboolean iptrace_read_2_0(wtap *wth, int *err, int *data_offset);
39 static int iptrace_seek_read_2_0(wtap *wth, int seek_off,
40     union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size);
41
42 static int iptrace_read_rec_header(FILE_T fh, guint8 *header, int header_len,
43     int *err);
44 static int iptrace_read_rec_data(FILE_T fh, guint8 *data_ptr, int packet_size,
45     int *err);
46 static void get_atm_pseudo_header(union wtap_pseudo_header *pseudo_header,
47     guint8 *header);
48 static int wtap_encap_ift(unsigned int  ift);
49
50 int iptrace_open(wtap *wth, int *err)
51 {
52         int bytes_read;
53         char name[12];
54
55         errno = WTAP_ERR_CANT_READ;
56         bytes_read = file_read(name, 1, 11, wth->fh);
57         if (bytes_read != 11) {
58                 *err = file_error(wth->fh);
59                 if (*err != 0)
60                         return -1;
61                 return 0;
62         }
63         wth->data_offset += 11;
64         name[11] = 0;
65
66         if (strcmp(name, "iptrace 1.0") == 0) {
67                 wth->file_type = WTAP_FILE_IPTRACE_1_0;
68                 wth->subtype_read = iptrace_read_1_0;
69                 wth->subtype_seek_read = iptrace_seek_read_1_0;
70         }
71         else if (strcmp(name, "iptrace 2.0") == 0) {
72                 wth->file_type = WTAP_FILE_IPTRACE_2_0;
73                 wth->subtype_read = iptrace_read_2_0;
74                 wth->subtype_seek_read = iptrace_seek_read_2_0;
75         }
76         else {
77                 return 0;
78         }
79
80         return 1;
81 }
82
83 /***********************************************************
84  * iptrace 1.0                                             *
85  ***********************************************************/
86
87 /* iptrace 1.0, discovered through inspection */
88 typedef struct {
89 /* 0-3 */       guint32         pkt_length;     /* packet length + 0x16 */
90 /* 4-7 */       guint32         tv_sec;         /* time stamp, seconds since the Epoch */
91 /* 8-11 */      guint32         junk1;          /* ???, not time */
92 /* 12-15 */     char            if_name[4];     /* null-terminated */
93 /* 16-27 */     char            junk2[12];      /* ??? */
94 /* 28 */        guint8          if_type;        /* BSD net/if_types.h */
95 /* 29 */        guint8          tx_flag;        /* 0=receive, 1=transmit */
96 } iptrace_1_0_phdr;
97
98 /* Read the next packet */
99 static gboolean iptrace_read_1_0(wtap *wth, int *err, int *data_offset)
100 {
101         int                     ret;
102         guint32                 packet_size;
103         guint8                  header[30];
104         guint8                  *data_ptr;
105         iptrace_1_0_phdr        pkt_hdr;
106
107         /* Read the descriptor data */
108         *data_offset = wth->data_offset;
109         ret = iptrace_read_rec_header(wth->fh, header, 30, err);
110         if (ret <= 0) {
111                 /* Read error or EOF */
112                 return FALSE;
113         }
114         wth->data_offset += 30;
115
116         /* Read the packet data */
117         packet_size = pntohl(&header[0]) - 0x16;
118         buffer_assure_space( wth->frame_buffer, packet_size );
119         data_ptr = buffer_start_ptr( wth->frame_buffer );
120         if (iptrace_read_rec_data(wth->fh, data_ptr, packet_size, err) < 0)
121                 return FALSE;   /* Read error */
122         wth->data_offset += packet_size;
123
124         wth->phdr.len = packet_size;
125         wth->phdr.caplen = packet_size;
126         wth->phdr.ts.tv_sec = pntohl(&header[4]);
127         wth->phdr.ts.tv_usec = 0;
128
129         /*
130          * Byte 28 of the frame header appears to be a BSD-style IFT_xxx
131          * value giving the type of the interface.  Check out the
132          * <net/if_types.h> header file.
133          */
134         pkt_hdr.if_type = header[28];
135         wth->phdr.pkt_encap = wtap_encap_ift(pkt_hdr.if_type);
136
137         if (wth->phdr.pkt_encap == WTAP_ENCAP_UNKNOWN) {
138                 g_message("iptrace: interface type IFT=0x%02x unknown or unsupported",
139                     pkt_hdr.if_type);
140                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
141                 return FALSE;
142         }
143
144         if ( wth->phdr.pkt_encap == WTAP_ENCAP_ATM_SNIFFER ) {
145                 get_atm_pseudo_header(&wth->pseudo_header, header);
146         }
147
148         /* If the per-file encapsulation isn't known, set it to this
149            packet's encapsulation.
150
151            If it *is* known, and it isn't this packet's encapsulation,
152            set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
153            have a single encapsulation for all packets in the file. */
154         if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
155                 wth->file_encap = wth->phdr.pkt_encap;
156         else {
157                 if (wth->file_encap != wth->phdr.pkt_encap)
158                         wth->file_encap = WTAP_ENCAP_PER_PACKET;
159         }
160
161         return TRUE;
162 }
163
164 static int iptrace_seek_read_1_0(wtap *wth, int seek_off,
165     union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size)
166 {
167         int                     ret;
168         int                     err;    /* XXX - return this */
169         guint8                  header[30];
170
171         file_seek(wth->random_fh, seek_off, SEEK_SET);
172
173         /* Read the descriptor data */
174         ret = iptrace_read_rec_header(wth->random_fh, header, 30, &err);
175         if (ret <= 0) {
176                 /* Read error or EOF */
177                 return ret;
178         }
179
180         if ( wtap_encap_ift(header[28]) == WTAP_ENCAP_ATM_SNIFFER ) {
181                 get_atm_pseudo_header(pseudo_header, header);
182         }
183
184         /* Read the packet data */
185         return iptrace_read_rec_data(wth->random_fh, pd, packet_size, &err);
186 }
187
188 /***********************************************************
189  * iptrace 2.0                                             *
190  ***********************************************************/
191
192 /* iptrace 2.0, discovered through inspection */
193 typedef struct {
194 /* 0-3 */       guint32         pkt_length;     /* packet length + 32 */
195 /* 4-7 */       guint32         tv_sec0;        /* time stamp, seconds since the Epoch */
196 /* 8-11 */      guint32         junk1;          /* ?? */
197 /* 12-15 */     char            if_name[4];     /* null-terminated */
198 /* 16-27 */     char            if_desc[12];    /* interface description. */
199 /* 28 */        guint8          if_type;        /* BSD net/if_types.h */
200 /* 29 */        guint8          tx_flag;        /* 0=receive, 1=transmit */
201 /* 30-31 */     guint16         junk3;
202 /* 32-35 */     guint32         tv_sec;         /* time stamp, seconds since the Epoch */
203 /* 36-39 */     guint32         tv_nsec;        /* nanoseconds since that second */
204 } iptrace_2_0_phdr;
205
206 /* Read the next packet */
207 static gboolean iptrace_read_2_0(wtap *wth, int *err, int *data_offset)
208 {
209         int                     ret;
210         guint32                 packet_size;
211         guint8                  header[40];
212         guint8                  *data_ptr;
213         iptrace_2_0_phdr        pkt_hdr;
214
215         /* Read the descriptor data */
216         *data_offset = wth->data_offset;
217         ret = iptrace_read_rec_header(wth->fh, header, 40, err);
218         if (ret <= 0) {
219                 /* Read error or EOF */
220                 return FALSE;
221         }
222         wth->data_offset += 40;
223
224         /* Read the packet data */
225         packet_size = pntohl(&header[0]) - 32;
226         buffer_assure_space( wth->frame_buffer, packet_size );
227         data_ptr = buffer_start_ptr( wth->frame_buffer );
228         if (iptrace_read_rec_data(wth->fh, data_ptr, packet_size, err) < 0)
229                 return FALSE;   /* Read error */
230         wth->data_offset += packet_size;
231
232         /* AIX saves time in nsec, not usec. It's easier to make iptrace
233          * files more Unix-compliant here than try to get the calling
234          * program to know when to use nsec or usec */
235
236         wth->phdr.len = packet_size;
237         wth->phdr.caplen = packet_size;
238         wth->phdr.ts.tv_sec = pntohl(&header[32]);
239         wth->phdr.ts.tv_usec = pntohl(&header[36]) / 1000;
240
241         /*
242          * Byte 28 of the frame header appears to be a BSD-style IFT_xxx
243          * value giving the type of the interface.  Check out the
244          * <net/if_types.h> header file.
245          */
246         pkt_hdr.if_type = header[28];
247         wth->phdr.pkt_encap = wtap_encap_ift(pkt_hdr.if_type);
248
249         if (wth->phdr.pkt_encap == WTAP_ENCAP_UNKNOWN) {
250                 g_message("iptrace: interface type IFT=0x%02x unknown or unsupported",
251                     pkt_hdr.if_type);
252                 *err = WTAP_ERR_UNSUPPORTED_ENCAP;
253                 return FALSE;
254         }
255
256         if ( wth->phdr.pkt_encap == WTAP_ENCAP_ATM_SNIFFER ) {
257                 get_atm_pseudo_header(&wth->pseudo_header, header);
258         }
259
260         /* If the per-file encapsulation isn't known, set it to this
261            packet's encapsulation.
262
263            If it *is* known, and it isn't this packet's encapsulation,
264            set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
265            have a single encapsulation for all packets in the file. */
266         if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
267                 wth->file_encap = wth->phdr.pkt_encap;
268         else {
269                 if (wth->file_encap != wth->phdr.pkt_encap)
270                         wth->file_encap = WTAP_ENCAP_PER_PACKET;
271         }
272
273         return TRUE;
274 }
275
276 static int iptrace_seek_read_2_0(wtap *wth, int seek_off,
277     union wtap_pseudo_header *pseudo_header, u_char *pd, int packet_size)
278 {
279         int                     ret;
280         int                     err;    /* XXX - return this */
281         guint8                  header[40];
282
283         file_seek(wth->random_fh, seek_off, SEEK_SET);
284
285         /* Read the descriptor data */
286         ret = iptrace_read_rec_header(wth->random_fh, header, 40, &err);
287         if (ret <= 0) {
288                 /* Read error or EOF */
289                 return ret;
290         }
291
292         if ( wtap_encap_ift(header[28]) == WTAP_ENCAP_ATM_SNIFFER ) {
293                 get_atm_pseudo_header(pseudo_header, header);
294         }
295
296         /* Read the packet data */
297         return iptrace_read_rec_data(wth->random_fh, pd, packet_size, &err);
298 }
299
300 static int
301 iptrace_read_rec_header(FILE_T fh, guint8 *header, int header_len, int *err)
302 {
303         int     bytes_read;
304
305         errno = WTAP_ERR_CANT_READ;
306         bytes_read = file_read(header, 1, header_len, fh);
307         if (bytes_read != header_len) {
308                 *err = file_error(fh);
309                 if (*err != 0)
310                         return -1;
311                 if (bytes_read != 0) {
312                         *err = WTAP_ERR_SHORT_READ;
313                         return -1;
314                 }
315                 return 0;
316         }
317         return 1;
318 }
319
320 static int
321 iptrace_read_rec_data(FILE_T fh, guint8 *data_ptr, int packet_size, int *err)
322 {
323         int     bytes_read;
324
325         errno = WTAP_ERR_CANT_READ;
326         bytes_read = file_read( data_ptr, 1, packet_size, fh );
327
328         if (bytes_read != packet_size) {
329                 *err = file_error(fh);
330                 if (*err == 0)
331                         *err = WTAP_ERR_SHORT_READ;
332                 return -1;
333         }
334         return 0;
335 }
336
337 /*
338  * Fill in the pseudo-header information we can; alas, "iptrace" doesn't
339  * tell us what type of traffic is in the packet - it was presumably
340  * run on a machine that was one of the endpoints of the connection, so
341  * in theory it could presumably have told us, but, for whatever reason,
342  * it failed to do so - perhaps the low-level mechanism that feeds the
343  * presumably-AAL5 frames to us doesn't have access to that information
344  * (e.g., because it's in the ATM driver, and the ATM driver merely knows
345  * that stuff on VPI/VCI X.Y should be handed up to some particular
346  * client, it doesn't know what that client is).
347  *
348  * We let our caller try to figure out what kind of traffic it is, either
349  * by guessing based on the VPI/VCI, guessing based on the header of the
350  * packet, seeing earlier traffic that set up the circuit and specified
351  * in some fashion what sort of traffic it is, or being told by the user.
352  */
353 static void
354 get_atm_pseudo_header(union wtap_pseudo_header *pseudo_header, guint8 *header)
355 {
356         char    if_text[9];
357         char    *decimal;
358         int     Vpi = 0;
359         int     Vci = 0;
360
361         /* Rip apart the "x.y" text into Vpi/Vci numbers */
362         memcpy(if_text, &header[20], 8);
363         if_text[8] = '\0';
364         decimal = strchr(if_text, '.');
365         if (decimal) {
366                 *decimal = '\0';
367                 Vpi = strtoul(if_text, NULL, 10);
368                 decimal++;
369                 Vci = strtoul(decimal, NULL, 10);
370         }
371         pseudo_header->ngsniffer_atm.Vpi = Vpi;
372         pseudo_header->ngsniffer_atm.Vci = Vci;
373
374         /*
375          * OK, which value means "DTE->DCE" and which value means
376          * "DCE->DTE"?
377          */
378         pseudo_header->ngsniffer_atm.channel = header[29];
379
380         /* We don't have this information */
381         pseudo_header->ngsniffer_atm.cells = 0;
382         pseudo_header->ngsniffer_atm.aal5t_u2u = 0;
383         pseudo_header->ngsniffer_atm.aal5t_len = 0;
384         pseudo_header->ngsniffer_atm.aal5t_chksum = 0;
385
386         /* Assume it's AAL5 traffic, but indicate that we don't know what
387            it is beyond that. */
388         pseudo_header->ngsniffer_atm.AppTrafType = ATT_AAL5|ATT_HL_UNKNOWN;
389         pseudo_header->ngsniffer_atm.AppHLType = AHLT_UNKNOWN;
390 }
391
392 /* Given an RFC1573 (SNMP ifType) interface type,
393  * return the appropriate Wiretap Encapsulation Type.
394  */
395 static int
396 wtap_encap_ift(unsigned int  ift)
397 {
398
399         static const int ift_encap[] = {
400 /* 0x0 */       WTAP_ENCAP_UNKNOWN,     /* nothing */
401 /* 0x1 */       WTAP_ENCAP_UNKNOWN,     /* IFT_OTHER */
402 /* 0x2 */       WTAP_ENCAP_UNKNOWN,     /* IFT_1822 */
403 /* 0x3 */       WTAP_ENCAP_UNKNOWN,     /* IFT_HDH1822 */
404 /* 0x4 */       WTAP_ENCAP_RAW_IP,      /* IFT_X25DDN */
405 /* 0x5 */       WTAP_ENCAP_UNKNOWN,     /* IFT_X25 */
406 /* 0x6 */       WTAP_ENCAP_ETHERNET,    /* IFT_ETHER */
407 /* 0x7 */       WTAP_ENCAP_UNKNOWN,     /* IFT_ISO88023 */
408 /* 0x8 */       WTAP_ENCAP_UNKNOWN,     /* IFT_ISO88024 */
409 /* 0x9 */       WTAP_ENCAP_TOKEN_RING,  /* IFT_ISO88025 */
410 /* 0xa */       WTAP_ENCAP_UNKNOWN,     /* IFT_ISO88026 */
411 /* 0xb */       WTAP_ENCAP_UNKNOWN,     /* IFT_STARLAN */
412 /* 0xc */       WTAP_ENCAP_RAW_IP,      /* IFT_P10, IBM SP switch */
413 /* 0xd */       WTAP_ENCAP_UNKNOWN,     /* IFT_P80 */
414 /* 0xe */       WTAP_ENCAP_UNKNOWN,     /* IFT_HY */
415 /* 0xf */       WTAP_ENCAP_FDDI_BITSWAPPED,     /* IFT_FDDI */
416 /* 0x10 */      WTAP_ENCAP_LAPB,        /* IFT_LAPB */  /* no data to back this up */
417 /* 0x11 */      WTAP_ENCAP_UNKNOWN,     /* IFT_SDLC */
418 /* 0x12 */      WTAP_ENCAP_UNKNOWN,     /* IFT_T1 */
419 /* 0x13 */      WTAP_ENCAP_UNKNOWN,     /* IFT_CEPT */
420 /* 0x14 */      WTAP_ENCAP_UNKNOWN,     /* IFT_ISDNBASIC */
421 /* 0x15 */      WTAP_ENCAP_UNKNOWN,     /* IFT_ISDNPRIMARY */
422 /* 0x16 */      WTAP_ENCAP_UNKNOWN,     /* IFT_PTPSERIAL */
423 /* 0x17 */      WTAP_ENCAP_UNKNOWN,     /* IFT_PPP */
424 /* 0x18 */      WTAP_ENCAP_RAW_IP,      /* IFT_LOOP */
425 /* 0x19 */      WTAP_ENCAP_UNKNOWN,     /* IFT_EON */
426 /* 0x1a */      WTAP_ENCAP_UNKNOWN,     /* IFT_XETHER */
427 /* 0x1b */      WTAP_ENCAP_UNKNOWN,     /* IFT_NSIP */
428 /* 0x1c */      WTAP_ENCAP_UNKNOWN,     /* IFT_SLIP */
429 /* 0x1d */      WTAP_ENCAP_UNKNOWN,     /* IFT_ULTRA */
430 /* 0x1e */      WTAP_ENCAP_UNKNOWN,     /* IFT_DS3 */
431 /* 0x1f */      WTAP_ENCAP_UNKNOWN,     /* IFT_SIP */
432 /* 0x20 */      WTAP_ENCAP_UNKNOWN,     /* IFT_FRELAY */
433 /* 0x21 */      WTAP_ENCAP_UNKNOWN,     /* IFT_RS232 */
434 /* 0x22 */      WTAP_ENCAP_UNKNOWN,     /* IFT_PARA */
435 /* 0x23 */      WTAP_ENCAP_UNKNOWN,     /* IFT_ARCNET */
436 /* 0x24 */      WTAP_ENCAP_UNKNOWN,     /* IFT_ARCNETPLUS */
437 /* 0x25 */      WTAP_ENCAP_ATM_SNIFFER, /* IFT_ATM */
438         };
439         #define NUM_IFT_ENCAPS (sizeof ift_encap / sizeof ift_encap[0])
440
441         if (ift < NUM_IFT_ENCAPS) {
442                 return ift_encap[ift];
443         }
444         else {
445                 return WTAP_ENCAP_UNKNOWN;
446         }
447 }