1 /*
2 ettercap -- session management
3
4 Copyright (C) ALoR & NaGA
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include <ec.h>
23 #include <ec_packet.h>
24 #include <ec_threads.h>
25 #include <ec_session.h>
26
27 #include <signal.h>
28
29 #define TABBIT 10 /* 2^10 bit tab entries: 1024 LISTS */
30 #define TABSIZE (1 << TABBIT)
31 #define TABMASK (TABSIZE - 1)
32
33 /* globals */
34
35 struct session_list {
36 time_t ts;
37 struct ec_session *s;
38 LIST_ENTRY (session_list) next;
39 };
40
41 /* global data */
42
43 static LIST_HEAD(, session_list) session_list_head[TABSIZE];
44
45 /* protos */
46
47 u_int32 session_hash(void *ident, size_t ilen);
48
49 static pthread_mutex_t session_mutex = PTHREAD_MUTEX_INITIALIZER;
50 #define SESSION_LOCK do{ pthread_mutex_lock(&session_mutex); } while(0)
51 #define SESSION_UNLOCK do{ pthread_mutex_unlock(&session_mutex); } while(0)
52
53 /************************************************/
54
55 /*
56 * create a session if it does not exits
57 * update a session if it already exists
58 *
59 * also check for timeouted session and remove them
60 */
61
session_put(struct ec_session * s)62 void session_put(struct ec_session *s)
63 {
64 struct session_list *sl, *tmp = NULL;
65 time_t ti = time(NULL);
66 u_int32 h;
67
68 SESSION_LOCK;
69
70 /* calculate the hash */
71 h = session_hash(s->ident, s->ident_len);
72
73 /* search if it already exist */
74 LIST_FOREACH_SAFE(sl, &session_list_head[h], next, tmp) {
75 if ( sl->s->match(sl->s->ident, s->ident) ) {
76
77 DEBUG_MSG("session_put: [%p] updated", sl->s->ident);
78 /* destroy the old session */
79 session_free(sl->s);
80 /* link the new session */
81 sl->s = s;
82 /* renew the timestamp */
83 sl->ts = ti;
84
85 SESSION_UNLOCK;
86 return;
87 }
88
89 if (sl->ts < (ti - EC_GBL_CONF->connection_timeout) ) {
90 DEBUG_MSG("session_put: [%p] timeouted", sl->s->ident);
91 session_free(sl->s);
92 LIST_REMOVE(sl, next);
93 SAFE_FREE(sl);
94 }
95 }
96
97 /* sanity check */
98 BUG_IF(s->match == NULL);
99
100 /* create the element in the list */
101 SAFE_CALLOC(sl, 1, sizeof(struct session_list));
102
103 /* the timestamp */
104 sl->ts = ti;
105
106 /* link the session */
107 sl->s = s;
108
109 DEBUG_MSG("session_put: [%p] new session", sl->s->ident);
110
111 /*
112 * put it in the head.
113 * it is likely to be retrived early
114 */
115 LIST_INSERT_HEAD(&session_list_head[h], sl, next);
116
117 SESSION_UNLOCK;
118
119 }
120
121
122 /*
123 * get the info contained in a session
124 */
125
session_get(struct ec_session ** s,void * ident,size_t ident_len)126 int session_get(struct ec_session **s, void *ident, size_t ident_len)
127 {
128 struct session_list *sl;
129 time_t ti = time(NULL);
130 u_int32 h;
131
132 SESSION_LOCK;
133
134 /* calculate the hash */
135 h = session_hash(ident, ident_len);
136
137 /* search if it already exist */
138 LIST_FOREACH(sl, &session_list_head[h], next) {
139 if ( sl->s->match(sl->s->ident, ident) ) {
140
141 //DEBUG_MSG("session_get: [%p]", sl->s->ident);
142 /* return the session */
143 *s = sl->s;
144
145 /* renew the timestamp */
146 sl->ts = ti;
147
148 SESSION_UNLOCK;
149 return E_SUCCESS;
150 }
151 }
152
153 SESSION_UNLOCK;
154
155 return -E_NOTFOUND;
156 }
157
158
159 /*
160 * delete a session
161 */
162
session_del(void * ident,size_t ident_len)163 int session_del(void *ident, size_t ident_len)
164 {
165 struct session_list *sl;
166 u_int32 h;
167
168 SESSION_LOCK;
169
170 /* calculate the hash */
171 h = session_hash(ident, ident_len);
172
173 /* search if it already exist */
174 LIST_FOREACH(sl, &session_list_head[h], next) {
175 if ( sl->s->match(sl->s->ident, ident) ) {
176
177 DEBUG_MSG("session_del: [%p]", sl->s->ident);
178
179 /* free the session */
180 session_free(sl->s);
181 /* remove the element in the list */
182 LIST_REMOVE(sl, next);
183 /* free the element in the list */
184 SAFE_FREE(sl);
185
186 SESSION_UNLOCK;
187 return E_SUCCESS;
188 }
189 }
190
191 SESSION_UNLOCK;
192
193 return -E_NOTFOUND;
194 }
195
196
197 /*
198 * get the info and delete the session
199 * atomic operations
200 */
201
session_get_and_del(struct ec_session ** s,void * ident,size_t ident_len)202 int session_get_and_del(struct ec_session **s, void *ident, size_t ident_len)
203 {
204 struct session_list *sl;
205 u_int32 h;
206
207 SESSION_LOCK;
208
209 /* calculate the hash */
210 h = session_hash(ident, ident_len);
211
212 /* search if it already exist */
213 LIST_FOREACH(sl, &session_list_head[h], next) {
214 if ( sl->s->match(sl->s->ident, ident) ) {
215
216 DEBUG_MSG("session_get_and_del: [%p]", sl->s->ident);
217
218 /* return the session */
219 *s = sl->s;
220 /* remove the element in the list */
221 LIST_REMOVE(sl, next);
222 /* free the element in the list */
223 SAFE_FREE(sl);
224
225 SESSION_UNLOCK;
226 return E_SUCCESS;
227 }
228 }
229
230 SESSION_UNLOCK;
231
232 return -E_NOTFOUND;
233 }
234
235 /*
236 * free a session structure
237 */
238
session_free(struct ec_session * s)239 void session_free(struct ec_session *s)
240 {
241 DEBUG_MSG("session_free: [%p] deleted", s->ident);
242 SAFE_FREE(s->ident);
243 /* call the cleanup function to free pointers in the data portion */
244 if (s->free)
245 s->free(s->data, s->data_len);
246 /* data is free'd here, don't free it in the s->free function */
247 SAFE_FREE(s->data);
248 SAFE_FREE(s);
249 }
250
251 /*
252 * calculate the hash for an ident.
253 * use a IP-like checksum so if some word will be exchanged
254 * the hash will be the same. it is useful for dissectors
255 * to find the same session if the packet is goint to the
256 * server or to the client.
257 */
session_hash(void * ident,size_t ilen)258 u_int32 session_hash(void *ident, size_t ilen)
259 {
260 u_int32 hash = 0;
261 u_int16 *buf = (u_int16 *)ident;
262
263 while(ilen > 1) {
264 hash += *buf++;
265 ilen -= sizeof(u_int16);
266 }
267
268 if (ilen == 1)
269 hash += htons(*(u_char *)buf << 8);
270
271 hash = (hash >> 16) + (hash & 0xffff);
272 hash += (hash >> 16);
273
274 /* the hash must be within the TABSIZE */
275 return (u_int16)(~hash) & TABMASK;
276 }
277
278 /* EOF */
279
280 // vim:ts=3:expandtab
281
282