Branch data Line data Source code
1 : : // $Id: PIA.cc,v 1.1.2.14 2006/05/31 23:19:07 sommer Exp $
2 : :
3 : : #include "PIA.h"
4 : : #include "RuleMatcher.h"
5 : : #include "TCP_Reassembler.h"
6 : :
7 : 1622 : PIA::PIA(Analyzer* arg_as_analyzer)
8 : : {
9 : 1622 : current_packet.data = 0;
10 : 1622 : as_analyzer = arg_as_analyzer;
11 : 1622 : }
12 : :
13 : 1622 : PIA::~PIA()
14 : : {
15 : 1622 : ClearBuffer(&pkt_buffer);
16 [ # # ][ # # ]: 1622 : }
[ - + ]
17 : :
18 : 2560 : void PIA::ClearBuffer(Buffer* buffer)
19 : : {
20 : 2560 : DataBlock* next = 0;
21 [ + + ]: 5615 : for ( DataBlock* b = buffer->head; b; b = next )
22 : : {
23 : 3055 : next = b->next;
24 [ + + ]: 3055 : delete [] b->data;
25 : 3055 : delete b;
26 : : }
27 : :
28 : 2560 : buffer->head = buffer->tail = 0;
29 : 2560 : buffer->size = 0;
30 : 2560 : }
31 : :
32 : : void PIA::AddToBuffer(Buffer* buffer, int seq, int len, const u_char* data,
33 : 3055 : bool is_orig)
34 : : {
35 : 3055 : u_char* tmp = 0;
36 : :
37 [ + + ]: 3055 : if ( data )
38 : : {
39 : 2986 : tmp = new u_char[len];
40 : 2986 : memcpy(tmp, data, len);
41 : : }
42 : :
43 : 3055 : DataBlock* b = new DataBlock;
44 : 3055 : b->data = tmp;
45 : 3055 : b->is_orig = is_orig;
46 : 3055 : b->len = len;
47 : 3055 : b->seq = seq;
48 : 3055 : b->next = 0;
49 : :
50 [ + + ]: 3055 : if ( buffer->tail )
51 : : {
52 : 1648 : buffer->tail->next = b;
53 : 1648 : buffer->tail = b;
54 : : }
55 : : else
56 : 1407 : buffer->head = buffer->tail = b;
57 : :
58 : 3055 : buffer->size += len;
59 : 3055 : }
60 : :
61 : 1478 : void PIA::AddToBuffer(Buffer* buffer, int len, const u_char* data, bool is_orig)
62 : : {
63 : 1478 : AddToBuffer(buffer, -1, len, data, is_orig);
64 : 1478 : }
65 : :
66 : 0 : void PIA::ReplayPacketBuffer(Analyzer* analyzer)
67 : : {
68 : 0 : DBG_LOG(DBG_DPD, "PIA replaying %d total packet bytes", pkt_buffer.size);
69 : :
70 [ # # ]: 0 : for ( DataBlock* b = pkt_buffer.head; b; b = b->next )
71 : 0 : analyzer->DeliverPacket(b->len, b->data, b->is_orig, -1, 0, 0);
72 : 0 : }
73 : :
74 : 1622 : void PIA::PIA_Done()
75 : : {
76 : 1622 : FinishEndpointMatcher();
77 : 1622 : }
78 : :
79 : : void PIA::PIA_DeliverPacket(int len, const u_char* data, bool is_orig, int seq,
80 : 1683 : const IP_Hdr* ip, int caplen)
81 : : {
82 [ + + ]: 1683 : if ( pkt_buffer.state == SKIPPING )
83 : 175 : return;
84 : :
85 : 1508 : current_packet.data = data;
86 : 1508 : current_packet.len = len;
87 : 1508 : current_packet.seq = seq;
88 : 1508 : current_packet.is_orig = is_orig;
89 : :
90 : 1508 : State new_state = pkt_buffer.state;
91 : :
92 [ + + ]: 1508 : if ( pkt_buffer.state == INIT )
93 : 684 : new_state = BUFFERING;
94 : :
95 [ + + ][ + - ]: 1508 : if ( (pkt_buffer.state == BUFFERING || new_state == BUFFERING) &&
[ + - ]
96 : : len > 0 )
97 : : {
98 : 1508 : AddToBuffer(&pkt_buffer, seq, len, data, is_orig);
99 [ + + ]: 1508 : if ( pkt_buffer.size > dpd_buffer_size )
100 : : new_state = dpd_match_only_beginning ?
101 [ + - ]: 26 : SKIPPING : MATCHING_ONLY;
102 : : }
103 : :
104 : : // FIXME: I'm not sure why it does not work with eol=true...
105 : 1508 : DoMatch(data, len, is_orig, true, false, false, ip);
106 : :
107 : 1508 : pkt_buffer.state = new_state;
108 : :
109 : 1683 : current_packet.data = 0;
110 : : }
111 : :
112 : : void PIA::Match(Rule::PatternType type, const u_char* data, int len,
113 : 26764 : bool is_orig, bool bol, bool eol, bool clear_state)
114 : : {
115 [ + - ]: 26764 : if ( ! MatcherInitialized(is_orig) )
116 : 26764 : InitEndpointMatcher(AsAnalyzer(), 0, 0, is_orig, this);
117 : :
118 : 26764 : RuleMatcherState::Match(type, data, len, is_orig, bol, eol, clear_state);
119 : 26764 : }
120 : :
121 : : void PIA::DoMatch(const u_char* data, int len, bool is_orig, bool bol, bool eol,
122 : 4708 : bool clear_state, const IP_Hdr* ip)
123 : : {
124 [ + - ]: 4708 : if ( ! rule_matcher )
125 : 4708 : return;
126 : :
127 [ # # ]: 0 : if ( ! MatcherInitialized(is_orig) )
128 : 0 : InitEndpointMatcher(AsAnalyzer(), ip, len, is_orig, this);
129 : :
130 : : RuleMatcherState::Match(Rule::PAYLOAD, data, len, is_orig,
131 : 4708 : bol, eol, clear_state);
132 : : }
133 : :
134 : 0 : void PIA_UDP::ActivateAnalyzer(AnalyzerTag::Tag tag, const Rule* rule)
135 : : {
136 [ # # ]: 0 : if ( pkt_buffer.state == MATCHING_ONLY )
137 : : {
138 : 0 : DBG_LOG(DBG_DPD, "analyzer found but buffer already exceeded");
139 : : // FIXME: This is where to check whether an analyzer
140 : : // supports partial connections once we get such.
141 : 0 : return;
142 : : }
143 : :
144 [ # # ]: 0 : if ( Parent()->HasChildAnalyzer(tag) )
145 : 0 : return;
146 : :
147 : 0 : Analyzer* a = Parent()->AddChildAnalyzer(tag);
148 : 0 : a->SetSignature(rule);
149 : :
150 [ # # ]: 0 : if ( a )
151 : 0 : ReplayPacketBuffer(a);
152 : : }
153 : :
154 : 0 : void PIA_UDP::DeactivateAnalyzer(AnalyzerTag::Tag tag)
155 : : {
156 : 0 : internal_error("PIA_UDP::Deact not implemented yet");
157 : : }
158 : :
159 : : //// TCP PIA
160 : :
161 : 938 : PIA_TCP::~PIA_TCP()
162 : : {
163 : 938 : ClearBuffer(&stream_buffer);
164 [ + - ][ # # ]: 938 : }
[ # # ]
165 : :
166 : 938 : void PIA_TCP::Init()
167 : : {
168 : 938 : TCP_ApplicationAnalyzer::Init();
169 : :
170 [ + - ]: 938 : if ( Parent()->GetTag() == AnalyzerTag::TCP )
171 : : {
172 : 938 : TCP_Analyzer* tcp = static_cast<TCP_Analyzer*>(Parent());
173 : 938 : SetTCP(tcp);
174 : 938 : tcp->SetPIA(this);
175 : : }
176 : 938 : }
177 : :
178 : 1722 : void PIA_TCP::FirstPacket(bool is_orig, const IP_Hdr* ip)
179 : : {
180 : : static char dummy_packet[sizeof(struct ip) + sizeof(struct tcphdr)];
181 : : static struct ip* ip4 = 0;
182 : : static struct tcphdr* tcp4 = 0;
183 : : static IP_Hdr* ip4_hdr = 0;
184 : :
185 [ + + ]: 1722 : DBG_LOG(DBG_DPD, "PIA_TCP[%d] FirstPacket(%s)", GetID(), (is_orig ? "T" : "F"));
186 : :
187 [ - + ]: 1722 : if ( ! ip )
188 : : {
189 : : // Create a dummy packet. Not very elegant, but everything
190 : : // else would be *really* ugly ...
191 [ # # ]: 0 : if ( ! ip4_hdr )
192 : : {
193 : 0 : ip4 = (struct ip*) dummy_packet;
194 : : tcp4 = (struct tcphdr*)
195 : 0 : (dummy_packet + sizeof(struct ip));
196 : 0 : ip4->ip_len = sizeof(struct ip) + sizeof(struct tcphdr);
197 : 0 : ip4->ip_hl = sizeof(struct ip) >> 2;
198 : 0 : ip4->ip_p = IPPROTO_TCP;
199 : :
200 : : // Cast to const so that it doesn't delete it.
201 : 0 : ip4_hdr = new IP_Hdr((const struct ip*) ip4);
202 : : }
203 : :
204 [ # # ]: 0 : if ( is_orig )
205 : : {
206 : 0 : copy_addr(Conn()->OrigAddr(), &ip4->ip_src.s_addr);
207 : 0 : copy_addr(Conn()->RespAddr(), &ip4->ip_dst.s_addr);
208 : 0 : tcp4->th_sport = htons(Conn()->OrigPort());
209 : 0 : tcp4->th_dport = htons(Conn()->RespPort());
210 : : }
211 : : else
212 : : {
213 : 0 : copy_addr(Conn()->RespAddr(), &ip4->ip_src.s_addr);
214 : 0 : copy_addr(Conn()->OrigAddr(), &ip4->ip_dst.s_addr);
215 : 0 : tcp4->th_sport = htons(Conn()->RespPort());
216 : 0 : tcp4->th_dport = htons(Conn()->OrigPort());
217 : : }
218 : :
219 : 0 : ip = ip4_hdr;
220 : : }
221 : :
222 [ + - ]: 1722 : if ( ! MatcherInitialized(is_orig) )
223 : 1722 : DoMatch((const u_char*)"", 0, is_orig, true, false, false, ip);
224 : 1722 : }
225 : :
226 : 7962 : void PIA_TCP::DeliverStream(int len, const u_char* data, bool is_orig)
227 : : {
228 : 7962 : TCP_ApplicationAnalyzer::DeliverStream(len, data, is_orig);
229 : :
230 [ + + ]: 7962 : if ( stream_buffer.state == SKIPPING )
231 : 6484 : return;
232 : :
233 : 1478 : stream_mode = true;
234 : :
235 : 1478 : State new_state = stream_buffer.state;
236 : :
237 [ + + ]: 1478 : if ( stream_buffer.state == INIT )
238 : : {
239 : : // FIXME: clear payload-matching state here...
240 : 723 : new_state = BUFFERING;
241 : : }
242 : :
243 [ + + ][ + - ]: 1478 : if ( stream_buffer.state == BUFFERING || new_state == BUFFERING )
244 : : {
245 : 1478 : AddToBuffer(&stream_buffer, len, data, is_orig);
246 [ + + ]: 1478 : if ( stream_buffer.size > dpd_buffer_size )
247 : : new_state = dpd_match_only_beginning ?
248 [ + - ]: 603 : SKIPPING : MATCHING_ONLY;
249 : : }
250 : :
251 : 1478 : DoMatch(data, len, is_orig, false, false, false, 0);
252 : :
253 : 7962 : stream_buffer.state = new_state;
254 : : }
255 : :
256 : 567 : void PIA_TCP::Undelivered(int seq, int len, bool is_orig)
257 : : {
258 : 567 : TCP_ApplicationAnalyzer::Undelivered(seq, len, is_orig);
259 : :
260 [ + + ]: 567 : if ( stream_buffer.state == BUFFERING )
261 : : // We use data=nil to mark an undelivered.
262 : 69 : AddToBuffer(&stream_buffer, seq, len, 0, is_orig);
263 : :
264 : : // No check for buffer overrun here. I think that's ok.
265 : 567 : }
266 : :
267 : 0 : void PIA_TCP::ActivateAnalyzer(AnalyzerTag::Tag tag, const Rule* rule)
268 : : {
269 [ # # ]: 0 : if ( stream_buffer.state == MATCHING_ONLY )
270 : : {
271 : 0 : DBG_LOG(DBG_DPD, "analyzer found but buffer already exceeded");
272 : : // FIXME: This is where to check whether an analyzer supports
273 : : // partial connections once we get such.
274 : 0 : return;
275 : : }
276 : :
277 [ # # ]: 0 : if ( Parent()->HasChildAnalyzer(tag) )
278 : 0 : return;
279 : :
280 : 0 : Analyzer* a = Parent()->AddChildAnalyzer(tag);
281 : 0 : a->SetSignature(rule);
282 : :
283 : : // We have two cases here:
284 : : //
285 : : // (a) We have already got stream input.
286 : : // => Great, somebody's already reassembling and we can just
287 : : // replay our stream buffer to the new analyzer.
288 [ # # ]: 0 : if ( stream_mode )
289 : : {
290 : 0 : ReplayStreamBuffer(a);
291 : 0 : return;
292 : : }
293 : :
294 : : // (b) We have only got packet input so far (or none at all).
295 : : // => We have to switch from packet-mode to stream-mode.
296 : : //
297 : : // Here's what we do:
298 : : //
299 : : // (1) We create new TCP_Reassemblers and feed them the buffered
300 : : // packets.
301 : : //
302 : : // (2) The reassembler will give us their results via the
303 : : // stream-interface and we buffer it as usual.
304 : : //
305 : : // (3) We replay the now-filled stream-buffer to the analyzer.
306 : : //
307 : : // (4) We hand the two reassemblers to the TCP Analyzer (our parent),
308 : : // turning reassembly now on for all subsequent data.
309 : :
310 : 0 : DBG_LOG(DBG_DPD, "DPM_TCP switching from packet-mode to stream-mode");
311 : 0 : stream_mode = true;
312 : :
313 : : // FIXME: The reassembler will query the endpoint for state. Not sure
314 : : // if this is works in all cases...
315 : :
316 [ # # ]: 0 : if ( Parent()->GetTag() != AnalyzerTag::TCP )
317 : : {
318 : : // Our parent is not the TCP analyzer, which can only mean
319 : : // we have been inserted somewhere further down in the
320 : : // analyzer tree. In this case, we will never have seen
321 : : // any input at this point (because we don't get packets).
322 [ # # ]: 0 : assert(!pkt_buffer.head);
323 [ # # ]: 0 : assert(!stream_buffer.head);
324 : 0 : return;
325 : : }
326 : :
327 : 0 : TCP_Analyzer* tcp = (TCP_Analyzer*) Parent();
328 : :
329 : : TCP_Reassembler* reass_orig =
330 : : new TCP_Reassembler(this, tcp, TCP_Reassembler::Direct,
331 : 0 : true, tcp->Orig());
332 : :
333 : : TCP_Reassembler* reass_resp =
334 : : new TCP_Reassembler(this, tcp, TCP_Reassembler::Direct,
335 : 0 : false, tcp->Resp());
336 : :
337 : 0 : int orig_seq = 0;
338 : 0 : int resp_seq = 0;
339 : :
340 [ # # ]: 0 : for ( DataBlock* b = pkt_buffer.head; b; b = b->next )
341 : : {
342 [ # # ]: 0 : if ( b->is_orig )
343 : : reass_orig->DataSent(network_time, orig_seq = b->seq,
344 : 0 : b->len, b->data, true);
345 : : else
346 : : reass_resp->DataSent(network_time, resp_seq = b->seq,
347 : 0 : b->len, b->data, true);
348 : : }
349 : :
350 : : // We also need to pass the current packet on.
351 : 0 : DataBlock* current = CurrentPacket();
352 [ # # ]: 0 : if ( current->data )
353 : : {
354 [ # # ]: 0 : if ( current->is_orig )
355 : : reass_orig->DataSent(network_time,
356 : : orig_seq = current->seq,
357 : 0 : current->len, current->data, true);
358 : : else
359 : : reass_resp->DataSent(network_time,
360 : : resp_seq = current->seq,
361 : 0 : current->len, current->data, true);
362 : : }
363 : :
364 : 0 : ClearBuffer(&pkt_buffer);
365 : :
366 : 0 : ReplayStreamBuffer(a);
367 : 0 : reass_orig->AckReceived(orig_seq);
368 : 0 : reass_resp->AckReceived(resp_seq);
369 : :
370 : 0 : reass_orig->SetType(TCP_Reassembler::Forward);
371 : 0 : reass_resp->SetType(TCP_Reassembler::Forward);
372 : :
373 : 0 : tcp->SetReassembler(reass_orig, reass_resp);
374 : : }
375 : :
376 : 0 : void PIA_TCP::DeactivateAnalyzer(AnalyzerTag::Tag tag)
377 : : {
378 : 0 : internal_error("PIA_TCP::Deact not implemented yet");
379 : : }
380 : :
381 : 0 : void PIA_TCP::ReplayStreamBuffer(Analyzer* analyzer)
382 : : {
383 : 0 : DBG_LOG(DBG_DPD, "PIA_TCP replaying %d total stream bytes", stream_buffer.size);
384 : :
385 [ # # ]: 0 : for ( DataBlock* b = stream_buffer.head; b; b = b->next )
386 : : {
387 [ # # ]: 0 : if ( b->data )
388 : 0 : analyzer->NextStream(b->len, b->data, b->is_orig);
389 : : else
390 : 0 : analyzer->NextUndelivered(b->seq, b->len, b->is_orig);
391 : : }
392 [ + - ][ + - ]: 6 : }
|