Branch data Line data Source code
1 : : // $Id: InterConn.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 "InterConn.h"
8 : : #include "Event.h"
9 : : #include "Net.h"
10 : : #include "TCP.h"
11 : :
12 : 0 : InterConnEndpoint::InterConnEndpoint(TCP_Endpoint* e)
13 : : {
14 : 0 : endp = e;
15 : 0 : max_top_seq = 0;
16 : : num_pkts = num_keystrokes_two_in_a_row = num_normal_interarrivals =
17 : : num_8k0_pkts = num_8k4_pkts = num_bytes = num_7bit_ascii =
18 : 0 : num_lines = num_normal_lines = 0;
19 : 0 : is_partial = keystroke_just_seen = 0;
20 : 0 : last_keystroke_time = 0.0;
21 : 0 : }
22 : :
23 : : #define NORMAL_LINE_LENGTH 80
24 : :
25 : : int InterConnEndpoint::DataSent(double t, int seq, int len, int caplen,
26 : : const u_char* data, const IP_Hdr* /* ip */,
27 : 0 : const struct tcphdr* /* tp */)
28 : : {
29 [ # # ]: 0 : if ( caplen < len )
30 : 0 : len = caplen;
31 : :
32 [ # # ]: 0 : if ( len <= 0 )
33 : 0 : return 0;
34 : :
35 [ # # ]: 0 : if ( endp->state == TCP_ENDPOINT_PARTIAL )
36 : 0 : is_partial = 1;
37 : :
38 : 0 : int ack = endp->AckSeq() - endp->StartSeq();
39 : 0 : int top_seq = seq + len;
40 : :
41 [ # # # # ]: 0 : if ( top_seq <= ack || top_seq <= max_top_seq )
42 : : // There is no new data in this packet
43 : 0 : return 0;
44 : :
45 [ # # ]: 0 : if ( seq < max_top_seq )
46 : : { // Only consider new data
47 : 0 : int amount_seen = max_top_seq - seq;
48 : 0 : seq += amount_seen;
49 : 0 : data += amount_seen;
50 : 0 : len -= amount_seen;
51 : : }
52 : :
53 [ # # ][ # # ]: 0 : if ( max_top_seq && seq > max_top_seq )
54 : : // We've got a pkt above a hole
55 : 0 : num_pkts += EstimateGapPacketNum(seq - max_top_seq);
56 : :
57 : 0 : ++num_pkts;
58 : 0 : max_top_seq = top_seq;
59 : :
60 : : // Count the bytes.
61 : 0 : num_bytes += len;
62 : :
63 : 0 : int last_char = 0;
64 : 0 : int offset = 0; // where we consider the latest line to have begun
65 : :
66 [ # # ]: 0 : for ( int i = 0; i < len; ++i )
67 : : {
68 : 0 : unsigned int c = data[i];
69 : :
70 [ # # ][ # # ]: 0 : if ( c == '\n' && last_char == '\r' )
71 : : {
72 : : // Compress CRLF to just one line termination.
73 : 0 : last_char = c;
74 : 0 : continue;
75 : : }
76 : :
77 [ # # ][ # # ]: 0 : if ( c == '\n' || c == '\r' )
78 : : {
79 : 0 : ++num_lines;
80 [ # # ]: 0 : if ( i - offset <= NORMAL_LINE_LENGTH )
81 : 0 : ++num_normal_lines;
82 : 0 : offset = i;
83 : : }
84 : :
85 [ # # ][ # # ]: 0 : else if ( c != 0 && c < 128 )
86 : 0 : ++num_7bit_ascii;
87 : :
88 : 0 : last_char = c;
89 : : }
90 : :
91 [ # # ]: 0 : if ( IsPotentialKeystrokePacket(len) )
92 : : {
93 [ # # ]: 0 : if ( keystroke_just_seen )
94 : : {
95 : 0 : ++num_keystrokes_two_in_a_row;
96 : :
97 [ # # ]: 0 : if ( IsNormalKeystrokeInterarrival(t - last_keystroke_time) )
98 : 0 : ++num_normal_interarrivals;
99 : : }
100 : : else
101 : 0 : keystroke_just_seen = 1;
102 : :
103 : : // Look for packets matching the SSH signature of
104 : : // being either 0 or 4 modulo 8.
105 [ # # # ]: 0 : switch ( len & 7 ) {
106 : : case 0:
107 [ # # ]: 0 : if ( len >= 16 )
108 : 0 : ++num_8k0_pkts;
109 : 0 : break;
110 : :
111 : : case 4:
112 : 0 : ++num_8k4_pkts;
113 : : break;
114 : : }
115 : :
116 : 0 : last_keystroke_time = t;
117 : : }
118 : : else
119 : 0 : keystroke_just_seen = 0;
120 : :
121 : 0 : return 1;
122 : : }
123 : :
124 : 0 : RecordVal* InterConnEndpoint::BuildStats()
125 : : {
126 : 0 : RecordVal* stats = new RecordVal(interconn_endp_stats);
127 : :
128 : 0 : stats->Assign(0, new Val(num_pkts, TYPE_COUNT));
129 : 0 : stats->Assign(1, new Val(num_keystrokes_two_in_a_row, TYPE_COUNT));
130 : 0 : stats->Assign(2, new Val(num_normal_interarrivals, TYPE_COUNT));
131 : 0 : stats->Assign(3, new Val(num_8k0_pkts, TYPE_COUNT));
132 : 0 : stats->Assign(4, new Val(num_8k4_pkts, TYPE_COUNT));
133 : 0 : stats->Assign(5, new Val(is_partial, TYPE_BOOL));
134 : 0 : stats->Assign(6, new Val(num_bytes, TYPE_COUNT));
135 : 0 : stats->Assign(7, new Val(num_7bit_ascii, TYPE_COUNT));
136 : 0 : stats->Assign(8, new Val(num_lines, TYPE_COUNT));
137 : 0 : stats->Assign(9, new Val(num_normal_lines, TYPE_COUNT));
138 : :
139 : 0 : return stats;
140 : : }
141 : :
142 : 0 : int InterConnEndpoint::EstimateGapPacketNum(int gap) const
143 : : {
144 : 0 : return (gap + interconn_default_pkt_size - 1) / interconn_default_pkt_size;
145 : : }
146 : :
147 : 0 : int InterConnEndpoint::IsPotentialKeystrokePacket(int len) const
148 : : {
149 : 0 : return len <= interconn_max_keystroke_pkt_size;
150 : : }
151 : :
152 : 0 : int InterConnEndpoint::IsNormalKeystrokeInterarrival(double t) const
153 : : {
154 [ # # ][ # # ]: 0 : return interconn_min_interarrival <= t && t <= interconn_max_interarrival;
155 : : }
156 : :
157 : 0 : InterConn_Analyzer::InterConn_Analyzer(Connection* c)
158 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::InterConn, c)
159 : : {
160 : 0 : orig_endp = resp_endp = 0;
161 : 0 : orig_stream_pos = resp_stream_pos = 1;
162 : :
163 : 0 : timeout = backdoor_stat_period;
164 : 0 : backoff = backdoor_stat_backoff;
165 : :
166 : 0 : c->GetTimerMgr()->Add(new InterConnTimer(network_time + timeout, this));
167 : 0 : }
168 : :
169 : 0 : InterConn_Analyzer::~InterConn_Analyzer()
170 : : {
171 : 0 : Unref(orig_endp);
172 : 0 : Unref(resp_endp);
173 [ # # ][ # # ]: 0 : }
[ # # ]
174 : :
175 : 0 : void InterConn_Analyzer::Init()
176 : : {
177 : 0 : TCP_ApplicationAnalyzer::Init();
178 : :
179 [ # # ]: 0 : assert(TCP());
180 : 0 : orig_endp = new InterConnEndpoint(TCP()->Orig());
181 : 0 : resp_endp = new InterConnEndpoint(TCP()->Resp());
182 : 0 : }
183 : :
184 : : void InterConn_Analyzer::DeliverPacket(int len, const u_char* data,
185 : 0 : bool is_orig, int seq, const IP_Hdr* ip, int caplen)
186 : : {
187 : : TCP_ApplicationAnalyzer::DeliverPacket(len, data, is_orig,
188 : 0 : seq, ip, caplen);
189 : :
190 [ # # ]: 0 : if ( is_orig )
191 : 0 : orig_endp->DataSent(network_time, seq, len, caplen, data, 0, 0);
192 : : else
193 : 0 : resp_endp->DataSent(network_time, seq, len, caplen, data, 0, 0);
194 : 0 : }
195 : :
196 : 0 : void InterConn_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
197 : : {
198 : 0 : TCP_ApplicationAnalyzer::DeliverStream(len, data, is_orig);
199 : :
200 [ # # ]: 0 : if ( is_orig )
201 : : {
202 : 0 : orig_endp->DataSent(network_time, orig_stream_pos, len, len, data, 0, 0);
203 : 0 : orig_stream_pos += len;
204 : : }
205 : :
206 : : else
207 : : {
208 : 0 : resp_endp->DataSent(network_time, resp_stream_pos, len, len, data, 0, 0);
209 : 0 : resp_stream_pos += len;
210 : : }
211 : 0 : }
212 : :
213 : 0 : void InterConn_Analyzer::Done()
214 : : {
215 [ # # ]: 0 : if ( ! IsFinished() )
216 : : {
217 [ # # ]: 0 : if ( ! Conn()->Skipping() )
218 : 0 : StatEvent();
219 : :
220 : 0 : RemoveEvent();
221 : : }
222 : :
223 : 0 : TCP_ApplicationAnalyzer::Done();
224 : 0 : }
225 : :
226 : 0 : void InterConn_Analyzer::StatTimer(double t, int is_expire)
227 : : {
228 [ # # ][ # # ]: 0 : if ( IsFinished() || Conn()->Skipping() )
[ # # ]
229 : 0 : return;
230 : :
231 : 0 : StatEvent();
232 : :
233 [ # # ]: 0 : if ( ! is_expire )
234 : : {
235 : 0 : timeout *= backoff;
236 : 0 : timer_mgr->Add(new InterConnTimer(t + timeout, this));
237 : : }
238 : : }
239 : :
240 : 0 : void InterConn_Analyzer::StatEvent()
241 : : {
242 : 0 : val_list* vl = new val_list;
243 : 0 : vl->append(Conn()->BuildConnVal());
244 : 0 : vl->append(orig_endp->BuildStats());
245 : 0 : vl->append(resp_endp->BuildStats());
246 : :
247 : 0 : Conn()->ConnectionEvent(interconn_stats, this, vl);
248 : 0 : }
249 : :
250 : 0 : void InterConn_Analyzer::RemoveEvent()
251 : : {
252 : 0 : val_list* vl = new val_list;
253 : 0 : vl->append(Conn()->BuildConnVal());
254 : :
255 : 0 : Conn()->ConnectionEvent(interconn_remove_conn, this, vl);
256 : 0 : }
257 : :
258 : 0 : InterConnTimer::InterConnTimer(double t, InterConn_Analyzer* a)
259 : 0 : : Timer(t, TIMER_INTERCONN)
260 : : {
261 : 0 : analyzer = a;
262 : : // Make sure connection does not expire.
263 : 0 : Ref(a->Conn());
264 : 0 : }
265 : :
266 : 0 : InterConnTimer::~InterConnTimer()
267 : : {
268 : 0 : Unref(analyzer->Conn());
269 [ # # ][ # # ]: 0 : }
[ # # ]
270 : :
271 : 0 : void InterConnTimer::Dispatch(double t, int is_expire)
272 : : {
273 : 0 : analyzer->StatTimer(t, is_expire);
274 [ + - ][ + - ]: 6 : }
|