1 /*
2     ettercap -- connection list handling module
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_threads.h>
24 #include <ec_packet.h>
25 #include <ec_proto.h>
26 #include <ec_hook.h>
27 #include <ec_conntrack.h>
28 #include <ec_hash.h>
29 #include <ec_sleep.h>
30 #include <ec_geoip.h>
31 
32 /* globals */
33 
34 /* the hash table used to index the tailq */
35 struct conn_hash_search {
36    struct conn_tail *cl;
37    LIST_ENTRY(conn_hash_search) next;
38 };
39 
40 #define TABBIT    10             /* 2^10 bit tab entries: 1024 LISTS */
41 #define TABSIZE   (1 << TABBIT)
42 #define TABMASK   (TABSIZE - 1)
43 
44 /*
45  * the connection list.
46  * this list is created adding new element in the tail.
47  * the search method is established in the search function.
48  * an hash table is used and it is double-linked with the
49  * tailq so from each element you can delete the corresponding
50  * in the tailq or viceversa
51  */
52 static TAILQ_HEAD(conn_head, conn_tail) conntrack_tail_head = TAILQ_HEAD_INITIALIZER(conntrack_tail_head);
53 static LIST_HEAD(, conn_hash_search) conntrack_search_head[TABSIZE];
54 
55 /* global mutex on connections list */
56 
57 static pthread_mutex_t conntrack_mutex = PTHREAD_MUTEX_INITIALIZER;
58 #define CONNTRACK_LOCK     do{ pthread_mutex_lock(&conntrack_mutex); }while(0)
59 #define CONNTRACK_UNLOCK   do{ pthread_mutex_unlock(&conntrack_mutex); }while(0)
60 
61 /* protos */
62 
63 void __init conntrack_init(void);
64 
65 static void conntrack_parse(struct packet_object *po);
66 static u_int32 conntrack_hash(struct packet_object *po);
67 static struct conn_object *conntrack_search(struct packet_object *po);
68 static void conntrack_update(struct conn_object *co, struct packet_object *po);
69 static void conntrack_add(struct packet_object *po);
70 static void conntrack_del(struct conn_object *co);
71 static int conntrack_match(struct conn_object *co, struct packet_object *po);
72 void conntrack_hook(struct conn_object *co, struct packet_object *po);
73 
74 /************************************************/
75 
76 /*
77  * add the hook function
78  */
conntrack_init(void)79 void __init conntrack_init(void)
80 {
81    /* receive all the top half packets */
82    hook_add(HOOK_DISPATCHER, &conntrack_parse);
83 }
84 
85 /*
86  * the conntrack main()
87  */
conntrack_parse(struct packet_object * po)88 static void conntrack_parse(struct packet_object *po)
89 {
90    struct conn_object *conn;
91 
92    CONNTRACK_LOCK;
93 
94    /* search if the connection already exists */
95    conn = conntrack_search(po);
96 
97    /* update if it was found, else add to the list */
98    if (conn)
99       conntrack_update(conn, po);
100    else
101       conntrack_add(po);
102 
103    CONNTRACK_UNLOCK;
104 }
105 
106 /*
107  * calculate the hash for a packet object
108  */
conntrack_hash(struct packet_object * po)109 static u_int32 conntrack_hash(struct packet_object *po)
110 {
111    u_int32 hash_array[3];
112 
113    /*
114     * put them in an array and then compute the hash on the array.
115     * use XOR on src and dst because the hash must be equal for
116     * packets from dst to src and viceversa
117     */
118    hash_array[0] = fnv_32((u_char *)&po->L3.src, sizeof(struct ip_addr)) ^
119                    fnv_32((u_char *)&po->L3.dst, sizeof(struct ip_addr));
120    hash_array[1] = po->L4.src ^ po->L4.dst;
121    hash_array[2] = po->L4.proto;
122 
123    /* compute the resulting hash */
124    return fnv_32((u_char *)&hash_array, sizeof(hash_array)) & TABMASK;
125 }
126 
127 /*
128  * search the connection in the connection table
129  * and return the pointer.
130  */
conntrack_search(struct packet_object * po)131 static struct conn_object *conntrack_search(struct packet_object *po)
132 {
133    struct conn_hash_search *cs;
134    u_int32 h;
135 
136    /* use the hash table to find the connection in the tailq */
137    h = conntrack_hash(po);
138 
139    LIST_FOREACH(cs, &conntrack_search_head[h], next) {
140       if (conntrack_match(cs->cl->co, po) == E_SUCCESS) {
141          return cs->cl->co;
142       }
143    }
144 
145    return NULL;
146 #if 0
147    struct conn_tail *cl;
148 
149    /* search in the list sequentially */
150    TAILQ_FOREACH(cl, &conntrack_tail_head, next) {
151       if (conntrack_match(cl->co, po) == E_SUCCESS) {
152          return cl->co;
153       }
154    }
155 
156    return NULL;
157 #endif
158 }
159 
160 
161 /*
162  * update the variable parameters in the connection struct.
163  * the status, the buffer and the timestamp will be updated
164  */
conntrack_update(struct conn_object * co,struct packet_object * po)165 static void conntrack_update(struct conn_object *co, struct packet_object *po)
166 {
167    /* update the timestamp */
168    gettimeofday(&co->ts, 0);
169 
170    /* update the status for TCP conn */
171    if (po->L4.flags & TH_SYN)
172       co->status = CONN_OPENING;
173    else if (po->L4.flags & TH_FIN)
174       co->status = CONN_CLOSING;
175    else if (po->L4.flags & TH_ACK) {
176       /* syn + ack,  ack */
177       if (co->status == CONN_OPENING )
178          co->status = CONN_OPEN;
179       /* fin + ack,  ack */
180       else if (co->status == CONN_CLOSING)
181          co->status = CONN_CLOSED;
182    }
183 
184    if (po->L4.flags & TH_PSH)
185       co->status = CONN_ACTIVE;
186 
187    if (po->L4.flags & TH_RST)
188       co->status = CONN_KILLED;
189 
190    /* update the buffer */
191    connbuf_add(&co->data, po);
192 
193 
194    /* update the status for UDP conn */
195    if (po->L4.proto == NL_TYPE_UDP)
196       co->status = CONN_ACTIVE;
197 
198    /*
199     * update the byte count
200     * use DATA.len and not DATA.disp_len to have an
201     * effective count of byte trasferred, disp_data
202     * may be longer or shorted than DATA.data
203     */
204    co->xferred += po->DATA.len;
205    if(!ip_addr_cmp(&co->L3_addr1, &po->L3.src))
206       co->tx += po->DATA.len;
207    else
208       co->rx += po->DATA.len;
209 
210    /*
211     * update the flags:
212     * if the packet was modified or dropped, the connection
213     * must be marked as well.
214     */
215    if (po->flags & PO_MODIFIED || po->flags & PO_DROPPED)
216       co->flags |= CONN_MODIFIED;
217 
218    /*
219     * update the password
220     * always overwrite the old one, a better one may
221     * has been collected...
222     */
223    if (po->DISSECTOR.user) {
224       SAFE_FREE(co->DISSECTOR.user);
225       SAFE_FREE(co->DISSECTOR.pass);
226       SAFE_FREE(co->DISSECTOR.info);
227       co->DISSECTOR.user = strdup(po->DISSECTOR.user);
228       if (po->DISSECTOR.pass)
229          co->DISSECTOR.pass = strdup(po->DISSECTOR.pass);
230       if (po->DISSECTOR.info)
231          co->DISSECTOR.info = strdup(po->DISSECTOR.info);
232    }
233 
234    /* execute the hookpoint */
235    conntrack_hook(co, po);
236 }
237 
238 
239 /*
240  * create a new entry in the tail
241  */
conntrack_add(struct packet_object * po)242 static void conntrack_add(struct packet_object *po)
243 {
244    struct conn_tail *cl;
245    struct conn_hash_search *cs;
246 
247    DEBUG_MSG("conntrack_add: NEW CONNECTION");
248 
249    /* alloc the list element */
250    SAFE_CALLOC(cl, 1, sizeof(struct conn_tail));
251 
252    /* alloc the conn object in the element */
253    SAFE_CALLOC(cl->co, 1, sizeof(struct conn_object));
254 
255    /*
256     * here we create the connection.
257     * this is the first packet seen...
258     * addr1 will be the source and addr2 the dest
259     */
260 
261    /* fill the addresses */
262    memcpy(&cl->co->L2_addr1, &po->L2.src, MEDIA_ADDR_LEN);
263    memcpy(&cl->co->L2_addr2, &po->L2.dst, MEDIA_ADDR_LEN);
264 
265    memcpy(&cl->co->L3_addr1, &po->L3.src, sizeof(struct ip_addr));
266    memcpy(&cl->co->L3_addr2, &po->L3.dst, sizeof(struct ip_addr));
267 
268    /* copy the port */
269    cl->co->L4_addr1 = po->L4.src;
270    cl->co->L4_addr2 = po->L4.dst;
271    cl->co->L4_proto = po->L4.proto;
272 
273    /* initialize the connection buffer */
274    connbuf_init(&cl->co->data, EC_GBL_CONF->connection_buffer);
275 
276    /* update the connection entry */
277    conntrack_update(cl->co, po);
278 
279    /* alloc the hash table element */
280    SAFE_CALLOC(cs, 1, sizeof(struct conn_hash_search));
281 
282    /* set the pointer to the list */
283    cs->cl = cl;
284 
285    /*
286     * set the pointer to the element in the hash table
287     * it is used when a connection is deleted because
288     * even the element in the hash table must be deleted
289     */
290    cl->cs = cs;
291 
292    /* insert the new connection in the tail */
293    TAILQ_INSERT_TAIL(&conntrack_tail_head, cl, next);
294    /* insert the new connection in the tail */
295    LIST_INSERT_HEAD(&conntrack_search_head[conntrack_hash(po)], cs, next);
296 }
297 
298 /*
299  * is the packet object belonging to this connection ?
300  */
conntrack_match(struct conn_object * co,struct packet_object * po)301 static int conntrack_match(struct conn_object *co, struct packet_object *po)
302 {
303    /* different protocol, they don't match */
304    if (co->L4_proto != po->L4.proto)
305       return -E_INVALID;
306 
307    /* match it in one way... */
308    if (!ip_addr_cmp(&co->L3_addr1, &po->L3.src) &&
309        !ip_addr_cmp(&co->L3_addr2, &po->L3.dst) &&
310        co->L4_addr1 == po->L4.src &&
311        co->L4_addr2 == po->L4.dst)
312       return E_SUCCESS;
313 
314    /* ...and in the other */
315    if (!ip_addr_cmp(&co->L3_addr1, &po->L3.dst) &&
316        !ip_addr_cmp(&co->L3_addr2, &po->L3.src) &&
317        co->L4_addr1 == po->L4.dst &&
318        co->L4_addr2 == po->L4.src)
319       return E_SUCCESS;
320 
321    return -E_NOMATCH;
322 }
323 
324 /*
325  * erase a connection object
326  */
conntrack_del(struct conn_object * co)327 static void conntrack_del(struct conn_object *co)
328 {
329    struct ct_hook_list *h, *tmp;
330 
331    /* remove the hooks */
332    SLIST_FOREACH_SAFE(h, &co->hook_head, next, tmp) {
333       SLIST_REMOVE(&co->hook_head, h, ct_hook_list, next);
334       SAFE_FREE(h);
335    }
336 
337    /* wipe the associated buffer */
338    connbuf_wipe(&co->data);
339 
340    SAFE_FREE(co);
341 }
342 
343 /*
344  * erase the whole connections list
345  */
conntrack_purge(void)346 void conntrack_purge(void)
347 {
348    struct conn_tail *cl, *tmp;
349 
350    DEBUG_MSG("conntrack_purge");
351 
352    TAILQ_FOREACH_SAFE(cl, &conntrack_tail_head, next, tmp) {
353       /* don't erase the connection if it is viewed */
354       if (cl->co->flags & CONN_VIEWING)
355          continue;
356 
357       CONNTRACK_LOCK;
358 
359       /* wipe the connection */
360       conntrack_del(cl->co);
361       /* remove the element in the hash table */
362       LIST_REMOVE(cl->cs, next);
363       SAFE_FREE(cl->cs);
364       /* remove the element in the tailq */
365       TAILQ_REMOVE(&conntrack_tail_head, cl, next);
366       SAFE_FREE(cl);
367 
368       CONNTRACK_UNLOCK;
369    }
370 
371 }
372 
373 
EC_THREAD_FUNC(conntrack_timeouter)374 EC_THREAD_FUNC(conntrack_timeouter)
375 {
376    struct timeval ts;
377    struct timeval diff;
378    struct conn_tail *cl;
379    struct conn_tail *tmp = NULL;
380    size_t sec;
381 
382    /* variable not used */
383    (void) EC_THREAD_PARAM;
384 
385    /* initialize the thread */
386    ec_thread_init();
387 
388    DEBUG_MSG("conntrack_timeouter: activated !");
389 
390    LOOP {
391 
392       /*
393        * sleep for the maximum time possible
394        * (determined as the minumum of the timeouts)
395        */
396       sec = MIN(EC_GBL_CONF->connection_idle, EC_GBL_CONF->connection_timeout);
397 
398       DEBUG_MSG("conntrack_timeouter: sleeping for %lu sec", (unsigned long)sec);
399 
400       /* always check if a cancel is requested */
401       CANCELLATION_POINT();
402 
403       ec_usleep(SEC2MICRO(sec));
404 
405       DEBUG_MSG("conntrack_timeouter: woke up");
406 
407       /* get current time */
408       gettimeofday(&ts, NULL);
409 
410       /*
411        * the timeouter is the only thread that erase a connection
412        * so we are sure that the list will be consistent till the
413        * end.
414        * we can lock and unlock every time we handle an element of
415        * the list to permit the conntrack functions to operate on the
416        * list even when timeouter goes thru the list
417        */
418       TAILQ_FOREACH_SAFE(cl, &conntrack_tail_head, next, tmp) {
419 
420          /* don't erase the connection if it is viewed */
421          if (cl->co->flags & CONN_VIEWING)
422             continue;
423 
424          CONNTRACK_LOCK;
425 
426          /* calculate the difference */
427          time_sub(&ts, &cl->co->ts, &diff);
428 
429          /*
430           * update it only if the staus is active,
431           * all the other status must be left as they are
432           */
433          if (cl->co->status == CONN_ACTIVE && diff.tv_sec >= EC_GBL_CONF->connection_idle)
434             cl->co->status = CONN_IDLE;
435 
436          /* delete the timeouted connections */
437          if (diff.tv_sec >= EC_GBL_CONF->connection_timeout) {
438             /* wipe the connection */
439             conntrack_del(cl->co);
440             /* remove the element in the hash table */
441             LIST_REMOVE(cl->cs, next);
442             SAFE_FREE(cl->cs);
443             /* remove the element in the tailq */
444             TAILQ_REMOVE(&conntrack_tail_head, cl, next);
445             SAFE_FREE(cl);
446          }
447 
448          CONNTRACK_UNLOCK;
449 
450          CANCELLATION_POINT();
451       }
452    }
453 
454    return NULL;
455 }
456 
457 
458 /*
459  * add the fucntion 'func' to the hookpoint of the
460  * connection owning the packet object
461  */
conntrack_hook_packet_add(struct packet_object * po,void (* func)(struct packet_object * po))462 int conntrack_hook_packet_add(struct packet_object *po, void (*func)(struct packet_object *po))
463 {
464    struct conn_object *conn;
465 
466    CONNTRACK_LOCK;
467 
468    /* search the connection already exists */
469    conn = conntrack_search(po);
470 
471    /*
472     * if the connection already exist, add the hook function
473     * else create the entry for the connection and add the hook
474     * this is useful to add hooks for future connections
475     */
476 
477    /* create the fake connection */
478    if (!conn) {
479 
480       DEBUG_MSG("conntrack_hook_packet_add: ephemeral connection");
481       conntrack_add(po);
482       conn = conntrack_search(po);
483    }
484 
485    /* add the hook point */
486    if (conn) {
487       struct ct_hook_list *h;
488 
489       DEBUG_MSG("conntrack_hook_packet_add: existing connection");
490 
491       SAFE_CALLOC(h, 1, sizeof(struct ct_hook_list));
492 
493       /* set the hook function */
494       h->func = func;
495 
496       SLIST_INSERT_HEAD(&conn->hook_head, h, next);
497 
498       CONNTRACK_UNLOCK;
499       return E_SUCCESS;
500    }
501 
502    CONNTRACK_UNLOCK;
503 
504    return -E_NOTFOUND;
505 }
506 
507 
508 /*
509  * removes a hook from a connection
510  */
conntrack_hook_packet_del(struct packet_object * po,void (* func)(struct packet_object * po))511 int conntrack_hook_packet_del(struct packet_object *po, void (*func)(struct packet_object *po))
512 {
513    struct conn_object *conn;
514 
515    DEBUG_MSG("conntrack_hook_packet_del");
516 
517    CONNTRACK_LOCK;
518 
519    /* search the connection already exists */
520    conn = conntrack_search(po);
521 
522    /* remove the hook function only if the connection exists */
523    if (conn) {
524       struct ct_hook_list *h;
525 
526       SLIST_FOREACH(h, &conn->hook_head, next) {
527          if (h->func == func) {
528             SLIST_REMOVE(&conn->hook_head, h, ct_hook_list, next);
529             SAFE_FREE(h);
530             break;
531          }
532       }
533 
534       CONNTRACK_UNLOCK;
535       return E_SUCCESS;
536    }
537 
538    CONNTRACK_UNLOCK;
539 
540    return -E_NOTFOUND;
541 }
542 
543 /*
544  * add the fucntion 'func' to the hookpoint of the
545  * connection 'co'
546  */
conntrack_hook_conn_add(struct conn_object * co,void (* func)(struct packet_object * po))547 int conntrack_hook_conn_add(struct conn_object *co, void (*func)(struct packet_object *po))
548 {
549    struct ct_hook_list *h;
550 
551    CONNTRACK_LOCK;
552 
553    /* add the hook point */
554 
555    DEBUG_MSG("conntrack_hook_conn_add");
556 
557    SAFE_CALLOC(h, 1, sizeof(struct ct_hook_list));
558 
559    /* set the hook function */
560    h->func = func;
561 
562    SLIST_INSERT_HEAD(&co->hook_head, h, next);
563 
564    CONNTRACK_UNLOCK;
565 
566    return E_SUCCESS;
567 }
568 
569 
570 /*
571  * removes a hook from a connection
572  */
conntrack_hook_conn_del(struct conn_object * co,void (* func)(struct packet_object * po))573 int conntrack_hook_conn_del(struct conn_object *co, void (*func)(struct packet_object *po))
574 {
575    struct ct_hook_list *h;
576 
577    DEBUG_MSG("conntrack_hook_conn_del");
578 
579    CONNTRACK_LOCK;
580 
581    SLIST_FOREACH(h, &co->hook_head, next) {
582       if (h->func == func) {
583          SLIST_REMOVE(&co->hook_head, h, ct_hook_list, next);
584          SAFE_FREE(h);
585          break;
586       }
587    }
588 
589    CONNTRACK_UNLOCK;
590    return E_SUCCESS;
591 }
592 
593 
594 /*
595  * executes the hook point
596  */
conntrack_hook(struct conn_object * co,struct packet_object * po)597 void conntrack_hook(struct conn_object *co, struct packet_object *po)
598 {
599    struct ct_hook_list *h;
600 
601    /* pass the po to all the hooked functions */
602    SLIST_FOREACH(h, &co->hook_head, next) {
603       h->func(po);
604    }
605 
606 }
607 
608 /*
609  * fill the desc and return the next/prev element
610  */
conntrack_print(int mode,void * list,char ** desc,size_t len)611 void * conntrack_print(int mode, void *list, char **desc, size_t len)
612 {
613    struct conn_tail *c = (struct conn_tail *)list;
614    struct conn_tail *cl;
615    char src[MAX_ASCII_ADDR_LEN];
616    char dst[MAX_ASCII_ADDR_LEN];
617    char proto[2], status[8], flags[2];
618 #ifdef HAVE_GEOIP
619    size_t slen;
620 #endif
621 
622    /* NULL is used to retrieve the first element */
623    if (list == NULL)
624       return TAILQ_FIRST(&conntrack_tail_head);
625 
626    /* the caller wants the description */
627    if (desc != NULL) {
628 
629       /* IP address to string */
630       ip_addr_ntoa(&c->co->L3_addr1, src);
631       ip_addr_ntoa(&c->co->L3_addr2, dst);
632 
633       /* determine the protocol */
634       conntrack_protostr(c->co, proto, sizeof(proto));
635 
636       /* determine the status */
637       conntrack_statusstr(c->co, status, sizeof(status));
638 
639       /* determine the flags */
640       conntrack_flagstr(c->co, flags, sizeof(flags));
641 
642       snprintf(*desc, len, "%1s %15s:%-5d - %15s:%-5d %1s %s TX: %lu RX: %lu",
643             flags, src, ntohs(c->co->L4_addr1), dst, ntohs(c->co->L4_addr2),
644             proto, status, (unsigned long)c->co->tx, (unsigned long)c->co->rx);
645 
646 #ifdef HAVE_GEOIP
647       /* determine current string length */
648       slen = strlen(*desc);
649 
650       /* check if enough space is available to append the GeoIP info */
651       if (len - slen > 14 && EC_GBL_CONF->geoip_support_enable) {
652          snprintf(*desc + slen, len - slen, ", CC: %2s > %2s",
653                geoip_ccode_by_ip(&c->co->L3_addr1),
654                geoip_ccode_by_ip(&c->co->L3_addr2));
655       }
656 #endif
657    }
658 
659    /* return the next/prev/current to the caller */
660    switch (mode) {
661       case -1:
662          return TAILQ_PREV(c, conn_head, next);
663          break;
664       case +1:
665          return TAILQ_NEXT(c, next);
666          break;
667       case 0:
668          /* if exists in the list, return it */
669          TAILQ_FOREACH(cl, &conntrack_tail_head, next) {
670             if (cl == c)
671                return c;
672          }
673          /* else, return NULL */
674          return NULL;
675       default:
676          return list;
677          break;
678    }
679 
680    return NULL;
681 }
682 
683 /*
684  * copy the connection object pointer to conn and return the next/prev element
685  */
conntrack_get(int mode,void * list,struct conn_object ** conn)686 void * conntrack_get(int mode, void *list, struct conn_object **conn)
687 {
688    struct conn_tail *c = (struct conn_tail *)list;
689    struct conn_tail *cl;
690 
691    /* NULL is used to retrieve the first element */
692    if (list == NULL)
693       return TAILQ_FIRST(&conntrack_tail_head);
694 
695    /* the caller wants the connection object */
696    if (conn != NULL)
697        *conn = c->co;
698 
699    /* return the next/prev/current to the caller */
700    switch (mode) {
701       case -1:
702          return TAILQ_PREV(c, conn_head, next);
703          break;
704       case +1:
705          return TAILQ_NEXT(c, next);
706          break;
707       case 0:
708          /* if exists in the list, return it */
709          TAILQ_FOREACH(cl, &conntrack_tail_head, next) {
710             if (cl == c)
711                return c;
712          }
713          /* else, return NULL */
714          return NULL;
715       default:
716          return list;
717          break;
718    }
719 
720    return NULL;
721 }
722 
723 
724 /*
725  * copies the protocol string of a given connection object into pstr
726  * E_SUCCESS is returned on success
727  * -E_INVALID is returned if parameters are not initialized
728  */
conntrack_protostr(struct conn_object * conn,char * pstr,int len)729 int conntrack_protostr(struct conn_object *conn, char *pstr, int len)
730 {
731     if (pstr == NULL || conn == NULL)
732         return -E_INVALID;
733 
734     memset(pstr, 0, len);
735 
736     switch (conn->L4_proto) {
737         case NL_TYPE_UDP:
738            strncpy(pstr, "UDP", len - 1);
739            break;
740         case NL_TYPE_TCP:
741            strncpy(pstr, "TCP", len - 1);
742            break;
743         default:
744            strncpy(pstr, "   ", len - 1);
745     }
746 
747     return E_SUCCESS;
748 }
749 
750 /*
751  * copies the flags string of a given connection object into pstr
752  * E_SUCCESS is returned on success
753  * -E_INVALID is returned if parameters are not initialized
754  */
conntrack_flagstr(struct conn_object * conn,char * pstr,int len)755 int conntrack_flagstr(struct conn_object *conn, char *pstr, int len)
756 {
757     if (pstr == NULL || conn == NULL)
758         return -E_INVALID;
759 
760     memset(pstr, 0, len);
761 
762     /*
763      * account collection has precedence over injection/modification
764      */
765     if (conn->flags & CONN_MODIFIED)
766         strncpy(pstr, "M", len - 1);
767 
768     if (conn->flags & CONN_INJECTED)
769         strncpy(pstr, "I", len - 1);
770 
771     if (conn->DISSECTOR.user)
772         strncpy(pstr, "*", len - 1);
773 
774     return E_SUCCESS;
775 }
776 
777 
778 /*
779  * copies the status string of a given connection object into pstr
780  * E_SUCCESS is returned on success
781  * -E_INVALID is returned if parameters are not initialized
782  */
conntrack_statusstr(struct conn_object * conn,char * pstr,int len)783 int conntrack_statusstr(struct conn_object *conn, char *pstr, int len)
784 {
785     if (pstr == NULL || conn == NULL)
786         return -E_INVALID;
787 
788     memset(pstr, 0, len);
789 
790     /* determine the status */
791     switch (conn->status) {
792         case CONN_IDLE:
793            strncpy(pstr, "idle   ", len - 1);
794            break;
795         case CONN_OPENING:
796            strncpy(pstr, "opening", len - 1);
797            break;
798         case CONN_OPEN:
799            strncpy(pstr, "open   ", len - 1);
800            break;
801         case CONN_ACTIVE:
802            strncpy(pstr, "active ", len - 1);
803            break;
804         case CONN_CLOSING:
805            strncpy(pstr, "closing", len - 1);
806            break;
807         case CONN_CLOSED:
808            strncpy(pstr, "closed ", len - 1);
809            break;
810         case CONN_KILLED:
811            strncpy(pstr, "killed ", len - 1);
812            break;
813     }
814 
815     return E_SUCCESS;
816 }
817 
818 /*
819  * copies the country codes of a given connection object into pstr
820  * E_SUCCESS is returned on success
821  * -E_INVALID is returned if parameters are not initialized
822  * -E_INITFAIL if geoip API is not initialized properly
823  */
conntrack_countrystr(struct conn_object * conn,char * pstr,int len)824 int conntrack_countrystr(struct conn_object *conn, char *pstr, int len)
825 {
826 #ifdef HAVE_GEOIP
827    const char *ccode_src, *ccode_dst = NULL;
828 #endif
829 
830    if (pstr == NULL || conn == NULL || len < 8)
831       return -E_INVALID;
832 
833 #ifdef HAVE_GEOIP
834    if (!EC_GBL_CONF->geoip_support_enable)
835       return -E_INITFAIL;
836 
837    if ((ccode_src = geoip_ccode_by_ip(&conn->L3_addr1)) == NULL)
838       return -E_INITFAIL;
839 
840    if ((ccode_dst = geoip_ccode_by_ip(&conn->L3_addr2)) == NULL)
841       return -E_INITFAIL;
842 
843    snprintf(pstr, len, "%2s > %2s", ccode_src, ccode_dst);
844 #endif
845 
846    return E_SUCCESS;
847 }
848 
849 /* EOF */
850 
851 // vim:ts=3:expandtab
852 
853