Remove some unnecessary dependencies and cleanup some code
[metze/wireshark/wip.git] / epan / follow.c
1 /* follow.c
2  *
3  * Copyright 1998 Mike Hall <mlh@io.com>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #include <glib.h>
35 #include <epan/packet.h>
36 #include <epan/to_str.h>
37 #include <epan/dissectors/packet-tcp.h>
38 #include <epan/dissectors/packet-udp.h>
39 #include "follow.h"
40 #include <epan/conversation.h>
41 #include <epan/tap.h>
42
43 typedef struct _tcp_frag {
44   guint32             seq;
45   guint32             len;
46   guint32             data_len;
47   gchar              *data;
48   struct _tcp_frag   *next;
49 } tcp_frag;
50
51 WS_DLL_PUBLIC_DEF
52 FILE* data_out_file = NULL;
53
54 gboolean empty_tcp_stream;
55 gboolean incomplete_tcp_stream;
56
57 static guint32 stream_to_follow[MAX_STREAM] = {0};
58 static gboolean find_addr[MAX_STREAM] = {FALSE};
59 static gboolean find_index[MAX_STREAM] = {FALSE};
60 static address tcp_addr[2];
61 static stream_addr ip_address[2];
62 static guint   port[2];
63 static guint   bytes_written[2];
64 static gboolean is_ipv6 = FALSE;
65
66 void
67 follow_stats(follow_stats_t* stats)
68 {
69   int i;
70
71   for (i = 0; i < 2 ; i++) {
72     stats->ip_address[i] = ip_address[i];
73     stats->port[i] = port[i];
74     stats->bytes_written[i] = bytes_written[i];
75   }
76   stats->is_ipv6 = is_ipv6;
77 }
78
79 /* This will build a display filter text that will only
80    pass the packets related to the stream. There is a
81    chance that two streams could intersect, but not a
82    very good one */
83 gchar*
84 build_follow_conv_filter( packet_info *pi, const char* append_filter ) {
85   char* buf;
86   int len;
87   conversation_t *conv=NULL;
88   struct tcp_analysis *tcpd;
89   struct udp_analysis *udpd;
90   wmem_list_frame_t* protos;
91   int proto_id;
92   const char* proto_name;
93   gboolean is_tcp = FALSE, is_udp = FALSE;
94
95   protos = wmem_list_head(pi->layers);
96
97   /* walk the list of a available protocols in the packet to
98       figure out if any of them affect context sensitivity */
99   while (protos != NULL)
100   {
101     proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
102     proto_name = proto_get_protocol_filter_name(proto_id);
103
104     if (!strcmp(proto_name, "tcp")) {
105         is_tcp = TRUE;
106     } else if (!strcmp(proto_name, "udp")) {
107         is_udp = TRUE;
108     }
109
110     protos = wmem_list_frame_next(protos);
111   }
112
113   if( ((pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4) ||
114        (pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6))
115        && is_tcp && (conv=find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
116               pi->srcport, pi->destport, 0)) != NULL ) {
117     /* TCP over IPv4/6 */
118     tcpd=get_tcp_conversation_data(conv, pi);
119     if (tcpd) {
120       if (append_filter == NULL) {
121         buf = g_strdup_printf("tcp.stream eq %d", tcpd->stream);
122       } else {
123         buf = g_strdup_printf("((tcp.stream eq %d) && (%s))", tcpd->stream, append_filter);
124       }
125       stream_to_follow[TCP_STREAM] = tcpd->stream;
126       if (pi->net_src.type == AT_IPv4) {
127         len = 4;
128         is_ipv6 = FALSE;
129       } else {
130         len = 16;
131         is_ipv6 = TRUE;
132       }
133     } else {
134       return NULL;
135     }
136   }
137   else if( ((pi->net_src.type == AT_IPv4 && pi->net_dst.type == AT_IPv4) ||
138             (pi->net_src.type == AT_IPv6 && pi->net_dst.type == AT_IPv6))
139           && is_udp && (conv=find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
140               pi->srcport, pi->destport, 0)) != NULL ) {
141     /* UDP over IPv4/6 */
142     udpd=get_udp_conversation_data(conv, pi);
143     if (udpd) {
144       if (append_filter == NULL) {
145         buf = g_strdup_printf("udp.stream eq %d", udpd->stream);
146       } else {
147         buf = g_strdup_printf("((udp.stream eq %d) && (%s))", udpd->stream, append_filter);
148       }
149       stream_to_follow[UDP_STREAM] = udpd->stream;
150       if (pi->net_src.type == AT_IPv4) {
151         len = 4;
152         is_ipv6 = FALSE;
153       } else {
154         len = 16;
155         is_ipv6 = TRUE;
156       }
157     } else {
158       return NULL;
159     }
160   }
161   else {
162     return NULL;
163   }
164   memcpy(&ip_address[0], pi->net_src.data, len);
165   memcpy(&ip_address[1], pi->net_dst.data, len);
166   port[0] = pi->srcport;
167   port[1] = pi->destport;
168   return buf;
169 }
170
171 static gboolean
172 udp_follow_packet(void *tapdata _U_, packet_info *pinfo,
173                   epan_dissect_t *edt _U_, const void *data _U_)
174 {
175   if (find_addr[UDP_STREAM]) {
176     if (pinfo->net_src.type == AT_IPv6) {
177       is_ipv6 = TRUE;
178     } else {
179       is_ipv6 = FALSE;
180     }
181     memcpy(&ip_address[0], pinfo->net_src.data, pinfo->net_src.len);
182     memcpy(&ip_address[1], pinfo->net_dst.data, pinfo->net_dst.len);
183     port[0] = pinfo->srcport;
184     port[1] = pinfo->destport;
185     find_addr[UDP_STREAM] = FALSE;
186   }
187
188   return FALSE;
189 }
190
191
192 /* here we are going to try and reconstruct the data portion of a TCP
193    session. We will try and handle duplicates, TCP fragments, and out
194    of order packets in a smart way. */
195
196 static tcp_frag *frags[2] = { 0, 0 };
197 static guint32 seq[2];
198 static stream_addr src_addr[2];
199 static guint src_port[2] = { 0, 0 };
200
201 void
202 reset_stream_follow(stream_type stream) {
203   tcp_frag *current, *next;
204   int i;
205
206   remove_tap_listener(&stream_to_follow[stream]);
207   find_addr[stream] = FALSE;
208   find_index[stream] = FALSE;
209   if (stream == TCP_STREAM) {
210     empty_tcp_stream = TRUE;
211     incomplete_tcp_stream = FALSE;
212
213     for( i=0; i<2; i++ ) {
214       seq[i] = 0;
215       memset(&src_addr[i], 0, sizeof(src_addr[i]));
216       src_port[i] = 0;
217       memset(&ip_address[i], 0, sizeof(src_addr[i]));
218       port[i] = 0;
219       bytes_written[i] = 0;
220       current = frags[i];
221       while( current ) {
222         next = current->next;
223         g_free( current->data );
224         g_free( current );
225         current = next;
226       }
227       frags[i] = NULL;
228     }
229   }
230 }
231
232 gchar*
233 build_follow_index_filter(stream_type stream) {
234   gchar *buf;
235
236   find_addr[stream] = TRUE;
237   if (stream == TCP_STREAM) {
238     buf = g_strdup_printf("tcp.stream eq %d", stream_to_follow[TCP_STREAM]);
239   } else {
240     GString * error_string;
241     buf = g_strdup_printf("udp.stream eq %d", stream_to_follow[UDP_STREAM]);
242     error_string = register_tap_listener("udp_follow", &stream_to_follow[UDP_STREAM], buf, 0, NULL, udp_follow_packet, NULL);
243     if (error_string) {
244       g_string_free(error_string, TRUE);
245     }
246   }
247   return buf;
248 }
249
250 /* select a tcp stream to follow via it's address/port pairs */
251 gboolean
252 follow_addr(stream_type stream, const address *addr0, guint port0,
253             const address *addr1, guint port1)
254 {
255   if (addr0 == NULL || addr1 == NULL || addr0->type != addr1->type ||
256       port0 > G_MAXUINT16 || port1 > G_MAXUINT16 )  {
257     return FALSE;
258   }
259
260   if (find_index[stream] || find_addr[stream]) {
261     return FALSE;
262   }
263
264   switch (addr0->type) {
265   default:
266     return FALSE;
267   case AT_IPv4:
268   case AT_IPv6:
269     is_ipv6 = addr0->type == AT_IPv6;
270     break;
271   }
272
273
274   memcpy(&ip_address[0], addr0->data, addr0->len);
275   port[0] = port0;
276
277   memcpy(&ip_address[1], addr1->data, addr1->len);
278   port[1] = port1;
279
280   if (stream == TCP_STREAM) {
281     find_index[TCP_STREAM] = TRUE;
282     set_address(&tcp_addr[0], addr0->type, addr0->len, &ip_address[0]);
283     set_address(&tcp_addr[1], addr1->type, addr1->len, &ip_address[1]);
284   }
285
286   return TRUE;
287 }
288
289 /* select a stream to follow via its index */
290 gboolean
291 follow_index(stream_type stream, guint32 indx)
292 {
293   if (find_index[stream] || find_addr[stream]) {
294     return FALSE;
295   }
296
297   find_addr[stream] = TRUE;
298   stream_to_follow[stream] = indx;
299   memset(ip_address, 0, sizeof ip_address);
300   port[0] = port[1] = 0;
301
302   return TRUE;
303 }
304
305 guint32
306 get_follow_index(stream_type stream) {
307   return stream_to_follow[stream];
308 }
309
310 /*
311  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
312  *
313  * Local Variables:
314  * c-basic-offset: 2
315  * tab-width: 8
316  * indent-tabs-mode: nil
317  * End:
318  *
319  * ex: set shiftwidth=2 tabstop=8 expandtab:
320  * :indentSize=2:tabSize=8:noTabs=true:
321  */