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