Branch data Line data Source code
1 : : // $Id: ConnCompressor.h 6008 2008-07-23 00:24:22Z vern $
2 : : //
3 : : // The ConnCompressor keeps track of the first packet seen for a conn_id using
4 : : // only a minimal amount of memory. This helps us to avoid instantiating
5 : : // full Connection objects for never-established sessions.
6 : : //
7 : : // TCP only.
8 : :
9 : : #ifndef CONNCOMPRESSOR_H
10 : : #define CONNCOMPRESSOR_H
11 : :
12 : : #include "Conn.h"
13 : : #include "Dict.h"
14 : : #include "NetVar.h"
15 : : #include "TCP.h"
16 : :
17 : : class ConnCompressor {
18 : : public:
19 : : ConnCompressor();
20 : : ~ConnCompressor();
21 : :
22 : : // Handle next packet. Returns 0 if packet in handled internally.
23 : : // Takes ownership of key.
24 : : Connection* NextPacket(double t, HashKey* k, const IP_Hdr* ip_hdr,
25 : : const struct pcap_pkthdr* hdr, const u_char* const pkt);
26 : :
27 : : // Look up a connection. Returns non-nil for connections for
28 : : // which a Connection object has already been instantiated.
29 : 8 : Connection* Lookup(HashKey* k)
30 : : {
31 : 8 : ConnData* c = conns.Lookup(k);
32 [ + - + - ]: 8 : return c && IsConnPtr(c) ? MakeConnPtr(c) : 0;
33 : : }
34 : :
35 : : // Inserts connection into compressor. If another entry with this key
36 : : // already exists, it's replaced. If that was a full connection, it is
37 : : // also returned.
38 : : Connection* Insert(Connection* c);
39 : :
40 : : // Remove all state belonging to the given connection. Returns
41 : : // true if the connection was found in the compressor's table,
42 : : // false if not.
43 : : bool Remove(HashKey* k);
44 : :
45 : : // Flush state.
46 : : void Drain();
47 : :
48 : : struct Sizes {
49 : : // Current number of already fully instantiated connections.
50 : : unsigned int connections;
51 : :
52 : : // Total number of fully instantiated connections.
53 : : unsigned int connections_total;
54 : :
55 : : // Current number of seen but non-yet instantiated connections.
56 : : unsigned int pending_valid;
57 : :
58 : : // Total number of seen but non-yet instantiated connections.
59 : : unsigned int pending_total;
60 : :
61 : : // Total number of all entries in pending list (some a which
62 : : // may already been invalid, but not yet removed from memory).
63 : : unsigned int pending_in_mem;
64 : :
65 : : // Total number of hash table entires
66 : : // (should equal connections + pending_valid)
67 : : unsigned int hash_table_size;
68 : :
69 : : // Total memory usage;
70 : : unsigned int memory;
71 : : };
72 : :
73 : 0 : const Sizes& Size()
74 : 0 : { sizes.hash_table_size = conns.Length(); return sizes; }
75 : :
76 : : unsigned int MemoryAllocation() const { return sizes.memory; }
77 : :
78 : : // As long as we have only seen packets from one side, we just
79 : : // store a PendingConn.
80 : : struct PendingConn {
81 : : // True if the block is indeed a PendingConn (see below).
82 : : unsigned int is_pending:1;
83 : :
84 : : // Whether roles in key are flipped.
85 : : unsigned int ip1_is_src:1;
86 : :
87 : : unsigned int invalid:1; // deleted
88 : : int window_scale:4;
89 : : unsigned int SYN:1;
90 : : unsigned int FIN:1;
91 : : unsigned int RST:1;
92 : : unsigned int ACK:1;
93 : :
94 : : double time;
95 : : ConnID::Key key;
96 : : uint32 seq;
97 : : uint32 ack;
98 : : hash_t hash;
99 : : uint16 window;
100 : : };
101 : :
102 : : private:
103 : : // Helpers to extract addrs/ports from PendingConn.
104 : :
105 : 2235 : const uint32* SrcAddr(const PendingConn* c)
106 [ + + ]: 2235 : { return c->ip1_is_src ? c->key.ip1 : c->key.ip2; }
107 : 1214 : const uint32* DstAddr(const PendingConn* c)
108 [ + + ]: 1214 : { return c->ip1_is_src ? c->key.ip2 : c->key.ip1; }
109 : :
110 : 2401 : uint16 SrcPort(const PendingConn* c)
111 [ + + ]: 2401 : { return c->ip1_is_src ? c->key.port1 : c->key.port2; }
112 : 1904 : uint16 DstPort(const PendingConn* c)
113 [ + + ]: 1904 : { return c->ip1_is_src ? c->key.port2 : c->key.port1; }
114 : :
115 : :
116 : : // Called for the first packet in a connection.
117 : : Connection* FirstFromOrig(double t, HashKey* key,
118 : : const IP_Hdr* ip, const tcphdr* tp);
119 : :
120 : : // Called for more packets from the orginator w/o seeing a response.
121 : : Connection* NextFromOrig(PendingConn* pending,
122 : : double t, HashKey* key, const tcphdr* tp);
123 : :
124 : : // Called for the first response packet. Instantiates a Connection.
125 : : Connection* Response(PendingConn* pending, double t, HashKey* key,
126 : : const IP_Hdr* ip, const tcphdr* tp);
127 : :
128 : : // Instantiates a full TCP connection (invalidates pending connection).
129 : : Connection* Instantiate(HashKey* key, PendingConn* pending);
130 : :
131 : : // Same but based on packet.
132 : : Connection* Instantiate(double t, HashKey* key, const IP_Hdr* ip);
133 : :
134 : : // Fills the attributes of a PendingConn based on the given arguments.
135 : : void PktHdrToPendingConn(double time, const HashKey* key,
136 : : const IP_Hdr* ip, const struct tcphdr* tp, PendingConn* c);
137 : :
138 : : // Fakes a TCP packet based on the available information.
139 : : const IP_Hdr* PendingConnToPacket(const PendingConn* c);
140 : :
141 : : // For changing the timestamp of PendingConn - allocates a new one,
142 : : // sets the given time, and copies all other data from old.
143 : : PendingConn* MoveState(double time, PendingConn* old);
144 : :
145 : : // Construct a TCP-flags byte.
146 : : uint8 MakeFlags(const PendingConn* c) const;
147 : :
148 : : // Allocate room for a new (Ext)PendingConn.
149 : : PendingConn* MakeNewState(double t);
150 : :
151 : : // Expire PendingConns.
152 : : void DoExpire(double t);
153 : :
154 : : // Remove all state belonging to the given connection.
155 : : void Invalidate(HashKey* k);
156 : :
157 : : // Sends the given connection_* event. If orig_state is
158 : : // TCP_ENDPOINT__INACTIVE, tries to guess a better one based
159 : : // on pending. If arg in non-nil, it will be used as the
160 : : // *first* argument of the event call (this is for conn_weird()).
161 : : void Event(const PendingConn* pending, double t,
162 : : const EventHandlerPtr& event, int orig_state,
163 : : int orig_size, int resp_state, Val* arg = 0);
164 : :
165 : 0 : void Weird(const PendingConn* pending, double t, const char* msg)
166 : : {
167 [ # # ]: 0 : if ( conn_weird )
168 : : Event(pending, t, conn_weird, TCP_ENDPOINT_INACTIVE, 0,
169 : 0 : TCP_ENDPOINT_INACTIVE, new StringVal(msg));
170 : : else
171 : 0 : fprintf(stderr, "%.06f weird: %s\n", t, msg);
172 : 0 : }
173 : :
174 : : static const int BLOCK_SIZE = 16 * 1024;
175 : :
176 : : // The memory managment for PendConns.
177 : : struct Block {
178 : : double time;
179 : : Block* prev;
180 : : Block* next;
181 : : int bytes_used;
182 : : unsigned char data[BLOCK_SIZE];
183 : : };
184 : :
185 : : // In the connection hash table, we store pointers to both PendingConns
186 : : // and Connections. Thus, we need a way to differentiate between
187 : : // these two types. To avoid an additional indirection, we use a little
188 : : // hack: a pointer retrieved from the table is interpreted as a
189 : : // PendingConn first. However, if is_pending is false, it's in fact a
190 : : // Connection which starts at offset 4. The methods below help to
191 : : // implement this scheme transparently. An "operator new" in
192 : : // Connection takes care of building Connection's accordingly.
193 : : typedef PendingConn ConnData;
194 [ - + ][ # # ]: 20526 : declare(PDict, ConnData);
195 : : typedef PDict(ConnData) ConnMap;
196 : : ConnMap conns;
197 : :
198 : 676 : static ConnData* MakeMapPtr(PendingConn* c)
199 [ - + ]: 676 : { assert(c->is_pending); return c; }
200 : :
201 : 938 : static ConnData* MakeMapPtr(Connection* c)
202 : : {
203 : 938 : ConnData* p = (ConnData*) (((char*) c) - 4);
204 [ - + ]: 938 : assert(!p->is_pending);
205 : 938 : return p;
206 : : }
207 : :
208 : 1043 : static PendingConn* MakePendingConnPtr(ConnData* c)
209 [ - + ]: 1043 : { assert(c->is_pending); return c; }
210 : :
211 : 17474 : static Connection* MakeConnPtr(ConnData* c)
212 : : {
213 [ - + ]: 17474 : assert(!c->is_pending);
214 : 17474 : return (Connection*) (((char*) c) + 4);
215 : : }
216 : :
217 : 18578 : static bool IsConnPtr(ConnData* c)
218 : 18578 : { return ! c->is_pending; }
219 : :
220 : : // New blocks are inserted at the end.
221 : : Block* first_block;
222 : : Block* last_block;
223 : :
224 : : // If we have already expired some entries in a block,
225 : : // this points to the first non-expired.
226 : : unsigned char* first_non_expired;
227 : :
228 : : // Last "connection" that we have build.
229 : : RecordVal* conn_val;
230 : :
231 : : // Statistics.
232 : : Sizes sizes;
233 : : };
234 : :
235 : : extern ConnCompressor* conn_compressor;
236 : :
237 : : #endif
|