/src/ec_streambuf.c

https://github.com/wertarbyte/ettercap · C · 261 lines · 108 code · 64 blank · 89 comment · 18 complexity · c2f1d5e681be406334ae4f472261766d MD5 · raw file

  1. /*
  2. ettercap -- stream buffer module
  3. Copyright (C) ALoR & NaGA
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. #include <ec.h>
  17. #include <ec_packet.h>
  18. #include <ec_streambuf.h>
  19. /* mutexes */
  20. #define STREAMBUF_INIT_LOCK(x) do{ pthread_mutex_init(&x, NULL); }while(0)
  21. #define STREAMBUF_LOCK(x) do{ pthread_mutex_lock(&x); }while(0)
  22. #define STREAMBUF_UNLOCK(x) do{ pthread_mutex_unlock(&x); }while(0)
  23. /* protos */
  24. void streambuf_init(struct stream_buf *sb);
  25. int streambuf_add(struct stream_buf *sb, struct packet_object *po);
  26. int streambuf_seq_add(struct stream_buf *sb, struct packet_object *po);
  27. int streambuf_get(struct stream_buf *sb, u_char *buf, size_t len, int mode);
  28. void streambuf_wipe(struct stream_buf *sb);
  29. int streambuf_read(struct stream_buf *sb, u_char *buf, size_t len, int mode);
  30. /************************************************/
  31. /*
  32. * initialize the buffer
  33. */
  34. void streambuf_init(struct stream_buf *sb)
  35. {
  36. //DEBUG_MSG("streambuf_init");
  37. /* init the size */
  38. sb->size = 0;
  39. /* init the tail */
  40. TAILQ_INIT(&sb->streambuf_tail);
  41. /* init the mutex */
  42. STREAMBUF_INIT_LOCK(sb->streambuf_mutex);
  43. }
  44. /*
  45. * add the packet to the stream_buf.
  46. */
  47. int streambuf_add(struct stream_buf *sb, struct packet_object *po)
  48. {
  49. struct stream_pck_list *p;
  50. SAFE_CALLOC(p, 1, sizeof(struct stream_pck_list));
  51. /* fill the struct */
  52. p->size = po->DATA.len;
  53. p->ptr = 0;
  54. /* copy the buffer */
  55. SAFE_CALLOC(p->buf, po->DATA.len, sizeof(u_char));
  56. memcpy(p->buf, po->DATA.data, po->DATA.len);
  57. STREAMBUF_LOCK(sb->streambuf_mutex);
  58. /* insert the packet in the tail */
  59. TAILQ_INSERT_TAIL(&sb->streambuf_tail, p, next);
  60. /* update the total size */
  61. sb->size += p->size;
  62. STREAMBUF_UNLOCK(sb->streambuf_mutex);
  63. return 0;
  64. }
  65. /* Insert data into the buffer only if it matches the correct
  66. * TCP sequence. It is a simple workaround used to avoid duplicated
  67. * packets in TCP streaming. If we see the same sequence twice, this
  68. * is a duplicated packet.
  69. */
  70. int streambuf_seq_add(struct stream_buf *sb, struct packet_object *po)
  71. {
  72. /* Same seq twice? a duplicated pck */
  73. if( sb->tcp_seq == po->L4.seq )
  74. return 0;
  75. sb->tcp_seq = po->L4.seq;
  76. return streambuf_add(sb, po);
  77. }
  78. /*
  79. * copies in the 'buf' the first 'len' bytes
  80. * of the stream buffer
  81. *
  82. * STREAM_ATOMIC returns an error if there is not enough
  83. * data to fill 'len' bytes in 'buf'
  84. *
  85. * STREAM_PARTIAL will fill the buffer 'buf' with the data
  86. * contained in the streambuf even if it is
  87. * less than 'len'. size is returned accordingly
  88. */
  89. int streambuf_get(struct stream_buf *sb, u_char *buf, size_t len, int mode)
  90. {
  91. struct stream_pck_list *p;
  92. struct stream_pck_list *tmp = NULL;
  93. size_t size = 0, to_copy = 0;
  94. /* check if we have enough data */
  95. if (mode == STREAM_ATOMIC && sb->size < len)
  96. return -EINVALID;
  97. STREAMBUF_LOCK(sb->streambuf_mutex);
  98. /* packets in the tail */
  99. TAILQ_FOREACH_SAFE(p, &sb->streambuf_tail, next, tmp) {
  100. /* we have copied all the needed bytes */
  101. if (size >= len)
  102. break;
  103. /* calculate the length to be copied */
  104. if (len - size < p->size)
  105. to_copy = len - size;
  106. else
  107. to_copy = p->size;
  108. if (p->ptr + to_copy > p->size)
  109. to_copy = p->size - p->ptr;
  110. /*
  111. * copy the data in the buffer
  112. * p->ptr is the pointer to last read
  113. * byte if the buffer was read partially
  114. */
  115. memcpy(buf + size, p->buf + p->ptr, to_copy);
  116. /* bytes in the buffer 'buf' */
  117. size += to_copy;
  118. /* remember how may byte we have read */
  119. p->ptr += to_copy;
  120. /* packet not completed */
  121. if (p->ptr < p->size) {
  122. break;
  123. }
  124. /* remove the entry from the tail */
  125. SAFE_FREE(p->buf);
  126. TAILQ_REMOVE(&sb->streambuf_tail, p, next);
  127. SAFE_FREE(p);
  128. }
  129. /* update the total size */
  130. sb->size -= size;
  131. STREAMBUF_UNLOCK(sb->streambuf_mutex);
  132. return size;
  133. }
  134. /* Same as streambuf_get(), but this will not erase
  135. * read data from the buffer
  136. */
  137. int streambuf_read(struct stream_buf *sb, u_char *buf, size_t len, int mode)
  138. {
  139. struct stream_pck_list *p;
  140. size_t size = 0, to_copy = 0;
  141. /* check if we have enough data */
  142. if (mode == STREAM_ATOMIC && sb->size < len)
  143. return -EINVALID;
  144. STREAMBUF_LOCK(sb->streambuf_mutex);
  145. /* packets in the tail */
  146. TAILQ_FOREACH(p, &sb->streambuf_tail, next) {
  147. /* we have copied all the needed bytes */
  148. if (size >= len)
  149. break;
  150. /* calculate the length to be copied */
  151. if (len - size < p->size)
  152. to_copy = len - size;
  153. else
  154. to_copy = p->size;
  155. if (p->ptr + to_copy > p->size)
  156. to_copy = p->size - p->ptr;
  157. /*
  158. * copy the data in the buffer
  159. * p->ptr is the pointer to last read
  160. * byte if the buffer was read partially
  161. */
  162. memcpy(buf + size, p->buf + p->ptr, to_copy);
  163. /* bytes in the buffer 'buf' */
  164. size += to_copy;
  165. /* packet not completed */
  166. if (p->ptr + to_copy < p->size) {
  167. break;
  168. }
  169. }
  170. STREAMBUF_UNLOCK(sb->streambuf_mutex);
  171. return size;
  172. }
  173. /*
  174. * empty a give buffer.
  175. * all the elements in the list are deleted
  176. */
  177. void streambuf_wipe(struct stream_buf *sb)
  178. {
  179. struct stream_pck_list *e;
  180. DEBUG_MSG("streambuf_wipe");
  181. STREAMBUF_LOCK(sb->streambuf_mutex);
  182. /* delete the list */
  183. while ((e = TAILQ_FIRST(&sb->streambuf_tail)) != TAILQ_END(&sb->streambuf_tail)) {
  184. TAILQ_REMOVE(&sb->streambuf_tail, e, next);
  185. SAFE_FREE(e->buf);
  186. SAFE_FREE(e);
  187. }
  188. /* reset the buffer */
  189. TAILQ_INIT(&sb->streambuf_tail);
  190. STREAMBUF_UNLOCK(sb->streambuf_mutex);
  191. }
  192. /* EOF */
  193. // vim:ts=3:expandtab