Branch data Line data Source code
1 : : // $Id: Gnutella.cc 6219 2008-10-01 05:39:07Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include <ctype.h>
8 : :
9 : : #include "NetVar.h"
10 : : #include "HTTP.h"
11 : : #include "Gnutella.h"
12 : : #include "Event.h"
13 : : #include "PIA.h"
14 : :
15 : :
16 : 0 : GnutellaMsgState::GnutellaMsgState()
17 : : {
18 : 0 : buffer = "";
19 : 0 : current_offset = 0;
20 : 0 : headers = "";
21 : 0 : msg_hops = 0;
22 : 0 : msg_len = 0;
23 : 0 : msg_pos = 0;
24 : 0 : msg_type = 0;
25 : 0 : msg_sent = 1;
26 : 0 : msg_ttl = 0;
27 : 0 : payload_left = 0;
28 : 0 : got_CR = 0;
29 : 0 : payload_len = 0;
30 : 0 : }
31 : :
32 : :
33 : 0 : Gnutella_Analyzer::Gnutella_Analyzer(Connection* conn)
34 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::Gnutella, conn)
35 : : {
36 : 0 : state = 0;
37 : 0 : new_state = 0;
38 : 0 : sent_establish = 0;
39 : :
40 : 0 : ms = 0;
41 : :
42 : 0 : orig_msg_state = new GnutellaMsgState();
43 : 0 : resp_msg_state = new GnutellaMsgState();
44 : 0 : }
45 : :
46 : 0 : void Gnutella_Analyzer::Done()
47 : : {
48 : 0 : TCP_ApplicationAnalyzer::Done();
49 : :
50 [ # # # # ]: 0 : if ( ! sent_establish && (gnutella_establish || gnutella_not_establish) )
[ # # ][ # # ]
51 : : {
52 : 0 : val_list* vl = new val_list;
53 : :
54 : 0 : vl->append(BuildConnVal());
55 : :
56 [ # # # # ]: 0 : if ( Established() && gnutella_establish )
[ # # ]
57 : 0 : ConnectionEvent(gnutella_establish, vl);
58 [ # # ][ # # ]: 0 : else if ( ! Established () && gnutella_not_establish )
[ # # ]
59 : 0 : ConnectionEvent(gnutella_not_establish, vl);
60 : : }
61 : :
62 [ # # ]: 0 : if ( gnutella_partial_binary_msg )
63 : : {
64 : 0 : GnutellaMsgState* p = orig_msg_state;
65 : :
66 [ # # ]: 0 : for ( int i = 0; i < 2; ++i, p = resp_msg_state )
67 : : {
68 [ # # ][ # # ]: 0 : if ( ! p->msg_sent && p->msg_pos )
69 : : {
70 : 0 : val_list* vl = new val_list;
71 : :
72 : 0 : vl->append(BuildConnVal());
73 : 0 : vl->append(new StringVal(p->msg));
74 : 0 : vl->append(new Val((i == 0), TYPE_BOOL));
75 : 0 : vl->append(new Val(p->msg_pos, TYPE_COUNT));
76 : :
77 : 0 : ConnectionEvent(gnutella_partial_binary_msg, vl);
78 : : }
79 : :
80 [ # # ][ # # ]: 0 : else if ( ! p->msg_sent && p->payload_left )
81 : 0 : SendEvents(p, (i == 0));
82 : : }
83 : : }
84 : 0 : }
85 : :
86 : :
87 : 0 : int Gnutella_Analyzer::NextLine(const u_char* data, int len)
88 : : {
89 [ # # ]: 0 : if ( ! ms )
90 : 0 : return 0;
91 : :
92 [ # # ][ # # ]: 0 : if ( Established() || ms->current_offset >= len )
[ # # ]
93 : 0 : return 0;
94 : :
95 [ # # ]: 0 : for ( ; ms->current_offset < len; ++ms->current_offset )
96 : : {
97 [ # # ]: 0 : if ( data[ms->current_offset] == '\r' )
98 : 0 : ms->got_CR = 1;
99 : :
100 [ # # ][ # # ]: 0 : else if ( data[ms->current_offset] == '\n' && ms->got_CR )
101 : : {
102 : 0 : ms->got_CR = 0;
103 : 0 : ++ms->current_offset;
104 : 0 : return 1;
105 : : }
106 : : else
107 : 0 : ms->buffer += data[ms->current_offset];
108 : : }
109 : :
110 : 0 : return 0;
111 : : }
112 : :
113 : :
114 : 0 : int Gnutella_Analyzer::IsHTTP(string header)
115 : : {
116 [ # # ]: 0 : if ( header.find(" HTTP/1.") == string::npos )
117 : 0 : return 0;
118 : :
119 [ # # ]: 0 : if ( gnutella_http_notify )
120 : : {
121 : 0 : val_list* vl = new val_list;
122 : :
123 : 0 : vl->append(BuildConnVal());
124 : 0 : ConnectionEvent(gnutella_http_notify, vl);
125 : : }
126 : :
127 [ # # ]: 0 : if ( HTTP_Analyzer::Available() )
128 : : {
129 : 0 : Analyzer* a = new HTTP_Analyzer(Conn());
130 : 0 : Parent()->AddChildAnalyzer(a);
131 : :
132 [ # # ]: 0 : if ( Parent()->GetTag() == AnalyzerTag::TCP )
133 : : {
134 : : // Replay buffered data.
135 : 0 : PIA* pia = static_cast<TransportLayerAnalyzer *>(Parent())->GetPIA();
136 [ # # ]: 0 : if ( pia )
137 : 0 : static_cast<PIA_TCP *>(pia)->ReplayStreamBuffer(a);
138 : : }
139 : :
140 : 0 : Parent()->RemoveChildAnalyzer(this);
141 : : }
142 : :
143 : 0 : return 1;
144 : : }
145 : :
146 : :
147 : 0 : int Gnutella_Analyzer::GnutellaOK(string header)
148 : : {
149 [ # # ]: 0 : if ( strncmp("GNUTELLA", header.data(), 8) )
150 : 0 : return 0;
151 : :
152 : 0 : int codepos = header.find(' ') + 1;
153 [ # # ]: 0 : if ( ! strncmp("200", header.data() + codepos, 3) )
154 : 0 : return 1;
155 : :
156 : 0 : return 0;
157 : : }
158 : :
159 : :
160 : 0 : void Gnutella_Analyzer::DeliverLines(int len, const u_char* data, bool orig)
161 : : {
162 [ # # ]: 0 : if ( ! ms )
163 : 0 : return;
164 : :
165 [ # # ]: 0 : while ( NextLine(data, len) )
166 : : {
167 [ # # ]: 0 : if ( ms->buffer.length() )
168 : : {
169 [ # # ]: 0 : if ( ms->headers.length() == 0 )
170 : : {
171 [ # # ]: 0 : if ( IsHTTP(ms->buffer) )
172 : 0 : return;
173 [ # # ]: 0 : if ( GnutellaOK(ms->buffer) )
174 : : new_state |=
175 [ # # ]: 0 : orig ? ORIG_OK : RESP_OK;
176 : : }
177 : :
178 : 0 : ms->headers = ms->headers + "\r\n" + ms->buffer;
179 : 0 : ms->buffer = "";
180 : : }
181 : : else
182 : : {
183 [ # # ]: 0 : if ( gnutella_text_msg )
184 : : {
185 : 0 : val_list* vl = new val_list;
186 : :
187 : 0 : vl->append(BuildConnVal());
188 : 0 : vl->append(new Val(orig, TYPE_BOOL));
189 : 0 : vl->append(new StringVal(ms->headers.data()));
190 : :
191 : 0 : ConnectionEvent(gnutella_text_msg, vl);
192 : : }
193 : :
194 : 0 : ms->headers = "";
195 : 0 : state |= new_state;
196 : :
197 [ # # # # ]: 0 : if ( Established () && gnutella_establish )
[ # # ]
198 : : {
199 : 0 : val_list* vl = new val_list;
200 : :
201 : 0 : sent_establish = 1;
202 : 0 : vl->append(BuildConnVal());
203 : :
204 : 0 : ConnectionEvent(gnutella_establish, vl);
205 : : }
206 : : }
207 : : }
208 : : }
209 : :
210 : 0 : void Gnutella_Analyzer::DissectMessage(char* msg)
211 : : {
212 [ # # ]: 0 : if ( ! ms )
213 : 0 : return;
214 : :
215 : 0 : ms->msg_type = msg[16];
216 : 0 : ms->msg_ttl = msg[17];
217 : 0 : ms->msg_hops = msg[18];
218 : :
219 : 0 : memcpy(&ms->msg_len, &msg[19], 4);
220 : : }
221 : :
222 : :
223 : 0 : void Gnutella_Analyzer::SendEvents(GnutellaMsgState* p, bool is_orig)
224 : : {
225 [ # # ]: 0 : if ( p->msg_sent )
226 : 0 : return;
227 : :
228 [ # # ]: 0 : if ( gnutella_binary_msg )
229 : : {
230 : 0 : val_list* vl = new val_list;
231 : :
232 : 0 : vl->append(BuildConnVal());
233 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
234 : 0 : vl->append(new Val(p->msg_type, TYPE_COUNT));
235 : 0 : vl->append(new Val(p->msg_ttl, TYPE_COUNT));
236 : 0 : vl->append(new Val(p->msg_hops, TYPE_COUNT));
237 : 0 : vl->append(new Val(p->msg_len, TYPE_COUNT));
238 : 0 : vl->append(new StringVal(p->payload));
239 : 0 : vl->append(new Val(p->payload_len, TYPE_COUNT));
240 : : vl->append(new Val((p->payload_len <
241 : : min(p->msg_len, GNUTELLA_MAX_PAYLOAD)),
242 : 0 : TYPE_BOOL));
243 : 0 : vl->append(new Val((p->payload_left == 0), TYPE_BOOL));
244 : :
245 : 0 : ConnectionEvent(gnutella_binary_msg, vl);
246 : : }
247 : : }
248 : :
249 : :
250 : 0 : void Gnutella_Analyzer::DeliverMessages(int len, const u_char* data, bool orig)
251 : : {
252 [ # # ]: 0 : if ( ! ms )
253 : 0 : return;
254 : :
255 [ # # ]: 0 : while ( ms->current_offset < len )
256 : : {
257 : 0 : ms->msg_sent = 0;
258 : :
259 : 0 : unsigned int bytes_left = len - ms->current_offset;
260 : 0 : unsigned int needed = 0;
261 : :
262 [ # # ]: 0 : if ( ms->msg_pos )
263 : 0 : needed = GNUTELLA_MSG_SIZE - ms->msg_pos;
264 : :
265 [ # # ][ # # ]: 0 : if ( (! ms->msg_pos && ! ms->payload_left &&
[ # # ][ # # ]
[ # # ]
266 : : (bytes_left >= GNUTELLA_MSG_SIZE)) ||
267 : : (ms->msg_pos && (bytes_left >= needed)) )
268 : : {
269 [ # # ]: 0 : int sz = ms->msg_pos ? needed : GNUTELLA_MSG_SIZE;
270 : :
271 : : memcpy(&ms->msg[ms->msg_pos],
272 : 0 : &data[ms->current_offset], sz);
273 : :
274 : 0 : ms->current_offset += sz;
275 : 0 : DissectMessage(ms->msg);
276 : 0 : ms->payload_left = ms->msg_len;
277 : 0 : ms->msg_pos = 0;
278 [ # # ]: 0 : if ( ms->msg_len == 0 )
279 : 0 : SendEvents(ms, orig);
280 : : }
281 : :
282 [ # # ][ # # ]: 0 : else if ( (! ms->msg_pos && ! ms->payload_left &&
[ # # ][ # # ]
[ # # ]
283 : : (bytes_left < GNUTELLA_MSG_SIZE)) ||
284 : : (ms->msg_pos && (bytes_left < needed)) )
285 : : {
286 : : memcpy(&ms->msg[ms->msg_pos], &data[ms->current_offset],
287 : 0 : bytes_left);
288 : 0 : ms->current_offset += bytes_left;
289 : 0 : ms->msg_pos += bytes_left;
290 : : }
291 : :
292 [ # # ]: 0 : else if ( ms->payload_left )
293 : : {
294 : : unsigned int space =
295 : : ms->payload_len >= GNUTELLA_MAX_PAYLOAD ?
296 [ # # ]: 0 : 0 : GNUTELLA_MAX_PAYLOAD - ms->payload_len;
297 : : unsigned int sz =
298 [ # # ]: 0 : (bytes_left < space) ? bytes_left : space;
299 : :
300 [ # # ]: 0 : if ( space )
301 : : {
302 : : memcpy(&ms->payload[ms->payload_len],
303 : 0 : &data[ms->current_offset], sz);
304 : 0 : ms->payload_len += sz;
305 : : }
306 : :
307 [ # # ]: 0 : if ( ms->payload_left > bytes_left )
308 : : {
309 : 0 : ms->current_offset += bytes_left;
310 : 0 : ms->payload_left -= bytes_left;
311 : : }
312 : : else
313 : : {
314 : 0 : ms->current_offset += ms->payload_left;
315 : 0 : ms->payload_left = 0;
316 : 0 : SendEvents(ms, orig);
317 : : }
318 : : }
319 : : }
320 : : }
321 : :
322 : :
323 : 0 : void Gnutella_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
324 : : {
325 : 0 : TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
326 : :
327 [ # # ]: 0 : ms = orig ? orig_msg_state : resp_msg_state;
328 : 0 : ms->current_offset = 0;
329 [ # # ]: 0 : if ( ! Established() )
330 : : {
331 : 0 : DeliverLines(len, data, orig);
332 : :
333 [ # # # # ]: 0 : if ( Established() && ms->current_offset < len &&
[ # # ][ # # ]
334 : : gnutella_binary_msg )
335 : 0 : DeliverMessages(len, data, orig);
336 : : }
337 : :
338 [ # # ]: 0 : else if ( gnutella_binary_msg )
339 : 0 : DeliverMessages(len, data, orig);
340 [ + - ][ + - ]: 6 : }
341 : 3 :
|